From e71253298871403d37855c2c9e242469d4ed17cc Mon Sep 17 00:00:00 2001 From: reed Date: Tue, 9 Feb 2016 11:59:24 -0800 Subject: [PATCH] implement more xfermodeproc4f and add GM BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1677293004 Review URL: https://codereview.chromium.org/1684623002 --- gm/xfermodes.cpp | 257 ++++++++++++++++++++-------- src/core/SkXfermode.cpp | 367 ++++++++++++++++++++++++++++++++-------- 2 files changed, 488 insertions(+), 136 deletions(-) diff --git a/gm/xfermodes.cpp b/gm/xfermodes.cpp index bc1bc7ff73..fa4461712d 100644 --- a/gm/xfermodes.cpp +++ b/gm/xfermodes.cpp @@ -10,7 +10,69 @@ #include "SkShader.h" #include "SkXfermode.h" -namespace skiagm { +enum SrcType { + //! A WxH image with a rectangle in the lower right. + kRectangleImage_SrcType = 0x01, + //! kRectangleImage_SrcType with an alpha of 34.5%. + kRectangleImageWithAlpha_SrcType = 0x02, + //! kRectnagleImageWithAlpha_SrcType scaled down by half. + kSmallRectangleImageWithAlpha_SrcType = 0x04, + //! kRectangleImage_SrcType drawn directly instead in an image. + kRectangle_SrcType = 0x08, + //! Two rectangles, first on the right half, second on the bottom half. + kQuarterClear_SrcType = 0x10, + //! kQuarterClear_SrcType in a layer. + kQuarterClearInLayer_SrcType = 0x20, + //! A W/2xH/2 transparent image. + kSmallTransparentImage_SrcType = 0x40, + //! kRectangleImage_SrcType drawn directly with a mask. + kRectangleWithMask_SrcType = 0x80, + + kAll_SrcType = 0xFF, //!< All the source types. + kBasic_SrcType = 0x03, //!< Just basic source types. +}; + +const struct { + SkXfermode::Mode fMode; + const char* fLabel; + int fSourceTypeMask; // The source types to use this + // mode with. See draw_mode for + // an explanation of each type. + // PDF has to play some tricks + // to support the base modes, + // test those more extensively. +} gModes[] = { + { SkXfermode::kClear_Mode, "Clear", kAll_SrcType }, + { SkXfermode::kSrc_Mode, "Src", kAll_SrcType }, + { SkXfermode::kDst_Mode, "Dst", kAll_SrcType }, + { SkXfermode::kSrcOver_Mode, "SrcOver", kAll_SrcType }, + { SkXfermode::kDstOver_Mode, "DstOver", kAll_SrcType }, + { SkXfermode::kSrcIn_Mode, "SrcIn", kAll_SrcType }, + { SkXfermode::kDstIn_Mode, "DstIn", kAll_SrcType }, + { SkXfermode::kSrcOut_Mode, "SrcOut", kAll_SrcType }, + { SkXfermode::kDstOut_Mode, "DstOut", kAll_SrcType }, + { SkXfermode::kSrcATop_Mode, "SrcATop", kAll_SrcType }, + { SkXfermode::kDstATop_Mode, "DstATop", kAll_SrcType }, + + { SkXfermode::kXor_Mode, "Xor", kBasic_SrcType }, + { SkXfermode::kPlus_Mode, "Plus", kBasic_SrcType }, + { SkXfermode::kModulate_Mode, "Modulate", kAll_SrcType }, + { SkXfermode::kScreen_Mode, "Screen", kBasic_SrcType }, + { SkXfermode::kOverlay_Mode, "Overlay", kBasic_SrcType }, + { SkXfermode::kDarken_Mode, "Darken", kBasic_SrcType }, + { SkXfermode::kLighten_Mode, "Lighten", kBasic_SrcType }, + { SkXfermode::kColorDodge_Mode, "ColorDodge", kBasic_SrcType }, + { SkXfermode::kColorBurn_Mode, "ColorBurn", kBasic_SrcType }, + { SkXfermode::kHardLight_Mode, "HardLight", kBasic_SrcType }, + { SkXfermode::kSoftLight_Mode, "SoftLight", kBasic_SrcType }, + { SkXfermode::kDifference_Mode, "Difference", kBasic_SrcType }, + { SkXfermode::kExclusion_Mode, "Exclusion", kBasic_SrcType }, + { SkXfermode::kMultiply_Mode, "Multiply", kAll_SrcType }, + { SkXfermode::kHue_Mode, "Hue", kBasic_SrcType }, + { SkXfermode::kSaturation_Mode, "Saturation", kBasic_SrcType }, + { SkXfermode::kColor_Mode, "Color", kBasic_SrcType }, + { SkXfermode::kLuminosity_Mode, "Luminosity", kBasic_SrcType }, +}; static void make_bitmaps(int w, int h, SkBitmap* src, SkBitmap* dst, SkBitmap* transparent) { @@ -47,29 +109,7 @@ static void make_bitmaps(int w, int h, SkBitmap* src, SkBitmap* dst, static uint16_t gData[] = { 0xFFFF, 0xCCCF, 0xCCCF, 0xFFFF }; -class XfermodesGM : public GM { - enum SrcType { - //! A WxH image with a rectangle in the lower right. - kRectangleImage_SrcType = 0x01, - //! kRectangleImage_SrcType with an alpha of 34.5%. - kRectangleImageWithAlpha_SrcType = 0x02, - //! kRectnagleImageWithAlpha_SrcType scaled down by half. - kSmallRectangleImageWithAlpha_SrcType = 0x04, - //! kRectangleImage_SrcType drawn directly instead in an image. - kRectangle_SrcType = 0x08, - //! Two rectangles, first on the right half, second on the bottom half. - kQuarterClear_SrcType = 0x10, - //! kQuarterClear_SrcType in a layer. - kQuarterClearInLayer_SrcType = 0x20, - //! A W/2xH/2 transparent image. - kSmallTransparentImage_SrcType = 0x40, - //! kRectangleImage_SrcType drawn directly with a mask. - kRectangleWithMask_SrcType = 0x80, - - kAll_SrcType = 0xFF, //!< All the source types. - kBasic_SrcType = 0x03, //!< Just basic source types. - }; - +class XfermodesGM : public skiagm::GM { SkBitmap fBG; SkBitmap fSrcB, fDstB, fTransparent; @@ -179,48 +219,6 @@ protected: void onDraw(SkCanvas* canvas) override { canvas->translate(SkIntToScalar(10), SkIntToScalar(20)); - const struct { - SkXfermode::Mode fMode; - const char* fLabel; - int fSourceTypeMask; // The source types to use this - // mode with. See draw_mode for - // an explanation of each type. - // PDF has to play some tricks - // to support the base modes, - // test those more extensively. - } gModes[] = { - { SkXfermode::kClear_Mode, "Clear", kAll_SrcType }, - { SkXfermode::kSrc_Mode, "Src", kAll_SrcType }, - { SkXfermode::kDst_Mode, "Dst", kAll_SrcType }, - { SkXfermode::kSrcOver_Mode, "SrcOver", kAll_SrcType }, - { SkXfermode::kDstOver_Mode, "DstOver", kAll_SrcType }, - { SkXfermode::kSrcIn_Mode, "SrcIn", kAll_SrcType }, - { SkXfermode::kDstIn_Mode, "DstIn", kAll_SrcType }, - { SkXfermode::kSrcOut_Mode, "SrcOut", kAll_SrcType }, - { SkXfermode::kDstOut_Mode, "DstOut", kAll_SrcType }, - { SkXfermode::kSrcATop_Mode, "SrcATop", kAll_SrcType }, - { SkXfermode::kDstATop_Mode, "DstATop", kAll_SrcType }, - - { SkXfermode::kXor_Mode, "Xor", kBasic_SrcType }, - { SkXfermode::kPlus_Mode, "Plus", kBasic_SrcType }, - { SkXfermode::kModulate_Mode, "Modulate", kAll_SrcType }, - { SkXfermode::kScreen_Mode, "Screen", kBasic_SrcType }, - { SkXfermode::kOverlay_Mode, "Overlay", kBasic_SrcType }, - { SkXfermode::kDarken_Mode, "Darken", kBasic_SrcType }, - { SkXfermode::kLighten_Mode, "Lighten", kBasic_SrcType }, - { SkXfermode::kColorDodge_Mode, "ColorDodge", kBasic_SrcType }, - { SkXfermode::kColorBurn_Mode, "ColorBurn", kBasic_SrcType }, - { SkXfermode::kHardLight_Mode, "HardLight", kBasic_SrcType }, - { SkXfermode::kSoftLight_Mode, "SoftLight", kBasic_SrcType }, - { SkXfermode::kDifference_Mode, "Difference", kBasic_SrcType }, - { SkXfermode::kExclusion_Mode, "Exclusion", kBasic_SrcType }, - { SkXfermode::kMultiply_Mode, "Multiply", kAll_SrcType }, - { SkXfermode::kHue_Mode, "Hue", kBasic_SrcType }, - { SkXfermode::kSaturation_Mode, "Saturation", kBasic_SrcType }, - { SkXfermode::kColor_Mode, "Color", kBasic_SrcType }, - { SkXfermode::kLuminosity_Mode, "Luminosity", kBasic_SrcType }, - }; - const SkScalar w = SkIntToScalar(W); const SkScalar h = SkIntToScalar(H); SkMatrix m; @@ -291,10 +289,129 @@ protected: private: typedef GM INHERITED; }; +DEF_GM( return new XfermodesGM; ) -////////////////////////////////////////////////////////////////////////////// - -static GM* MyFactory(void*) { return new XfermodesGM; } -static GMRegistry reg(MyFactory); +/////////////////////////////////////////////////////////////////////////////////////////////////// +#include "SkNx.h" +static SkPMColor apply_proc(SkPMColor src, SkPMColor dst, SkXfermodeProc4f proc, float src_alpha) { + SkPM4f src4 = SkPM4f::FromPMColor(src); + for (int i = 0; i < 4; ++i) { + src4.fVec[i] *= src_alpha; + } + SkPM4f dst4 = SkPM4f::FromPMColor(dst); + SkPM4f res4 = proc(src4, dst4); + SkPMColor res; + SkNx_cast(Sk4f::Load(res4.fVec) * Sk4f(255) + Sk4f(0.5f)).store(&res); + return res; +} + +static bool apply_mode(const SkPixmap& res, const SkPixmap& src, const SkPixmap& dst, + SkXfermode* xfer, float src_alpha) { + SkXfermode::Mode mode; + if (!xfer) { + mode = SkXfermode::kSrcOver_Mode; + } else if (!xfer->asMode(&mode)) { + return false; + } + SkXfermodeProc4f proc = SkXfermode::GetProc4f(mode); + if (!proc) { + return false; + } + + for (int y = 0; y < res.height(); ++y) { + for (int x = 0; x < res.width(); ++x) { + *res.writable_addr32(x, y) = apply_proc(*src.addr32(x, y), *dst.addr32(x, y), + proc, src_alpha); + } + } + return true; +} + +void draw_mode(const SkBitmap& srcB, const SkBitmap& dstB, + SkCanvas* canvas, SkXfermode* mode, SkScalar x, SkScalar y, float src_alpha) { + SkBitmap resB; + resB.allocN32Pixels(64, 64); + + SkPixmap srcPM, dstPM, resPM; + srcB.peekPixels(&srcPM); + dstB.peekPixels(&dstPM); + resB.peekPixels(&resPM); + + if (apply_mode(resPM, srcPM, dstPM, mode, src_alpha)) { + canvas->drawBitmap(resB, x, y, nullptr); + } +} + +DEF_SIMPLE_GM(xfermodes_proc4f, canvas, 1000, 1000) { + SkBitmap bg, srcB, dstB, transparent; + + bg.installPixels(SkImageInfo::Make(2, 2, kARGB_4444_SkColorType, kOpaque_SkAlphaType), + gData, 4); + make_bitmaps(64, 64, &dstB, &srcB, &transparent); + + canvas->translate(10, 20); + + const SkScalar w = 64; + const SkScalar h = 64; + SkMatrix m = SkMatrix::MakeScale(6, 6); + SkShader* s = SkShader::CreateBitmapShader(bg, + SkShader::kRepeat_TileMode, + SkShader::kRepeat_TileMode, + &m); + + SkPaint labelP; + labelP.setAntiAlias(true); + sk_tool_utils::set_portable_typeface(&labelP); + labelP.setTextAlign(SkPaint::kCenter_Align); + + const int W = 5; + + const float alphas[] = { 1.0f, 0.5f }; + + for (auto alpha : alphas) { + SkScalar x0 = 0; + SkScalar y0 = 0; + SkScalar x = x0, y = y0; + for (size_t i = 0; i < SK_ARRAY_COUNT(gModes); i++) { + SkXfermode* mode = SkXfermode::Create(gModes[i].fMode); + SkAutoUnref aur(mode); + SkRect r; + r.set(x, y, x+w, y+h); + + SkPaint p; + p.setStyle(SkPaint::kFill_Style); + p.setShader(s); + canvas->drawRect(r, p); + + draw_mode(srcB, dstB, canvas, mode, r.fLeft, r.fTop, alpha); + + r.inset(-SK_ScalarHalf, -SK_ScalarHalf); + p.setStyle(SkPaint::kStroke_Style); + p.setShader(nullptr); + canvas->drawRect(r, p); + + #if 1 + canvas->drawText(gModes[i].fLabel, strlen(gModes[i].fLabel), + x + w/2, y - labelP.getTextSize()/2, labelP); + #endif + x += w + SkIntToScalar(10); + if ((i % W) == W - 1) { + x = x0; + y += h + SkIntToScalar(30); + } + } + if (y < 320) { + if (x > x0) { + y += h + SkIntToScalar(30); + } + y0 = y; + } else { + x0 += SkIntToScalar(400); + y0 = 0; + } + + canvas->translate(400, 0); + } + s->unref(); } diff --git a/src/core/SkXfermode.cpp b/src/core/SkXfermode.cpp index 2f29f1a63d..22881c6cfe 100644 --- a/src/core/SkXfermode.cpp +++ b/src/core/SkXfermode.cpp @@ -53,6 +53,21 @@ 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 color_alpha(const Sk4f& color, float newAlpha) { + return Sk4f(color.kth<0>(), color.kth<1>(), color.kth<2>(), newAlpha); +} +static Sk4f color_alpha(const Sk4f& color, const Sk4f& newAlpha) { + return color_alpha(color, newAlpha.kth<3>()); +} + +static Sk4f set_argb(float a, float r, float g, float b) { + if (0 == SkPM4f::R) { + return Sk4f(r, g, b, a); + } else { + return Sk4f(b, g, r, a); + } +} + 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; } @@ -73,29 +88,264 @@ 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 overlay_4f(const Sk4f& s, const Sk4f& d) { + Sk4f sa = alpha(s); + Sk4f da = alpha(d); + Sk4f two = Sk4f(2); + Sk4f rc = (two * d <= da).thenElse(two * s * d, + sa * da - two * (da - d) * (sa - s)); + return s + d - s * da + color_alpha(rc - d * sa, 0); } -static Sk4f as_4f(const SkPM4f& pm4) { - return Sk4f::Load(pm4.fVec); +static Sk4f hardlight_4f(const Sk4f& s, const Sk4f& d) { + return overlay_4f(d, s); } -template -SkPM4f proc_4f(const SkPM4f& src, const SkPM4f& dst) { - return as_pm4f(blend(as_4f(src), as_4f(dst))); +static Sk4f darken_4f(const Sk4f& s, const Sk4f& d) { + Sk4f sa = alpha(s); + Sk4f da = alpha(d); + return s + d - Sk4f::Max(s * da, d * sa); +} + +static Sk4f lighten_4f(const Sk4f& s, const Sk4f& d) { + Sk4f sa = alpha(s); + Sk4f da = alpha(d); + return s + d - Sk4f::Min(s * da, d * sa); +} + +static Sk4f colordodge_4f(const Sk4f& s, const Sk4f& d) { + Sk4f sa = alpha(s); + Sk4f da = alpha(d); + Sk4f isa = Sk4f(1) - sa; + Sk4f ida = Sk4f(1) - da; + + Sk4f srcover = s + d * isa; + Sk4f dstover = d + s * ida; + Sk4f otherwise = sa * Sk4f::Min(da, (d * sa) / (sa - s)) + s * ida + d * isa; + + // Order matters here, preferring d==0 over s==sa. + auto colors = (d == Sk4f(0)).thenElse(dstover, + (s == sa).thenElse(srcover, + otherwise)); + return color_alpha(colors, srcover); +} + +static Sk4f colorburn_4f(const Sk4f& s, const Sk4f& d) { + Sk4f sa = alpha(s); + Sk4f da = alpha(d); + Sk4f isa = Sk4f(1) - sa; + Sk4f ida = Sk4f(1) - da; + + Sk4f srcover = s + d * isa; + Sk4f dstover = d + s * ida; + Sk4f otherwise = sa * (da - Sk4f::Min(da, (da - d) * sa / s)) + s * ida + d * isa; + + // Order matters here, preferring d==da over s==0. + auto colors = (d == da).thenElse(dstover, + (s == Sk4f(0)).thenElse(srcover, + otherwise)); + return color_alpha(colors, srcover); +} + +static Sk4f softlight_4f(const Sk4f& s, const Sk4f& d) { + Sk4f sa = alpha(s); + Sk4f da = alpha(d); + Sk4f isa = Sk4f(1) - sa; + Sk4f ida = Sk4f(1) - da; + + // Some common terms. + Sk4f m = (da > Sk4f(0)).thenElse(d / da, Sk4f(0)); + Sk4f s2 = Sk4f(2) * s; + Sk4f m4 = Sk4f(4) * m; + + // The logic forks three ways: + // 1. dark src? + // 2. light src, dark dst? + // 3. light src, light dst? + Sk4f darkSrc = d * (sa + (s2 - sa) * (Sk4f(1) - m)); // Used in case 1. + Sk4f darkDst = (m4 * m4 + m4) * (m - Sk4f(1)) + Sk4f(7) * m; // Used in case 2. + Sk4f liteDst = m.sqrt() - m; // Used in case 3. + Sk4f liteSrc = d * sa + da * (s2 - sa) * (Sk4f(4) * d <= da).thenElse(darkDst, + liteDst); // Case 2 or 3? + + return color_alpha(s * ida + d * isa + (s2 <= sa).thenElse(darkSrc, liteSrc), // Case 1 or 2/3? + s + d * isa); +} + +static Sk4f difference_4f(const Sk4f& s, const Sk4f& d) { + Sk4f min = Sk4f::Min(s * alpha(d), d * alpha(s)); + return s + d - min - color_alpha(min, 0); +} + +static Sk4f exclusion_4f(const Sk4f& s, const Sk4f& d) { + Sk4f product = s * d; + return s + d - product - color_alpha(product, 0); +} + +//////////////////////////////////////////////////// + +// The CSS compositing spec introduces the following formulas: +// (See https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#blendingnonseparable) +// SkComputeLuminance is similar to this formula but it uses the new definition from Rec. 709 +// while PDF and CG uses the one from Rec. Rec. 601 +// See http://www.glennchan.info/articles/technical/hd-versus-sd-color-space/hd-versus-sd-color-space.htm +static inline float Lum(float r, float g, float b) { + return r * 0.2126f + g * 0.7152f + b * 0.0722f; +} + +static inline float max(float a, float b, float c) { + return SkTMax(a, SkTMax(b, c)); +} + +static inline float min(float a, float b, float c) { + return SkTMin(a, SkTMin(b, c)); +} + +static inline float Sat(float r, float g, float b) { + return max(r, g, b) - min(r, g, b); +} + +static inline void setSaturationComponents(float* Cmin, float* Cmid, float* Cmax, float s) { + if(*Cmax > *Cmin) { + *Cmid = (*Cmid - *Cmin) * s / (*Cmax - *Cmin); + *Cmax = s; + } else { + *Cmax = 0; + *Cmid = 0; + } + *Cmin = 0; +} + +static inline void SetSat(float* r, float* g, float* b, float s) { + if(*r <= *g) { + if(*g <= *b) { + setSaturationComponents(r, g, b, s); + } else if(*r <= *b) { + setSaturationComponents(r, b, g, s); + } else { + setSaturationComponents(b, r, g, s); + } + } else if(*r <= *b) { + setSaturationComponents(g, r, b, s); + } else if(*g <= *b) { + setSaturationComponents(g, b, r, s); + } else { + setSaturationComponents(b, g, r, s); + } +} + +static inline void clipColor(float* r, float* g, float* b, float a) { + float L = Lum(*r, *g, *b); + float n = min(*r, *g, *b); + float x = max(*r, *g, *b); + float denom; + if ((n < 0) && (denom = L - n)) { // Compute denom and make sure it's non zero + float scale = L / denom; + *r = L + (*r - L) * scale; + *g = L + (*g - L) * scale; + *b = L + (*b - L) * scale; + } + + if ((x > a) && (denom = x - L)) { // Compute denom and make sure it's non zero + float scale = (a - L) / denom; + *r = L + (*r - L) * scale; + *g = L + (*g - L) * scale; + *b = L + (*b - L) * scale; + } +} + +static inline void SetLum(float* r, float* g, float* b, float a, float l) { + float d = l - Lum(*r, *g, *b); + *r += d; + *g += d; + *b += d; + clipColor(r, g, b, a); +} + +static Sk4f hue_4f(const Sk4f& s, const Sk4f& d) { + float sa = s.kth(); + float sr = s.kth(); + float sg = s.kth(); + float sb = s.kth(); + + float da = d.kth(); + float dr = d.kth(); + float dg = d.kth(); + float db = d.kth(); + + float Sr = sr; + float Sg = sg; + float Sb = sb; + SetSat(&Sr, &Sg, &Sb, Sat(dr, dg, db) * sa); + SetLum(&Sr, &Sg, &Sb, sa * da, Lum(dr, dg, db) * sa); + + return color_alpha(s * inv_alpha(d) + d * inv_alpha(s) + set_argb(0, Sr, Sg, Sb), + sa + da - sa * da); +} + +static Sk4f saturation_4f(const Sk4f& s, const Sk4f& d) { + float sa = s.kth(); + float sr = s.kth(); + float sg = s.kth(); + float sb = s.kth(); + + float da = d.kth(); + float dr = d.kth(); + float dg = d.kth(); + float db = d.kth(); + + float Dr = dr; + float Dg = dg; + float Db = db; + SetSat(&Dr, &Dg, &Db, Sat(sr, sg, sb) * da); + SetLum(&Dr, &Dg, &Db, sa * da, Lum(dr, dg, db) * sa); + + return color_alpha(s * inv_alpha(d) + d * inv_alpha(s) + set_argb(0, Dr, Dg, Db), + sa + da - sa * da); +} + +static Sk4f color_4f(const Sk4f& s, const Sk4f& d) { + float sa = s.kth(); + float sr = s.kth(); + float sg = s.kth(); + float sb = s.kth(); + + float da = d.kth(); + float dr = d.kth(); + float dg = d.kth(); + float db = d.kth(); + + float Sr = sr; + float Sg = sg; + float Sb = sb; + SetLum(&Sr, &Sg, &Sb, sa * da, Lum(dr, dg, db) * sa); + + return color_alpha(s * inv_alpha(d) + d * inv_alpha(s) + set_argb(0, Sr, Sg, Sb), + sa + da - sa * da); +} + +static Sk4f luminosity_4f(const Sk4f& s, const Sk4f& d) { + float sa = s.kth(); + float sr = s.kth(); + float sg = s.kth(); + float sb = s.kth(); + + float da = d.kth(); + float dr = d.kth(); + float dg = d.kth(); + float db = d.kth(); + + float Dr = dr; + float Dg = dg; + float Db = db; + SetLum(&Dr, &Dg, &Db, sa * da, Lum(sr, sg, sb) * da); + + return color_alpha(s * inv_alpha(d) + d * inv_alpha(s) + set_argb(0, Dr, Dg, Db), + sa + da - sa * da); } /////////////////////////////////////////////////////////////////////////////// -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) { return 0; @@ -267,9 +517,6 @@ 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) { @@ -292,9 +539,6 @@ 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) { @@ -317,9 +561,6 @@ 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) { @@ -344,9 +585,6 @@ 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) { @@ -371,9 +609,6 @@ 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) { @@ -394,9 +629,6 @@ 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) { @@ -427,9 +659,6 @@ 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) { @@ -445,9 +674,6 @@ 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) { @@ -467,9 +693,6 @@ 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) @@ -585,9 +808,6 @@ 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)) @@ -622,9 +842,6 @@ 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)) @@ -658,9 +875,6 @@ 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)) @@ -694,8 +908,29 @@ 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); + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +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& s, const SkPM4f& d) { + SkPM4f r = as_pm4f(blend(as_4f(s), as_4f(d))); +#ifdef SK_DEBUG + const float min = 0; + const float max = 1; + for (int i = 0; i < 4; ++i) { + SkASSERT(r.fVec[i] >= min && r.fVec[i] <= max); + } +#endif + return r; } const ProcCoeff gProcCoeffs[] = { @@ -715,20 +950,20 @@ const ProcCoeff gProcCoeffs[] = { { 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 }, + { overlay_modeproc, proc_4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { darken_modeproc, proc_4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { lighten_modeproc, proc_4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { colordodge_modeproc, proc_4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { colorburn_modeproc, proc_4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { hardlight_modeproc, proc_4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { softlight_modeproc, proc_4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { difference_modeproc, proc_4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { exclusion_modeproc, proc_4f, 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 }, + { hue_modeproc, proc_4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { saturation_modeproc, proc_4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { color_modeproc, proc_4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, + { luminosity_modeproc, proc_4f, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, }; ///////////////////////////////////////////////////////////////////////////////