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, src, srcOffset, &dstBounds, &srcBounds)) { | 85 if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &srcBounds, &src)) { |
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(dstBounds.width(), dst
Bounds.height())); | 94 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(srcBounds.width(), src
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); |
100 | 101 |
101 SkVector sigma = mapSigma(fSigma, ctx.ctm()); | 102 SkVector sigma = mapSigma(fSigma, ctx.ctm()); |
102 | 103 |
103 int kernelSizeX, kernelSizeX3, lowOffsetX, highOffsetX; | 104 int kernelSizeX, kernelSizeX3, lowOffsetX, highOffsetX; |
104 int kernelSizeY, kernelSizeY3, lowOffsetY, highOffsetY; | 105 int kernelSizeY, kernelSizeY3, lowOffsetY, highOffsetY; |
105 getBox3Params(sigma.x(), &kernelSizeX, &kernelSizeX3, &lowOffsetX, &highOffs
etX); | 106 getBox3Params(sigma.x(), &kernelSizeX, &kernelSizeX3, &lowOffsetX, &highOffs
etX); |
106 getBox3Params(sigma.y(), &kernelSizeY, &kernelSizeY3, &lowOffsetY, &highOffs
etY); | 107 getBox3Params(sigma.y(), &kernelSizeY, &kernelSizeY3, &lowOffsetY, &highOffs
etY); |
107 | 108 |
108 if (kernelSizeX < 0 || kernelSizeY < 0) { | 109 if (kernelSizeX < 0 || kernelSizeY < 0) { |
109 return false; | 110 return false; |
110 } | 111 } |
111 | 112 |
112 if (kernelSizeX == 0 && kernelSizeY == 0) { | 113 if (kernelSizeX == 0 && kernelSizeY == 0) { |
113 src.copyTo(dst, dst->colorType()); | 114 src.copyTo(dst, dst->colorType()); |
114 offset->fX = dstBounds.fLeft; | 115 offset->fX = srcBounds.fLeft; |
115 offset->fY = dstBounds.fTop; | 116 offset->fY = srcBounds.fTop; |
116 return true; | 117 return true; |
117 } | 118 } |
118 | 119 |
119 SkAutoTUnref<SkBaseDevice> tempDevice(proxy->createDevice(dst->width(), dst-
>height())); | 120 SkAutoTUnref<SkBaseDevice> tempDevice(proxy->createDevice(dst->width(), dst-
>height())); |
120 if (!tempDevice) { | 121 if (!tempDevice) { |
121 return false; | 122 return false; |
122 } | 123 } |
123 SkBitmap temp = tempDevice->accessBitmap(false); | 124 SkBitmap temp = tempDevice->accessBitmap(false); |
124 SkAutoLockPixels alpTemp(temp); | 125 SkAutoLockPixels alpTemp(temp); |
125 | 126 |
126 offset->fX = dstBounds.fLeft; | 127 offset->fX = srcBounds.fLeft; |
127 offset->fY = dstBounds.fTop; | 128 offset->fY = srcBounds.fTop; |
| 129 srcBounds.offset(-srcOffset); |
| 130 const SkPMColor* s = src.getAddr32(srcBounds.left(), srcBounds.top()); |
128 SkPMColor* t = temp.getAddr32(0, 0); | 131 SkPMColor* t = temp.getAddr32(0, 0); |
129 SkPMColor* d = dst->getAddr32(0, 0); | 132 SkPMColor* d = dst->getAddr32(0, 0); |
130 int w = dstBounds.width(), h = dstBounds.height(); | 133 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()); | |
136 int sw = src.rowBytesAsPixels(); | 134 int sw = src.rowBytesAsPixels(); |
137 | 135 |
138 /** | 136 /** |
139 * | 137 * |
140 * In order to make memory accesses cache-friendly, we reorder the passes to | 138 * In order to make memory accesses cache-friendly, we reorder the passes to |
141 * use contiguous memory reads wherever possible. | 139 * use contiguous memory reads wherever possible. |
142 * | 140 * |
143 * For example, the 6 passes of the X-and-Y blur case are rewritten as | 141 * For example, the 6 passes of the X-and-Y blur case are rewritten as |
144 * follows. Instead of 3 passes in X and 3 passes in Y, we perform | 142 * follows. Instead of 3 passes in X and 3 passes in Y, we perform |
145 * 2 passes in X, 1 pass in X transposed to Y on write, 2 passes in X, | 143 * 2 passes in X, 1 pass in X transposed to Y on write, 2 passes in X, |
146 * then 1 pass in X transposed to Y on write. | 144 * then 1 pass in X transposed to Y on write. |
147 * | 145 * |
148 * +----+ +----+ +----+ +---+ +---+ +---+
+----+ | 146 * +----+ +----+ +----+ +---+ +---+ +---+
+----+ |
149 * + AB + ----> | AB | ----> | AB | -----> | A | ----> | A | ----> | A | ---
--> | AB | | 147 * + AB + ----> | AB | ----> | AB | -----> | A | ----> | A | ----> | A | ---
--> | AB | |
150 * +----+ blurX +----+ blurX +----+ blurXY | B | blurX | B | blurX | B | blu
rXY +----+ | 148 * +----+ blurX +----+ blurX +----+ blurXY | B | blurX | B | blurX | B | blu
rXY +----+ |
151 * +---+ +---+ +---+ | 149 * +---+ +---+ +---+ |
152 * | 150 * |
153 * In this way, two of the y-blurs become x-blurs applied to transposed | 151 * In this way, two of the y-blurs become x-blurs applied to transposed |
154 * images, and all memory reads are contiguous. | 152 * images, and all memory reads are contiguous. |
155 */ | 153 */ |
156 if (kernelSizeX > 0 && kernelSizeY > 0) { | 154 if (kernelSizeX > 0 && kernelSizeY > 0) { |
157 SkOpts::box_blur_xx(s, sw, srcBounds, t, kernelSizeX, lowOffsetX, hi
ghOffsetX, w, h); | 155 SkOpts::box_blur_xx(s, sw, t, kernelSizeX, lowOffsetX, highOffsetX, w
, h); |
158 SkOpts::box_blur_xx(t, w, dstBounds, d, kernelSizeX, highOffsetX, lo
wOffsetX, w, h); | 156 SkOpts::box_blur_xx(t, w, d, kernelSizeX, highOffsetX, lowOffsetX, w
, h); |
159 SkOpts::box_blur_xy(d, w, dstBounds, t, kernelSizeX3, highOffsetX, hi
ghOffsetX, w, h); | 157 SkOpts::box_blur_xy(d, w, t, kernelSizeX3, highOffsetX, highOffsetX, w
, h); |
160 SkOpts::box_blur_xx(t, h, dstBoundsT, d, kernelSizeY, lowOffsetY, hi
ghOffsetY, h, w); | 158 SkOpts::box_blur_xx(t, h, d, kernelSizeY, lowOffsetY, highOffsetY, h
, w); |
161 SkOpts::box_blur_xx(d, h, dstBoundsT, t, kernelSizeY, highOffsetY, lo
wOffsetY, h, w); | 159 SkOpts::box_blur_xx(d, h, t, kernelSizeY, highOffsetY, lowOffsetY, h
, w); |
162 SkOpts::box_blur_xy(t, h, dstBoundsT, d, kernelSizeY3, highOffsetY, hi
ghOffsetY, h, w); | 160 SkOpts::box_blur_xy(t, h, d, kernelSizeY3, highOffsetY, highOffsetY, h
, w); |
163 } else if (kernelSizeX > 0) { | 161 } else if (kernelSizeX > 0) { |
164 SkOpts::box_blur_xx(s, sw, srcBounds, d, kernelSizeX, lowOffsetX, hi
ghOffsetX, w, h); | 162 SkOpts::box_blur_xx(s, sw, d, kernelSizeX, lowOffsetX, highOffsetX, w
, h); |
165 SkOpts::box_blur_xx(d, w, dstBounds, t, kernelSizeX, highOffsetX, lo
wOffsetX, w, h); | 163 SkOpts::box_blur_xx(d, w, t, kernelSizeX, highOffsetX, lowOffsetX, w
, h); |
166 SkOpts::box_blur_xx(t, w, dstBounds, d, kernelSizeX3, highOffsetX, hi
ghOffsetX, w, h); | 164 SkOpts::box_blur_xx(t, w, d, kernelSizeX3, highOffsetX, highOffsetX, w
, h); |
167 } else if (kernelSizeY > 0) { | 165 } else if (kernelSizeY > 0) { |
168 SkOpts::box_blur_yx(s, sw, srcBoundsT, d, kernelSizeY, lowOffsetY, hi
ghOffsetY, h, w); | 166 SkOpts::box_blur_yx(s, sw, d, kernelSizeY, lowOffsetY, highOffsetY, h
, w); |
169 SkOpts::box_blur_xx(d, h, dstBoundsT, t, kernelSizeY, highOffsetY, lo
wOffsetY, h, w); | 167 SkOpts::box_blur_xx(d, h, t, kernelSizeY, highOffsetY, lowOffsetY, h
, w); |
170 SkOpts::box_blur_xy(t, h, dstBoundsT, d, kernelSizeY3, highOffsetY, hi
ghOffsetY, h, w); | 168 SkOpts::box_blur_xy(t, h, d, kernelSizeY3, highOffsetY, highOffsetY, h
, w); |
171 } | 169 } |
172 return true; | 170 return true; |
173 } | 171 } |
174 | 172 |
175 | 173 |
176 void SkBlurImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const
{ | 174 void SkBlurImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const
{ |
177 if (this->getInput(0)) { | 175 if (this->getInput(0)) { |
178 this->getInput(0)->computeFastBounds(src, dst); | 176 this->getInput(0)->computeFastBounds(src, dst); |
179 } else { | 177 } else { |
180 *dst = src; | 178 *dst = src; |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
239 str->appendf("SkBlurImageFilter: ("); | 237 str->appendf("SkBlurImageFilter: ("); |
240 str->appendf("sigma: (%f, %f) input (", fSigma.fWidth, fSigma.fHeight); | 238 str->appendf("sigma: (%f, %f) input (", fSigma.fWidth, fSigma.fHeight); |
241 | 239 |
242 if (this->getInput(0)) { | 240 if (this->getInput(0)) { |
243 this->getInput(0)->toString(str); | 241 this->getInput(0)->toString(str); |
244 } | 242 } |
245 | 243 |
246 str->append("))"); | 244 str->append("))"); |
247 } | 245 } |
248 #endif | 246 #endif |
OLD | NEW |