OLD | NEW |
---|---|
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2006 The Android Open Source Project | 3 * Copyright 2006 The Android Open Source Project |
4 * | 4 * |
5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
7 */ | 7 */ |
8 | 8 |
9 #include "SkBlurMaskFilter.h" | 9 #include "SkBlurMaskFilter.h" |
10 #include "SkBlurMask.h" | 10 #include "SkBlurMask.h" |
11 #include "SkGpuBlurUtils.h" | 11 #include "SkGpuBlurUtils.h" |
12 #include "SkFlattenableBuffers.h" | 12 #include "SkFlattenableBuffers.h" |
13 #include "SkMaskFilter.h" | 13 #include "SkMaskFilter.h" |
14 #include "SkRRect.h" | |
14 #include "SkRTConf.h" | 15 #include "SkRTConf.h" |
15 #include "SkStringUtils.h" | 16 #include "SkStringUtils.h" |
16 #include "SkStrokeRec.h" | 17 #include "SkStrokeRec.h" |
17 | 18 |
18 #if SK_SUPPORT_GPU | 19 #if SK_SUPPORT_GPU |
19 #include "GrContext.h" | 20 #include "GrContext.h" |
20 #include "GrTexture.h" | 21 #include "GrTexture.h" |
21 #include "effects/GrSimpleTextureEffect.h" | 22 #include "effects/GrSimpleTextureEffect.h" |
22 #include "SkGrPixelRef.h" | 23 #include "SkGrPixelRef.h" |
23 #endif | 24 #endif |
(...skipping 21 matching lines...) Expand all Loading... | |
45 virtual void computeFastBounds(const SkRect&, SkRect*) const SK_OVERRIDE; | 46 virtual void computeFastBounds(const SkRect&, SkRect*) const SK_OVERRIDE; |
46 | 47 |
47 SkDEVCODE(virtual void toString(SkString* str) const SK_OVERRIDE;) | 48 SkDEVCODE(virtual void toString(SkString* str) const SK_OVERRIDE;) |
48 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBlurMaskFilterImpl) | 49 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBlurMaskFilterImpl) |
49 | 50 |
50 protected: | 51 protected: |
51 virtual FilterReturn filterRectsToNine(const SkRect[], int count, const SkMa trix&, | 52 virtual FilterReturn filterRectsToNine(const SkRect[], int count, const SkMa trix&, |
52 const SkIRect& clipBounds, | 53 const SkIRect& clipBounds, |
53 NinePatch*) const SK_OVERRIDE; | 54 NinePatch*) const SK_OVERRIDE; |
54 | 55 |
56 virtual FilterReturn filterRRectToNine(const SkRRect&, const SkMatrix&, | |
57 const SkIRect& clipBounds, | |
58 NinePatch*) const SK_OVERRIDE; | |
59 | |
55 bool filterRectMask(SkMask* dstM, const SkRect& r, const SkMatrix& matrix, | 60 bool filterRectMask(SkMask* dstM, const SkRect& r, const SkMatrix& matrix, |
56 SkIPoint* margin, SkMask::CreateMode createMode) const; | 61 SkIPoint* margin, SkMask::CreateMode createMode) const; |
57 | 62 |
58 private: | 63 private: |
59 // To avoid unseemly allocation requests (esp. for finite platforms like | 64 // To avoid unseemly allocation requests (esp. for finite platforms like |
60 // handset) we limit the radius so something manageable. (as opposed to | 65 // handset) we limit the radius so something manageable. (as opposed to |
61 // a request like 10,000) | 66 // a request like 10,000) |
62 static const SkScalar kMAX_BLUR_SIGMA; | 67 static const SkScalar kMAX_BLUR_SIGMA; |
63 | 68 |
64 SkScalar fSigma; | 69 SkScalar fSigma; |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
148 const SkMatrix& matrix, | 153 const SkMatrix& matrix, |
149 SkIPoint* margin, SkMask::CreateMode c reateMode) const{ | 154 SkIPoint* margin, SkMask::CreateMode c reateMode) const{ |
150 SkScalar sigma = computeXformedSigma(matrix); | 155 SkScalar sigma = computeXformedSigma(matrix); |
151 | 156 |
152 return SkBlurMask::BlurRect(sigma, dst, r, (SkBlurMask::Style)fBlurStyle, | 157 return SkBlurMask::BlurRect(sigma, dst, r, (SkBlurMask::Style)fBlurStyle, |
153 margin, createMode); | 158 margin, createMode); |
154 } | 159 } |
155 | 160 |
156 #include "SkCanvas.h" | 161 #include "SkCanvas.h" |
157 | 162 |
158 static bool drawRectsIntoMask(const SkRect rects[], int count, SkMask* mask) { | 163 static SkCanvas* prepare_to_draw_into_mask(const SkRect& bounds, SkMask* mask) { |
159 rects[0].roundOut(&mask->fBounds); | 164 SkASSERT(mask != NULL); |
165 | |
166 bounds.roundOut(&mask->fBounds); | |
160 mask->fRowBytes = SkAlign4(mask->fBounds.width()); | 167 mask->fRowBytes = SkAlign4(mask->fBounds.width()); |
161 mask->fFormat = SkMask::kA8_Format; | 168 mask->fFormat = SkMask::kA8_Format; |
162 size_t size = mask->computeImageSize(); | 169 const size_t size = mask->computeImageSize(); |
163 mask->fImage = SkMask::AllocImage(size); | 170 mask->fImage = SkMask::AllocImage(size); |
164 if (NULL == mask->fImage) { | 171 if (NULL == mask->fImage) { |
165 return false; | 172 return NULL; |
166 } | 173 } |
174 | |
175 // FIXME: use sk_calloc in AllocImage? | |
167 sk_bzero(mask->fImage, size); | 176 sk_bzero(mask->fImage, size); |
168 | |
169 SkBitmap bitmap; | 177 SkBitmap bitmap; |
170 bitmap.setConfig(SkBitmap::kA8_Config, | 178 bitmap.setConfig(SkBitmap::kA8_Config, |
171 mask->fBounds.width(), mask->fBounds.height(), | 179 mask->fBounds.width(), mask->fBounds.height(), |
172 mask->fRowBytes); | 180 mask->fRowBytes); |
173 bitmap.setPixels(mask->fImage); | 181 bitmap.setPixels(mask->fImage); |
174 | 182 |
175 SkCanvas canvas(bitmap); | 183 SkCanvas* canvas = SkNEW_ARGS(SkCanvas, (bitmap)); |
scroggo
2013/10/30 22:51:31
In trying to share code, I've added an allocation!
robertphillips
2013/10/31 00:24:58
Can you just set up the mask then return true or f
scroggo
2013/11/01 21:45:46
I could, but that means I'm still duplicating code
| |
176 canvas.translate(-SkIntToScalar(mask->fBounds.left()), | 184 canvas->translate(-SkIntToScalar(mask->fBounds.left()), |
177 -SkIntToScalar(mask->fBounds.top())); | 185 -SkIntToScalar(mask->fBounds.top())); |
186 return canvas; | |
187 } | |
188 | |
189 static bool draw_rrect_into_mask(const SkRRect rrect, SkMask* mask) { | |
190 SkAutoTUnref<SkCanvas> canvas(prepare_to_draw_into_mask(rrect.rect(), mask)) ; | |
191 if (NULL == canvas.get()) { | |
192 return false; | |
193 } | |
194 | |
195 SkPaint paint; | |
196 paint.setAntiAlias(true); | |
197 canvas->drawRRect(rrect, paint); | |
198 return true; | |
199 } | |
200 | |
201 static bool drawRectsIntoMask(const SkRect rects[], int count, SkMask* mask) { | |
202 SkAutoTUnref<SkCanvas> canvas(prepare_to_draw_into_mask(rects[0], mask)); | |
203 if (NULL == canvas.get()) { | |
204 return false; | |
205 } | |
178 | 206 |
179 SkPaint paint; | 207 SkPaint paint; |
180 paint.setAntiAlias(true); | 208 paint.setAntiAlias(true); |
181 | 209 |
182 if (1 == count) { | 210 if (1 == count) { |
183 canvas.drawRect(rects[0], paint); | 211 canvas->drawRect(rects[0], paint); |
184 } else { | 212 } else { |
185 // todo: do I need a fast way to do this? | 213 // todo: do I need a fast way to do this? |
186 SkPath path; | 214 SkPath path; |
187 path.addRect(rects[0]); | 215 path.addRect(rects[0]); |
188 path.addRect(rects[1]); | 216 path.addRect(rects[1]); |
189 path.setFillType(SkPath::kEvenOdd_FillType); | 217 path.setFillType(SkPath::kEvenOdd_FillType); |
190 canvas.drawPath(path, paint); | 218 canvas->drawPath(path, paint); |
191 } | 219 } |
192 return true; | 220 return true; |
193 } | 221 } |
194 | 222 |
195 static bool rect_exceeds(const SkRect& r, SkScalar v) { | 223 static bool rect_exceeds(const SkRect& r, SkScalar v) { |
196 return r.fLeft < -v || r.fTop < -v || r.fRight > v || r.fBottom > v || | 224 return r.fLeft < -v || r.fTop < -v || r.fRight > v || r.fBottom > v || |
197 r.width() > v || r.height() > v; | 225 r.width() > v || r.height() > v; |
198 } | 226 } |
199 | 227 |
228 SkMaskFilter::FilterReturn | |
229 SkBlurMaskFilterImpl::filterRRectToNine(const SkRRect& rrect, const SkMatrix& ma trix, | |
230 const SkIRect& clipBounds, | |
231 NinePatch* patch) const { | |
232 switch (rrect.getType()) { | |
233 case SkRRect::kUnknown_Type: | |
234 // Unknown should never be returned. | |
235 SkASSERT(false); | |
236 // Fall through. | |
237 case SkRRect::kEmpty_Type: | |
238 // Nothing to draw. | |
239 return kFalse_FilterReturn; | |
240 | |
241 case SkRRect::kRect_Type: | |
robertphillips
2013/10/31 00:24:58
I think we should assert here (that the RRect isn'
scroggo
2013/11/01 21:45:46
Done.
| |
242 // Fall through. | |
243 case SkRRect::kOval_Type: | |
244 // The nine patch special case does not handle ovals, and we | |
245 // already have code for rectangles. | |
246 return kUnimplemented_FilterReturn; | |
247 | |
248 case SkRRect::kSimple_Type: | |
249 // Fall through. | |
250 case SkRRect::kComplex_Type: | |
251 // These can take advantage of this fast path. | |
252 break; | |
253 } | |
254 | |
255 // TODO: report correct metrics for innerstyle, where we do not grow the | |
256 // total bounds, but we do need an inset the size of our blur-radius | |
257 if (SkBlurMaskFilter::kInner_BlurStyle == fBlurStyle) { | |
258 return kUnimplemented_FilterReturn; | |
259 } | |
260 | |
261 // TODO: take clipBounds into account to limit our coordinates up front | |
262 // for now, just skip too-large src rects (to take the old code path). | |
263 if (rect_exceeds(rrect.rect(), SkIntToScalar(32767))) { | |
264 return kUnimplemented_FilterReturn; | |
265 } | |
266 | |
267 SkIPoint margin; | |
268 SkMask srcM, dstM; | |
269 rrect.rect().roundOut(&srcM.fBounds); | |
270 srcM.fImage = NULL; | |
271 srcM.fFormat = SkMask::kA8_Format; | |
272 srcM.fRowBytes = 0; | |
273 | |
274 if (!this->filterMask(&dstM, srcM, matrix, &margin)) { | |
275 return kFalse_FilterReturn; | |
276 } | |
277 | |
robertphillips
2013/10/31 13:30:31
Does this behave correctly if the RR is 100x100 wi
scroggo
2013/11/01 21:45:46
No. Latest patch fixes this. Thank you for the sug
| |
278 // Now we figure out the appropriate width and height of the stretchy | |
279 // rectangle. | |
280 const SkVector& UL = rrect.radii(SkRRect::kUpperLeft_Corner); | |
281 const SkVector& UR = rrect.radii(SkRRect::kUpperRight_Corner); | |
282 const SkVector& LR = rrect.radii(SkRRect::kLowerRight_Corner); | |
283 const SkVector& LL = rrect.radii(SkRRect::kLowerLeft_Corner); | |
284 | |
285 // The smaller rectangle must be large enough to include the larger | |
286 // radius of all four sides, plus some extra for stretching. | |
287 const SkScalar maxLeftXRadius = SkTMax(UL.fX, LL.fX); | |
288 const SkScalar maxRightXRadius = SkTMax(UR.fX, LR.fX); | |
289 | |
robertphillips
2013/10/31 00:24:58
I think there should be a +3 in here and maybe mak
scroggo
2013/11/01 21:45:46
Done.
| |
290 if (maxLeftXRadius + maxRightXRadius >= rrect.rect().width()) { | |
291 // There is no valid piece to stretch. | |
292 return kUnimplemented_FilterReturn; | |
293 } | |
294 | |
295 const SkScalar maxTopYRadius = SkTMax(UL.fY, UR.fY); | |
296 const SkScalar maxBottomYRadius = SkTMax(LL.fY, LR.fY); | |
297 | |
robertphillips
2013/10/31 00:24:58
Here too
scroggo
2013/11/01 21:45:46
Done.
| |
298 if (maxTopYRadius + maxBottomYRadius >= rrect.rect().height()) { | |
299 // There is no valid piece to stretch. | |
300 return kUnimplemented_FilterReturn; | |
301 } | |
302 | |
303 // Add some extra space to make sure we have a stretch row/col | |
robertphillips
2013/10/31 00:24:58
Are the x & y values correct? Can they be 0 & 0?
scroggo
2013/11/01 21:45:46
The x and y values are irrelevant. I have switched
| |
304 SkRect smallR = SkRect::MakeXYWH(rrect.rect().left(), rrect.rect().top(), | |
305 maxLeftXRadius + maxRightXRadius + SkIntToS calar(3), | |
306 maxTopYRadius + maxBottomYRadius + SkIntToS calar(3)); | |
307 | |
308 SkRRect smallRR; | |
robertphillips
2013/10/31 00:24:58
Maybe change setRectRadii to setAllRadii?
scroggo
2013/11/01 21:45:46
I think the current name makes sense. It sets both
| |
309 smallRR.setRectRadii(smallR, rrect.getAllRadii()); | |
310 | |
311 if (!draw_rrect_into_mask(smallRR, &srcM)) { | |
312 return kFalse_FilterReturn; | |
313 } | |
314 | |
315 if (!this->filterMask(&patch->fMask, srcM, matrix, &margin)) { | |
316 return kFalse_FilterReturn; | |
317 } | |
318 | |
319 patch->fMask.fBounds.offsetTo(0, 0); | |
320 patch->fOuterRect = dstM.fBounds; | |
321 // Stretch just beyond the radii. | |
322 patch->fCenter.fX = SkScalarCeilToInt(maxLeftXRadius) + 1; | |
323 patch->fCenter.fY = SkScalarCeilToInt(maxTopYRadius) + 1; | |
324 return kTrue_FilterReturn; | |
325 } | |
326 | |
200 #ifdef SK_IGNORE_FAST_RECT_BLUR | 327 #ifdef SK_IGNORE_FAST_RECT_BLUR |
201 SK_CONF_DECLARE( bool, c_analyticBlurNinepatch, "mask.filter.analyticNinePatch", false, "Use the faster analytic blur approach for ninepatch rects" ); | 328 SK_CONF_DECLARE( bool, c_analyticBlurNinepatch, "mask.filter.analyticNinePatch", false, "Use the faster analytic blur approach for ninepatch rects" ); |
202 #else | 329 #else |
203 SK_CONF_DECLARE( bool, c_analyticBlurNinepatch, "mask.filter.analyticNinePatch", true, "Use the faster analytic blur approach for ninepatch rects" ); | 330 SK_CONF_DECLARE( bool, c_analyticBlurNinepatch, "mask.filter.analyticNinePatch", true, "Use the faster analytic blur approach for ninepatch rects" ); |
204 #endif | 331 #endif |
205 | 332 |
206 SkMaskFilter::FilterReturn | 333 SkMaskFilter::FilterReturn |
207 SkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count, | 334 SkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count, |
208 const SkMatrix& matrix, | 335 const SkMatrix& matrix, |
209 const SkIRect& clipBounds, | 336 const SkIRect& clipBounds, |
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
473 } else { | 600 } else { |
474 str->append("None"); | 601 str->append("None"); |
475 } | 602 } |
476 str->append("))"); | 603 str->append("))"); |
477 } | 604 } |
478 #endif | 605 #endif |
479 | 606 |
480 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkBlurMaskFilter) | 607 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkBlurMaskFilter) |
481 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurMaskFilterImpl) | 608 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurMaskFilterImpl) |
482 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END | 609 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END |
OLD | NEW |