Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / 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 "GrContext.h"
22 #include "GrTexture.h"
23 #include "GrEffect.h"
24 #include "gl/GrGLEffect.h"
25 #include "effects/GrSimpleTextureEffect.h"
26 #include "GrTBackendEffectFactory.h"
27 #include "SkGrPixelRef.h"
28 #endif
29
30 class SkBlurMaskFilterImpl : public SkMaskFilter {
31 public:
32     SkBlurMaskFilterImpl(SkScalar sigma, SkBlurMaskFilter::BlurStyle, uint32_t flags);
33
34     // overrides from SkMaskFilter
35     virtual SkMask::Format getFormat() const SK_OVERRIDE;
36     virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&,
37                             SkIPoint* margin) const SK_OVERRIDE;
38
39 #if SK_SUPPORT_GPU
40     virtual bool canFilterMaskGPU(const SkRect& devBounds,
41                                   const SkIRect& clipBounds,
42                                   const SkMatrix& ctm,
43                                   SkRect* maskRect) const SK_OVERRIDE;
44     virtual bool directFilterMaskGPU(GrContext* context,
45                                      GrPaint* grp,
46                                      const SkStrokeRec& strokeRec,
47                                      const SkPath& path) const SK_OVERRIDE;
48
49     virtual bool filterMaskGPU(GrTexture* src,
50                                const SkMatrix& ctm,
51                                const SkRect& maskRect,
52                                GrTexture** result,
53                                bool canOverwriteSrc) const SK_OVERRIDE;
54 #endif
55
56     virtual void computeFastBounds(const SkRect&, SkRect*) const SK_OVERRIDE;
57
58     SkDEVCODE(virtual void toString(SkString* str) const SK_OVERRIDE;)
59     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBlurMaskFilterImpl)
60
61 protected:
62     virtual FilterReturn filterRectsToNine(const SkRect[], int count, const SkMatrix&,
63                                            const SkIRect& clipBounds,
64                                            NinePatch*) const SK_OVERRIDE;
65
66     virtual FilterReturn filterRRectToNine(const SkRRect&, const SkMatrix&,
67                                            const SkIRect& clipBounds,
68                                            NinePatch*) const SK_OVERRIDE;
69
70     bool filterRectMask(SkMask* dstM, const SkRect& r, const SkMatrix& matrix,
71                         SkIPoint* margin, SkMask::CreateMode createMode) const;
72
73 private:
74     // To avoid unseemly allocation requests (esp. for finite platforms like
75     // handset) we limit the radius so something manageable. (as opposed to
76     // a request like 10,000)
77     static const SkScalar kMAX_BLUR_SIGMA;
78
79     SkScalar                    fSigma;
80     SkBlurMaskFilter::BlurStyle fBlurStyle;
81     uint32_t                    fBlurFlags;
82
83     SkBlurMaskFilterImpl(SkReadBuffer&);
84     virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE;
85
86     SkScalar computeXformedSigma(const SkMatrix& ctm) const {
87         bool ignoreTransform = SkToBool(fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag);
88
89         SkScalar xformedSigma = ignoreTransform ? fSigma : ctm.mapRadius(fSigma);
90         return SkMinScalar(xformedSigma, kMAX_BLUR_SIGMA);
91     }
92
93     typedef SkMaskFilter INHERITED;
94 };
95
96 const SkScalar SkBlurMaskFilterImpl::kMAX_BLUR_SIGMA = SkIntToScalar(128);
97
98 SkMaskFilter* SkBlurMaskFilter::Create(SkScalar radius,
99                                        SkBlurMaskFilter::BlurStyle style,
100                                        uint32_t flags) {
101     // use !(radius > 0) instead of radius <= 0 to reject NaN values
102     if (!(radius > 0) || (unsigned)style >= SkBlurMaskFilter::kBlurStyleCount
103         || flags > SkBlurMaskFilter::kAll_BlurFlag) {
104         return NULL;
105     }
106
107     SkScalar sigma = SkBlurMask::ConvertRadiusToSigma(radius);
108
109     return SkNEW_ARGS(SkBlurMaskFilterImpl, (sigma, style, flags));
110 }
111
112 SkMaskFilter* SkBlurMaskFilter::Create(SkBlurMaskFilter::BlurStyle style,
113                                        SkScalar sigma,
114                                        uint32_t flags) {
115     // use !(sigma > 0) instead of sigma <= 0 to reject NaN values
116     if (!(sigma > 0) || (unsigned)style >= SkBlurMaskFilter::kBlurStyleCount
117         || flags > SkBlurMaskFilter::kAll_BlurFlag) {
118         return NULL;
119     }
120
121     return SkNEW_ARGS(SkBlurMaskFilterImpl, (sigma, style, flags));
122 }
123
124 ///////////////////////////////////////////////////////////////////////////////
125
126 SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkScalar sigma,
127                                            SkBlurMaskFilter::BlurStyle style,
128                                            uint32_t flags)
129     : fSigma(sigma), fBlurStyle(style), fBlurFlags(flags) {
130 #if 0
131     fGamma = NULL;
132     if (gammaScale) {
133         fGamma = new U8[256];
134         if (gammaScale > 0)
135             SkBlurMask::BuildSqrGamma(fGamma, gammaScale);
136         else
137             SkBlurMask::BuildSqrtGamma(fGamma, -gammaScale);
138     }
139 #endif
140     SkASSERT(fSigma >= 0);
141     SkASSERT((unsigned)style < SkBlurMaskFilter::kBlurStyleCount);
142     SkASSERT(flags <= SkBlurMaskFilter::kAll_BlurFlag);
143 }
144
145 SkMask::Format SkBlurMaskFilterImpl::getFormat() const {
146     return SkMask::kA8_Format;
147 }
148
149 bool SkBlurMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src,
150                                       const SkMatrix& matrix,
151                                       SkIPoint* margin) const{
152     SkScalar sigma = this->computeXformedSigma(matrix);
153
154     SkBlurMask::Quality blurQuality =
155         (fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag) ?
156             SkBlurMask::kHigh_Quality : SkBlurMask::kLow_Quality;
157
158     return SkBlurMask::BoxBlur(dst, src, sigma, (SkBlurMask::Style)fBlurStyle,
159                                blurQuality, margin);
160 }
161
162 bool SkBlurMaskFilterImpl::filterRectMask(SkMask* dst, const SkRect& r,
163                                           const SkMatrix& matrix,
164                                           SkIPoint* margin, SkMask::CreateMode createMode) const{
165     SkScalar sigma = computeXformedSigma(matrix);
166
167     return SkBlurMask::BlurRect(sigma, dst, r, (SkBlurMask::Style)fBlurStyle,
168                                 margin, createMode);
169 }
170
171 #include "SkCanvas.h"
172
173 static bool prepare_to_draw_into_mask(const SkRect& bounds, SkMask* mask) {
174     SkASSERT(mask != NULL);
175
176     bounds.roundOut(&mask->fBounds);
177     mask->fRowBytes = SkAlign4(mask->fBounds.width());
178     mask->fFormat = SkMask::kA8_Format;
179     const size_t size = mask->computeImageSize();
180     mask->fImage = SkMask::AllocImage(size);
181     if (NULL == mask->fImage) {
182         return false;
183     }
184
185     // FIXME: use sk_calloc in AllocImage?
186     sk_bzero(mask->fImage, size);
187     return true;
188 }
189
190 static bool draw_rrect_into_mask(const SkRRect rrect, SkMask* mask) {
191     if (!prepare_to_draw_into_mask(rrect.rect(), mask)) {
192         return false;
193     }
194
195     // FIXME: This code duplicates code in draw_rects_into_mask, below. Is there a
196     // clean way to share more code?
197     SkBitmap bitmap;
198     bitmap.setConfig(SkBitmap::kA8_Config,
199                      mask->fBounds.width(), mask->fBounds.height(),
200                      mask->fRowBytes);
201     bitmap.setPixels(mask->fImage);
202
203     SkCanvas canvas(bitmap);
204     canvas.translate(-SkIntToScalar(mask->fBounds.left()),
205                      -SkIntToScalar(mask->fBounds.top()));
206
207     SkPaint paint;
208     paint.setAntiAlias(true);
209     canvas.drawRRect(rrect, paint);
210     return true;
211 }
212
213 static bool draw_rects_into_mask(const SkRect rects[], int count, SkMask* mask) {
214     if (!prepare_to_draw_into_mask(rects[0], mask)) {
215         return false;
216     }
217
218     SkBitmap bitmap;
219     bitmap.setConfig(SkBitmap::kA8_Config,
220                      mask->fBounds.width(), mask->fBounds.height(),
221                      mask->fRowBytes);
222     bitmap.setPixels(mask->fImage);
223
224     SkCanvas canvas(bitmap);
225     canvas.translate(-SkIntToScalar(mask->fBounds.left()),
226                      -SkIntToScalar(mask->fBounds.top()));
227
228     SkPaint paint;
229     paint.setAntiAlias(true);
230
231     if (1 == count) {
232         canvas.drawRect(rects[0], paint);
233     } else {
234         // todo: do I need a fast way to do this?
235         SkPath path;
236         path.addRect(rects[0]);
237         path.addRect(rects[1]);
238         path.setFillType(SkPath::kEvenOdd_FillType);
239         canvas.drawPath(path, paint);
240     }
241     return true;
242 }
243
244 static bool rect_exceeds(const SkRect& r, SkScalar v) {
245     return r.fLeft < -v || r.fTop < -v || r.fRight > v || r.fBottom > v ||
246            r.width() > v || r.height() > v;
247 }
248
249 SkMaskFilter::FilterReturn
250 SkBlurMaskFilterImpl::filterRRectToNine(const SkRRect& rrect, const SkMatrix& matrix,
251                                         const SkIRect& clipBounds,
252                                         NinePatch* patch) const {
253     SkASSERT(patch != NULL);
254     switch (rrect.getType()) {
255         case SkRRect::kUnknown_Type:
256             // Unknown should never be returned.
257             SkASSERT(false);
258             // Fall through.
259         case SkRRect::kEmpty_Type:
260             // Nothing to draw.
261             return kFalse_FilterReturn;
262
263         case SkRRect::kRect_Type:
264             // We should have caught this earlier.
265             SkASSERT(false);
266             // Fall through.
267         case SkRRect::kOval_Type:
268             // The nine patch special case does not handle ovals, and we
269             // already have code for rectangles.
270             return kUnimplemented_FilterReturn;
271
272         case SkRRect::kSimple_Type:
273             // Fall through.
274         case SkRRect::kComplex_Type:
275             // These can take advantage of this fast path.
276             break;
277     }
278
279     // TODO: report correct metrics for innerstyle, where we do not grow the
280     // total bounds, but we do need an inset the size of our blur-radius
281     if (SkBlurMaskFilter::kInner_BlurStyle == fBlurStyle) {
282         return kUnimplemented_FilterReturn;
283     }
284
285     // TODO: take clipBounds into account to limit our coordinates up front
286     // for now, just skip too-large src rects (to take the old code path).
287     if (rect_exceeds(rrect.rect(), SkIntToScalar(32767))) {
288         return kUnimplemented_FilterReturn;
289     }
290
291     SkIPoint margin;
292     SkMask  srcM, dstM;
293     rrect.rect().roundOut(&srcM.fBounds);
294     srcM.fImage = NULL;
295     srcM.fFormat = SkMask::kA8_Format;
296     srcM.fRowBytes = 0;
297
298     if (!this->filterMask(&dstM, srcM, matrix, &margin)) {
299         return kFalse_FilterReturn;
300     }
301
302     // Now figure out the appropriate width and height of the smaller round rectangle
303     // to stretch. It will take into account the larger radius per side as well as double
304     // the margin, to account for inner and outer blur.
305     const SkVector& UL = rrect.radii(SkRRect::kUpperLeft_Corner);
306     const SkVector& UR = rrect.radii(SkRRect::kUpperRight_Corner);
307     const SkVector& LR = rrect.radii(SkRRect::kLowerRight_Corner);
308     const SkVector& LL = rrect.radii(SkRRect::kLowerLeft_Corner);
309
310     const SkScalar leftUnstretched = SkTMax(UL.fX, LL.fX) + SkIntToScalar(2 * margin.fX);
311     const SkScalar rightUnstretched = SkTMax(UR.fX, LR.fX) + SkIntToScalar(2 * margin.fX);
312
313     // Extra space in the middle to ensure an unchanging piece for stretching. Use 3 to cover
314     // any fractional space on either side plus 1 for the part to stretch.
315     const SkScalar stretchSize = SkIntToScalar(3);
316
317     const SkScalar totalSmallWidth = leftUnstretched + rightUnstretched + stretchSize;
318     if (totalSmallWidth >= rrect.rect().width()) {
319         // There is no valid piece to stretch.
320         return kUnimplemented_FilterReturn;
321     }
322
323     const SkScalar topUnstretched = SkTMax(UL.fY, UR.fY) + SkIntToScalar(2 * margin.fY);
324     const SkScalar bottomUnstretched = SkTMax(LL.fY, LR.fY) + SkIntToScalar(2 * margin.fY);
325
326     const SkScalar totalSmallHeight = topUnstretched + bottomUnstretched + stretchSize;
327     if (totalSmallHeight >= rrect.rect().height()) {
328         // There is no valid piece to stretch.
329         return kUnimplemented_FilterReturn;
330     }
331
332     SkRect smallR = SkRect::MakeWH(totalSmallWidth, totalSmallHeight);
333
334     SkRRect smallRR;
335     SkVector radii[4];
336     radii[SkRRect::kUpperLeft_Corner] = UL;
337     radii[SkRRect::kUpperRight_Corner] = UR;
338     radii[SkRRect::kLowerRight_Corner] = LR;
339     radii[SkRRect::kLowerLeft_Corner] = LL;
340     smallRR.setRectRadii(smallR, radii);
341
342     if (!draw_rrect_into_mask(smallRR, &srcM)) {
343         return kFalse_FilterReturn;
344     }
345
346     SkAutoMaskFreeImage amf(srcM.fImage);
347
348     if (!this->filterMask(&patch->fMask, srcM, matrix, &margin)) {
349         return kFalse_FilterReturn;
350     }
351
352     patch->fMask.fBounds.offsetTo(0, 0);
353     patch->fOuterRect = dstM.fBounds;
354     patch->fCenter.fX = SkScalarCeilToInt(leftUnstretched) + 1;
355     patch->fCenter.fY = SkScalarCeilToInt(topUnstretched) + 1;
356     return kTrue_FilterReturn;
357 }
358
359 #ifdef SK_IGNORE_FAST_RECT_BLUR
360 SK_CONF_DECLARE( bool, c_analyticBlurNinepatch, "mask.filter.analyticNinePatch", false, "Use the faster analytic blur approach for ninepatch rects" );
361 #else
362 SK_CONF_DECLARE( bool, c_analyticBlurNinepatch, "mask.filter.analyticNinePatch", true, "Use the faster analytic blur approach for ninepatch rects" );
363 #endif
364
365 SkMaskFilter::FilterReturn
366 SkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count,
367                                         const SkMatrix& matrix,
368                                         const SkIRect& clipBounds,
369                                         NinePatch* patch) const {
370     if (count < 1 || count > 2) {
371         return kUnimplemented_FilterReturn;
372     }
373
374     // TODO: report correct metrics for innerstyle, where we do not grow the
375     // total bounds, but we do need an inset the size of our blur-radius
376     if (SkBlurMaskFilter::kInner_BlurStyle == fBlurStyle ||
377         SkBlurMaskFilter::kOuter_BlurStyle == fBlurStyle) {
378         return kUnimplemented_FilterReturn;
379     }
380
381     // TODO: take clipBounds into account to limit our coordinates up front
382     // for now, just skip too-large src rects (to take the old code path).
383     if (rect_exceeds(rects[0], SkIntToScalar(32767))) {
384         return kUnimplemented_FilterReturn;
385     }
386
387     SkIPoint margin;
388     SkMask  srcM, dstM;
389     rects[0].roundOut(&srcM.fBounds);
390     srcM.fImage = NULL;
391     srcM.fFormat = SkMask::kA8_Format;
392     srcM.fRowBytes = 0;
393
394     bool filterResult = false;
395     if (count == 1 && c_analyticBlurNinepatch) {
396         // special case for fast rect blur
397         // don't actually do the blur the first time, just compute the correct size
398         filterResult = this->filterRectMask(&dstM, rects[0], matrix, &margin,
399                                             SkMask::kJustComputeBounds_CreateMode);
400     } else {
401         filterResult = this->filterMask(&dstM, srcM, matrix, &margin);
402     }
403
404     if (!filterResult) {
405         return kFalse_FilterReturn;
406     }
407
408     /*
409      *  smallR is the smallest version of 'rect' that will still guarantee that
410      *  we get the same blur results on all edges, plus 1 center row/col that is
411      *  representative of the extendible/stretchable edges of the ninepatch.
412      *  Since our actual edge may be fractional we inset 1 more to be sure we
413      *  don't miss any interior blur.
414      *  x is an added pixel of blur, and { and } are the (fractional) edge
415      *  pixels from the original rect.
416      *
417      *   x x { x x .... x x } x x
418      *
419      *  Thus, in this case, we inset by a total of 5 (on each side) beginning
420      *  with our outer-rect (dstM.fBounds)
421      */
422     SkRect smallR[2];
423     SkIPoint center;
424
425     // +2 is from +1 for each edge (to account for possible fractional edges
426     int smallW = dstM.fBounds.width() - srcM.fBounds.width() + 2;
427     int smallH = dstM.fBounds.height() - srcM.fBounds.height() + 2;
428     SkIRect innerIR;
429
430     if (1 == count) {
431         innerIR = srcM.fBounds;
432         center.set(smallW, smallH);
433     } else {
434         SkASSERT(2 == count);
435         rects[1].roundIn(&innerIR);
436         center.set(smallW + (innerIR.left() - srcM.fBounds.left()),
437                    smallH + (innerIR.top() - srcM.fBounds.top()));
438     }
439
440     // +1 so we get a clean, stretchable, center row/col
441     smallW += 1;
442     smallH += 1;
443
444     // we want the inset amounts to be integral, so we don't change any
445     // fractional phase on the fRight or fBottom of our smallR.
446     const SkScalar dx = SkIntToScalar(innerIR.width() - smallW);
447     const SkScalar dy = SkIntToScalar(innerIR.height() - smallH);
448     if (dx < 0 || dy < 0) {
449         // we're too small, relative to our blur, to break into nine-patch,
450         // so we ask to have our normal filterMask() be called.
451         return kUnimplemented_FilterReturn;
452     }
453
454     smallR[0].set(rects[0].left(), rects[0].top(), rects[0].right() - dx, rects[0].bottom() - dy);
455     if (smallR[0].width() < 2 || smallR[0].height() < 2) {
456         return kUnimplemented_FilterReturn;
457     }
458     if (2 == count) {
459         smallR[1].set(rects[1].left(), rects[1].top(),
460                       rects[1].right() - dx, rects[1].bottom() - dy);
461         SkASSERT(!smallR[1].isEmpty());
462     }
463
464     if (count > 1 || !c_analyticBlurNinepatch) {
465         if (!draw_rects_into_mask(smallR, count, &srcM)) {
466             return kFalse_FilterReturn;
467         }
468
469         SkAutoMaskFreeImage amf(srcM.fImage);
470
471         if (!this->filterMask(&patch->fMask, srcM, matrix, &margin)) {
472             return kFalse_FilterReturn;
473         }
474     } else {
475         if (!this->filterRectMask(&patch->fMask, smallR[0], matrix, &margin,
476                                   SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
477             return kFalse_FilterReturn;
478         }
479     }
480     patch->fMask.fBounds.offsetTo(0, 0);
481     patch->fOuterRect = dstM.fBounds;
482     patch->fCenter = center;
483     return kTrue_FilterReturn;
484 }
485
486 void SkBlurMaskFilterImpl::computeFastBounds(const SkRect& src,
487                                              SkRect* dst) const {
488     SkScalar pad = 3.0f * fSigma;
489
490     dst->set(src.fLeft  - pad, src.fTop    - pad,
491              src.fRight + pad, src.fBottom + pad);
492 }
493
494 SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkReadBuffer& buffer)
495         : SkMaskFilter(buffer) {
496     fSigma = buffer.readScalar();
497     fBlurStyle = (SkBlurMaskFilter::BlurStyle)buffer.readInt();
498     fBlurFlags = buffer.readUInt() & SkBlurMaskFilter::kAll_BlurFlag;
499     SkASSERT(fSigma >= 0);
500     SkASSERT((unsigned)fBlurStyle < SkBlurMaskFilter::kBlurStyleCount);
501 }
502
503 void SkBlurMaskFilterImpl::flatten(SkWriteBuffer& buffer) const {
504     this->INHERITED::flatten(buffer);
505     buffer.writeScalar(fSigma);
506     buffer.writeInt(fBlurStyle);
507     buffer.writeUInt(fBlurFlags);
508 }
509
510 #if SK_SUPPORT_GPU
511
512 class GrGLRectBlurEffect;
513
514 class GrRectBlurEffect : public GrEffect {
515 public:
516     virtual ~GrRectBlurEffect();
517
518     static const char* Name() { return "RectBlur"; }
519
520     typedef GrGLRectBlurEffect GLEffect;
521
522     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
523     virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
524
525     /**
526      * Create a simple filter effect with custom bicubic coefficients.
527      */
528     static GrEffectRef* Create(GrContext *context, const SkRect& rect,
529                                float sigma) {
530         GrTexture *horizontalScanline = NULL, *verticalScanline = NULL;
531         bool createdScanlines = CreateScanlineTextures(context, sigma,
532                                                        SkScalarCeilToInt(rect.width()),
533                                                        SkScalarCeilToInt(rect.height()),
534                                                        &horizontalScanline, &verticalScanline);
535          SkAutoTUnref<GrTexture> hunref(horizontalScanline), vunref(verticalScanline);
536          if (!createdScanlines) {
537             return NULL;
538         }
539         AutoEffectUnref effect(SkNEW_ARGS(GrRectBlurEffect, (rect, sigma,
540                                                              horizontalScanline, verticalScanline)));
541         return CreateEffectRef(effect);
542     }
543
544     unsigned int getWidth() const { return fWidth; }
545     unsigned int getHeight() const { return fHeight; }
546     float getSigma() const { return fSigma; }
547     const GrCoordTransform& getTransform() const { return fTransform; }
548
549 private:
550     GrRectBlurEffect(const SkRect& rect, float sigma,
551                      GrTexture *horizontal_scanline, GrTexture *vertical_scanline);
552     virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
553
554     static bool CreateScanlineTextures(GrContext *context, float sigma,
555                                        unsigned int width, unsigned int height,
556                                        GrTexture **horizontalScanline,
557                                        GrTexture **verticalScanline);
558
559     unsigned int fWidth, fHeight;
560     float fSigma;
561     GrTextureAccess  fHorizontalScanlineAccess;
562     GrTextureAccess  fVerticalScanlineAccess;
563     GrCoordTransform fTransform;
564
565     GR_DECLARE_EFFECT_TEST;
566
567     typedef GrEffect INHERITED;
568 };
569
570 class GrGLRectBlurEffect : public GrGLEffect {
571 public:
572     GrGLRectBlurEffect(const GrBackendEffectFactory& factory,
573                       const GrDrawEffect&);
574     virtual void emitCode(GrGLShaderBuilder*,
575                           const GrDrawEffect&,
576                           EffectKey,
577                           const char* outputColor,
578                           const char* inputColor,
579                           const TransformedCoordsArray&,
580                           const TextureSamplerArray&) SK_OVERRIDE;
581
582     virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
583
584 private:
585     typedef GrGLUniformManager::UniformHandle        UniformHandle;
586
587     UniformHandle       fWidthUni;
588     UniformHandle       fHeightUni;
589
590     typedef GrGLEffect INHERITED;
591 };
592
593 GrGLRectBlurEffect::GrGLRectBlurEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
594     : INHERITED(factory) {
595 }
596
597 void GrGLRectBlurEffect::emitCode(GrGLShaderBuilder* builder,
598                                  const GrDrawEffect&,
599                                  EffectKey key,
600                                  const char* outputColor,
601                                  const char* inputColor,
602                                  const TransformedCoordsArray& coords,
603                                  const TextureSamplerArray& samplers) {
604
605     SkString texture_coords = builder->ensureFSCoords2D(coords, 0);
606
607     if (inputColor) {
608         builder->fsCodeAppendf("\tvec4 src=%s;\n", inputColor);
609     } else {
610         builder->fsCodeAppendf("\tvec4 src=vec4(1)\n;");
611     }
612
613     builder->fsCodeAppendf("\tvec4 horiz = ");
614     builder->fsAppendTextureLookup( samplers[0], texture_coords.c_str() );
615     builder->fsCodeAppendf(";\n");
616     builder->fsCodeAppendf("\tvec4 vert = ");
617     builder->fsAppendTextureLookup( samplers[1], texture_coords.c_str() );
618     builder->fsCodeAppendf(";\n");
619
620     builder->fsCodeAppendf("\tfloat final = (horiz*vert).r;\n");
621     builder->fsCodeAppendf("\t%s = final*src;\n", outputColor);
622 }
623
624 void GrGLRectBlurEffect::setData(const GrGLUniformManager& uman,
625                                 const GrDrawEffect& drawEffect) {
626 }
627
628 bool GrRectBlurEffect::CreateScanlineTextures(GrContext *context, float sigma,
629                                               unsigned int width, unsigned int height,
630                                               GrTexture **horizontalScanline,
631                                               GrTexture **verticalScanline) {
632     GrTextureParams params;
633     GrTextureDesc texDesc;
634
635     unsigned int profile_size = SkScalarFloorToInt(6*sigma);
636
637     texDesc.fWidth = width;
638     texDesc.fHeight = 1;
639     texDesc.fConfig = kAlpha_8_GrPixelConfig;
640
641     static const GrCacheID::Domain gBlurProfileDomain = GrCacheID::GenerateDomain();
642     GrCacheID::Key key;
643     memset(&key, 0, sizeof(key));
644     key.fData32[0] = profile_size;
645     key.fData32[1] = width;
646     key.fData32[2] = 1;
647     GrCacheID horizontalCacheID(gBlurProfileDomain, key);
648
649     uint8_t *profile = NULL;
650     SkAutoTDeleteArray<uint8_t> ada(NULL);
651
652     *horizontalScanline = context->findAndRefTexture(texDesc, horizontalCacheID, &params);
653
654     if (NULL == *horizontalScanline) {
655
656         SkBlurMask::ComputeBlurProfile(sigma, &profile);
657         ada.reset(profile);
658
659         SkAutoTMalloc<uint8_t> horizontalPixels(width);
660         SkBlurMask::ComputeBlurredScanline(horizontalPixels, profile, width, sigma);
661
662         *horizontalScanline = context->createTexture(&params, texDesc, horizontalCacheID,
663                                                      horizontalPixels, 0);
664
665         if (NULL == *horizontalScanline) {
666             return false;
667         }
668     }
669
670     texDesc.fWidth = 1;
671     texDesc.fHeight = height;
672     key.fData32[1] = 1;
673     key.fData32[2] = height;
674     GrCacheID verticalCacheID(gBlurProfileDomain, key);
675
676     *verticalScanline = context->findAndRefTexture(texDesc, verticalCacheID, &params);
677     if (NULL == *verticalScanline) {
678         if (NULL == profile) {
679             SkBlurMask::ComputeBlurProfile(sigma, &profile);
680             ada.reset(profile);
681         }
682
683         SkAutoTMalloc<uint8_t> verticalPixels(height);
684         SkBlurMask::ComputeBlurredScanline(verticalPixels, profile, height, sigma);
685
686         *verticalScanline = context->createTexture(&params, texDesc, verticalCacheID,
687                                                    verticalPixels, 0);
688
689         if (NULL == *verticalScanline) {
690             SkSafeSetNull(*horizontalScanline);
691             return false;
692         }
693
694     }
695     return true;
696 }
697
698 GrRectBlurEffect::GrRectBlurEffect(const SkRect& rect, float sigma,
699                                    GrTexture *horizontal_scanline, GrTexture *vertical_scanline)
700   : INHERITED(),
701     fWidth(horizontal_scanline->width()),
702     fHeight(vertical_scanline->width()),
703     fSigma(sigma),
704     fHorizontalScanlineAccess(horizontal_scanline),
705     fVerticalScanlineAccess(vertical_scanline) {
706     SkMatrix mat;
707     mat.setRectToRect(rect, SkRect::MakeWH(1,1), SkMatrix::kFill_ScaleToFit);
708     fTransform.reset(kLocal_GrCoordSet, mat);
709     this->addTextureAccess(&fHorizontalScanlineAccess);
710     this->addTextureAccess(&fVerticalScanlineAccess);
711     this->addCoordTransform(&fTransform);
712 }
713
714 GrRectBlurEffect::~GrRectBlurEffect() {
715 }
716
717 const GrBackendEffectFactory& GrRectBlurEffect::getFactory() const {
718     return GrTBackendEffectFactory<GrRectBlurEffect>::getInstance();
719 }
720
721 bool GrRectBlurEffect::onIsEqual(const GrEffect& sBase) const {
722     const GrRectBlurEffect& s = CastEffect<GrRectBlurEffect>(sBase);
723     return this->getWidth() == s.getWidth() &&
724            this->getHeight() == s.getHeight() &&
725            this->getSigma() == s.getSigma() &&
726            this->getTransform() == s.getTransform();
727 }
728
729 void GrRectBlurEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
730     *validFlags = 0;
731     return;
732 }
733
734 GR_DEFINE_EFFECT_TEST(GrRectBlurEffect);
735
736 GrEffectRef* GrRectBlurEffect::TestCreate(SkRandom* random,
737                                          GrContext* context,
738                                          const GrDrawTargetCaps&,
739                                          GrTexture**) {
740     float sigma = random->nextRangeF(3,8);
741     float width = random->nextRangeF(200,300);
742     float height = random->nextRangeF(200,300);
743     return GrRectBlurEffect::Create(context, SkRect::MakeWH(width, height), sigma);
744 }
745
746
747 bool SkBlurMaskFilterImpl::directFilterMaskGPU(GrContext* context,
748                                                GrPaint* grp,
749                                                const SkStrokeRec& strokeRec,
750                                                const SkPath& path) const {
751     if (fBlurStyle != SkBlurMaskFilter::kNormal_BlurStyle) {
752         return false;
753     }
754
755     SkRect rect;
756     if (!path.isRect(&rect)) {
757         return false;
758     }
759
760     if (!strokeRec.isFillStyle()) {
761         return false;
762     }
763
764     SkMatrix ctm = context->getMatrix();
765     SkScalar xformedSigma = this->computeXformedSigma(ctm);
766     rect.outset(3*xformedSigma, 3*xformedSigma);
767
768     SkAutoTUnref<GrEffectRef> effect(GrRectBlurEffect::Create(
769             context, rect, xformedSigma));
770     if (!effect) {
771         return false;
772     }
773
774     GrContext::AutoMatrix am;
775     if (!am.setIdentity(context, grp)) {
776        return false;
777     }
778
779
780     grp->addCoverageEffect(effect);
781
782     context->drawRect(*grp, rect);
783     return true;
784 }
785
786 bool SkBlurMaskFilterImpl::canFilterMaskGPU(const SkRect& srcBounds,
787                                             const SkIRect& clipBounds,
788                                             const SkMatrix& ctm,
789                                             SkRect* maskRect) const {
790     SkScalar xformedSigma = this->computeXformedSigma(ctm);
791     if (xformedSigma <= 0) {
792         return false;
793     }
794
795     static const SkScalar kMIN_GPU_BLUR_SIZE  = SkIntToScalar(64);
796     static const SkScalar kMIN_GPU_BLUR_SIGMA = SkIntToScalar(32);
797
798     if (srcBounds.width() <= kMIN_GPU_BLUR_SIZE &&
799         srcBounds.height() <= kMIN_GPU_BLUR_SIZE &&
800         xformedSigma <= kMIN_GPU_BLUR_SIGMA) {
801         // We prefer to blur small rect with small radius via CPU.
802         return false;
803     }
804
805     if (NULL == maskRect) {
806         // don't need to compute maskRect
807         return true;
808     }
809
810     float sigma3 = 3 * SkScalarToFloat(xformedSigma);
811
812     SkRect clipRect = SkRect::Make(clipBounds);
813     SkRect srcRect(srcBounds);
814
815     // Outset srcRect and clipRect by 3 * sigma, to compute affected blur area.
816     srcRect.outset(sigma3, sigma3);
817     clipRect.outset(sigma3, sigma3);
818     srcRect.intersect(clipRect);
819     *maskRect = srcRect;
820     return true;
821 }
822
823 bool SkBlurMaskFilterImpl::filterMaskGPU(GrTexture* src,
824                                          const SkMatrix& ctm,
825                                          const SkRect& maskRect,
826                                          GrTexture** result,
827                                          bool canOverwriteSrc) const {
828     SkRect clipRect = SkRect::MakeWH(maskRect.width(), maskRect.height());
829
830     GrContext* context = src->getContext();
831
832     GrContext::AutoWideOpenIdentityDraw awo(context, NULL);
833
834     SkScalar xformedSigma = this->computeXformedSigma(ctm);
835     SkASSERT(xformedSigma > 0);
836
837     // If we're doing a normal blur, we can clobber the pathTexture in the
838     // gaussianBlur.  Otherwise, we need to save it for later compositing.
839     bool isNormalBlur = (SkBlurMaskFilter::kNormal_BlurStyle == fBlurStyle);
840     *result = SkGpuBlurUtils::GaussianBlur(context, src, isNormalBlur && canOverwriteSrc,
841                                            clipRect, false, xformedSigma, xformedSigma);
842     if (NULL == *result) {
843         return false;
844     }
845
846     if (!isNormalBlur) {
847         context->setIdentityMatrix();
848         GrPaint paint;
849         SkMatrix matrix;
850         matrix.setIDiv(src->width(), src->height());
851         // Blend pathTexture over blurTexture.
852         GrContext::AutoRenderTarget art(context, (*result)->asRenderTarget());
853         paint.addColorEffect(GrSimpleTextureEffect::Create(src, matrix))->unref();
854         if (SkBlurMaskFilter::kInner_BlurStyle == fBlurStyle) {
855             // inner:  dst = dst * src
856             paint.setBlendFunc(kDC_GrBlendCoeff, kZero_GrBlendCoeff);
857         } else if (SkBlurMaskFilter::kSolid_BlurStyle == fBlurStyle) {
858             // solid:  dst = src + dst - src * dst
859             //             = (1 - dst) * src + 1 * dst
860             paint.setBlendFunc(kIDC_GrBlendCoeff, kOne_GrBlendCoeff);
861         } else if (SkBlurMaskFilter::kOuter_BlurStyle == fBlurStyle) {
862             // outer:  dst = dst * (1 - src)
863             //             = 0 * src + (1 - src) * dst
864             paint.setBlendFunc(kZero_GrBlendCoeff, kISC_GrBlendCoeff);
865         }
866         context->drawRect(paint, clipRect);
867     }
868
869     return true;
870 }
871
872 #endif // SK_SUPPORT_GPU
873
874
875 #ifdef SK_DEVELOPER
876 void SkBlurMaskFilterImpl::toString(SkString* str) const {
877     str->append("SkBlurMaskFilterImpl: (");
878
879     str->append("sigma: ");
880     str->appendScalar(fSigma);
881     str->append(" ");
882
883     static const char* gStyleName[SkBlurMaskFilter::kBlurStyleCount] = {
884         "normal", "solid", "outer", "inner"
885     };
886
887     str->appendf("style: %s ", gStyleName[fBlurStyle]);
888     str->append("flags: (");
889     if (fBlurFlags) {
890         bool needSeparator = false;
891         SkAddFlagToString(str,
892                           SkToBool(fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag),
893                           "IgnoreXform", &needSeparator);
894         SkAddFlagToString(str,
895                           SkToBool(fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag),
896                           "HighQuality", &needSeparator);
897     } else {
898         str->append("None");
899     }
900     str->append("))");
901 }
902 #endif
903
904 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkBlurMaskFilter)
905     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkBlurMaskFilterImpl)
906 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END