1
2 /*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9 #include "SkBlurMaskFilter.h"
10 #include "SkBlurMask.h"
11 #include "SkGpuBlurUtils.h"
12 #include "SkFlattenableBuffers.h"
13 #include "SkMaskFilter.h"
14 #include "SkRRect.h"
15 #include "SkRTConf.h"
16 #include "SkStringUtils.h"
17 #include "SkStrokeRec.h"
18
19 #if SK_SUPPORT_GPU
20 #include "GrContext.h"
21 #include "GrTexture.h"
22 #include "effects/GrSimpleTextureEffect.h"
23 #include "SkGrPixelRef.h"
24 #endif
25
26 class SkBlurMaskFilterImpl : public SkMaskFilter {
27 public:
28 SkBlurMaskFilterImpl(SkScalar sigma, SkBlurMaskFilter::BlurStyle, uint32_t flags);
29
30 // overrides from SkMaskFilter
31 virtual SkMask::Format getFormat() const SK_OVERRIDE;
32 virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&,
33 SkIPoint* margin) const SK_OVERRIDE;
34
35 #if SK_SUPPORT_GPU
36 virtual bool canFilterMaskGPU(const SkRect& devBounds,
37 const SkIRect& clipBounds,
38 const SkMatrix& ctm,
39 SkRect* maskRect) const SK_OVERRIDE;
40 virtual bool filterMaskGPU(GrTexture* src,
41 const SkRect& maskRect,
42 GrTexture** result,
43 bool canOverwriteSrc) const;
44 #endif
45
46 virtual void computeFastBounds(const SkRect&, SkRect*) const SK_OVERRIDE;
47
48 SkDEVCODE(virtual void toString(SkString* str) const SK_OVERRIDE;)
49 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBlurMaskFilterImpl)
50
51 protected:
52 virtual FilterReturn filterRectsToNine(const SkRect[], int count, const SkMatrix&,
53 const SkIRect& clipBounds,
54 NinePatch*) const SK_OVERRIDE;
55
56 virtual FilterReturn filterRRectToNine(const SkRRect&, const SkMatrix&,
57 const SkIRect& clipBounds,
58 NinePatch*) const SK_OVERRIDE;
59
60 bool filterRectMask(SkMask* dstM, const SkRect& r, const SkMatrix& matrix,
61 SkIPoint* margin, SkMask::CreateMode createMode) const;
62
63 private:
64 // To avoid unseemly allocation requests (esp. for finite platforms like
65 // handset) we limit the radius so something manageable. (as opposed to
66 // a request like 10,000)
67 static const SkScalar kMAX_BLUR_SIGMA;
68
69 SkScalar fSigma;
70 SkBlurMaskFilter::BlurStyle fBlurStyle;
71 uint32_t fBlurFlags;
72
73 SkBlurMaskFilterImpl(SkFlattenableReadBuffer&);
74 virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;
75
computeXformedSigma(const SkMatrix & ctm) const76 SkScalar computeXformedSigma(const SkMatrix& ctm) const {
77 bool ignoreTransform = SkToBool(fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag);
78
79 SkScalar xformedSigma = ignoreTransform ? fSigma : ctm.mapRadius(fSigma);
80 return SkMinScalar(xformedSigma, kMAX_BLUR_SIGMA);
81 }
82
83 typedef SkMaskFilter INHERITED;
84 };
85
86 const SkScalar SkBlurMaskFilterImpl::kMAX_BLUR_SIGMA = SkIntToScalar(128);
87
Create(SkScalar radius,SkBlurMaskFilter::BlurStyle style,uint32_t flags)88 SkMaskFilter* SkBlurMaskFilter::Create(SkScalar radius,
89 SkBlurMaskFilter::BlurStyle style,
90 uint32_t flags) {
91 // use !(radius > 0) instead of radius <= 0 to reject NaN values
92 if (!(radius > 0) || (unsigned)style >= SkBlurMaskFilter::kBlurStyleCount
93 || flags > SkBlurMaskFilter::kAll_BlurFlag) {
94 return NULL;
95 }
96
97 SkScalar sigma = SkBlurMask::ConvertRadiusToSigma(radius);
98
99 return SkNEW_ARGS(SkBlurMaskFilterImpl, (sigma, style, flags));
100 }
101
Create(SkBlurMaskFilter::BlurStyle style,SkScalar sigma,uint32_t flags)102 SkMaskFilter* SkBlurMaskFilter::Create(SkBlurMaskFilter::BlurStyle style,
103 SkScalar sigma,
104 uint32_t flags) {
105 // use !(sigma > 0) instead of sigma <= 0 to reject NaN values
106 if (!(sigma > 0) || (unsigned)style >= SkBlurMaskFilter::kBlurStyleCount
107 || flags > SkBlurMaskFilter::kAll_BlurFlag) {
108 return NULL;
109 }
110
111 return SkNEW_ARGS(SkBlurMaskFilterImpl, (sigma, style, flags));
112 }
113
114 ///////////////////////////////////////////////////////////////////////////////
115
SkBlurMaskFilterImpl(SkScalar sigma,SkBlurMaskFilter::BlurStyle style,uint32_t flags)116 SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkScalar sigma,
117 SkBlurMaskFilter::BlurStyle style,
118 uint32_t flags)
119 : fSigma(sigma), fBlurStyle(style), fBlurFlags(flags) {
120 #if 0
121 fGamma = NULL;
122 if (gammaScale) {
123 fGamma = new U8[256];
124 if (gammaScale > 0)
125 SkBlurMask::BuildSqrGamma(fGamma, gammaScale);
126 else
127 SkBlurMask::BuildSqrtGamma(fGamma, -gammaScale);
128 }
129 #endif
130 SkASSERT(fSigma >= 0);
131 SkASSERT((unsigned)style < SkBlurMaskFilter::kBlurStyleCount);
132 SkASSERT(flags <= SkBlurMaskFilter::kAll_BlurFlag);
133 }
134
getFormat() const135 SkMask::Format SkBlurMaskFilterImpl::getFormat() const {
136 return SkMask::kA8_Format;
137 }
138
filterMask(SkMask * dst,const SkMask & src,const SkMatrix & matrix,SkIPoint * margin) const139 bool SkBlurMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src,
140 const SkMatrix& matrix,
141 SkIPoint* margin) const{
142 SkScalar sigma = this->computeXformedSigma(matrix);
143
144 SkBlurMask::Quality blurQuality =
145 (fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag) ?
146 SkBlurMask::kHigh_Quality : SkBlurMask::kLow_Quality;
147
148 return SkBlurMask::BoxBlur(dst, src, sigma, (SkBlurMask::Style)fBlurStyle,
149 blurQuality, margin);
150 }
151
filterRectMask(SkMask * dst,const SkRect & r,const SkMatrix & matrix,SkIPoint * margin,SkMask::CreateMode createMode) const152 bool SkBlurMaskFilterImpl::filterRectMask(SkMask* dst, const SkRect& r,
153 const SkMatrix& matrix,
154 SkIPoint* margin, SkMask::CreateMode createMode) const{
155 SkScalar sigma = computeXformedSigma(matrix);
156
157 return SkBlurMask::BlurRect(sigma, dst, r, (SkBlurMask::Style)fBlurStyle,
158 margin, createMode);
159 }
160
161 #include "SkCanvas.h"
162
prepare_to_draw_into_mask(const SkRect & bounds,SkMask * mask)163 static bool prepare_to_draw_into_mask(const SkRect& bounds, SkMask* mask) {
164 SkASSERT(mask != NULL);
165
166 bounds.roundOut(&mask->fBounds);
167 mask->fRowBytes = SkAlign4(mask->fBounds.width());
168 mask->fFormat = SkMask::kA8_Format;
169 const size_t size = mask->computeImageSize();
170 mask->fImage = SkMask::AllocImage(size);
171 if (NULL == mask->fImage) {
172 return false;
173 }
174
175 // FIXME: use sk_calloc in AllocImage?
176 sk_bzero(mask->fImage, size);
177 return true;
178 }
179
draw_rrect_into_mask(const SkRRect rrect,SkMask * mask)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 draw_rects_into_mask, 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
draw_rects_into_mask(const SkRect rects[],int count,SkMask * mask)203 static bool draw_rects_into_mask(const SkRect rects[], int count, SkMask* mask) {
204 if (!prepare_to_draw_into_mask(rects[0], mask)) {
205 return false;
206 }
207
208 SkBitmap bitmap;
209 bitmap.setConfig(SkBitmap::kA8_Config,
210 mask->fBounds.width(), mask->fBounds.height(),
211 mask->fRowBytes);
212 bitmap.setPixels(mask->fImage);
213
214 SkCanvas canvas(bitmap);
215 canvas.translate(-SkIntToScalar(mask->fBounds.left()),
216 -SkIntToScalar(mask->fBounds.top()));
217
218 SkPaint paint;
219 paint.setAntiAlias(true);
220
221 if (1 == count) {
222 canvas.drawRect(rects[0], paint);
223 } else {
224 // todo: do I need a fast way to do this?
225 SkPath path;
226 path.addRect(rects[0]);
227 path.addRect(rects[1]);
228 path.setFillType(SkPath::kEvenOdd_FillType);
229 canvas.drawPath(path, paint);
230 }
231 return true;
232 }
233
rect_exceeds(const SkRect & r,SkScalar v)234 static bool rect_exceeds(const SkRect& r, SkScalar v) {
235 return r.fLeft < -v || r.fTop < -v || r.fRight > v || r.fBottom > v ||
236 r.width() > v || r.height() > v;
237 }
238
239 SkMaskFilter::FilterReturn
filterRRectToNine(const SkRRect & rrect,const SkMatrix & matrix,const SkIRect & clipBounds,NinePatch * patch) const240 SkBlurMaskFilterImpl::filterRRectToNine(const SkRRect& rrect, const SkMatrix& matrix,
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 rectangle
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 * margin.fX);
301 const SkScalar rightUnstretched = SkTMax(UR.fX, LR.fX) + SkIntToScalar(2 * margin.fX);
302
303 // Extra space in the middle to ensure an unchanging piece for stretching. Use 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 + stretchSize;
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 * margin.fY);
314 const SkScalar bottomUnstretched = SkTMax(LL.fY, LR.fY) + SkIntToScalar(2 * margin.fY);
315
316 const SkScalar totalSmallHeight = topUnstretched + bottomUnstretched + stretchSize;
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 SkAutoMaskFreeImage amf(srcM.fImage);
337
338 if (!this->filterMask(&patch->fMask, srcM, matrix, &margin)) {
339 return kFalse_FilterReturn;
340 }
341
342 patch->fMask.fBounds.offsetTo(0, 0);
343 patch->fOuterRect = dstM.fBounds;
344 patch->fCenter.fX = SkScalarCeilToInt(leftUnstretched) + 1;
345 patch->fCenter.fY = SkScalarCeilToInt(topUnstretched) + 1;
346 return kTrue_FilterReturn;
347 }
348
349 #ifdef SK_IGNORE_FAST_RECT_BLUR
350 SK_CONF_DECLARE( bool, c_analyticBlurNinepatch, "mask.filter.analyticNinePatch", false, "Use the faster analytic blur approach for ninepatch rects" );
351 #else
352 SK_CONF_DECLARE( bool, c_analyticBlurNinepatch, "mask.filter.analyticNinePatch", true, "Use the faster analytic blur approach for ninepatch rects" );
353 #endif
354
355 SkMaskFilter::FilterReturn
filterRectsToNine(const SkRect rects[],int count,const SkMatrix & matrix,const SkIRect & clipBounds,NinePatch * patch) const356 SkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count,
357 const SkMatrix& matrix,
358 const SkIRect& clipBounds,
359 NinePatch* patch) const {
360 if (count < 1 || count > 2) {
361 return kUnimplemented_FilterReturn;
362 }
363
364 // TODO: report correct metrics for innerstyle, where we do not grow the
365 // total bounds, but we do need an inset the size of our blur-radius
366 if (SkBlurMaskFilter::kInner_BlurStyle == fBlurStyle ||
367 SkBlurMaskFilter::kOuter_BlurStyle == fBlurStyle) {
368 return kUnimplemented_FilterReturn;
369 }
370
371 // TODO: take clipBounds into account to limit our coordinates up front
372 // for now, just skip too-large src rects (to take the old code path).
373 if (rect_exceeds(rects[0], SkIntToScalar(32767))) {
374 return kUnimplemented_FilterReturn;
375 }
376
377 SkIPoint margin;
378 SkMask srcM, dstM;
379 rects[0].roundOut(&srcM.fBounds);
380 srcM.fImage = NULL;
381 srcM.fFormat = SkMask::kA8_Format;
382 srcM.fRowBytes = 0;
383
384 bool filterResult = false;
385 if (count == 1 && c_analyticBlurNinepatch) {
386 // special case for fast rect blur
387 // don't actually do the blur the first time, just compute the correct size
388 filterResult = this->filterRectMask(&dstM, rects[0], matrix, &margin,
389 SkMask::kJustComputeBounds_CreateMode);
390 } else {
391 filterResult = this->filterMask(&dstM, srcM, matrix, &margin);
392 }
393
394 if (!filterResult) {
395 return kFalse_FilterReturn;
396 }
397
398 /*
399 * smallR is the smallest version of 'rect' that will still guarantee that
400 * we get the same blur results on all edges, plus 1 center row/col that is
401 * representative of the extendible/stretchable edges of the ninepatch.
402 * Since our actual edge may be fractional we inset 1 more to be sure we
403 * don't miss any interior blur.
404 * x is an added pixel of blur, and { and } are the (fractional) edge
405 * pixels from the original rect.
406 *
407 * x x { x x .... x x } x x
408 *
409 * Thus, in this case, we inset by a total of 5 (on each side) beginning
410 * with our outer-rect (dstM.fBounds)
411 */
412 SkRect smallR[2];
413 SkIPoint center;
414
415 // +2 is from +1 for each edge (to account for possible fractional edges
416 int smallW = dstM.fBounds.width() - srcM.fBounds.width() + 2;
417 int smallH = dstM.fBounds.height() - srcM.fBounds.height() + 2;
418 SkIRect innerIR;
419
420 if (1 == count) {
421 innerIR = srcM.fBounds;
422 center.set(smallW, smallH);
423 } else {
424 SkASSERT(2 == count);
425 rects[1].roundIn(&innerIR);
426 center.set(smallW + (innerIR.left() - srcM.fBounds.left()),
427 smallH + (innerIR.top() - srcM.fBounds.top()));
428 }
429
430 // +1 so we get a clean, stretchable, center row/col
431 smallW += 1;
432 smallH += 1;
433
434 // we want the inset amounts to be integral, so we don't change any
435 // fractional phase on the fRight or fBottom of our smallR.
436 const SkScalar dx = SkIntToScalar(innerIR.width() - smallW);
437 const SkScalar dy = SkIntToScalar(innerIR.height() - smallH);
438 if (dx < 0 || dy < 0) {
439 // we're too small, relative to our blur, to break into nine-patch,
440 // so we ask to have our normal filterMask() be called.
441 return kUnimplemented_FilterReturn;
442 }
443
444 smallR[0].set(rects[0].left(), rects[0].top(), rects[0].right() - dx, rects[0].bottom() - dy);
445 if (smallR[0].width() < 2 || smallR[0].height() < 2) {
446 return kUnimplemented_FilterReturn;
447 }
448 if (2 == count) {
449 smallR[1].set(rects[1].left(), rects[1].top(),
450 rects[1].right() - dx, rects[1].bottom() - dy);
451 SkASSERT(!smallR[1].isEmpty());
452 }
453
454 if (count > 1 || !c_analyticBlurNinepatch) {
455 if (!draw_rects_into_mask(smallR, count, &srcM)) {
456 return kFalse_FilterReturn;
457 }
458
459 SkAutoMaskFreeImage amf(srcM.fImage);
460
461 if (!this->filterMask(&patch->fMask, srcM, matrix, &margin)) {
462 return kFalse_FilterReturn;
463 }
464 } else {
465 if (!this->filterRectMask(&patch->fMask, smallR[0], matrix, &margin,
466 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
467 return kFalse_FilterReturn;
468 }
469 }
470 patch->fMask.fBounds.offsetTo(0, 0);
471 patch->fOuterRect = dstM.fBounds;
472 patch->fCenter = center;
473 return kTrue_FilterReturn;
474 }
475
computeFastBounds(const SkRect & src,SkRect * dst) const476 void SkBlurMaskFilterImpl::computeFastBounds(const SkRect& src,
477 SkRect* dst) const {
478 SkScalar pad = 3.0f * fSigma;
479
480 dst->set(src.fLeft - pad, src.fTop - pad,
481 src.fRight + pad, src.fBottom + pad);
482 }
483
SkBlurMaskFilterImpl(SkFlattenableReadBuffer & buffer)484 SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkFlattenableReadBuffer& buffer)
485 : SkMaskFilter(buffer) {
486 #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V16_AND_ALL_OTHER_INSTANCES_TOO
487 // TODO: when the skps are recaptured at > v15 the SkScalarAbs can be removed
488 #endif
489 fSigma = SkScalarAbs(buffer.readScalar());
490 fBlurStyle = (SkBlurMaskFilter::BlurStyle)buffer.readInt();
491 fBlurFlags = buffer.readUInt() & SkBlurMaskFilter::kAll_BlurFlag;
492 SkASSERT(fSigma >= 0);
493 SkASSERT((unsigned)fBlurStyle < SkBlurMaskFilter::kBlurStyleCount);
494 }
495
flatten(SkFlattenableWriteBuffer & buffer) const496 void SkBlurMaskFilterImpl::flatten(SkFlattenableWriteBuffer& buffer) const {
497 this->INHERITED::flatten(buffer);
498 buffer.writeScalar(fSigma);
499 buffer.writeInt(fBlurStyle);
500 buffer.writeUInt(fBlurFlags);
501 }
502
503 #if SK_SUPPORT_GPU
504
canFilterMaskGPU(const SkRect & srcBounds,const SkIRect & clipBounds,const SkMatrix & ctm,SkRect * maskRect) const505 bool SkBlurMaskFilterImpl::canFilterMaskGPU(const SkRect& srcBounds,
506 const SkIRect& clipBounds,
507 const SkMatrix& ctm,
508 SkRect* maskRect) const {
509 SkScalar xformedSigma = this->computeXformedSigma(ctm);
510 if (xformedSigma <= 0) {
511 return false;
512 }
513
514 static const SkScalar kMIN_GPU_BLUR_SIZE = SkIntToScalar(64);
515 static const SkScalar kMIN_GPU_BLUR_SIGMA = SkIntToScalar(32);
516
517 if (srcBounds.width() <= kMIN_GPU_BLUR_SIZE &&
518 srcBounds.height() <= kMIN_GPU_BLUR_SIZE &&
519 xformedSigma <= kMIN_GPU_BLUR_SIGMA) {
520 // We prefer to blur small rect with small radius via CPU.
521 return false;
522 }
523
524 if (NULL == maskRect) {
525 // don't need to compute maskRect
526 return true;
527 }
528
529 float sigma3 = 3 * SkScalarToFloat(xformedSigma);
530
531 SkRect clipRect = SkRect::Make(clipBounds);
532 SkRect srcRect(srcBounds);
533
534 // Outset srcRect and clipRect by 3 * sigma, to compute affected blur area.
535 srcRect.outset(sigma3, sigma3);
536 clipRect.outset(sigma3, sigma3);
537 srcRect.intersect(clipRect);
538 *maskRect = srcRect;
539 return true;
540 }
541
filterMaskGPU(GrTexture * src,const SkRect & maskRect,GrTexture ** result,bool canOverwriteSrc) const542 bool SkBlurMaskFilterImpl::filterMaskGPU(GrTexture* src,
543 const SkRect& maskRect,
544 GrTexture** result,
545 bool canOverwriteSrc) const {
546 SkRect clipRect = SkRect::MakeWH(maskRect.width(), maskRect.height());
547
548 GrContext* context = src->getContext();
549
550 GrContext::AutoWideOpenIdentityDraw awo(context, NULL);
551
552 SkScalar xformedSigma = this->computeXformedSigma(context->getMatrix());
553 SkASSERT(xformedSigma > 0);
554
555 // If we're doing a normal blur, we can clobber the pathTexture in the
556 // gaussianBlur. Otherwise, we need to save it for later compositing.
557 bool isNormalBlur = (SkBlurMaskFilter::kNormal_BlurStyle == fBlurStyle);
558 *result = SkGpuBlurUtils::GaussianBlur(context, src, isNormalBlur && canOverwriteSrc,
559 clipRect, false, xformedSigma, xformedSigma);
560 if (NULL == *result) {
561 return false;
562 }
563
564 if (!isNormalBlur) {
565 context->setIdentityMatrix();
566 GrPaint paint;
567 SkMatrix matrix;
568 matrix.setIDiv(src->width(), src->height());
569 // Blend pathTexture over blurTexture.
570 GrContext::AutoRenderTarget art(context, (*result)->asRenderTarget());
571 paint.addColorEffect(GrSimpleTextureEffect::Create(src, matrix))->unref();
572 if (SkBlurMaskFilter::kInner_BlurStyle == fBlurStyle) {
573 // inner: dst = dst * src
574 paint.setBlendFunc(kDC_GrBlendCoeff, kZero_GrBlendCoeff);
575 } else if (SkBlurMaskFilter::kSolid_BlurStyle == fBlurStyle) {
576 // solid: dst = src + dst - src * dst
577 // = (1 - dst) * src + 1 * dst
578 paint.setBlendFunc(kIDC_GrBlendCoeff, kOne_GrBlendCoeff);
579 } else if (SkBlurMaskFilter::kOuter_BlurStyle == fBlurStyle) {
580 // outer: dst = dst * (1 - src)
581 // = 0 * src + (1 - src) * dst
582 paint.setBlendFunc(kZero_GrBlendCoeff, kISC_GrBlendCoeff);
583 }
584 context->drawRect(paint, clipRect);
585 }
586
587 return true;
588 }
589
590 #endif // SK_SUPPORT_GPU
591
592
593 #ifdef SK_DEVELOPER
toString(SkString * str) const594 void SkBlurMaskFilterImpl::toString(SkString* str) const {
595 str->append("SkBlurMaskFilterImpl: (");
596
597 str->append("sigma: ");
598 str->appendScalar(fSigma);
599 str->append(" ");
600
601 static const char* gStyleName[SkBlurMaskFilter::kBlurStyleCount] = {
602 "normal", "solid", "outer", "inner"
603 };
604
605 str->appendf("style: %s ", gStyleName[fBlurStyle]);
606 str->append("flags: (");
607 if (fBlurFlags) {
608 bool needSeparator = false;
609 SkAddFlagToString(str,
610 SkToBool(fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag),
611 "IgnoreXform", &needSeparator);
612 SkAddFlagToString(str,
613 SkToBool(fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag),
614 "HighQuality", &needSeparator);
615 } else {
616 str->append("None");
617 }
618 str->append("))");
619 }
620 #endif
621
622 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkBlurMaskFilter)
623 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurMaskFilterImpl)
624 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
625