add asAShadowBlur for android to drawlooper
BUG=skia:
R=djsollen@google.com, scroggo@google.com
Review URL: https://codereview.chromium.org/253633003
git-svn-id: http://skia.googlecode.com/svn/trunk@14431 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/core/SkDrawLooper.h b/include/core/SkDrawLooper.h
index cc42952..b92bacc 100644
--- a/include/core/SkDrawLooper.h
+++ b/include/core/SkDrawLooper.h
@@ -10,7 +10,10 @@
#ifndef SkDrawLooper_DEFINED
#define SkDrawLooper_DEFINED
+#include "SkBlurTypes.h"
#include "SkFlattenable.h"
+#include "SkPoint.h"
+#include "SkColor.h"
class SkCanvas;
class SkPaint;
@@ -88,6 +91,24 @@
virtual void computeFastBounds(const SkPaint& paint,
const SkRect& src, SkRect* dst) const;
+ struct BlurShadowRec {
+ SkScalar fSigma;
+ SkVector fOffset;
+ SkColor fColor;
+ SkBlurStyle fStyle;
+ SkBlurQuality fQuality;
+ };
+ /**
+ * If this looper can be interpreted as having two layers, such that
+ * 1. The first layer (bottom most) just has a blur and translate
+ * 2. The second layer has no modifications to either paint or canvas
+ * 3. No other layers.
+ * then return true, and if not null, fill out the BlurShadowRec).
+ *
+ * If any of the above are not met, return false and ignore the BlurShadowRec parameter.
+ */
+ virtual bool asABlurShadow(BlurShadowRec*) const;
+
SK_TO_STRING_PUREVIRT()
SK_DEFINE_FLATTENABLE_TYPE(SkDrawLooper)
diff --git a/include/core/SkMaskFilter.h b/include/core/SkMaskFilter.h
index 3113c93..8051e7d 100644
--- a/include/core/SkMaskFilter.h
+++ b/include/core/SkMaskFilter.h
@@ -10,6 +10,7 @@
#ifndef SkMaskFilter_DEFINED
#define SkMaskFilter_DEFINED
+#include "SkBlurTypes.h"
#include "SkFlattenable.h"
#include "SkMask.h"
#include "SkPaint.h"
@@ -138,6 +139,18 @@
*/
virtual void computeFastBounds(const SkRect& src, SkRect* dest) const;
+ struct BlurRec {
+ SkScalar fSigma;
+ SkBlurStyle fStyle;
+ SkBlurQuality fQuality;
+ };
+ /**
+ * If this filter can be represented by a BlurRec, return true and (if not null) fill in the
+ * provided BlurRec parameter. If this effect cannot be represented as a BlurRec, return false
+ * and ignore the BlurRec parameter.
+ */
+ virtual bool asABlur(BlurRec*) const;
+
SK_TO_STRING_PUREVIRT()
SK_DEFINE_FLATTENABLE_TYPE(SkMaskFilter)
diff --git a/include/effects/SkBlurDrawLooper.h b/include/effects/SkBlurDrawLooper.h
index fe945c3..75ed80e 100644
--- a/include/effects/SkBlurDrawLooper.h
+++ b/include/effects/SkBlurDrawLooper.h
@@ -61,10 +61,12 @@
SkBlurDrawLooper(SkReadBuffer&);
virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE;
+ virtual bool asABlurShadow(BlurShadowRec*) const SK_OVERRIDE;
+
private:
SkMaskFilter* fBlur;
SkColorFilter* fColorFilter;
- SkScalar fDx, fDy;
+ SkScalar fDx, fDy, fSigma;
SkColor fBlurColor;
uint32_t fBlurFlags;
@@ -86,6 +88,7 @@
};
void init(SkScalar sigma, SkScalar dx, SkScalar dy, SkColor color, uint32_t flags);
+ void initEffects();
typedef SkDrawLooper INHERITED;
};
diff --git a/include/effects/SkEmbossMaskFilter.h b/include/effects/SkEmbossMaskFilter.h
index eb8f811..65dbbe7 100644
--- a/include/effects/SkEmbossMaskFilter.h
+++ b/include/effects/SkEmbossMaskFilter.h
@@ -23,9 +23,7 @@
uint8_t fSpecular; // exponent, 4.4 right now
};
- static SkEmbossMaskFilter* Create(SkScalar blurSigma, const Light& light) {
- return SkNEW_ARGS(SkEmbossMaskFilter, (blurSigma, light));
- }
+ static SkEmbossMaskFilter* Create(SkScalar blurSigma, const Light& light);
// overrides from SkMaskFilter
// This method is not exported to java.
diff --git a/include/effects/SkLayerDrawLooper.h b/include/effects/SkLayerDrawLooper.h
index fe660a8..ac56e28 100644
--- a/include/effects/SkLayerDrawLooper.h
+++ b/include/effects/SkLayerDrawLooper.h
@@ -77,6 +77,8 @@
virtual size_t contextSize() const SK_OVERRIDE { return sizeof(LayerDrawLooperContext); }
+ virtual bool asABlurShadow(BlurShadowRec* rec) const SK_OVERRIDE;
+
SK_TO_STRING_OVERRIDE()
/// Implements Flattenable.
diff --git a/src/core/SkDrawLooper.cpp b/src/core/SkDrawLooper.cpp
index c620cd0..d18d127 100644
--- a/src/core/SkDrawLooper.cpp
+++ b/src/core/SkDrawLooper.cpp
@@ -59,3 +59,7 @@
}
}
}
+
+bool SkDrawLooper::asABlurShadow(BlurShadowRec*) const {
+ return false;
+}
diff --git a/src/core/SkMaskFilter.cpp b/src/core/SkMaskFilter.cpp
index 9b023d0..8b9792c 100644
--- a/src/core/SkMaskFilter.cpp
+++ b/src/core/SkMaskFilter.cpp
@@ -26,6 +26,10 @@
return false;
}
+bool SkMaskFilter::asABlur(BlurRec*) const {
+ return false;
+}
+
static void extractMaskSubset(const SkMask& src, SkMask* dst) {
SkASSERT(src.fBounds.contains(dst->fBounds));
diff --git a/src/effects/SkBlurDrawLooper.cpp b/src/effects/SkBlurDrawLooper.cpp
index 03e635b..5af02db 100644
--- a/src/effects/SkBlurDrawLooper.cpp
+++ b/src/effects/SkBlurDrawLooper.cpp
@@ -1,10 +1,10 @@
-
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
+
#include "SkBlurDrawLooper.h"
#include "SkBlurMask.h" // just for SkBlurMask::ConvertRadiusToSigma
#include "SkBlurMaskFilter.h"
@@ -29,32 +29,27 @@
this->init(sigma, dx, dy, color, flags);
}
-void SkBlurDrawLooper::init(SkScalar sigma, SkScalar dx, SkScalar dy,
- SkColor color, uint32_t flags) {
- fDx = dx;
- fDy = dy;
- fBlurColor = color;
- fBlurFlags = flags;
-
- SkASSERT(flags <= kAll_BlurFlag);
- if (sigma > 0) {
- uint32_t blurFlags = flags & kIgnoreTransform_BlurFlag ?
- SkBlurMaskFilter::kIgnoreTransform_BlurFlag :
- SkBlurMaskFilter::kNone_BlurFlag;
-
- blurFlags |= flags & kHighQuality_BlurFlag ?
- SkBlurMaskFilter::kHighQuality_BlurFlag :
- SkBlurMaskFilter::kNone_BlurFlag;
-
- fBlur = SkBlurMaskFilter::Create(kNormal_SkBlurStyle, sigma, blurFlags);
+// only call from constructor
+void SkBlurDrawLooper::initEffects() {
+ SkASSERT(fBlurFlags <= kAll_BlurFlag);
+ if (fSigma > 0) {
+ uint32_t flags = fBlurFlags & kIgnoreTransform_BlurFlag ?
+ SkBlurMaskFilter::kIgnoreTransform_BlurFlag :
+ SkBlurMaskFilter::kNone_BlurFlag;
+
+ flags |= fBlurFlags & kHighQuality_BlurFlag ?
+ SkBlurMaskFilter::kHighQuality_BlurFlag :
+ SkBlurMaskFilter::kNone_BlurFlag;
+
+ fBlur = SkBlurMaskFilter::Create(kNormal_SkBlurStyle, fSigma, flags);
} else {
fBlur = NULL;
}
-
- if (flags & kOverrideColor_BlurFlag) {
+
+ if (fBlurFlags & kOverrideColor_BlurFlag) {
// Set alpha to 1 for the override since transparency will already
// be baked into the blurred mask.
- SkColor opaqueColor = SkColorSetA(color, 255);
+ SkColor opaqueColor = SkColorSetA(fBlurColor, 255);
//The SrcIn xfer mode will multiply 'color' by the incoming alpha
fColorFilter = SkColorFilter::CreateModeFilter(opaqueColor,
SkXfermode::kSrcIn_Mode);
@@ -63,15 +58,35 @@
}
}
-SkBlurDrawLooper::SkBlurDrawLooper(SkReadBuffer& buffer)
-: INHERITED(buffer) {
+void SkBlurDrawLooper::init(SkScalar sigma, SkScalar dx, SkScalar dy,
+ SkColor color, uint32_t flags) {
+ fSigma = sigma;
+ fDx = dx;
+ fDy = dy;
+ fBlurColor = color;
+ fBlurFlags = flags;
+ this->initEffects();
+}
+
+SkBlurDrawLooper::SkBlurDrawLooper(SkReadBuffer& buffer) : INHERITED(buffer) {
+
+ fSigma = buffer.readScalar();
fDx = buffer.readScalar();
fDy = buffer.readScalar();
fBlurColor = buffer.readColor();
- fBlur = buffer.readMaskFilter();
- fColorFilter = buffer.readColorFilter();
fBlurFlags = buffer.readUInt() & kAll_BlurFlag;
+
+ this->initEffects();
+}
+
+void SkBlurDrawLooper::flatten(SkWriteBuffer& buffer) const {
+ this->INHERITED::flatten(buffer);
+ buffer.writeScalar(fSigma);
+ buffer.writeScalar(fDx);
+ buffer.writeScalar(fDy);
+ buffer.writeColor(fBlurColor);
+ buffer.write32(fBlurFlags);
}
SkBlurDrawLooper::~SkBlurDrawLooper() {
@@ -79,16 +94,24 @@
SkSafeUnref(fColorFilter);
}
-void SkBlurDrawLooper::flatten(SkWriteBuffer& buffer) const {
- this->INHERITED::flatten(buffer);
- buffer.writeScalar(fDx);
- buffer.writeScalar(fDy);
- buffer.writeColor(fBlurColor);
- buffer.writeFlattenable(fBlur);
- buffer.writeFlattenable(fColorFilter);
- buffer.writeUInt(fBlurFlags);
+bool SkBlurDrawLooper::asABlurShadow(BlurShadowRec* rec) const {
+ if (fSigma <= 0 || (fBlurFlags & fBlurFlags & kIgnoreTransform_BlurFlag)) {
+ return false;
+ }
+
+ if (rec) {
+ rec->fSigma = fSigma;
+ rec->fColor = fBlurColor;
+ rec->fOffset.set(fDx, fDy);
+ rec->fStyle = kNormal_SkBlurStyle;
+ rec->fQuality = (fBlurFlags & kHighQuality_BlurFlag) ?
+ kHigh_SkBlurQuality : kLow_SkBlurQuality;
+ }
+ return true;
}
+////////////////////////////////////////////////////////////////////////////////////////
+
SkDrawLooper::Context* SkBlurDrawLooper::createContext(SkCanvas*, void* storage) const {
return SkNEW_PLACEMENT_ARGS(storage, BlurDrawLooperContext, (this));
}
diff --git a/src/effects/SkBlurMask.cpp b/src/effects/SkBlurMask.cpp
index c04a6f8..bf50845 100644
--- a/src/effects/SkBlurMask.cpp
+++ b/src/effects/SkBlurMask.cpp
@@ -13,17 +13,21 @@
#include "SkEndian.h"
-SkScalar SkBlurMask::ConvertRadiusToSigma(SkScalar radius) {
- // This constant approximates the scaling done in the software path's
- // "high quality" mode, in SkBlurMask::Blur() (1 / sqrt(3)).
- // IMHO, it actually should be 1: we blur "less" than we should do
- // according to the CSS and canvas specs, simply because Safari does the same.
- // Firefox used to do the same too, until 4.0 where they fixed it. So at some
- // point we should probably get rid of these scaling constants and rebaseline
- // all the blur tests.
- static const SkScalar kBLUR_SIGMA_SCALE = 0.57735f;
+// This constant approximates the scaling done in the software path's
+// "high quality" mode, in SkBlurMask::Blur() (1 / sqrt(3)).
+// IMHO, it actually should be 1: we blur "less" than we should do
+// according to the CSS and canvas specs, simply because Safari does the same.
+// Firefox used to do the same too, until 4.0 where they fixed it. So at some
+// point we should probably get rid of these scaling constants and rebaseline
+// all the blur tests.
+static const SkScalar kBLUR_SIGMA_SCALE = 0.57735f;
- return radius ? kBLUR_SIGMA_SCALE * radius + 0.5f : 0.0f;
+SkScalar SkBlurMask::ConvertRadiusToSigma(SkScalar radius) {
+ return radius > 0 ? kBLUR_SIGMA_SCALE * radius + 0.5f : 0.0f;
+}
+
+SkScalar SkBlurMask::ConvertSigmaToRadius(SkScalar sigma) {
+ return sigma > 0.5f ? (sigma - 0.5f) / kBLUR_SIGMA_SCALE : 0.0f;
}
#define UNROLL_SEPARABLE_LOOPS
diff --git a/src/effects/SkBlurMask.h b/src/effects/SkBlurMask.h
index 39adb96..71f60d9 100644
--- a/src/effects/SkBlurMask.h
+++ b/src/effects/SkBlurMask.h
@@ -39,7 +39,10 @@
static bool BlurGroundTruth(SkScalar sigma, SkMask* dst, const SkMask& src, SkBlurStyle,
SkIPoint* margin = NULL);
+ // If radius > 0, return the corresponding sigma, else return 0
static SkScalar ConvertRadiusToSigma(SkScalar radius);
+ // If sigma > 0.5, return the corresponding radius, else return 0
+ static SkScalar ConvertSigmaToRadius(SkScalar sigma);
/* Helper functions for analytic rectangle blurs */
diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp
index 2bed2fe..5dffd6f 100644
--- a/src/effects/SkBlurMaskFilter.cpp
+++ b/src/effects/SkBlurMaskFilter.cpp
@@ -59,6 +59,7 @@
#endif
virtual void computeFastBounds(const SkRect&, SkRect*) const SK_OVERRIDE;
+ virtual bool asABlur(BlurRec*) const SK_OVERRIDE;
SK_TO_STRING_OVERRIDE()
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkBlurMaskFilterImpl)
@@ -87,6 +88,11 @@
SkBlurStyle fBlurStyle;
uint32_t fBlurFlags;
+ SkBlurQuality getQuality() const {
+ return (fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag) ?
+ kHigh_SkBlurQuality : kLow_SkBlurQuality;
+ }
+
SkBlurMaskFilterImpl(SkReadBuffer&);
virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE;
@@ -145,16 +151,24 @@
return SkMask::kA8_Format;
}
+bool SkBlurMaskFilterImpl::asABlur(BlurRec* rec) const {
+ if (fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag) {
+ return false;
+ }
+
+ if (rec) {
+ rec->fSigma = fSigma;
+ rec->fStyle = fBlurStyle;
+ rec->fQuality = this->getQuality();
+ }
+ return true;
+}
+
bool SkBlurMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src,
const SkMatrix& matrix,
SkIPoint* margin) const{
SkScalar sigma = this->computeXformedSigma(matrix);
-
- SkBlurQuality blurQuality =
- (fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag) ?
- kHigh_SkBlurQuality : kLow_SkBlurQuality;
-
- return SkBlurMask::BoxBlur(dst, src, sigma, fBlurStyle, blurQuality, margin);
+ return SkBlurMask::BoxBlur(dst, src, sigma, fBlurStyle, this->getQuality(), margin);
}
bool SkBlurMaskFilterImpl::filterRectMask(SkMask* dst, const SkRect& r,
diff --git a/src/effects/SkEmbossMaskFilter.cpp b/src/effects/SkEmbossMaskFilter.cpp
index 9bf5025..cdd55fc 100644
--- a/src/effects/SkEmbossMaskFilter.cpp
+++ b/src/effects/SkEmbossMaskFilter.cpp
@@ -1,4 +1,3 @@
-
/*
* Copyright 2006 The Android Open Source Project
*
@@ -6,7 +5,6 @@
* found in the LICENSE file.
*/
-
#include "SkEmbossMaskFilter.h"
#include "SkBlurMaskFilter.h"
#include "SkBlurMask.h"
@@ -15,6 +13,10 @@
#include "SkWriteBuffer.h"
#include "SkString.h"
+SkEmbossMaskFilter* SkEmbossMaskFilter::Create(SkScalar blurSigma, const Light& light) {
+ return SkNEW_ARGS(SkEmbossMaskFilter, (blurSigma, light));
+}
+
static inline int pin2byte(int n) {
if (n < 0) {
n = 0;
diff --git a/src/effects/SkLayerDrawLooper.cpp b/src/effects/SkLayerDrawLooper.cpp
index fa590d2..aed2c9b 100644
--- a/src/effects/SkLayerDrawLooper.cpp
+++ b/src/effects/SkLayerDrawLooper.cpp
@@ -153,6 +153,50 @@
return true;
}
+bool SkLayerDrawLooper::asABlurShadow(BlurShadowRec* bsRec) const {
+ if (fCount != 2) {
+ return false;
+ }
+ const Rec* rec = fRecs;
+
+ // bottom layer needs to be just blur(maskfilter)
+ if ((rec->fInfo.fPaintBits & ~kMaskFilter_Bit)) {
+ return false;
+ }
+ if (SkXfermode::kSrc_Mode != rec->fInfo.fColorMode) {
+ return false;
+ }
+ const SkMaskFilter* mf = rec->fPaint.getMaskFilter();
+ if (NULL == mf) {
+ return false;
+ }
+ SkMaskFilter::BlurRec maskBlur;
+ if (!mf->asABlur(&maskBlur)) {
+ return false;
+ }
+
+ rec = rec->fNext;
+ // top layer needs to be "plain"
+ if (rec->fInfo.fPaintBits) {
+ return false;
+ }
+ if (SkXfermode::kDst_Mode != rec->fInfo.fColorMode) {
+ return false;
+ }
+ if (!rec->fInfo.fOffset.equals(0, 0)) {
+ return false;
+ }
+
+ if (bsRec) {
+ bsRec->fSigma = maskBlur.fSigma;
+ bsRec->fOffset = fRecs->fInfo.fOffset;
+ bsRec->fColor = fRecs->fPaint.getColor();
+ bsRec->fStyle = maskBlur.fStyle;
+ bsRec->fQuality = maskBlur.fQuality;
+ }
+ return true;
+}
+
///////////////////////////////////////////////////////////////////////////////
void SkLayerDrawLooper::flatten(SkWriteBuffer& buffer) const {
diff --git a/tests/BlurTest.cpp b/tests/BlurTest.cpp
index 028b509..c09a4ee 100644
--- a/tests/BlurTest.cpp
+++ b/tests/BlurTest.cpp
@@ -1,12 +1,15 @@
-
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
+
#include "SkBlurMask.h"
#include "SkBlurMaskFilter.h"
+#include "SkBlurDrawLooper.h"
+#include "SkLayerDrawLooper.h"
+#include "SkEmbossMaskFilter.h"
#include "SkCanvas.h"
#include "SkMath.h"
#include "SkPaint.h"
@@ -380,7 +383,187 @@
}
}
+///////////////////////////////////////////////////////////////////////////////////////////
+
+static SkBlurQuality blurMaskFilterFlags_as_quality(uint32_t blurMaskFilterFlags) {
+ return (blurMaskFilterFlags & SkBlurMaskFilter::kHighQuality_BlurFlag) ?
+ kHigh_SkBlurQuality : kLow_SkBlurQuality;
+}
+
+static uint32_t blurMaskFilterFlags_to_blurDrawLooperFlags(uint32_t bmf) {
+ const struct {
+ uint32_t fBlurMaskFilterFlag;
+ uint32_t fBlurDrawLooperFlag;
+ } pairs[] = {
+ { SkBlurMaskFilter::kIgnoreTransform_BlurFlag, SkBlurDrawLooper::kIgnoreTransform_BlurFlag },
+ { SkBlurMaskFilter::kHighQuality_BlurFlag, SkBlurDrawLooper::kHighQuality_BlurFlag },
+ };
+
+ uint32_t bdl = 0;
+ for (size_t i = 0; i < SK_ARRAY_COUNT(pairs); ++i) {
+ if (bmf & pairs[i].fBlurMaskFilterFlag) {
+ bdl |= pairs[i].fBlurDrawLooperFlag;
+ }
+ }
+ return bdl;
+}
+
+static void test_blurDrawLooper(skiatest::Reporter* reporter, SkScalar sigma,
+ SkBlurStyle style, uint32_t blurMaskFilterFlags) {
+ if (kNormal_SkBlurStyle != style) {
+ return; // blurdrawlooper only supports normal
+ }
+
+ const SkColor color = 0xFF335577;
+ const SkScalar dx = 10;
+ const SkScalar dy = -5;
+ const SkBlurQuality quality = blurMaskFilterFlags_as_quality(blurMaskFilterFlags);
+ uint32_t flags = blurMaskFilterFlags_to_blurDrawLooperFlags(blurMaskFilterFlags);
+
+ SkAutoTUnref<SkDrawLooper> lp(SkBlurDrawLooper::Create(color, sigma, dx, dy, flags));
+
+ const bool expectSuccess = sigma > 0 &&
+ 0 == (flags & SkBlurDrawLooper::kIgnoreTransform_BlurFlag);
+
+ if (NULL == lp.get()) {
+ REPORTER_ASSERT(reporter, sigma <= 0);
+ } else {
+ SkDrawLooper::BlurShadowRec rec;
+ bool success = lp->asABlurShadow(&rec);
+ REPORTER_ASSERT(reporter, success == expectSuccess);
+ if (success) {
+ REPORTER_ASSERT(reporter, rec.fSigma == sigma);
+ REPORTER_ASSERT(reporter, rec.fOffset.x() == dx);
+ REPORTER_ASSERT(reporter, rec.fOffset.y() == dy);
+ REPORTER_ASSERT(reporter, rec.fColor == color);
+ REPORTER_ASSERT(reporter, rec.fStyle == style);
+ REPORTER_ASSERT(reporter, rec.fQuality == quality);
+ }
+ }
+}
+
+static void test_delete_looper(skiatest::Reporter* reporter, SkDrawLooper* lp, SkScalar sigma,
+ SkBlurStyle style, SkBlurQuality quality, bool expectSuccess) {
+ SkDrawLooper::BlurShadowRec rec;
+ bool success = lp->asABlurShadow(&rec);
+ REPORTER_ASSERT(reporter, success == expectSuccess);
+ if (success != expectSuccess) {
+ lp->asABlurShadow(&rec);
+ }
+ if (success) {
+ REPORTER_ASSERT(reporter, rec.fSigma == sigma);
+ REPORTER_ASSERT(reporter, rec.fStyle == style);
+ REPORTER_ASSERT(reporter, rec.fQuality == quality);
+ }
+ lp->unref();
+}
+
+static void make_noop_layer(SkLayerDrawLooper::Builder* builder) {
+ SkLayerDrawLooper::LayerInfo info;
+
+ info.fPaintBits = 0;
+ info.fColorMode = SkXfermode::kDst_Mode;
+ builder->addLayer(info);
+}
+
+static void make_blur_layer(SkLayerDrawLooper::Builder* builder, SkMaskFilter* mf) {
+ SkLayerDrawLooper::LayerInfo info;
+
+ info.fPaintBits = SkLayerDrawLooper::kMaskFilter_Bit;
+ info.fColorMode = SkXfermode::kSrc_Mode;
+ SkPaint* paint = builder->addLayer(info);
+ paint->setMaskFilter(mf);
+}
+
+static void test_layerDrawLooper(skiatest::Reporter* reporter, SkMaskFilter* mf, SkScalar sigma,
+ SkBlurStyle style, SkBlurQuality quality, bool expectSuccess) {
+
+ SkLayerDrawLooper::LayerInfo info;
+ SkLayerDrawLooper::Builder builder;
+
+ // 1 layer is too few
+ make_noop_layer(&builder);
+ test_delete_looper(reporter, builder.detachLooper(), sigma, style, quality, false);
+
+ // 2 layers is good, but need blur
+ make_noop_layer(&builder);
+ make_noop_layer(&builder);
+ test_delete_looper(reporter, builder.detachLooper(), sigma, style, quality, false);
+
+ // 2 layers is just right
+ make_noop_layer(&builder);
+ make_blur_layer(&builder, mf);
+ test_delete_looper(reporter, builder.detachLooper(), sigma, style, quality, expectSuccess);
+
+ // 3 layers is too many
+ make_noop_layer(&builder);
+ make_blur_layer(&builder, mf);
+ make_noop_layer(&builder);
+ test_delete_looper(reporter, builder.detachLooper(), sigma, style, quality, false);
+}
+
+static void test_asABlur(skiatest::Reporter* reporter) {
+ const SkBlurStyle styles[] = {
+ kNormal_SkBlurStyle, kSolid_SkBlurStyle, kOuter_SkBlurStyle, kInner_SkBlurStyle
+ };
+ const SkScalar sigmas[] = {
+ // values <= 0 should not success for a blur
+ -1, 0, 0.5f, 2
+ };
+
+ // Test asABlur for SkBlurMaskFilter
+ //
+ for (size_t i = 0; i < SK_ARRAY_COUNT(styles); ++i) {
+ const SkBlurStyle style = (SkBlurStyle)styles[i];
+ for (size_t j = 0; j < SK_ARRAY_COUNT(sigmas); ++j) {
+ const SkScalar sigma = sigmas[j];
+ for (int flags = 0; flags <= SkBlurMaskFilter::kAll_BlurFlag; ++flags) {
+ const SkBlurQuality quality = blurMaskFilterFlags_as_quality(flags);
+
+ SkAutoTUnref<SkMaskFilter> mf(SkBlurMaskFilter::Create(style, sigma, flags));
+ if (NULL == mf.get()) {
+ REPORTER_ASSERT(reporter, sigma <= 0);
+ } else {
+ REPORTER_ASSERT(reporter, sigma > 0);
+ SkMaskFilter::BlurRec rec;
+ bool success = mf->asABlur(&rec);
+ if (flags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag) {
+ REPORTER_ASSERT(reporter, !success);
+ } else {
+ REPORTER_ASSERT(reporter, success);
+ REPORTER_ASSERT(reporter, rec.fSigma == sigma);
+ REPORTER_ASSERT(reporter, rec.fStyle == style);
+ REPORTER_ASSERT(reporter, rec.fQuality == quality);
+ }
+ test_layerDrawLooper(reporter, mf, sigma, style, quality, success);
+ }
+ test_blurDrawLooper(reporter, sigma, style, flags);
+ }
+ }
+ }
+
+ // Test asABlur for SkEmbossMaskFilter -- should never succeed
+ //
+ {
+ SkEmbossMaskFilter::Light light = {
+ { 1, 1, 1 }, 0, 127, 127
+ };
+ for (size_t j = 0; j < SK_ARRAY_COUNT(sigmas); ++j) {
+ const SkScalar sigma = sigmas[j];
+ SkAutoTUnref<SkMaskFilter> mf(SkEmbossMaskFilter::Create(sigma, light));
+ if (mf.get()) {
+ SkMaskFilter::BlurRec rec;
+ bool success = mf->asABlur(&rec);
+ REPORTER_ASSERT(reporter, !success);
+ }
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
DEF_GPUTEST(Blur, reporter, factory) {
test_blur_drawing(reporter);
test_sigma_range(reporter, factory);
+ test_asABlur(reporter);
}