From 43c50c8c77df82c5cffb55cae2d386e59802b88f Mon Sep 17 00:00:00 2001 From: "reed@google.com" Date: Thu, 14 Apr 2011 15:50:52 +0000 Subject: [PATCH] add reflection asColorMode to SkColorFilter (for gpu) git-svn-id: http://skia.googlecode.com/svn/trunk@1126 2bbb7eff-a529-9590-31e7-b0007b416f81 --- include/core/SkColorFilter.h | 7 +++ include/core/SkXfermode.h | 27 +++++++-- src/core/SkColorFilter.cpp | 4 ++ src/core/SkXfermode.cpp | 43 ++++++++++++-- src/effects/SkColorFilters.cpp | 123 +++++++++++++++++++++++++++++------------ tests/ColorFilterTest.cpp | 93 +++++++++++++++++++++++++++++++ tests/tests_files.mk | 1 + 7 files changed, 253 insertions(+), 45 deletions(-) create mode 100644 tests/ColorFilterTest.cpp diff --git a/include/core/SkColorFilter.h b/include/core/SkColorFilter.h index 3bdf815..20e3660 100644 --- a/include/core/SkColorFilter.h +++ b/include/core/SkColorFilter.h @@ -23,6 +23,13 @@ class SkColorFilter : public SkFlattenable { public: + /** + * If the filter can be represented by a source color plus Mode, this + * returns true, and sets (if not NULL) the color and mode appropriately. + * If not, this returns false and ignores the parameters. + */ + virtual bool asColorMode(SkColor* color, SkXfermode::Mode* mode); + /** Called with a scanline of colors, as if there was a shader installed. The implementation writes out its filtered version into result[]. Note: shader and result may be the same buffer. diff --git a/include/core/SkXfermode.h b/include/core/SkXfermode.h index 506f336..0f2efbd 100644 --- a/include/core/SkXfermode.h +++ b/include/core/SkXfermode.h @@ -75,6 +75,12 @@ public: */ virtual bool asCoeff(Coeff* src, Coeff* dst); + /** + * The same as calling xfermode->asCoeff(..), except that this also checks + * if the xfermode is NULL, and if so, treats its as kSrcOver_Mode. + */ + static bool AsCoeff(SkXfermode*, Coeff* src, Coeff* dst); + /** List of predefined xfermodes. The algebra for the modes uses the following symbols: Sa, Sc - source alpha and color @@ -122,6 +128,12 @@ public: */ virtual bool asMode(Mode* mode); + /** + * The same as calling xfermode->asMode(mode), except that this also checks + * if the xfermode is NULL, and if so, treats its as kSrcOver_Mode. + */ + static bool AsMode(SkXfermode*, Mode* mode); + /** Return an SkXfermode object for the specified mode. */ static SkXfermode* Create(Mode mode); @@ -137,13 +149,20 @@ public: 16bit proc, and this will return NULL. */ static SkXfermodeProc16 GetProc16(Mode mode, SkColor srcColor); - + /** - * The same as calling xfermode->asMode(mode), except that this also checks - * if the xfermode is NULL, and if so, treats its as kSrcOver_Mode. + * If the specified mode can be represented by a pair of Coeff, then return + * true and set (if not NULL) the corresponding coeffs. If the mode is + * not representable as a pair of Coeffs, return false and ignore the + * src and dst parameters. */ - static bool IsMode(SkXfermode*, Mode* mode); + static bool ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst); + // DEPRECATED: call AsMode(...) + static bool IsMode(SkXfermode* xfer, Mode* mode) { + return AsMode(xfer, mode); + } + protected: SkXfermode(SkFlattenableReadBuffer& rb) : SkFlattenable(rb) {} diff --git a/src/core/SkColorFilter.cpp b/src/core/SkColorFilter.cpp index bb4be48..6bc6d08 100644 --- a/src/core/SkColorFilter.cpp +++ b/src/core/SkColorFilter.cpp @@ -18,6 +18,10 @@ #include "SkColorFilter.h" #include "SkShader.h" +bool SkColorFilter::asColorMode(SkColor* color, SkXfermode::Mode* mode) { + return false; +} + void SkColorFilter::filterSpan16(const uint16_t s[], int count, uint16_t d[]) { SkASSERT(this->getFlags() & SkColorFilter::kHasFilter16_Flag); diff --git a/src/core/SkXfermode.cpp b/src/core/SkXfermode.cpp index 87d6078..06b97a9 100644 --- a/src/core/SkXfermode.cpp +++ b/src/core/SkXfermode.cpp @@ -977,7 +977,39 @@ SkXfermode* SkXfermode::Create(Mode mode) { } } -bool SkXfermode::IsMode(SkXfermode* xfer, Mode* mode) { +SkXfermodeProc SkXfermode::GetProc(Mode mode) { + SkXfermodeProc proc = NULL; + if ((unsigned)mode < kModeCount) { + proc = gProcCoeffs[mode].fProc; + } + return proc; +} + +bool SkXfermode::ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst) { + SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount); + + if ((unsigned)mode >= (unsigned)kModeCount) { + // illegal mode parameter + return false; + } + + const ProcCoeff& rec = gProcCoeffs[mode]; + + if (CANNOT_USE_COEFF == rec.fSC) { + return false; + } + + SkASSERT(CANNOT_USE_COEFF != rec.fDC); + if (src) { + *src = rec.fSC; + } + if (dst) { + *dst = rec.fDC; + } + return true; +} + +bool SkXfermode::AsMode(SkXfermode* xfer, Mode* mode) { if (NULL == xfer) { if (mode) { *mode = kSrcOver_Mode; @@ -987,12 +1019,11 @@ bool SkXfermode::IsMode(SkXfermode* xfer, Mode* mode) { return xfer->asMode(mode); } -SkXfermodeProc SkXfermode::GetProc(Mode mode) { - SkXfermodeProc proc = NULL; - if ((unsigned)mode < kModeCount) { - proc = gProcCoeffs[mode].fProc; +bool SkXfermode::AsCoeff(SkXfermode* xfer, Coeff* src, Coeff* dst) { + if (NULL == xfer) { + return ModeAsCoeff(kSrcOver_Mode, src, dst); } - return proc; + return xfer->asCoeff(src, dst); } /////////////////////////////////////////////////////////////////////////////// diff --git a/src/effects/SkColorFilters.cpp b/src/effects/SkColorFilters.cpp index a396d35..64445a9 100644 --- a/src/effects/SkColorFilters.cpp +++ b/src/effects/SkColorFilters.cpp @@ -19,26 +19,67 @@ #include "SkColorPriv.h" #include "SkUtils.h" -// common baseclass -class Sk_XfermodeColorFilter : public SkColorFilter { -protected: - Sk_XfermodeColorFilter(SkColor color) - : fPMColor(SkPreMultiplyColor(color)) {} +#define ILLEGAL_XFERMODE_MODE ((SkXfermode::Mode)-1) + +// baseclass for filters that store a color and mode +class SkModeColorFilter : public SkColorFilter { +public: + SkModeColorFilter(SkColor color) { + fColor = color; + fMode = ILLEGAL_XFERMODE_MODE; + + fPMColor = SkPreMultiplyColor(fColor); + } + + SkModeColorFilter(SkColor color, SkXfermode::Mode mode) { + fColor = color; + fMode = mode; + + fPMColor = SkPreMultiplyColor(fColor); + }; + + virtual bool asColorMode(SkColor* color, SkXfermode::Mode* mode) { + if (ILLEGAL_XFERMODE_MODE == fMode) { + return false; + } + + if (color) { + *color = fColor; + } + if (mode) { + *mode = fMode; + } + return true; + } + SkColor getColor() const { return fColor; } + SkXfermode::Mode getMode() const { return fMode; } + bool isModeValid() const { return ILLEGAL_XFERMODE_MODE != fMode; } + +protected: virtual void flatten(SkFlattenableWriteBuffer& buffer) { - buffer.write32(fPMColor); + buffer.write32(fColor); + buffer.write32(fMode); } + + SkModeColorFilter(SkFlattenableReadBuffer& buffer) { + fColor = buffer.readU32(); + fMode = (SkXfermode::Mode)buffer.readU32(); - Sk_XfermodeColorFilter(SkFlattenableReadBuffer& buffer) { - fPMColor = buffer.readU32(); + fPMColor = SkPreMultiplyColor(fColor); } + // cache of fColor in premultiply space SkPMColor fPMColor; + +private: + SkColor fColor; + SkXfermode::Mode fMode; }; -class SkSrc_XfermodeColorFilter : public Sk_XfermodeColorFilter { +class Src_SkModeColorFilter : public SkModeColorFilter { public: - SkSrc_XfermodeColorFilter(SkColor color) : INHERITED(color) {} + Src_SkModeColorFilter(SkColor color) : INHERITED(color, SkXfermode::kSrc_Mode) {} virtual uint32_t getFlags() { if (SkGetPackedA32(fPMColor) == 0xFF) { @@ -62,21 +103,23 @@ public: protected: virtual Factory getFactory() { return CreateProc; } - SkSrc_XfermodeColorFilter(SkFlattenableReadBuffer& buffer) + Src_SkModeColorFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {} private: static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { - return SkNEW_ARGS(SkSrc_XfermodeColorFilter, (buffer)); + return SkNEW_ARGS(Src_SkModeColorFilter, (buffer)); } - typedef Sk_XfermodeColorFilter INHERITED; + typedef SkModeColorFilter INHERITED; }; -class SkSrcOver_XfermodeColorFilter : public Sk_XfermodeColorFilter { +class SrcOver_SkModeColorFilter : public SkModeColorFilter { public: - SkSrcOver_XfermodeColorFilter(SkColor color) - : INHERITED(color), fColor32Proc(SkBlitRow::ColorProcFactory()) {} + SrcOver_SkModeColorFilter(SkColor color) + : INHERITED(color, SkXfermode::kSrcOver_Mode) { + fColor32Proc = NULL; + } virtual uint32_t getFlags() { if (SkGetPackedA32(fPMColor) == 0xFF) { @@ -88,6 +131,9 @@ public: virtual void filterSpan(const SkPMColor shader[], int count, SkPMColor result[]) { + if (NULL == fColor32Proc) { + fColor32Proc = SkBlitRow::ColorProcFactory(); + } fColor32Proc(result, shader, count, fPMColor); } @@ -100,24 +146,31 @@ public: protected: virtual Factory getFactory() { return CreateProc; } - SkSrcOver_XfermodeColorFilter(SkFlattenableReadBuffer& buffer) - : INHERITED(buffer), fColor32Proc(SkBlitRow::ColorProcFactory()) {} + SrcOver_SkModeColorFilter(SkFlattenableReadBuffer& buffer) + : INHERITED(buffer), fColor32Proc(NULL) {} private: static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { - return SkNEW_ARGS(SkSrcOver_XfermodeColorFilter, (buffer)); + return SkNEW_ARGS(SrcOver_SkModeColorFilter, (buffer)); } - typedef Sk_XfermodeColorFilter INHERITED; SkBlitRow::ColorProc fColor32Proc; + + typedef SkModeColorFilter INHERITED; }; -////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// -class SkXfermodeColorFilter : public Sk_XfermodeColorFilter { +class Proc_SkModeColorFilter : public SkModeColorFilter { public: - SkXfermodeColorFilter(SkColor color, SkXfermodeProc proc, - SkXfermodeProc16 proc16) : INHERITED(color) { + Proc_SkModeColorFilter(SkColor color, SkXfermode::Mode mode) : INHERITED(color, mode) { + fProc = SkXfermode::GetProc(mode); + fProc16 = SkXfermode::GetProc16(mode, color); + } + + Proc_SkModeColorFilter(SkColor color, + SkXfermodeProc proc, SkXfermodeProc16 proc16) + : INHERITED(color, ILLEGAL_XFERMODE_MODE) { fProc = proc; fProc16 = proc16; } @@ -159,26 +212,27 @@ protected: return CreateProc; } - SkXfermodeColorFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) { + Proc_SkModeColorFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) { fProc = (SkXfermodeProc) buffer.readFunctionPtr(); fProc16 = (SkXfermodeProc16) buffer.readFunctionPtr(); } + private: static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) { - return SkNEW_ARGS(SkXfermodeColorFilter, (buffer)); + return SkNEW_ARGS(Proc_SkModeColorFilter, (buffer)); } SkXfermodeProc fProc; SkXfermodeProc16 fProc16; - typedef Sk_XfermodeColorFilter INHERITED; + typedef SkModeColorFilter INHERITED; }; SkColorFilter* SkColorFilter::CreateProcFilter(SkColor color, SkXfermodeProc proc, SkXfermodeProc16 proc16) { return proc ? - SkNEW_ARGS(SkXfermodeColorFilter, (color, proc, proc16)) : + SkNEW_ARGS(Proc_SkModeColorFilter, (color, proc, proc16)) : NULL; } @@ -215,13 +269,12 @@ SkColorFilter* SkColorFilter::CreateModeFilter(SkColor color, } switch (mode) { - case SkXfermode::kSrc_Mode: - return SkNEW_ARGS(SkSrc_XfermodeColorFilter, (color)); - case SkXfermode::kSrcOver_Mode: - return SkNEW_ARGS(SkSrcOver_XfermodeColorFilter, (color)); - default: - return SkColorFilter::CreateProcFilter(color, SkXfermode::GetProc(mode), - SkXfermode::GetProc16(mode, color)); + case SkXfermode::kSrc_Mode: + return SkNEW_ARGS(Src_SkModeColorFilter, (color)); + case SkXfermode::kSrcOver_Mode: + return SkNEW_ARGS(SrcOver_SkModeColorFilter, (color)); + default: + return SkNEW_ARGS(Proc_SkModeColorFilter, (color, mode)); } } diff --git a/tests/ColorFilterTest.cpp b/tests/ColorFilterTest.cpp new file mode 100644 index 0000000..77575eb --- /dev/null +++ b/tests/ColorFilterTest.cpp @@ -0,0 +1,93 @@ +#include "Test.h" +#include "SkColor.h" +#include "SkColorFilter.h" +#include "SkRandom.h" +#include "SkXfermode.h" + +static SkFlattenable* reincarnate_flattenable(SkFlattenable* obj) { + SkFlattenable::Factory fact = obj->getFactory(); + if (NULL == fact) { + return NULL; + } + + SkFlattenableWriteBuffer wb(1024); + obj->flatten(wb); + + size_t size = wb.size(); + SkAutoSMalloc<1024> storage(size); + // make a copy into storage + wb.flatten(storage.get()); + + SkFlattenableReadBuffer rb(storage.get(), size); + return fact(rb); +} + +template T* reincarnate(T* obj) { + return (T*)reincarnate_flattenable(obj); +} + +/////////////////////////////////////////////////////////////////////////////// + +#define ILLEGAL_MODE ((SkXfermode::Mode)-1) + +static void test_asColorMode(skiatest::Reporter* reporter) { + SkRandom rand; + + for (int mode = 0; mode <= SkXfermode::kLastMode; mode++) { + SkColor color = rand.nextU(); + + // ensure we always get a filter, by avoiding the possibility of a + // special case that would return NULL (if color's alpha is 0 or 0xFF) + color = SkColorSetA(color, 0x7F); + + SkColorFilter* cf = SkColorFilter::CreateModeFilter(color, + (SkXfermode::Mode)mode); + + // allow for no filter if we're in Dst mode (its a no op) + if (SkXfermode::kDst_Mode == mode && NULL == cf) { + continue; + } + + SkAutoUnref aur(cf); + REPORTER_ASSERT(reporter, cf); + + SkColor c = ~color; + SkXfermode::Mode m = ILLEGAL_MODE; + + SkColor expectedColor = color; + SkXfermode::Mode expectedMode = (SkXfermode::Mode)mode; + +// SkDebugf("--- mc [%d %x] ", mode, color); + + REPORTER_ASSERT(reporter, cf->asColorMode(&c, &m)); + // handle special-case folding by the factory + if (SkXfermode::kClear_Mode == mode) { + if (c != expectedColor) { + expectedColor = 0; + } + if (m != expectedMode) { + expectedMode = SkXfermode::kSrc_Mode; + } + } + +// SkDebugf("--- got [%d %x] expected [%d %x]\n", m, c, expectedMode, expectedColor); + + REPORTER_ASSERT(reporter, c == expectedColor); + REPORTER_ASSERT(reporter, m == expectedMode); + + { + SkColorFilter* cf2 = reincarnate(cf); + SkAutoUnref aur2(cf2); + REPORTER_ASSERT(reporter, cf2); + + SkColor c2 = ~color; + SkXfermode::Mode m2 = ILLEGAL_MODE; + REPORTER_ASSERT(reporter, cf2->asColorMode(&c2, &m2)); + REPORTER_ASSERT(reporter, c2 == expectedColor); + REPORTER_ASSERT(reporter, m2 == expectedMode); + } + } +} + +#include "TestClassDef.h" +DEFINE_TESTCLASS("ColorFilter", ColorFilterTestClass, test_asColorMode) diff --git a/tests/tests_files.mk b/tests/tests_files.mk index 9f8d6df..526a219 100644 --- a/tests/tests_files.mk +++ b/tests/tests_files.mk @@ -5,6 +5,7 @@ SOURCE := \ ClipCubicTest.cpp \ ClipStackTest.cpp \ ClipperTest.cpp \ + ColorFilterTest.cpp \ DequeTest.cpp \ DrawBitmapRectTest.cpp \ FillPathTest.cpp \ -- 2.7.4