8dd82c5ac369851076dc21ef424e28d699dc655e
[platform/upstream/libSkiaSharp.git] / src / effects / SkBlurMaskFilter.cpp
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 "SkReadBuffer.h"
13 #include "SkWriteBuffer.h"
14 #include "SkMaskFilter.h"
15 #include "SkRRect.h"
16 #include "SkRTConf.h"
17 #include "SkStringUtils.h"
18 #include "SkStrokeRec.h"
19
20 #if SK_SUPPORT_GPU
21 #include "GrCircleBlurFragmentProcessor.h"
22 #include "GrContext.h"
23 #include "GrDrawContext.h"
24 #include "GrTexture.h"
25 #include "GrFragmentProcessor.h"
26 #include "GrInvariantOutput.h"
27 #include "SkGrPixelRef.h"
28 #include "SkDraw.h"
29 #include "effects/GrSimpleTextureEffect.h"
30 #include "glsl/GrGLSLFragmentProcessor.h"
31 #include "glsl/GrGLSLFragmentShaderBuilder.h"
32 #include "glsl/GrGLSLProgramBuilder.h"
33 #include "glsl/GrGLSLProgramDataManager.h"
34 #include "glsl/GrGLSLTextureSampler.h"
35 #endif
36
37 SkScalar SkBlurMaskFilter::ConvertRadiusToSigma(SkScalar radius) {
38     return SkBlurMask::ConvertRadiusToSigma(radius);
39 }
40
41 class SkBlurMaskFilterImpl : public SkMaskFilter {
42 public:
43     SkBlurMaskFilterImpl(SkScalar sigma, SkBlurStyle, uint32_t flags);
44
45     // overrides from SkMaskFilter
46     SkMask::Format getFormat() const override;
47     bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&,
48                     SkIPoint* margin) const override;
49
50 #if SK_SUPPORT_GPU
51     bool canFilterMaskGPU(const SkRRect& devRRect,
52                           const SkIRect& clipBounds,
53                           const SkMatrix& ctm,
54                           SkRect* maskRect) const override;
55     bool directFilterMaskGPU(GrTextureProvider* texProvider,
56                              GrDrawContext* drawContext,
57                              GrPaint* grp,
58                              const GrClip&,
59                              const SkMatrix& viewMatrix,
60                              const SkStrokeRec& strokeRec,
61                              const SkPath& path) const override;
62     bool directFilterRRectMaskGPU(GrTextureProvider* texProvider,
63                                   GrDrawContext* drawContext,
64                                   GrPaint* grp,
65                                   const GrClip&,
66                                   const SkMatrix& viewMatrix,
67                                   const SkStrokeRec& strokeRec,
68                                   const SkRRect& rrect) const override;
69     bool filterMaskGPU(GrTexture* src,
70                        const SkMatrix& ctm,
71                        const SkRect& maskRect,
72                        GrTexture** result,
73                        bool canOverwriteSrc) const override;
74 #endif
75
76     void computeFastBounds(const SkRect&, SkRect*) const override;
77     bool asABlur(BlurRec*) const override;
78
79     SK_TO_STRING_OVERRIDE()
80     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBlurMaskFilterImpl)
81
82 protected:
83     FilterReturn filterRectsToNine(const SkRect[], int count, const SkMatrix&,
84                                    const SkIRect& clipBounds,
85                                    NinePatch*) const override;
86
87     FilterReturn filterRRectToNine(const SkRRect&, const SkMatrix&,
88                                    const SkIRect& clipBounds,
89                                    NinePatch*) const override;
90
91     bool filterRectMask(SkMask* dstM, const SkRect& r, const SkMatrix& matrix,
92                         SkIPoint* margin, SkMask::CreateMode createMode) const;
93     bool filterRRectMask(SkMask* dstM, const SkRRect& r, const SkMatrix& matrix,
94                         SkIPoint* margin, SkMask::CreateMode createMode) const;
95
96 private:
97     // To avoid unseemly allocation requests (esp. for finite platforms like
98     // handset) we limit the radius so something manageable. (as opposed to
99     // a request like 10,000)
100     static const SkScalar kMAX_BLUR_SIGMA;
101
102     SkScalar    fSigma;
103     SkBlurStyle fBlurStyle;
104     uint32_t    fBlurFlags;
105
106     SkBlurQuality getQuality() const {
107         return (fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag) ?
108                 kHigh_SkBlurQuality : kLow_SkBlurQuality;
109     }
110
111     SkBlurMaskFilterImpl(SkReadBuffer&);
112     void flatten(SkWriteBuffer&) const override;
113
114     SkScalar computeXformedSigma(const SkMatrix& ctm) const {
115         bool ignoreTransform = SkToBool(fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag);
116
117         SkScalar xformedSigma = ignoreTransform ? fSigma : ctm.mapRadius(fSigma);
118         return SkMinScalar(xformedSigma, kMAX_BLUR_SIGMA);
119     }
120
121     friend class SkBlurMaskFilter;
122
123     typedef SkMaskFilter INHERITED;
124 };
125
126 const SkScalar SkBlurMaskFilterImpl::kMAX_BLUR_SIGMA = SkIntToScalar(128);
127
128 SkMaskFilter* SkBlurMaskFilter::Create(SkBlurStyle style, SkScalar sigma, uint32_t flags) {
129     if (!SkScalarIsFinite(sigma) || sigma <= 0) {
130         return nullptr;
131     }
132     if ((unsigned)style > (unsigned)kLastEnum_SkBlurStyle) {
133         return nullptr;
134     }
135     if (flags > SkBlurMaskFilter::kAll_BlurFlag) {
136         return nullptr;
137     }
138     return new SkBlurMaskFilterImpl(sigma, style, flags);
139 }
140
141 ///////////////////////////////////////////////////////////////////////////////
142
143 SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkScalar sigma, SkBlurStyle style, uint32_t flags)
144     : fSigma(sigma)
145     , fBlurStyle(style)
146     , fBlurFlags(flags) {
147     SkASSERT(fSigma > 0);
148     SkASSERT((unsigned)style <= kLastEnum_SkBlurStyle);
149     SkASSERT(flags <= SkBlurMaskFilter::kAll_BlurFlag);
150 }
151
152 SkMask::Format SkBlurMaskFilterImpl::getFormat() const {
153     return SkMask::kA8_Format;
154 }
155
156 bool SkBlurMaskFilterImpl::asABlur(BlurRec* rec) const {
157     if (fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag) {
158         return false;
159     }
160
161     if (rec) {
162         rec->fSigma = fSigma;
163         rec->fStyle = fBlurStyle;
164         rec->fQuality = this->getQuality();
165     }
166     return true;
167 }
168
169 bool SkBlurMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src,
170                                       const SkMatrix& matrix,
171                                       SkIPoint* margin) const {
172     SkScalar sigma = this->computeXformedSigma(matrix);
173     return SkBlurMask::BoxBlur(dst, src, sigma, fBlurStyle, this->getQuality(), margin);
174 }
175
176 bool SkBlurMaskFilterImpl::filterRectMask(SkMask* dst, const SkRect& r,
177                                           const SkMatrix& matrix,
178                                           SkIPoint* margin, SkMask::CreateMode createMode) const {
179     SkScalar sigma = computeXformedSigma(matrix);
180
181     return SkBlurMask::BlurRect(sigma, dst, r, fBlurStyle, margin, createMode);
182 }
183
184 bool SkBlurMaskFilterImpl::filterRRectMask(SkMask* dst, const SkRRect& r,
185                                           const SkMatrix& matrix,
186                                           SkIPoint* margin, SkMask::CreateMode createMode) const {
187     SkScalar sigma = computeXformedSigma(matrix);
188
189     return SkBlurMask::BlurRRect(sigma, dst, r, fBlurStyle, margin, createMode);
190 }
191
192 #include "SkCanvas.h"
193
194 static bool prepare_to_draw_into_mask(const SkRect& bounds, SkMask* mask) {
195     SkASSERT(mask != nullptr);
196
197     mask->fBounds = bounds.roundOut();
198     mask->fRowBytes = SkAlign4(mask->fBounds.width());
199     mask->fFormat = SkMask::kA8_Format;
200     const size_t size = mask->computeImageSize();
201     mask->fImage = SkMask::AllocImage(size);
202     if (nullptr == mask->fImage) {
203         return false;
204     }
205
206     // FIXME: use sk_calloc in AllocImage?
207     sk_bzero(mask->fImage, size);
208     return true;
209 }
210
211 static bool draw_rrect_into_mask(const SkRRect rrect, SkMask* mask) {
212     if (!prepare_to_draw_into_mask(rrect.rect(), mask)) {
213         return false;
214     }
215
216     // FIXME: This code duplicates code in draw_rects_into_mask, below. Is there a
217     // clean way to share more code?
218     SkBitmap bitmap;
219     bitmap.installMaskPixels(*mask);
220
221     SkCanvas canvas(bitmap);
222     canvas.translate(-SkIntToScalar(mask->fBounds.left()),
223                      -SkIntToScalar(mask->fBounds.top()));
224
225     SkPaint paint;
226     paint.setAntiAlias(true);
227     canvas.drawRRect(rrect, paint);
228     return true;
229 }
230
231 static bool draw_rects_into_mask(const SkRect rects[], int count, SkMask* mask) {
232     if (!prepare_to_draw_into_mask(rects[0], mask)) {
233         return false;
234     }
235
236     SkBitmap bitmap;
237     bitmap.installPixels(SkImageInfo::Make(mask->fBounds.width(),
238                                            mask->fBounds.height(),
239                                            kAlpha_8_SkColorType,
240                                            kPremul_SkAlphaType),
241                          mask->fImage, mask->fRowBytes);
242
243     SkCanvas canvas(bitmap);
244     canvas.translate(-SkIntToScalar(mask->fBounds.left()),
245                      -SkIntToScalar(mask->fBounds.top()));
246
247     SkPaint paint;
248     paint.setAntiAlias(true);
249
250     if (1 == count) {
251         canvas.drawRect(rects[0], paint);
252     } else {
253         // todo: do I need a fast way to do this?
254         SkPath path;
255         path.addRect(rects[0]);
256         path.addRect(rects[1]);
257         path.setFillType(SkPath::kEvenOdd_FillType);
258         canvas.drawPath(path, paint);
259     }
260     return true;
261 }
262
263 static bool rect_exceeds(const SkRect& r, SkScalar v) {
264     return r.fLeft < -v || r.fTop < -v || r.fRight > v || r.fBottom > v ||
265            r.width() > v || r.height() > v;
266 }
267
268 #include "SkMaskCache.h"
269
270 static SkCachedData* copy_mask_to_cacheddata(SkMask* mask) {
271     const size_t size = mask->computeTotalImageSize();
272     SkCachedData* data = SkResourceCache::NewCachedData(size);
273     if (data) {
274         memcpy(data->writable_data(), mask->fImage, size);
275         SkMask::FreeImage(mask->fImage);
276         mask->fImage = (uint8_t*)data->data();
277     }
278     return data;
279 }
280
281 static SkCachedData* find_cached_rrect(SkMask* mask, SkScalar sigma, SkBlurStyle style,
282                                        SkBlurQuality quality, const SkRRect& rrect) {
283     return SkMaskCache::FindAndRef(sigma, style, quality, rrect, mask);
284 }
285
286 static SkCachedData* add_cached_rrect(SkMask* mask, SkScalar sigma, SkBlurStyle style,
287                                       SkBlurQuality quality, const SkRRect& rrect) {
288     SkCachedData* cache = copy_mask_to_cacheddata(mask);
289     if (cache) {
290         SkMaskCache::Add(sigma, style, quality, rrect, *mask, cache);
291     }
292     return cache;
293 }
294
295 static SkCachedData* find_cached_rects(SkMask* mask, SkScalar sigma, SkBlurStyle style,
296                                        SkBlurQuality quality, const SkRect rects[], int count) {
297     return SkMaskCache::FindAndRef(sigma, style, quality, rects, count, mask);
298 }
299
300 static SkCachedData* add_cached_rects(SkMask* mask, SkScalar sigma, SkBlurStyle style,
301                                       SkBlurQuality quality, const SkRect rects[], int count) {
302     SkCachedData* cache = copy_mask_to_cacheddata(mask);
303     if (cache) {
304         SkMaskCache::Add(sigma, style, quality, rects, count, *mask, cache);
305     }
306     return cache;
307 }
308
309 #ifdef SK_IGNORE_FAST_RRECT_BLUR
310 SK_CONF_DECLARE(bool, c_analyticBlurRRect, "mask.filter.blur.analyticblurrrect", false, "Use the faster analytic blur approach for ninepatch rects");
311 #else
312 SK_CONF_DECLARE(bool, c_analyticBlurRRect, "mask.filter.blur.analyticblurrrect", true, "Use the faster analytic blur approach for ninepatch round rects");
313 #endif
314
315 SkMaskFilter::FilterReturn
316 SkBlurMaskFilterImpl::filterRRectToNine(const SkRRect& rrect, const SkMatrix& matrix,
317                                         const SkIRect& clipBounds,
318                                         NinePatch* patch) const {
319     SkASSERT(patch != nullptr);
320     switch (rrect.getType()) {
321         case SkRRect::kEmpty_Type:
322             // Nothing to draw.
323             return kFalse_FilterReturn;
324
325         case SkRRect::kRect_Type:
326             // We should have caught this earlier.
327             SkASSERT(false);
328             // Fall through.
329         case SkRRect::kOval_Type:
330             // The nine patch special case does not handle ovals, and we
331             // already have code for rectangles.
332             return kUnimplemented_FilterReturn;
333
334         // These three can take advantage of this fast path.
335         case SkRRect::kSimple_Type:
336         case SkRRect::kNinePatch_Type:
337         case SkRRect::kComplex_Type:
338             break;
339     }
340
341     // TODO: report correct metrics for innerstyle, where we do not grow the
342     // total bounds, but we do need an inset the size of our blur-radius
343     if (kInner_SkBlurStyle == fBlurStyle) {
344         return kUnimplemented_FilterReturn;
345     }
346
347     // TODO: take clipBounds into account to limit our coordinates up front
348     // for now, just skip too-large src rects (to take the old code path).
349     if (rect_exceeds(rrect.rect(), SkIntToScalar(32767))) {
350         return kUnimplemented_FilterReturn;
351     }
352
353     SkIPoint margin;
354     SkMask  srcM, dstM;
355     srcM.fBounds = rrect.rect().roundOut();
356     srcM.fImage = nullptr;
357     srcM.fFormat = SkMask::kA8_Format;
358     srcM.fRowBytes = 0;
359
360     bool filterResult = false;
361     if (c_analyticBlurRRect) {
362         // special case for fast round rect blur
363         // don't actually do the blur the first time, just compute the correct size
364         filterResult = this->filterRRectMask(&dstM, rrect, matrix, &margin,
365                                             SkMask::kJustComputeBounds_CreateMode);
366     }
367
368     if (!filterResult) {
369         filterResult = this->filterMask(&dstM, srcM, matrix, &margin);
370     }
371
372     if (!filterResult) {
373         return kFalse_FilterReturn;
374     }
375
376     // Now figure out the appropriate width and height of the smaller round rectangle
377     // to stretch. It will take into account the larger radius per side as well as double
378     // the margin, to account for inner and outer blur.
379     const SkVector& UL = rrect.radii(SkRRect::kUpperLeft_Corner);
380     const SkVector& UR = rrect.radii(SkRRect::kUpperRight_Corner);
381     const SkVector& LR = rrect.radii(SkRRect::kLowerRight_Corner);
382     const SkVector& LL = rrect.radii(SkRRect::kLowerLeft_Corner);
383
384     const SkScalar leftUnstretched = SkTMax(UL.fX, LL.fX) + SkIntToScalar(2 * margin.fX);
385     const SkScalar rightUnstretched = SkTMax(UR.fX, LR.fX) + SkIntToScalar(2 * margin.fX);
386
387     // Extra space in the middle to ensure an unchanging piece for stretching. Use 3 to cover
388     // any fractional space on either side plus 1 for the part to stretch.
389     const SkScalar stretchSize = SkIntToScalar(3);
390
391     const SkScalar totalSmallWidth = leftUnstretched + rightUnstretched + stretchSize;
392     if (totalSmallWidth >= rrect.rect().width()) {
393         // There is no valid piece to stretch.
394         return kUnimplemented_FilterReturn;
395     }
396
397     const SkScalar topUnstretched = SkTMax(UL.fY, UR.fY) + SkIntToScalar(2 * margin.fY);
398     const SkScalar bottomUnstretched = SkTMax(LL.fY, LR.fY) + SkIntToScalar(2 * margin.fY);
399
400     const SkScalar totalSmallHeight = topUnstretched + bottomUnstretched + stretchSize;
401     if (totalSmallHeight >= rrect.rect().height()) {
402         // There is no valid piece to stretch.
403         return kUnimplemented_FilterReturn;
404     }
405
406     SkRect smallR = SkRect::MakeWH(totalSmallWidth, totalSmallHeight);
407
408     SkRRect smallRR;
409     SkVector radii[4];
410     radii[SkRRect::kUpperLeft_Corner] = UL;
411     radii[SkRRect::kUpperRight_Corner] = UR;
412     radii[SkRRect::kLowerRight_Corner] = LR;
413     radii[SkRRect::kLowerLeft_Corner] = LL;
414     smallRR.setRectRadii(smallR, radii);
415
416     const SkScalar sigma = this->computeXformedSigma(matrix);
417     SkCachedData* cache = find_cached_rrect(&patch->fMask, sigma, fBlurStyle,
418                                             this->getQuality(), smallRR);
419     if (!cache) {
420         bool analyticBlurWorked = false;
421         if (c_analyticBlurRRect) {
422             analyticBlurWorked =
423                 this->filterRRectMask(&patch->fMask, smallRR, matrix, &margin,
424                                       SkMask::kComputeBoundsAndRenderImage_CreateMode);
425         }
426
427         if (!analyticBlurWorked) {
428             if (!draw_rrect_into_mask(smallRR, &srcM)) {
429                 return kFalse_FilterReturn;
430             }
431
432             SkAutoMaskFreeImage amf(srcM.fImage);
433
434             if (!this->filterMask(&patch->fMask, srcM, matrix, &margin)) {
435                 return kFalse_FilterReturn;
436             }
437         }
438         cache = add_cached_rrect(&patch->fMask, sigma, fBlurStyle, this->getQuality(), smallRR);
439     }
440
441     patch->fMask.fBounds.offsetTo(0, 0);
442     patch->fOuterRect = dstM.fBounds;
443     patch->fCenter.fX = SkScalarCeilToInt(leftUnstretched) + 1;
444     patch->fCenter.fY = SkScalarCeilToInt(topUnstretched) + 1;
445     SkASSERT(nullptr == patch->fCache);
446     patch->fCache = cache;  // transfer ownership to patch
447     return kTrue_FilterReturn;
448 }
449
450 SK_CONF_DECLARE(bool, c_analyticBlurNinepatch, "mask.filter.analyticNinePatch", true, "Use the faster analytic blur approach for ninepatch rects");
451
452 SkMaskFilter::FilterReturn
453 SkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count,
454                                         const SkMatrix& matrix,
455                                         const SkIRect& clipBounds,
456                                         NinePatch* patch) const {
457     if (count < 1 || count > 2) {
458         return kUnimplemented_FilterReturn;
459     }
460
461     // TODO: report correct metrics for innerstyle, where we do not grow the
462     // total bounds, but we do need an inset the size of our blur-radius
463     if (kInner_SkBlurStyle == fBlurStyle || kOuter_SkBlurStyle == fBlurStyle) {
464         return kUnimplemented_FilterReturn;
465     }
466
467     // TODO: take clipBounds into account to limit our coordinates up front
468     // for now, just skip too-large src rects (to take the old code path).
469     if (rect_exceeds(rects[0], SkIntToScalar(32767))) {
470         return kUnimplemented_FilterReturn;
471     }
472
473     SkIPoint margin;
474     SkMask  srcM, dstM;
475     srcM.fBounds = rects[0].roundOut();
476     srcM.fImage = nullptr;
477     srcM.fFormat = SkMask::kA8_Format;
478     srcM.fRowBytes = 0;
479
480     bool filterResult = false;
481     if (count == 1 && c_analyticBlurNinepatch) {
482         // special case for fast rect blur
483         // don't actually do the blur the first time, just compute the correct size
484         filterResult = this->filterRectMask(&dstM, rects[0], matrix, &margin,
485                                             SkMask::kJustComputeBounds_CreateMode);
486     } else {
487         filterResult = this->filterMask(&dstM, srcM, matrix, &margin);
488     }
489
490     if (!filterResult) {
491         return kFalse_FilterReturn;
492     }
493
494     /*
495      *  smallR is the smallest version of 'rect' that will still guarantee that
496      *  we get the same blur results on all edges, plus 1 center row/col that is
497      *  representative of the extendible/stretchable edges of the ninepatch.
498      *  Since our actual edge may be fractional we inset 1 more to be sure we
499      *  don't miss any interior blur.
500      *  x is an added pixel of blur, and { and } are the (fractional) edge
501      *  pixels from the original rect.
502      *
503      *   x x { x x .... x x } x x
504      *
505      *  Thus, in this case, we inset by a total of 5 (on each side) beginning
506      *  with our outer-rect (dstM.fBounds)
507      */
508     SkRect smallR[2];
509     SkIPoint center;
510
511     // +2 is from +1 for each edge (to account for possible fractional edges
512     int smallW = dstM.fBounds.width() - srcM.fBounds.width() + 2;
513     int smallH = dstM.fBounds.height() - srcM.fBounds.height() + 2;
514     SkIRect innerIR;
515
516     if (1 == count) {
517         innerIR = srcM.fBounds;
518         center.set(smallW, smallH);
519     } else {
520         SkASSERT(2 == count);
521         rects[1].roundIn(&innerIR);
522         center.set(smallW + (innerIR.left() - srcM.fBounds.left()),
523                    smallH + (innerIR.top() - srcM.fBounds.top()));
524     }
525
526     // +1 so we get a clean, stretchable, center row/col
527     smallW += 1;
528     smallH += 1;
529
530     // we want the inset amounts to be integral, so we don't change any
531     // fractional phase on the fRight or fBottom of our smallR.
532     const SkScalar dx = SkIntToScalar(innerIR.width() - smallW);
533     const SkScalar dy = SkIntToScalar(innerIR.height() - smallH);
534     if (dx < 0 || dy < 0) {
535         // we're too small, relative to our blur, to break into nine-patch,
536         // so we ask to have our normal filterMask() be called.
537         return kUnimplemented_FilterReturn;
538     }
539
540     smallR[0].set(rects[0].left(), rects[0].top(), rects[0].right() - dx, rects[0].bottom() - dy);
541     if (smallR[0].width() < 2 || smallR[0].height() < 2) {
542         return kUnimplemented_FilterReturn;
543     }
544     if (2 == count) {
545         smallR[1].set(rects[1].left(), rects[1].top(),
546                       rects[1].right() - dx, rects[1].bottom() - dy);
547         SkASSERT(!smallR[1].isEmpty());
548     }
549
550     const SkScalar sigma = this->computeXformedSigma(matrix);
551     SkCachedData* cache = find_cached_rects(&patch->fMask, sigma, fBlurStyle,
552                                             this->getQuality(), smallR, count);
553     if (!cache) {
554         if (count > 1 || !c_analyticBlurNinepatch) {
555             if (!draw_rects_into_mask(smallR, count, &srcM)) {
556                 return kFalse_FilterReturn;
557             }
558
559             SkAutoMaskFreeImage amf(srcM.fImage);
560
561             if (!this->filterMask(&patch->fMask, srcM, matrix, &margin)) {
562                 return kFalse_FilterReturn;
563             }
564         } else {
565             if (!this->filterRectMask(&patch->fMask, smallR[0], matrix, &margin,
566                                       SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
567                 return kFalse_FilterReturn;
568             }
569         }
570         cache = add_cached_rects(&patch->fMask, sigma, fBlurStyle, this->getQuality(), smallR, count);
571     }
572     patch->fMask.fBounds.offsetTo(0, 0);
573     patch->fOuterRect = dstM.fBounds;
574     patch->fCenter = center;
575     SkASSERT(nullptr == patch->fCache);
576     patch->fCache = cache;  // transfer ownership to patch
577     return kTrue_FilterReturn;
578 }
579
580 void SkBlurMaskFilterImpl::computeFastBounds(const SkRect& src,
581                                              SkRect* dst) const {
582     SkScalar pad = 3.0f * fSigma;
583
584     dst->set(src.fLeft  - pad, src.fTop    - pad,
585              src.fRight + pad, src.fBottom + pad);
586 }
587
588 SkFlattenable* SkBlurMaskFilterImpl::CreateProc(SkReadBuffer& buffer) {
589     const SkScalar sigma = buffer.readScalar();
590     const unsigned style = buffer.readUInt();
591     const unsigned flags = buffer.readUInt();
592     if (style <= kLastEnum_SkBlurStyle) {
593         return SkBlurMaskFilter::Create((SkBlurStyle)style, sigma, flags);
594     }
595     return nullptr;
596 }
597
598 void SkBlurMaskFilterImpl::flatten(SkWriteBuffer& buffer) const {
599     buffer.writeScalar(fSigma);
600     buffer.writeUInt(fBlurStyle);
601     buffer.writeUInt(fBlurFlags);
602 }
603
604 #if SK_SUPPORT_GPU
605
606 class GrGLRectBlurEffect;
607
608 class GrRectBlurEffect : public GrFragmentProcessor {
609 public:
610     ~GrRectBlurEffect() override { }
611
612     const char* name() const override { return "RectBlur"; }
613
614     static GrFragmentProcessor* Create(GrTextureProvider *textureProvider,
615                                        const SkRect& rect, float sigma) {
616         int doubleProfileSize = SkScalarCeilToInt(12*sigma);
617
618         if (doubleProfileSize >= rect.width() || doubleProfileSize >= rect.height()) {
619             // if the blur sigma is too large so the gaussian overlaps the whole
620             // rect in either direction, fall back to CPU path for now.
621             return nullptr;
622         }
623
624         SkAutoTUnref<GrTexture> blurProfile(CreateBlurProfileTexture(textureProvider, sigma));
625         if (!blurProfile) {
626            return nullptr;
627         }
628         // in OpenGL ES, mediump floats have a minimum range of 2^14. If we have coordinates bigger
629         // than that, the shader math will end up with infinities and result in the blur effect not
630         // working correctly. To avoid this, we switch into highp when the coordinates are too big.
631         // As 2^14 is the minimum range but the actual range can be bigger, we might end up 
632         // switching to highp sooner than strictly necessary, but most devices that have a bigger 
633         // range for mediump also have mediump being exactly the same as highp (e.g. all non-OpenGL
634         // ES devices), and thus incur no additional penalty for the switch.
635         static const SkScalar kMAX_BLUR_COORD = SkIntToScalar(16000);
636         GrSLPrecision precision;
637         if (SkScalarAbs(rect.top()) > kMAX_BLUR_COORD ||
638             SkScalarAbs(rect.left()) > kMAX_BLUR_COORD ||
639             SkScalarAbs(rect.bottom()) > kMAX_BLUR_COORD ||
640             SkScalarAbs(rect.right()) > kMAX_BLUR_COORD ||
641             SkScalarAbs(rect.width()) > kMAX_BLUR_COORD ||
642             SkScalarAbs(rect.height()) > kMAX_BLUR_COORD) {
643             precision = kHigh_GrSLPrecision;
644         }
645         else {
646             precision = kDefault_GrSLPrecision;
647         }
648         return new GrRectBlurEffect(rect, sigma, blurProfile, precision);
649     }
650
651     const SkRect& getRect() const { return fRect; }
652     float getSigma() const { return fSigma; }
653
654 private:
655     GrRectBlurEffect(const SkRect& rect, float sigma, GrTexture *blurProfile,
656                      GrSLPrecision fPrecision);
657
658     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
659
660     void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
661
662     bool onIsEqual(const GrFragmentProcessor&) const override;
663
664     void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
665
666     static GrTexture* CreateBlurProfileTexture(GrTextureProvider*, float sigma);
667
668     SkRect          fRect;
669     float           fSigma;
670     GrTextureAccess fBlurProfileAccess;
671     GrSLPrecision   fPrecision;
672
673     GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
674
675     typedef GrFragmentProcessor INHERITED;
676 };
677
678 class GrGLRectBlurEffect : public GrGLSLFragmentProcessor {
679 public:
680     GrGLRectBlurEffect(const GrProcessor&, GrSLPrecision precision) 
681     : fPrecision(precision) {
682     }
683     void emitCode(EmitArgs&) override;
684
685     static void GenKey(GrSLPrecision precision, GrProcessorKeyBuilder* b);
686
687 protected:
688     void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
689
690 private:
691     typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
692
693     UniformHandle       fProxyRectUniform;
694     UniformHandle       fProfileSizeUniform;
695     GrSLPrecision       fPrecision;
696
697     typedef GrGLSLFragmentProcessor INHERITED;
698 };
699
700 void OutputRectBlurProfileLookup(GrGLSLFragmentBuilder* fragBuilder,
701                                  const GrGLSLTextureSampler& sampler,
702                                  const char *output,
703                                  const char *profileSize, const char *loc,
704                                  const char *blurred_width,
705                                  const char *sharp_width) {
706     fragBuilder->codeAppendf("float %s;", output);
707     fragBuilder->codeAppendf("{");
708     fragBuilder->codeAppendf("float coord = ((abs(%s - 0.5 * %s) - 0.5 * %s)) / %s;",
709                            loc, blurred_width, sharp_width, profileSize);
710     fragBuilder->codeAppendf("%s = ", output);
711     fragBuilder->appendTextureLookup(sampler, "vec2(coord,0.5)");
712     fragBuilder->codeAppend(".a;");
713     fragBuilder->codeAppendf("}");
714 }
715
716
717 void GrGLRectBlurEffect::GenKey(GrSLPrecision precision, GrProcessorKeyBuilder* b) {
718     b->add32(precision);
719 }
720
721
722 void GrGLRectBlurEffect::emitCode(EmitArgs& args) {
723
724     const char *rectName;
725     const char *profileSizeName;
726
727     const char* precisionString = GrGLSLShaderVar::PrecisionString(args.fGLSLCaps, fPrecision);
728     fProxyRectUniform = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
729                                             kVec4f_GrSLType,
730                                             fPrecision,
731                                             "proxyRect",
732                                             &rectName);
733     fProfileSizeUniform = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
734                                             kFloat_GrSLType,
735                                             kDefault_GrSLPrecision,
736                                             "profileSize",
737                                             &profileSizeName);
738
739     GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
740     const char *fragmentPos = fragBuilder->fragmentPosition();
741
742     if (args.fInputColor) {
743         fragBuilder->codeAppendf("vec4 src=%s;", args.fInputColor);
744     } else {
745         fragBuilder->codeAppendf("vec4 src=vec4(1);");
746     }
747
748     fragBuilder->codeAppendf("%s vec2 translatedPos = %s.xy - %s.xy;", precisionString, fragmentPos, 
749                              rectName);
750     fragBuilder->codeAppendf("%s float width = %s.z - %s.x;", precisionString, rectName, rectName);
751     fragBuilder->codeAppendf("%s float height = %s.w - %s.y;", precisionString, rectName, rectName);
752
753     fragBuilder->codeAppendf("%s vec2 smallDims = vec2(width - %s, height - %s);", precisionString, 
754                              profileSizeName, profileSizeName);
755     fragBuilder->codeAppendf("%s float center = 2.0 * floor(%s/2.0 + .25) - 1.0;", precisionString,
756                              profileSizeName);
757     fragBuilder->codeAppendf("%s vec2 wh = smallDims - vec2(center,center);", precisionString);
758
759     OutputRectBlurProfileLookup(fragBuilder, args.fSamplers[0], "horiz_lookup", profileSizeName,
760                                 "translatedPos.x", "width", "wh.x");
761     OutputRectBlurProfileLookup(fragBuilder, args.fSamplers[0], "vert_lookup", profileSizeName, 
762                                 "translatedPos.y", "height", "wh.y");
763
764     fragBuilder->codeAppendf("float final = horiz_lookup * vert_lookup;");
765     fragBuilder->codeAppendf("%s = src * final;", args.fOutputColor);
766 }
767
768 void GrGLRectBlurEffect::onSetData(const GrGLSLProgramDataManager& pdman,
769                                    const GrProcessor& proc) {
770     const GrRectBlurEffect& rbe = proc.cast<GrRectBlurEffect>();
771     SkRect rect = rbe.getRect();
772
773     pdman.set4f(fProxyRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
774     pdman.set1f(fProfileSizeUniform, SkScalarCeilToScalar(6*rbe.getSigma()));
775 }
776
777 GrTexture* GrRectBlurEffect::CreateBlurProfileTexture(GrTextureProvider* textureProvider,
778                                                       float sigma) {
779     GrSurfaceDesc texDesc;
780
781     unsigned int profileSize = SkScalarCeilToInt(6*sigma);
782
783     texDesc.fWidth = profileSize;
784     texDesc.fHeight = 1;
785     texDesc.fConfig = kAlpha_8_GrPixelConfig;
786
787     static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
788     GrUniqueKey key;
789     GrUniqueKey::Builder builder(&key, kDomain, 1);
790     builder[0] = profileSize;
791     builder.finish();
792
793     GrTexture *blurProfile = textureProvider->findAndRefTextureByUniqueKey(key);
794
795     if (!blurProfile) {
796         SkAutoTDeleteArray<uint8_t> profile(SkBlurMask::ComputeBlurProfile(sigma));
797
798         blurProfile = textureProvider->createTexture(texDesc, true, profile.get(), 0);
799         if (blurProfile) {
800             textureProvider->assignUniqueKeyToTexture(key, blurProfile);
801         }
802     }
803
804     return blurProfile;
805 }
806
807 GrRectBlurEffect::GrRectBlurEffect(const SkRect& rect, float sigma, GrTexture *blurProfile,
808                                    GrSLPrecision precision)
809     : fRect(rect)
810     , fSigma(sigma)
811     , fBlurProfileAccess(blurProfile)
812     , fPrecision(precision) {
813     this->initClassID<GrRectBlurEffect>();
814     this->addTextureAccess(&fBlurProfileAccess);
815     this->setWillReadFragmentPosition();
816 }
817
818 void GrRectBlurEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
819                                              GrProcessorKeyBuilder* b) const {
820     GrGLRectBlurEffect::GenKey(fPrecision, b);
821 }
822
823 GrGLSLFragmentProcessor* GrRectBlurEffect::onCreateGLSLInstance() const {
824     return new GrGLRectBlurEffect(*this, fPrecision);
825 }
826
827 bool GrRectBlurEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
828     const GrRectBlurEffect& s = sBase.cast<GrRectBlurEffect>();
829     return this->getSigma() == s.getSigma() && this->getRect() == s.getRect();
830 }
831
832 void GrRectBlurEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
833     inout->mulByUnknownSingleComponent();
834 }
835
836 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRectBlurEffect);
837
838 const GrFragmentProcessor* GrRectBlurEffect::TestCreate(GrProcessorTestData* d) {
839     float sigma = d->fRandom->nextRangeF(3,8);
840     float width = d->fRandom->nextRangeF(200,300);
841     float height = d->fRandom->nextRangeF(200,300);
842     return GrRectBlurEffect::Create(d->fContext->textureProvider(), SkRect::MakeWH(width, height),
843                                     sigma);
844 }
845
846
847 bool SkBlurMaskFilterImpl::directFilterMaskGPU(GrTextureProvider* texProvider,
848                                                GrDrawContext* drawContext,
849                                                GrPaint* grp,
850                                                const GrClip& clip,
851                                                const SkMatrix& viewMatrix,
852                                                const SkStrokeRec& strokeRec,
853                                                const SkPath& path) const {
854     SkASSERT(drawContext);
855
856     if (fBlurStyle != kNormal_SkBlurStyle) {
857         return false;
858     }
859
860     // TODO: we could handle blurred stroked circles
861     if (!strokeRec.isFillStyle()) {
862         return false;
863     }
864
865     SkScalar xformedSigma = this->computeXformedSigma(viewMatrix);
866
867     SkAutoTUnref<const GrFragmentProcessor> fp;
868
869     SkRect rect;
870     if (path.isRect(&rect)) {
871         int pad = SkScalarCeilToInt(6*xformedSigma)/2;
872         rect.outset(SkIntToScalar(pad), SkIntToScalar(pad));
873
874         fp.reset(GrRectBlurEffect::Create(texProvider, rect, xformedSigma));
875     } else if (path.isOval(&rect) && SkScalarNearlyEqual(rect.width(), rect.height())) {
876         fp.reset(GrCircleBlurFragmentProcessor::Create(texProvider, rect, xformedSigma));
877
878         // expand the rect for the coverage geometry
879         int pad = SkScalarCeilToInt(6*xformedSigma)/2;
880         rect.outset(SkIntToScalar(pad), SkIntToScalar(pad));
881     } else {
882         return false;
883     }
884
885     if (!fp) {
886         return false;
887     }
888
889     grp->addCoverageFragmentProcessor(fp);
890
891     SkMatrix inverse;
892     if (!viewMatrix.invert(&inverse)) {
893         return false;
894     }
895
896     drawContext->fillRectWithLocalMatrix(clip, *grp, SkMatrix::I(), rect, inverse);
897     return true;
898 }
899
900 //////////////////////////////////////////////////////////////////////////////
901
902 class GrRRectBlurEffect : public GrFragmentProcessor {
903 public:
904
905     static const GrFragmentProcessor* Create(GrTextureProvider*, float sigma, const SkRRect&);
906
907     virtual ~GrRRectBlurEffect() {};
908     const char* name() const override { return "GrRRectBlur"; }
909
910     const SkRRect& getRRect() const { return fRRect; }
911     float getSigma() const { return fSigma; }
912
913 private:
914     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
915
916     GrRRectBlurEffect(float sigma, const SkRRect&, GrTexture* profileTexture);
917
918     virtual void onGetGLSLProcessorKey(const GrGLSLCaps& caps,
919                                        GrProcessorKeyBuilder* b) const override;
920
921     bool onIsEqual(const GrFragmentProcessor& other) const override;
922
923     void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
924
925     SkRRect             fRRect;
926     float               fSigma;
927     GrTextureAccess     fNinePatchAccess;
928
929     GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
930
931     typedef GrFragmentProcessor INHERITED;
932 };
933
934
935 const GrFragmentProcessor* GrRRectBlurEffect::Create(GrTextureProvider* texProvider, float sigma,
936                                                      const SkRRect& rrect) {
937     if (rrect.isCircle()) {
938         return GrCircleBlurFragmentProcessor::Create(texProvider, rrect.rect(), sigma);
939     }
940
941     if (!rrect.isSimpleCircular()) {
942         return nullptr;
943     }
944
945     // Make sure we can successfully ninepatch this rrect -- the blur sigma has to be
946     // sufficiently small relative to both the size of the corner radius and the
947     // width (and height) of the rrect.
948
949     unsigned int blurRadius = 3*SkScalarCeilToInt(sigma-1/6.0f);
950     unsigned int cornerRadius = SkScalarCeilToInt(rrect.getSimpleRadii().x());
951     if (cornerRadius + blurRadius > rrect.width()/2 ||
952         cornerRadius + blurRadius > rrect.height()/2) {
953         return nullptr;
954     }
955
956     static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
957     GrUniqueKey key;
958     GrUniqueKey::Builder builder(&key, kDomain, 2);
959     builder[0] = blurRadius;
960     builder[1] = cornerRadius;
961     builder.finish();
962
963     SkAutoTUnref<GrTexture> blurNinePatchTexture(texProvider->findAndRefTextureByUniqueKey(key));
964
965     if (!blurNinePatchTexture) {
966         SkMask mask;
967
968         unsigned int smallRectSide = 2*(blurRadius + cornerRadius) + 1;
969
970         mask.fBounds = SkIRect::MakeWH(smallRectSide, smallRectSide);
971         mask.fFormat = SkMask::kA8_Format;
972         mask.fRowBytes = mask.fBounds.width();
973         mask.fImage = SkMask::AllocImage(mask.computeTotalImageSize());
974         SkAutoMaskFreeImage amfi(mask.fImage);
975
976         memset(mask.fImage, 0, mask.computeTotalImageSize());
977
978         SkRect smallRect;
979         smallRect.setWH(SkIntToScalar(smallRectSide), SkIntToScalar(smallRectSide));
980
981         SkRRect smallRRect;
982         smallRRect.setRectXY(smallRect, SkIntToScalar(cornerRadius), SkIntToScalar(cornerRadius));
983
984         SkPath path;
985         path.addRRect(smallRRect);
986
987         SkDraw::DrawToMask(path, &mask.fBounds, nullptr, nullptr, &mask,
988                            SkMask::kJustRenderImage_CreateMode, SkPaint::kFill_Style);
989
990         SkMask blurredMask;
991         SkBlurMask::BoxBlur(&blurredMask, mask, sigma, kNormal_SkBlurStyle, kHigh_SkBlurQuality,
992                             nullptr, true);
993
994         unsigned int texSide = smallRectSide + 2*blurRadius;
995         GrSurfaceDesc texDesc;
996         texDesc.fWidth = texSide;
997         texDesc.fHeight = texSide;
998         texDesc.fConfig = kAlpha_8_GrPixelConfig;
999
1000         blurNinePatchTexture.reset(
1001             texProvider->createTexture(texDesc, true, blurredMask.fImage, 0));
1002         SkMask::FreeImage(blurredMask.fImage);
1003         if (!blurNinePatchTexture) {
1004             return nullptr;
1005         }
1006         texProvider->assignUniqueKeyToTexture(key, blurNinePatchTexture);
1007     }
1008     return new GrRRectBlurEffect(sigma, rrect, blurNinePatchTexture);
1009 }
1010
1011 void GrRRectBlurEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
1012     inout->mulByUnknownSingleComponent();
1013 }
1014
1015 GrRRectBlurEffect::GrRRectBlurEffect(float sigma, const SkRRect& rrect, GrTexture *ninePatchTexture)
1016     : fRRect(rrect),
1017       fSigma(sigma),
1018       fNinePatchAccess(ninePatchTexture) {
1019     this->initClassID<GrRRectBlurEffect>();
1020     this->addTextureAccess(&fNinePatchAccess);
1021     this->setWillReadFragmentPosition();
1022 }
1023
1024 bool GrRRectBlurEffect::onIsEqual(const GrFragmentProcessor& other) const {
1025     const GrRRectBlurEffect& rrbe = other.cast<GrRRectBlurEffect>();
1026     return fRRect.getSimpleRadii().fX == rrbe.fRRect.getSimpleRadii().fX && fSigma == rrbe.fSigma;
1027 }
1028
1029 //////////////////////////////////////////////////////////////////////////////
1030
1031 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRRectBlurEffect);
1032
1033 const GrFragmentProcessor* GrRRectBlurEffect::TestCreate(GrProcessorTestData* d) {
1034     SkScalar w = d->fRandom->nextRangeScalar(100.f, 1000.f);
1035     SkScalar h = d->fRandom->nextRangeScalar(100.f, 1000.f);
1036     SkScalar r = d->fRandom->nextRangeF(1.f, 9.f);
1037     SkScalar sigma = d->fRandom->nextRangeF(1.f,10.f);
1038     SkRRect rrect;
1039     rrect.setRectXY(SkRect::MakeWH(w, h), r, r);
1040     return GrRRectBlurEffect::Create(d->fContext->textureProvider(), sigma, rrect);
1041 }
1042
1043 //////////////////////////////////////////////////////////////////////////////
1044
1045 class GrGLRRectBlurEffect : public GrGLSLFragmentProcessor {
1046 public:
1047     GrGLRRectBlurEffect(const GrProcessor&) {}
1048
1049     virtual void emitCode(EmitArgs&) override;
1050
1051 protected:
1052     void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
1053
1054 private:
1055     GrGLSLProgramDataManager::UniformHandle fProxyRectUniform;
1056     GrGLSLProgramDataManager::UniformHandle fCornerRadiusUniform;
1057     GrGLSLProgramDataManager::UniformHandle fBlurRadiusUniform;
1058     typedef GrGLSLFragmentProcessor INHERITED;
1059 };
1060
1061 void GrGLRRectBlurEffect::emitCode(EmitArgs& args) {
1062     const char *rectName;
1063     const char *cornerRadiusName;
1064     const char *blurRadiusName;
1065
1066     // The proxy rect has left, top, right, and bottom edges correspond to
1067     // components x, y, z, and w, respectively.
1068
1069     fProxyRectUniform = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
1070                                                   kVec4f_GrSLType,
1071                                                   kDefault_GrSLPrecision,
1072                                                   "proxyRect",
1073                                                   &rectName);
1074     fCornerRadiusUniform = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
1075                                                      kFloat_GrSLType,
1076                                                      kDefault_GrSLPrecision,
1077                                                      "cornerRadius",
1078                                                      &cornerRadiusName);
1079     fBlurRadiusUniform = args.fBuilder->addUniform(GrGLSLProgramBuilder::kFragment_Visibility,
1080                                                    kFloat_GrSLType,
1081                                                    kDefault_GrSLPrecision,
1082                                                    "blurRadius",
1083                                                    &blurRadiusName);
1084
1085     GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
1086     const char* fragmentPos = fragBuilder->fragmentPosition();
1087
1088     // warp the fragment position to the appropriate part of the 9patch blur texture
1089
1090     fragBuilder->codeAppendf("vec2 rectCenter = (%s.xy + %s.zw)/2.0;", rectName, rectName);
1091     fragBuilder->codeAppendf("vec2 translatedFragPos = %s.xy - %s.xy;", fragmentPos, rectName);
1092     fragBuilder->codeAppendf("float threshold = %s + 2.0*%s;", cornerRadiusName, blurRadiusName);
1093     fragBuilder->codeAppendf("vec2 middle = %s.zw - %s.xy - 2.0*threshold;", rectName, rectName);
1094
1095     fragBuilder->codeAppendf(
1096            "if (translatedFragPos.x >= threshold && translatedFragPos.x < (middle.x+threshold)) {");
1097     fragBuilder->codeAppendf("translatedFragPos.x = threshold;\n");
1098     fragBuilder->codeAppendf("} else if (translatedFragPos.x >= (middle.x + threshold)) {");
1099     fragBuilder->codeAppendf("translatedFragPos.x -= middle.x - 1.0;");
1100     fragBuilder->codeAppendf("}");
1101
1102     fragBuilder->codeAppendf(
1103             "if (translatedFragPos.y > threshold && translatedFragPos.y < (middle.y+threshold)) {");
1104     fragBuilder->codeAppendf("translatedFragPos.y = threshold;");
1105     fragBuilder->codeAppendf("} else if (translatedFragPos.y >= (middle.y + threshold)) {");
1106     fragBuilder->codeAppendf("translatedFragPos.y -= middle.y - 1.0;");
1107     fragBuilder->codeAppendf("}");
1108
1109     fragBuilder->codeAppendf("vec2 proxyDims = vec2(2.0*threshold+1.0);");
1110     fragBuilder->codeAppendf("vec2 texCoord = translatedFragPos / proxyDims;");
1111
1112     fragBuilder->codeAppendf("%s = ", args.fOutputColor);
1113     fragBuilder->appendTextureLookupAndModulate(args.fInputColor, args.fSamplers[0], "texCoord");
1114     fragBuilder->codeAppend(";");
1115 }
1116
1117 void GrGLRRectBlurEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1118                                     const GrProcessor& proc) {
1119     const GrRRectBlurEffect& brre = proc.cast<GrRRectBlurEffect>();
1120     SkRRect rrect = brre.getRRect();
1121
1122     float blurRadius = 3.f*SkScalarCeilToScalar(brre.getSigma()-1/6.0f);
1123     pdman.set1f(fBlurRadiusUniform, blurRadius);
1124
1125     SkRect rect = rrect.getBounds();
1126     rect.outset(blurRadius, blurRadius);
1127     pdman.set4f(fProxyRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
1128
1129     SkScalar radius = 0;
1130     SkASSERT(rrect.isSimpleCircular() || rrect.isRect());
1131     radius = rrect.getSimpleRadii().fX;
1132     pdman.set1f(fCornerRadiusUniform, radius);
1133 }
1134
1135 void GrRRectBlurEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
1136                                               GrProcessorKeyBuilder* b) const {
1137     GrGLRRectBlurEffect::GenKey(*this, caps, b);
1138 }
1139
1140 GrGLSLFragmentProcessor* GrRRectBlurEffect::onCreateGLSLInstance() const {
1141     return new GrGLRRectBlurEffect(*this);
1142 }
1143
1144 bool SkBlurMaskFilterImpl::directFilterRRectMaskGPU(GrTextureProvider* texProvider,
1145                                                     GrDrawContext* drawContext,
1146                                                     GrPaint* grp,
1147                                                     const GrClip& clip,
1148                                                     const SkMatrix& viewMatrix,
1149                                                     const SkStrokeRec& strokeRec,
1150                                                     const SkRRect& rrect) const {
1151     SkASSERT(drawContext);
1152
1153     if (fBlurStyle != kNormal_SkBlurStyle) {
1154         return false;
1155     }
1156
1157     if (!strokeRec.isFillStyle()) {
1158         return false;
1159     }
1160
1161     SkScalar xformedSigma = this->computeXformedSigma(viewMatrix);
1162     float extra=3.f*SkScalarCeilToScalar(xformedSigma-1/6.0f);
1163
1164     SkRect proxyRect = rrect.rect();
1165     proxyRect.outset(extra, extra);
1166
1167     SkAutoTUnref<const GrFragmentProcessor> fp(GrRRectBlurEffect::Create(texProvider, 
1168                                                                          xformedSigma, rrect));
1169     if (!fp) {
1170         return false;
1171     }
1172
1173     grp->addCoverageFragmentProcessor(fp);
1174
1175     SkMatrix inverse;
1176     if (!viewMatrix.invert(&inverse)) {
1177         return false;
1178     }
1179
1180     drawContext->fillRectWithLocalMatrix(clip, *grp, SkMatrix::I(), proxyRect, inverse);
1181     return true;
1182 }
1183
1184 bool SkBlurMaskFilterImpl::canFilterMaskGPU(const SkRRect& devRRect,
1185                                             const SkIRect& clipBounds,
1186                                             const SkMatrix& ctm,
1187                                             SkRect* maskRect) const {
1188     SkScalar xformedSigma = this->computeXformedSigma(ctm);
1189     if (xformedSigma <= 0) {
1190         return false;
1191     }
1192
1193     // We always do circles on the GPU
1194     if (!devRRect.isCircle()) {
1195         static const SkScalar kMIN_GPU_BLUR_SIZE  = SkIntToScalar(64);
1196         static const SkScalar kMIN_GPU_BLUR_SIGMA = SkIntToScalar(32);
1197
1198         if (devRRect.width() <= kMIN_GPU_BLUR_SIZE &&
1199             devRRect.height() <= kMIN_GPU_BLUR_SIZE &&
1200             xformedSigma <= kMIN_GPU_BLUR_SIGMA) {
1201             // We prefer to blur small rects with small radii on the CPU.
1202             return false;
1203         }
1204     }
1205
1206     if (nullptr == maskRect) {
1207         // don't need to compute maskRect
1208         return true;
1209     }
1210
1211     float sigma3 = 3 * SkScalarToFloat(xformedSigma);
1212
1213     SkRect clipRect = SkRect::Make(clipBounds);
1214     SkRect srcRect(devRRect.rect());
1215
1216     // Outset srcRect and clipRect by 3 * sigma, to compute affected blur area.
1217     srcRect.outset(sigma3, sigma3);
1218     clipRect.outset(sigma3, sigma3);
1219     if (!srcRect.intersect(clipRect)) {
1220         srcRect.setEmpty();
1221     }
1222     *maskRect = srcRect;
1223     return true;
1224 }
1225
1226 bool SkBlurMaskFilterImpl::filterMaskGPU(GrTexture* src,
1227                                          const SkMatrix& ctm,
1228                                          const SkRect& maskRect,
1229                                          GrTexture** result,
1230                                          bool canOverwriteSrc) const {
1231     SkRect clipRect = SkRect::MakeWH(maskRect.width(), maskRect.height());
1232
1233     GrContext* context = src->getContext();
1234
1235     SkScalar xformedSigma = this->computeXformedSigma(ctm);
1236     SkASSERT(xformedSigma > 0);
1237
1238     // If we're doing a normal blur, we can clobber the pathTexture in the
1239     // gaussianBlur.  Otherwise, we need to save it for later compositing.
1240     bool isNormalBlur = (kNormal_SkBlurStyle == fBlurStyle);
1241     *result = SkGpuBlurUtils::GaussianBlur(context, src, isNormalBlur && canOverwriteSrc,
1242                                            clipRect, nullptr, xformedSigma, xformedSigma,
1243                                            GrTextureProvider::kApprox_SizeConstraint);
1244     if (nullptr == *result) {
1245         return false;
1246     }
1247
1248     if (!isNormalBlur) {
1249         GrPaint paint;
1250         SkMatrix matrix;
1251         matrix.setIDiv(src->width(), src->height());
1252         // Blend pathTexture over blurTexture.
1253         paint.addCoverageFragmentProcessor(GrSimpleTextureEffect::Create(src, matrix))->unref();
1254         if (kInner_SkBlurStyle == fBlurStyle) {
1255             // inner:  dst = dst * src
1256             paint.setCoverageSetOpXPFactory(SkRegion::kIntersect_Op);
1257         } else if (kSolid_SkBlurStyle == fBlurStyle) {
1258             // solid:  dst = src + dst - src * dst
1259             //             = src + (1 - src) * dst
1260             paint.setCoverageSetOpXPFactory(SkRegion::kUnion_Op);
1261         } else if (kOuter_SkBlurStyle == fBlurStyle) {
1262             // outer:  dst = dst * (1 - src)
1263             //             = 0 * src + (1 - src) * dst
1264             paint.setCoverageSetOpXPFactory(SkRegion::kDifference_Op);
1265         } else {
1266             paint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op);
1267         }
1268
1269         SkAutoTUnref<GrDrawContext> drawContext(context->drawContext((*result)->asRenderTarget()));
1270         if (!drawContext) {
1271             return false;
1272         }
1273
1274         drawContext->drawRect(GrClip::WideOpen(), paint, SkMatrix::I(), clipRect);
1275     }
1276
1277     return true;
1278 }
1279
1280 #endif // SK_SUPPORT_GPU
1281
1282
1283 #ifndef SK_IGNORE_TO_STRING
1284 void SkBlurMaskFilterImpl::toString(SkString* str) const {
1285     str->append("SkBlurMaskFilterImpl: (");
1286
1287     str->append("sigma: ");
1288     str->appendScalar(fSigma);
1289     str->append(" ");
1290
1291     static const char* gStyleName[kLastEnum_SkBlurStyle + 1] = {
1292         "normal", "solid", "outer", "inner"
1293     };
1294
1295     str->appendf("style: %s ", gStyleName[fBlurStyle]);
1296     str->append("flags: (");
1297     if (fBlurFlags) {
1298         bool needSeparator = false;
1299         SkAddFlagToString(str,
1300                           SkToBool(fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag),
1301                           "IgnoreXform", &needSeparator);
1302         SkAddFlagToString(str,
1303                           SkToBool(fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag),
1304                           "HighQuality", &needSeparator);
1305     } else {
1306         str->append("None");
1307     }
1308     str->append("))");
1309 }
1310 #endif
1311
1312 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkBlurMaskFilter)
1313     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurMaskFilterImpl)
1314 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END