From 3125565804054691b110b4731bc5a32070fab780 Mon Sep 17 00:00:00 2001 From: reed Date: Mon, 8 Feb 2016 12:56:56 -0800 Subject: [PATCH] extend modecolorfilter to 4f BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1670063002 Review URL: https://codereview.chromium.org/1670063002 --- gm/color4f.cpp | 16 ++-- include/core/SkColor.h | 2 + include/core/SkXfermode.h | 2 + src/core/SkModeColorFilter.cpp | 14 ++- src/core/SkModeColorFilter.h | 1 + src/core/SkXfermode.cpp | 153 ++++++++++++++++++++++++++------ src/core/SkXfermode_proccoeff.h | 1 + tests/SkColor4fTest.cpp | 46 +++++++++- 8 files changed, 196 insertions(+), 39 deletions(-) diff --git a/gm/color4f.cpp b/gm/color4f.cpp index e912654bc9..9e6fcf6060 100644 --- a/gm/color4f.cpp +++ b/gm/color4f.cpp @@ -45,10 +45,14 @@ static SkColorFilter* make_cf1() { return SkColorFilter::CreateComposeFilter(a, b); } +static SkColorFilter* make_cf2() { + return SkColorFilter::CreateModeFilter(0x8044CC88, SkXfermode::kSrcATop_Mode); +} + static void draw_into_canvas(SkCanvas* canvas) { - const SkRect r = SkRect::MakeWH(100, 100); + const SkRect r = SkRect::MakeWH(50, 100); SkShader* (*shaders[])() { make_opaque_color, make_alpha_color }; - SkColorFilter* (*filters[])() { make_cf_null, make_cf0, make_cf1 }; + SkColorFilter* (*filters[])() { make_cf_null, make_cf0, make_cf1, make_cf2 }; SkPaint paint; for (auto shProc : shaders) { @@ -56,13 +60,13 @@ static void draw_into_canvas(SkCanvas* canvas) { for (auto cfProc : filters) { SkSafeUnref(paint.setColorFilter(cfProc())); canvas->drawRect(r, paint); - canvas->translate(120, 0); + canvas->translate(60, 0); } } } -DEF_SIMPLE_GM(color4f, canvas, 620, 260) { - canvas->translate(20, 20); +DEF_SIMPLE_GM(color4f, canvas, 1024, 260) { + canvas->translate(10, 10); SkPaint bg; // need the target to be opaque, so we can draw it to the screen @@ -71,7 +75,7 @@ DEF_SIMPLE_GM(color4f, canvas, 620, 260) { SkColorProfileType const profiles[] { kLinear_SkColorProfileType, kSRGB_SkColorProfileType }; for (auto profile : profiles) { - const SkImageInfo info = SkImageInfo::Make(600, 100, kN32_SkColorType, kPremul_SkAlphaType, + const SkImageInfo info = SkImageInfo::Make(1024, 100, kN32_SkColorType, kPremul_SkAlphaType, profile); SkAutoTUnref surface(SkSurface::NewRaster(info)); surface->getCanvas()->drawPaint(bg); diff --git a/include/core/SkColor.h b/include/core/SkColor.h index b1571c7009..101a9bdbed 100644 --- a/include/core/SkColor.h +++ b/include/core/SkColor.h @@ -192,6 +192,8 @@ struct SkPM4f { #endif }; +typedef SkPM4f (*SkXfermodeProc4f)(const SkPM4f& src, const SkPM4f& dst); + /* * The float values are 0...1 unpremultiplied */ diff --git a/include/core/SkXfermode.h b/include/core/SkXfermode.h index f2d8d57865..9549452960 100644 --- a/include/core/SkXfermode.h +++ b/include/core/SkXfermode.h @@ -144,6 +144,7 @@ public: porter-duff transfer mode. */ static SkXfermodeProc GetProc(Mode mode); + static SkXfermodeProc4f GetProc4f(Mode); /** * If the specified mode can be represented by a pair of Coeff, then return @@ -241,6 +242,7 @@ public: int count, const SkAlpha coverage[]); typedef void (*PM4fProcN)(const PM4fState&, uint32_t dst[], const SkPM4f src[], int count, const SkAlpha coverage[]); + static PM4fProc1 GetPM4fProc1(Mode, uint32_t flags); static PM4fProcN GetPM4fProcN(Mode, uint32_t flags); virtual PM4fProc1 getPM4fProc1(uint32_t flags) const; diff --git a/src/core/SkModeColorFilter.cpp b/src/core/SkModeColorFilter.cpp index df1051abb0..14e3fb7068 100644 --- a/src/core/SkModeColorFilter.cpp +++ b/src/core/SkModeColorFilter.cpp @@ -37,20 +37,30 @@ bool SkModeColorFilter::asColorMode(SkColor* color, SkXfermode::Mode* mode) cons } uint32_t SkModeColorFilter::getFlags() const { + uint32_t flags = kSupports4f_Flag; switch (fMode) { case SkXfermode::kDst_Mode: //!< [Da, Dc] case SkXfermode::kSrcATop_Mode: //!< [Da, Sc * Da + (1 - Sa) * Dc] - return kAlphaUnchanged_Flag; + flags |= kAlphaUnchanged_Flag; default: break; } - return 0; + return flags; } void SkModeColorFilter::filterSpan(const SkPMColor shader[], int count, SkPMColor result[]) const { SkPMColor color = fPMColor; SkXfermodeProc proc = fProc; + + for (int i = 0; i < count; i++) { + result[i] = proc(color, shader[i]); + } +} +void SkModeColorFilter::filterSpan4f(const SkPM4f shader[], int count, SkPM4f result[]) const { + SkPM4f color = SkPM4f::FromPMColor(fPMColor); + SkXfermodeProc4f proc = SkXfermode::GetProc4f(fMode); + for (int i = 0; i < count; i++) { result[i] = proc(color, shader[i]); } diff --git a/src/core/SkModeColorFilter.h b/src/core/SkModeColorFilter.h index 9fa7717b84..44e618a3ad 100644 --- a/src/core/SkModeColorFilter.h +++ b/src/core/SkModeColorFilter.h @@ -24,6 +24,7 @@ public: bool asColorMode(SkColor*, SkXfermode::Mode*) const override; uint32_t getFlags() const override; void filterSpan(const SkPMColor shader[], int count, SkPMColor result[]) const override; + void filterSpan4f(const SkPM4f shader[], int count, SkPM4f result[]) const override; #ifndef SK_IGNORE_TO_STRING void toString(SkString* str) const override; diff --git a/src/core/SkXfermode.cpp b/src/core/SkXfermode.cpp index 86e3ed5dcf..81083199b3 100644 --- a/src/core/SkXfermode.cpp +++ b/src/core/SkXfermode.cpp @@ -47,6 +47,54 @@ static inline int clamp_div255round(int prod) { } /////////////////////////////////////////////////////////////////////////////// +#include "SkNx.h" + +static Sk4f alpha(const Sk4f& color) { return Sk4f(color.kth<3>()); } +static Sk4f inv_alpha(const Sk4f& color) { return Sk4f(1 - color.kth<3>()); } +static Sk4f pin_1(const Sk4f& value) { return Sk4f::Min(value, Sk4f(1)); } + +static Sk4f clear_4f(const Sk4f& s, const Sk4f& d) { return Sk4f(0); } +static Sk4f src_4f(const Sk4f& s, const Sk4f& d) { return s; } +static Sk4f dst_4f(const Sk4f& s, const Sk4f& d) { return d; } +static Sk4f srcover_4f(const Sk4f& s, const Sk4f& d) { return s + inv_alpha(s) * d; } +static Sk4f dstover_4f(const Sk4f& s, const Sk4f& d) { return d + inv_alpha(d) * s; } +static Sk4f srcin_4f(const Sk4f& s, const Sk4f& d) { return s * alpha(d); } +static Sk4f dstin_4f(const Sk4f& s, const Sk4f& d) { return d * alpha(s); } +static Sk4f srcout_4f(const Sk4f& s, const Sk4f& d) { return s * inv_alpha(d); } +static Sk4f dstout_4f(const Sk4f& s, const Sk4f& d) { return d * inv_alpha(s); } +static Sk4f srcatop_4f(const Sk4f& s, const Sk4f& d) { return s * alpha(d) + d * inv_alpha(s); } +static Sk4f dstatop_4f(const Sk4f& s, const Sk4f& d) { return d * alpha(s) + s * inv_alpha(d); } +static Sk4f xor_4f(const Sk4f& s, const Sk4f& d) { return s * inv_alpha(d) + d * inv_alpha(s);} +static Sk4f plus_4f(const Sk4f& s, const Sk4f& d) { return pin_1(s + d); } +static Sk4f modulate_4f(const Sk4f& s, const Sk4f& d) { return s * d; } +static Sk4f screen_4f(const Sk4f& s, const Sk4f& d) { return s + d - s * d; } + +static Sk4f multiply_4f(const Sk4f& s, const Sk4f& d) { + return s * inv_alpha(d) + d * inv_alpha(s) + s * d; +} + +/////////////////////////////////////////////////////////////////////////////// + +static SkPM4f as_pm4f(const Sk4f& x) { + SkPM4f pm4; + x.store(pm4.fVec); + return pm4; +} + +static Sk4f as_4f(const SkPM4f& pm4) { + return Sk4f::Load(pm4.fVec); +} + +template +SkPM4f proc_4f(const SkPM4f& src, const SkPM4f& dst) { + return as_pm4f(blend(as_4f(src), as_4f(dst))); +} + +/////////////////////////////////////////////////////////////////////////////// + +static SkPM4f not_implemented_yet_proc4f(const SkPM4f& src, const SkPM4f& dst) { + return {{ 0.5f, 1.0f, 0.25f, 0.5f }}; +} // kClear_Mode, //!< [0, 0] static SkPMColor clear_modeproc(SkPMColor src, SkPMColor dst) { @@ -219,6 +267,9 @@ static SkPMColor overlay_modeproc(SkPMColor src, SkPMColor dst) { int b = overlay_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); return SkPackARGB32(a, r, g, b); } +static SkPM4f overlay_proc4f(const SkPM4f& src, const SkPM4f& dst) { + return not_implemented_yet_proc4f(src, dst); +} // kDarken_Mode static inline int darken_byte(int sc, int dc, int sa, int da) { @@ -241,6 +292,9 @@ static SkPMColor darken_modeproc(SkPMColor src, SkPMColor dst) { int b = darken_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); return SkPackARGB32(a, r, g, b); } +static SkPM4f darken_proc4f(const SkPM4f& src, const SkPM4f& dst) { + return not_implemented_yet_proc4f(src, dst); +} // kLighten_Mode static inline int lighten_byte(int sc, int dc, int sa, int da) { @@ -263,6 +317,9 @@ static SkPMColor lighten_modeproc(SkPMColor src, SkPMColor dst) { int b = lighten_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); return SkPackARGB32(a, r, g, b); } +static SkPM4f lighten_proc4f(const SkPM4f& src, const SkPM4f& dst) { + return not_implemented_yet_proc4f(src, dst); +} // kColorDodge_Mode static inline int colordodge_byte(int sc, int dc, int sa, int da) { @@ -287,6 +344,9 @@ static SkPMColor colordodge_modeproc(SkPMColor src, SkPMColor dst) { int b = colordodge_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); return SkPackARGB32(a, r, g, b); } +static SkPM4f colordodge_proc4f(const SkPM4f& src, const SkPM4f& dst) { + return not_implemented_yet_proc4f(src, dst); +} // kColorBurn_Mode static inline int colorburn_byte(int sc, int dc, int sa, int da) { @@ -311,6 +371,9 @@ static SkPMColor colorburn_modeproc(SkPMColor src, SkPMColor dst) { int b = colorburn_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); return SkPackARGB32(a, r, g, b); } +static SkPM4f colorburn_proc4f(const SkPM4f& src, const SkPM4f& dst) { + return not_implemented_yet_proc4f(src, dst); +} // kHardLight_Mode static inline int hardlight_byte(int sc, int dc, int sa, int da) { @@ -331,6 +394,9 @@ static SkPMColor hardlight_modeproc(SkPMColor src, SkPMColor dst) { int b = hardlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); return SkPackARGB32(a, r, g, b); } +static SkPM4f hardlight_proc4f(const SkPM4f& src, const SkPM4f& dst) { + return not_implemented_yet_proc4f(src, dst); +} // returns 255 * sqrt(n/255) static U8CPU sqrt_unit_byte(U8CPU n) { @@ -361,6 +427,9 @@ static SkPMColor softlight_modeproc(SkPMColor src, SkPMColor dst) { int b = softlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); return SkPackARGB32(a, r, g, b); } +static SkPM4f softlight_proc4f(const SkPM4f& src, const SkPM4f& dst) { + return not_implemented_yet_proc4f(src, dst); +} // kDifference_Mode static inline int difference_byte(int sc, int dc, int sa, int da) { @@ -376,6 +445,9 @@ static SkPMColor difference_modeproc(SkPMColor src, SkPMColor dst) { int b = difference_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); return SkPackARGB32(a, r, g, b); } +static SkPM4f difference_proc4f(const SkPM4f& src, const SkPM4f& dst) { + return not_implemented_yet_proc4f(src, dst); +} // kExclusion_Mode static inline int exclusion_byte(int sc, int dc, int, int) { @@ -395,6 +467,9 @@ static SkPMColor exclusion_modeproc(SkPMColor src, SkPMColor dst) { int b = exclusion_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); return SkPackARGB32(a, r, g, b); } +static SkPM4f exclusion_proc4f(const SkPM4f& src, const SkPM4f& dst) { + return not_implemented_yet_proc4f(src, dst); +} // The CSS compositing spec introduces the following formulas: // (See https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#blendingnonseparable) @@ -510,6 +585,9 @@ static SkPMColor hue_modeproc(SkPMColor src, SkPMColor dst) { int b = blendfunc_nonsep_byte(sb, db, sa, da, Sb); return SkPackARGB32(a, r, g, b); } +static SkPM4f hue_proc4f(const SkPM4f& src, const SkPM4f& dst) { + return not_implemented_yet_proc4f(src, dst); +} // kSaturation_Mode // B(Cb, Cs) = SetLum(SetSat(Cb, Sat(Cs)), Lum(Cb)) @@ -544,6 +622,9 @@ static SkPMColor saturation_modeproc(SkPMColor src, SkPMColor dst) { int b = blendfunc_nonsep_byte(sb, db, sa, da, Db); return SkPackARGB32(a, r, g, b); } +static SkPM4f saturation_proc4f(const SkPM4f& src, const SkPM4f& dst) { + return not_implemented_yet_proc4f(src, dst); +} // kColor_Mode // B(Cb, Cs) = SetLum(Cs, Lum(Cb)) @@ -577,6 +658,9 @@ static SkPMColor color_modeproc(SkPMColor src, SkPMColor dst) { int b = blendfunc_nonsep_byte(sb, db, sa, da, Sb); return SkPackARGB32(a, r, g, b); } +static SkPM4f color_proc4f(const SkPM4f& src, const SkPM4f& dst) { + return not_implemented_yet_proc4f(src, dst); +} // kLuminosity_Mode // B(Cb, Cs) = SetLum(Cb, Lum(Cs)) @@ -610,38 +694,41 @@ static SkPMColor luminosity_modeproc(SkPMColor src, SkPMColor dst) { int b = blendfunc_nonsep_byte(sb, db, sa, da, Db); return SkPackARGB32(a, r, g, b); } +static SkPM4f luminosity_proc4f(const SkPM4f& src, const SkPM4f& dst) { + return not_implemented_yet_proc4f(src, dst); +} const ProcCoeff gProcCoeffs[] = { - { clear_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kZero_Coeff }, - { src_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kZero_Coeff }, - { dst_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kOne_Coeff }, - { srcover_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kISA_Coeff }, - { dstover_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kOne_Coeff }, - { srcin_modeproc, SkXfermode::kDA_Coeff, SkXfermode::kZero_Coeff }, - { dstin_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kSA_Coeff }, - { srcout_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kZero_Coeff }, - { dstout_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kISA_Coeff }, - { srcatop_modeproc, SkXfermode::kDA_Coeff, SkXfermode::kISA_Coeff }, - { dstatop_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kSA_Coeff }, - { xor_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kISA_Coeff }, + { clear_modeproc, proc_4f, SkXfermode::kZero_Coeff, SkXfermode::kZero_Coeff }, + { src_modeproc, proc_4f, SkXfermode::kOne_Coeff, SkXfermode::kZero_Coeff }, + { dst_modeproc, proc_4f, SkXfermode::kZero_Coeff, SkXfermode::kOne_Coeff }, + { srcover_modeproc, proc_4f, SkXfermode::kOne_Coeff, SkXfermode::kISA_Coeff }, + { dstover_modeproc, proc_4f, SkXfermode::kIDA_Coeff, SkXfermode::kOne_Coeff }, + { srcin_modeproc, proc_4f, SkXfermode::kDA_Coeff, SkXfermode::kZero_Coeff }, + { dstin_modeproc, proc_4f, SkXfermode::kZero_Coeff, SkXfermode::kSA_Coeff }, + { srcout_modeproc, proc_4f, SkXfermode::kIDA_Coeff, SkXfermode::kZero_Coeff }, + { dstout_modeproc, proc_4f, SkXfermode::kZero_Coeff, SkXfermode::kISA_Coeff }, + { srcatop_modeproc, proc_4f, SkXfermode::kDA_Coeff, SkXfermode::kISA_Coeff }, + { dstatop_modeproc, proc_4f, SkXfermode::kIDA_Coeff, SkXfermode::kSA_Coeff }, + { xor_modeproc, proc_4f, SkXfermode::kIDA_Coeff, SkXfermode::kISA_Coeff }, - { plus_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kOne_Coeff }, - { modulate_modeproc,SkXfermode::kZero_Coeff, SkXfermode::kSC_Coeff }, - { screen_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kISC_Coeff }, - { overlay_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, - { darken_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, - { lighten_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, - { colordodge_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, - { colorburn_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, - { hardlight_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, - { softlight_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, - { difference_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, - { exclusion_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, - { multiply_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, - { hue_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, - { saturation_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, - { color_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, - { luminosity_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { plus_modeproc, proc_4f, SkXfermode::kOne_Coeff, SkXfermode::kOne_Coeff }, + { modulate_modeproc, proc_4f, SkXfermode::kZero_Coeff, SkXfermode::kSC_Coeff }, + { screen_modeproc, proc_4f, SkXfermode::kOne_Coeff, SkXfermode::kISC_Coeff }, + { overlay_modeproc, overlay_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { darken_modeproc, darken_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { lighten_modeproc, lighten_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { colordodge_modeproc, colordodge_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { colorburn_modeproc, colorburn_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { hardlight_modeproc, hardlight_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { softlight_modeproc, softlight_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { difference_modeproc, difference_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { exclusion_modeproc, exclusion_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { multiply_modeproc, proc_4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { hue_modeproc, hue_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { saturation_modeproc, saturation_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { color_modeproc, color_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { luminosity_modeproc, luminosity_proc4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, }; /////////////////////////////////////////////////////////////////////////////// @@ -1006,6 +1093,14 @@ SkXfermodeProc SkXfermode::GetProc(Mode mode) { return proc; } +SkXfermodeProc4f SkXfermode::GetProc4f(Mode mode) { + SkXfermodeProc4f proc = nullptr; + if ((unsigned)mode < kModeCount) { + proc = gProcCoeffs[mode].fProc4f; + } + return proc; +} + bool SkXfermode::ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst) { SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount); diff --git a/src/core/SkXfermode_proccoeff.h b/src/core/SkXfermode_proccoeff.h index f86af2df01..264d65c2bc 100644 --- a/src/core/SkXfermode_proccoeff.h +++ b/src/core/SkXfermode_proccoeff.h @@ -14,6 +14,7 @@ struct ProcCoeff { SkXfermodeProc fProc; + SkXfermodeProc4f fProc4f; SkXfermode::Coeff fSC; SkXfermode::Coeff fDC; }; diff --git a/tests/SkColor4fTest.cpp b/tests/SkColor4fTest.cpp index 48a0c38286..b9dcd0d35e 100644 --- a/tests/SkColor4fTest.cpp +++ b/tests/SkColor4fTest.cpp @@ -168,9 +168,9 @@ DEF_TEST(Color4f_colorfilter, reporter) { SkColorFilter* (*fFact)(); bool fSupports4f; } recs[] = { - { make_mode_cf, false }, + { make_mode_cf, true }, { make_mx_cf, true }, - { make_compose_cf, false }, + { make_compose_cf, true }, }; // prepare the src @@ -197,3 +197,45 @@ DEF_TEST(Color4f_colorfilter, reporter) { } } } + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +typedef SkPM4f (*SkXfermodeProc4f)(const SkPM4f& src, const SkPM4f& dst); + +static bool compare_procs(SkXfermodeProc proc32, SkXfermodeProc4f proc4f) { + const float kTolerance = 1.0f / 255; + + const SkColor colors[] = { + 0, 0xFF000000, 0xFFFFFFFF, 0x80FF0000 + }; + + for (auto s32 : colors) { + SkPMColor s_pm32 = SkPreMultiplyColor(s32); + SkPM4f s_pm4f = SkColor4f::FromColor(s32).premul(); + for (auto d32 : colors) { + SkPMColor d_pm32 = SkPreMultiplyColor(d32); + SkPM4f d_pm4f = SkColor4f::FromColor(d32).premul(); + + SkPMColor r32 = proc32(s_pm32, d_pm32); + SkPM4f r4f = proc4f(s_pm4f, d_pm4f); + + SkPM4f r32_4f = SkPM4f::FromPMColor(r32); + if (!nearly_equal(r4f, r32_4f, kTolerance)) { + return false; + } + } + } + return true; +} + +// Check that our Proc and Proc4f return (nearly) the same results +// +DEF_TEST(Color4f_xfermode_proc4f, reporter) { + // TODO: extend xfermodes so that all cases can be tested. + // + for (int mode = SkXfermode::kClear_Mode; mode <= SkXfermode::kScreen_Mode; ++mode) { + SkXfermodeProc proc32 = SkXfermode::GetProc((SkXfermode::Mode)mode); + SkXfermodeProc4f proc4f = SkXfermode::GetProc4f((SkXfermode::Mode)mode); + REPORTER_ASSERT(reporter, compare_procs(proc32, proc4f)); + } +}