Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(783)

Side by Side Diff: src/effects/SkBlurMaskFilter.cpp

Issue 48623006: Add ability to ninepatch blurred rounded rectangle (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: rebase Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/core/SkMaskFilter.cpp ('k') | src/pdf/SkPDFDevice.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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 bool 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 false;
166 } 173 }
174
175 // FIXME: use sk_calloc in AllocImage?
167 sk_bzero(mask->fImage, size); 176 sk_bzero(mask->fImage, size);
177 return true;
178 }
179
180 static bool draw_rrect_into_mask(const SkRRect rrect, SkMask* mask) {
181 if (!prepare_to_draw_into_mask(rrect.rect(), mask)) {
182 return false;
183 }
184
185 // FIXME: This code duplicates code in drawRectsIntoMask, below. Is there a
186 // clean way to share more code?
187 SkBitmap bitmap;
188 bitmap.setConfig(SkBitmap::kA8_Config,
189 mask->fBounds.width(), mask->fBounds.height(),
190 mask->fRowBytes);
191 bitmap.setPixels(mask->fImage);
192
193 SkCanvas canvas(bitmap);
194 canvas.translate(-SkIntToScalar(mask->fBounds.left()),
195 -SkIntToScalar(mask->fBounds.top()));
196
197 SkPaint paint;
198 paint.setAntiAlias(true);
199 canvas.drawRRect(rrect, paint);
200 return true;
201 }
202
robertphillips 2013/11/05 17:26:22 draw_rects_into_mask?
scroggo 2013/11/05 21:15:07 Done.
203 static bool drawRectsIntoMask(const SkRect rects[], int count, SkMask* mask) {
204 if (!prepare_to_draw_into_mask(rects[0], mask)) {
205 return false;
206 }
168 207
169 SkBitmap bitmap; 208 SkBitmap bitmap;
170 bitmap.setConfig(SkBitmap::kA8_Config, 209 bitmap.setConfig(SkBitmap::kA8_Config,
171 mask->fBounds.width(), mask->fBounds.height(), 210 mask->fBounds.width(), mask->fBounds.height(),
172 mask->fRowBytes); 211 mask->fRowBytes);
173 bitmap.setPixels(mask->fImage); 212 bitmap.setPixels(mask->fImage);
174 213
175 SkCanvas canvas(bitmap); 214 SkCanvas canvas(bitmap);
176 canvas.translate(-SkIntToScalar(mask->fBounds.left()), 215 canvas.translate(-SkIntToScalar(mask->fBounds.left()),
177 -SkIntToScalar(mask->fBounds.top())); 216 -SkIntToScalar(mask->fBounds.top()));
(...skipping 12 matching lines...) Expand all
190 canvas.drawPath(path, paint); 229 canvas.drawPath(path, paint);
191 } 230 }
192 return true; 231 return true;
193 } 232 }
194 233
195 static bool rect_exceeds(const SkRect& r, SkScalar v) { 234 static bool rect_exceeds(const SkRect& r, SkScalar v) {
196 return r.fLeft < -v || r.fTop < -v || r.fRight > v || r.fBottom > v || 235 return r.fLeft < -v || r.fTop < -v || r.fRight > v || r.fBottom > v ||
197 r.width() > v || r.height() > v; 236 r.width() > v || r.height() > v;
198 } 237 }
199 238
239 SkMaskFilter::FilterReturn
240 SkBlurMaskFilterImpl::filterRRectToNine(const SkRRect& rrect, const SkMatrix& ma trix,
241 const SkIRect& clipBounds,
242 NinePatch* patch) const {
243 SkASSERT(patch != NULL);
244 switch (rrect.getType()) {
245 case SkRRect::kUnknown_Type:
246 // Unknown should never be returned.
247 SkASSERT(false);
248 // Fall through.
249 case SkRRect::kEmpty_Type:
250 // Nothing to draw.
251 return kFalse_FilterReturn;
252
253 case SkRRect::kRect_Type:
254 // We should have caught this earlier.
255 SkASSERT(false);
256 // Fall through.
257 case SkRRect::kOval_Type:
258 // The nine patch special case does not handle ovals, and we
259 // already have code for rectangles.
260 return kUnimplemented_FilterReturn;
261
262 case SkRRect::kSimple_Type:
263 // Fall through.
264 case SkRRect::kComplex_Type:
265 // These can take advantage of this fast path.
266 break;
267 }
268
269 // TODO: report correct metrics for innerstyle, where we do not grow the
270 // total bounds, but we do need an inset the size of our blur-radius
271 if (SkBlurMaskFilter::kInner_BlurStyle == fBlurStyle) {
272 return kUnimplemented_FilterReturn;
273 }
274
275 // TODO: take clipBounds into account to limit our coordinates up front
276 // for now, just skip too-large src rects (to take the old code path).
277 if (rect_exceeds(rrect.rect(), SkIntToScalar(32767))) {
278 return kUnimplemented_FilterReturn;
279 }
280
281 SkIPoint margin;
282 SkMask srcM, dstM;
283 rrect.rect().roundOut(&srcM.fBounds);
284 srcM.fImage = NULL;
285 srcM.fFormat = SkMask::kA8_Format;
286 srcM.fRowBytes = 0;
287
288 if (!this->filterMask(&dstM, srcM, matrix, &margin)) {
289 return kFalse_FilterReturn;
290 }
291
292 // Now figure out the appropriate width and height of the smaller round rect angle
293 // to stretch. It will take into account the larger radius per side as well as double
294 // the margin, to account for inner and outer blur.
295 const SkVector& UL = rrect.radii(SkRRect::kUpperLeft_Corner);
296 const SkVector& UR = rrect.radii(SkRRect::kUpperRight_Corner);
297 const SkVector& LR = rrect.radii(SkRRect::kLowerRight_Corner);
298 const SkVector& LL = rrect.radii(SkRRect::kLowerLeft_Corner);
299
300 const SkScalar leftUnstretched = SkTMax(UL.fX, LL.fX) + SkIntToScalar(2 * ma rgin.fX);
301 const SkScalar rightUnstretched = SkTMax(UR.fX, LR.fX) + SkIntToScalar(2 * m argin.fX);
302
303 // Extra space in the middle to ensure an unchanging piece for stretching. U se 3 to cover
304 // any fractional space on either side plus 1 for the part to stretch.
305 const SkScalar stretchSize = SkIntToScalar(3);
306
307 const SkScalar totalSmallWidth = leftUnstretched + rightUnstretched + stretc hSize;
308 if (totalSmallWidth >= rrect.rect().width()) {
309 // There is no valid piece to stretch.
310 return kUnimplemented_FilterReturn;
311 }
312
313 const SkScalar topUnstretched = SkTMax(UL.fY, UR.fY) + SkIntToScalar(2 * mar gin.fY);
314 const SkScalar bottomUnstretched = SkTMax(LL.fY, LR.fY) + SkIntToScalar(2 * margin.fY);
315
316 const SkScalar totalSmallHeight = topUnstretched + bottomUnstretched + stret chSize;
317 if (totalSmallHeight >= rrect.rect().height()) {
318 // There is no valid piece to stretch.
319 return kUnimplemented_FilterReturn;
320 }
321
322 SkRect smallR = SkRect::MakeWH(totalSmallWidth, totalSmallHeight);
323
324 SkRRect smallRR;
325 SkVector radii[4];
326 radii[SkRRect::kUpperLeft_Corner] = UL;
327 radii[SkRRect::kUpperRight_Corner] = UR;
328 radii[SkRRect::kLowerRight_Corner] = LR;
329 radii[SkRRect::kLowerLeft_Corner] = LL;
330 smallRR.setRectRadii(smallR, radii);
331
332 if (!draw_rrect_into_mask(smallRR, &srcM)) {
333 return kFalse_FilterReturn;
334 }
335
336 if (!this->filterMask(&patch->fMask, srcM, matrix, &margin)) {
337 return kFalse_FilterReturn;
338 }
339
340 patch->fMask.fBounds.offsetTo(0, 0);
341 patch->fOuterRect = dstM.fBounds;
342 patch->fCenter.fX = SkScalarCeilToInt(leftUnstretched) + 1;
343 patch->fCenter.fY = SkScalarCeilToInt(topUnstretched) + 1;
344 return kTrue_FilterReturn;
345 }
346
200 #ifdef SK_IGNORE_FAST_RECT_BLUR 347 #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" ); 348 SK_CONF_DECLARE( bool, c_analyticBlurNinepatch, "mask.filter.analyticNinePatch", false, "Use the faster analytic blur approach for ninepatch rects" );
202 #else 349 #else
203 SK_CONF_DECLARE( bool, c_analyticBlurNinepatch, "mask.filter.analyticNinePatch", true, "Use the faster analytic blur approach for ninepatch rects" ); 350 SK_CONF_DECLARE( bool, c_analyticBlurNinepatch, "mask.filter.analyticNinePatch", true, "Use the faster analytic blur approach for ninepatch rects" );
204 #endif 351 #endif
205 352
206 SkMaskFilter::FilterReturn 353 SkMaskFilter::FilterReturn
207 SkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count, 354 SkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count,
208 const SkMatrix& matrix, 355 const SkMatrix& matrix,
209 const SkIRect& clipBounds, 356 const SkIRect& clipBounds,
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after
473 } else { 620 } else {
474 str->append("None"); 621 str->append("None");
475 } 622 }
476 str->append("))"); 623 str->append("))");
477 } 624 }
478 #endif 625 #endif
479 626
480 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkBlurMaskFilter) 627 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkBlurMaskFilter)
481 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurMaskFilterImpl) 628 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurMaskFilterImpl)
482 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END 629 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
OLDNEW
« no previous file with comments | « src/core/SkMaskFilter.cpp ('k') | src/pdf/SkPDFDevice.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698