OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2011 The Android Open Source Project | 2 * Copyright 2011 The Android Open Source Project |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkBitmap.h" | 8 #include "SkBitmap.h" |
9 #include "SkBlurImageFilter.h" | 9 #include "SkBlurImageFilter.h" |
10 #include "SkColorPriv.h" | 10 #include "SkColorPriv.h" |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
75 SkIPoint srcOffset = SkIPoint::Make(0, 0); | 75 SkIPoint srcOffset = SkIPoint::Make(0, 0); |
76 if (!this->filterInput(0, proxy, source, ctx, &src, &srcOffset)) { | 76 if (!this->filterInput(0, proxy, source, ctx, &src, &srcOffset)) { |
77 return false; | 77 return false; |
78 } | 78 } |
79 | 79 |
80 if (src.colorType() != kN32_SkColorType) { | 80 if (src.colorType() != kN32_SkColorType) { |
81 return false; | 81 return false; |
82 } | 82 } |
83 | 83 |
84 SkIRect srcBounds, dstBounds; | 84 SkIRect srcBounds, dstBounds; |
85 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &srcBounds, &src)) { | 85 if (!this->applyCropRect(ctx, src, srcOffset, &dstBounds, &srcBounds)) { |
86 return false; | 86 return false; |
87 } | 87 } |
88 | 88 |
89 SkAutoLockPixels alp(src); | 89 SkAutoLockPixels alp(src); |
90 if (!src.getPixels()) { | 90 if (!src.getPixels()) { |
91 return false; | 91 return false; |
92 } | 92 } |
93 | 93 |
94 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(srcBounds.width(), src
Bounds.height())); | 94 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(dstBounds.width(), dst
Bounds.height())); |
95 if (!device) { | 95 if (!device) { |
96 return false; | 96 return false; |
97 } | 97 } |
98 *dst = device->accessBitmap(false); | 98 *dst = device->accessBitmap(false); |
99 SkAutoLockPixels alp_dst(*dst); | 99 SkAutoLockPixels alp_dst(*dst); |
100 dst->getBounds(&dstBounds); | |
101 | 100 |
102 SkVector sigma = mapSigma(fSigma, ctx.ctm()); | 101 SkVector sigma = mapSigma(fSigma, ctx.ctm()); |
103 | 102 |
104 int kernelSizeX, kernelSizeX3, lowOffsetX, highOffsetX; | 103 int kernelSizeX, kernelSizeX3, lowOffsetX, highOffsetX; |
105 int kernelSizeY, kernelSizeY3, lowOffsetY, highOffsetY; | 104 int kernelSizeY, kernelSizeY3, lowOffsetY, highOffsetY; |
106 getBox3Params(sigma.x(), &kernelSizeX, &kernelSizeX3, &lowOffsetX, &highOffs
etX); | 105 getBox3Params(sigma.x(), &kernelSizeX, &kernelSizeX3, &lowOffsetX, &highOffs
etX); |
107 getBox3Params(sigma.y(), &kernelSizeY, &kernelSizeY3, &lowOffsetY, &highOffs
etY); | 106 getBox3Params(sigma.y(), &kernelSizeY, &kernelSizeY3, &lowOffsetY, &highOffs
etY); |
108 | 107 |
109 if (kernelSizeX < 0 || kernelSizeY < 0) { | 108 if (kernelSizeX < 0 || kernelSizeY < 0) { |
110 return false; | 109 return false; |
111 } | 110 } |
112 | 111 |
113 if (kernelSizeX == 0 && kernelSizeY == 0) { | 112 if (kernelSizeX == 0 && kernelSizeY == 0) { |
114 src.copyTo(dst, dst->colorType()); | 113 src.copyTo(dst, dst->colorType()); |
115 offset->fX = srcBounds.fLeft; | 114 offset->fX = dstBounds.x() + srcOffset.x(); |
116 offset->fY = srcBounds.fTop; | 115 offset->fY = dstBounds.y() + srcOffset.y(); |
117 return true; | 116 return true; |
118 } | 117 } |
119 | 118 |
120 SkAutoTUnref<SkBaseDevice> tempDevice(proxy->createDevice(dst->width(), dst-
>height())); | 119 SkAutoTUnref<SkBaseDevice> tempDevice(proxy->createDevice(dst->width(), dst-
>height())); |
121 if (!tempDevice) { | 120 if (!tempDevice) { |
122 return false; | 121 return false; |
123 } | 122 } |
124 SkBitmap temp = tempDevice->accessBitmap(false); | 123 SkBitmap temp = tempDevice->accessBitmap(false); |
125 SkAutoLockPixels alpTemp(temp); | 124 SkAutoLockPixels alpTemp(temp); |
126 | 125 |
127 offset->fX = srcBounds.fLeft; | 126 offset->fX = dstBounds.fLeft; |
128 offset->fY = srcBounds.fTop; | 127 offset->fY = dstBounds.fTop; |
129 srcBounds.offset(-srcOffset); | |
130 const SkPMColor* s = src.getAddr32(srcBounds.left(), srcBounds.top()); | |
131 SkPMColor* t = temp.getAddr32(0, 0); | 128 SkPMColor* t = temp.getAddr32(0, 0); |
132 SkPMColor* d = dst->getAddr32(0, 0); | 129 SkPMColor* d = dst->getAddr32(0, 0); |
133 int w = dstBounds.width(), h = dstBounds.height(); | 130 int w = dstBounds.width(), h = dstBounds.height(); |
| 131 const SkPMColor* s = src.getAddr32(srcBounds.x() - srcOffset.x(), srcBounds.
y() - srcOffset.y()); |
| 132 srcBounds.offset(-dstBounds.x(), -dstBounds.y()); |
| 133 dstBounds.offset(-dstBounds.x(), -dstBounds.y()); |
| 134 SkIRect srcBoundsT = SkIRect::MakeLTRB(srcBounds.top(), srcBounds.left(), sr
cBounds.bottom(), srcBounds.right()); |
| 135 SkIRect dstBoundsT = SkIRect::MakeWH(dstBounds.height(), dstBounds.width()); |
134 int sw = src.rowBytesAsPixels(); | 136 int sw = src.rowBytesAsPixels(); |
135 | 137 |
136 /** | 138 /** |
137 * | 139 * |
138 * In order to make memory accesses cache-friendly, we reorder the passes to | 140 * In order to make memory accesses cache-friendly, we reorder the passes to |
139 * use contiguous memory reads wherever possible. | 141 * use contiguous memory reads wherever possible. |
140 * | 142 * |
141 * For example, the 6 passes of the X-and-Y blur case are rewritten as | 143 * For example, the 6 passes of the X-and-Y blur case are rewritten as |
142 * follows. Instead of 3 passes in X and 3 passes in Y, we perform | 144 * follows. Instead of 3 passes in X and 3 passes in Y, we perform |
143 * 2 passes in X, 1 pass in X transposed to Y on write, 2 passes in X, | 145 * 2 passes in X, 1 pass in X transposed to Y on write, 2 passes in X, |
144 * then 1 pass in X transposed to Y on write. | 146 * then 1 pass in X transposed to Y on write. |
145 * | 147 * |
146 * +----+ +----+ +----+ +---+ +---+ +---+
+----+ | 148 * +----+ +----+ +----+ +---+ +---+ +---+
+----+ |
147 * + AB + ----> | AB | ----> | AB | -----> | A | ----> | A | ----> | A | ---
--> | AB | | 149 * + AB + ----> | AB | ----> | AB | -----> | A | ----> | A | ----> | A | ---
--> | AB | |
148 * +----+ blurX +----+ blurX +----+ blurXY | B | blurX | B | blurX | B | blu
rXY +----+ | 150 * +----+ blurX +----+ blurX +----+ blurXY | B | blurX | B | blurX | B | blu
rXY +----+ |
149 * +---+ +---+ +---+ | 151 * +---+ +---+ +---+ |
150 * | 152 * |
151 * In this way, two of the y-blurs become x-blurs applied to transposed | 153 * In this way, two of the y-blurs become x-blurs applied to transposed |
152 * images, and all memory reads are contiguous. | 154 * images, and all memory reads are contiguous. |
153 */ | 155 */ |
154 if (kernelSizeX > 0 && kernelSizeY > 0) { | 156 if (kernelSizeX > 0 && kernelSizeY > 0) { |
155 SkOpts::box_blur_xx(s, sw, t, kernelSizeX, lowOffsetX, highOffsetX, w
, h); | 157 SkOpts::box_blur_xx(s, sw, srcBounds, t, kernelSizeX, lowOffsetX, hi
ghOffsetX, w, h); |
156 SkOpts::box_blur_xx(t, w, d, kernelSizeX, highOffsetX, lowOffsetX, w
, h); | 158 SkOpts::box_blur_xx(t, w, dstBounds, d, kernelSizeX, highOffsetX, lo
wOffsetX, w, h); |
157 SkOpts::box_blur_xy(d, w, t, kernelSizeX3, highOffsetX, highOffsetX, w
, h); | 159 SkOpts::box_blur_xy(d, w, dstBounds, t, kernelSizeX3, highOffsetX, hi
ghOffsetX, w, h); |
158 SkOpts::box_blur_xx(t, h, d, kernelSizeY, lowOffsetY, highOffsetY, h
, w); | 160 SkOpts::box_blur_xx(t, h, dstBoundsT, d, kernelSizeY, lowOffsetY, hi
ghOffsetY, h, w); |
159 SkOpts::box_blur_xx(d, h, t, kernelSizeY, highOffsetY, lowOffsetY, h
, w); | 161 SkOpts::box_blur_xx(d, h, dstBoundsT, t, kernelSizeY, highOffsetY, lo
wOffsetY, h, w); |
160 SkOpts::box_blur_xy(t, h, d, kernelSizeY3, highOffsetY, highOffsetY, h
, w); | 162 SkOpts::box_blur_xy(t, h, dstBoundsT, d, kernelSizeY3, highOffsetY, hi
ghOffsetY, h, w); |
161 } else if (kernelSizeX > 0) { | 163 } else if (kernelSizeX > 0) { |
162 SkOpts::box_blur_xx(s, sw, d, kernelSizeX, lowOffsetX, highOffsetX, w
, h); | 164 SkOpts::box_blur_xx(s, sw, srcBounds, d, kernelSizeX, lowOffsetX, hi
ghOffsetX, w, h); |
163 SkOpts::box_blur_xx(d, w, t, kernelSizeX, highOffsetX, lowOffsetX, w
, h); | 165 SkOpts::box_blur_xx(d, w, dstBounds, t, kernelSizeX, highOffsetX, lo
wOffsetX, w, h); |
164 SkOpts::box_blur_xx(t, w, d, kernelSizeX3, highOffsetX, highOffsetX, w
, h); | 166 SkOpts::box_blur_xx(t, w, dstBounds, d, kernelSizeX3, highOffsetX, hi
ghOffsetX, w, h); |
165 } else if (kernelSizeY > 0) { | 167 } else if (kernelSizeY > 0) { |
166 SkOpts::box_blur_yx(s, sw, d, kernelSizeY, lowOffsetY, highOffsetY, h
, w); | 168 SkOpts::box_blur_yx(s, sw, srcBoundsT, d, kernelSizeY, lowOffsetY, hi
ghOffsetY, h, w); |
167 SkOpts::box_blur_xx(d, h, t, kernelSizeY, highOffsetY, lowOffsetY, h
, w); | 169 SkOpts::box_blur_xx(d, h, dstBoundsT, t, kernelSizeY, highOffsetY, lo
wOffsetY, h, w); |
168 SkOpts::box_blur_xy(t, h, d, kernelSizeY3, highOffsetY, highOffsetY, h
, w); | 170 SkOpts::box_blur_xy(t, h, dstBoundsT, d, kernelSizeY3, highOffsetY, hi
ghOffsetY, h, w); |
169 } | 171 } |
170 return true; | 172 return true; |
171 } | 173 } |
172 | 174 |
173 | 175 |
174 void SkBlurImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const
{ | 176 void SkBlurImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const
{ |
175 if (this->getInput(0)) { | 177 if (this->getInput(0)) { |
176 this->getInput(0)->computeFastBounds(src, dst); | 178 this->getInput(0)->computeFastBounds(src, dst); |
177 } else { | 179 } else { |
178 *dst = src; | 180 *dst = src; |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
237 str->appendf("SkBlurImageFilter: ("); | 239 str->appendf("SkBlurImageFilter: ("); |
238 str->appendf("sigma: (%f, %f) input (", fSigma.fWidth, fSigma.fHeight); | 240 str->appendf("sigma: (%f, %f) input (", fSigma.fWidth, fSigma.fHeight); |
239 | 241 |
240 if (this->getInput(0)) { | 242 if (this->getInput(0)) { |
241 this->getInput(0)->toString(str); | 243 this->getInput(0)->toString(str); |
242 } | 244 } |
243 | 245 |
244 str->append("))"); | 246 str->append("))"); |
245 } | 247 } |
246 #endif | 248 #endif |
OLD | NEW |