diff options
author | Mike Klein <mtklein@chromium.org> | 2017-06-13 22:01:22 +0000 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-06-13 22:01:29 +0000 |
commit | 4f8c695736c8ae4fed2190a8e1301a4f4a979898 (patch) | |
tree | cd6d227170579292b755470dfd3f24cc5a54e823 /src/core/SkXfermode.cpp | |
parent | 9e99b3de69b29f6a6511ef7b90e24442478be1e2 (diff) |
Revert "use pipeline for non-opt xfermodes"
This reverts commit e93cf97175d348ce1400762bdd8d9acabdd29766.
Reason for revert: unblock Chrome roll
Original change's description:
> use pipeline for non-opt xfermodes
>
> Produces slightly different results for Hue, Saturation, Color, Luminosity,
> seemingly around the aa edging.
>
> Bug: skia:
> Change-Id: I6364818c9788863e5fad6d14cad4797d073dbea3
> Reviewed-on: https://skia-review.googlesource.com/19554
> Reviewed-by: Mike Klein <mtklein@google.com>
> Commit-Queue: Mike Reed <reed@google.com>
TBR=mtklein@google.com,fmalita@chromium.org,reed@google.com
Change-Id: Ib85a51753d21ce778fa5cfedd6b7d1b5b2b87096
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: skia:
Reviewed-on: https://skia-review.googlesource.com/19745
Reviewed-by: Mike Klein <mtklein@chromium.org>
Commit-Queue: Mike Klein <mtklein@chromium.org>
Diffstat (limited to 'src/core/SkXfermode.cpp')
-rw-r--r-- | src/core/SkXfermode.cpp | 696 |
1 files changed, 662 insertions, 34 deletions
diff --git a/src/core/SkXfermode.cpp b/src/core/SkXfermode.cpp index 54ac5891a3..0dd9e87cdf 100644 --- a/src/core/SkXfermode.cpp +++ b/src/core/SkXfermode.cpp @@ -6,16 +6,16 @@ */ #include "SkBlendModePriv.h" +#include "SkXfermode_proccoeff.h" #include "SkColorPriv.h" #include "SkMathPriv.h" #include "SkOnce.h" #include "SkOpts.h" -#include "SkPM4f.h" #include "SkRasterPipeline.h" #include "SkReadBuffer.h" #include "SkString.h" #include "SkWriteBuffer.h" -#include "SkXfermodePriv.h" +#include "SkPM4f.h" #if SK_SUPPORT_GPU #include "GrFragmentProcessor.h" @@ -24,50 +24,668 @@ #include "effects/GrXfermodeFragmentProcessor.h" #endif -/////////////////////////////////////////////////////////////////////////////////////////////////// +#define SkAlphaMulAlpha(a, b) SkMulDiv255Round(a, b) -class SkProcCoeffXfermode : public SkXfermode { -public: - SkProcCoeffXfermode(SkBlendMode mode) : fMode(mode) {} +static inline unsigned saturated_add(unsigned a, unsigned b) { + SkASSERT(a <= 255); + SkASSERT(b <= 255); + unsigned sum = a + b; + if (sum > 255) { + sum = 255; + } + return sum; +} - void xfer32(SkPMColor dst[], const SkPMColor src[], int count, - const SkAlpha aa[]) const override { - SkASSERT(dst && src && count >= 0); +static inline int clamp_signed_byte(int n) { + if (n < 0) { + n = 0; + } else if (n > 255) { + n = 255; + } + return n; +} - bool needs_swap = (kN32_SkColorType == kBGRA_8888_SkColorType) && - SkBlendMode_CaresAboutRBOrder(fMode); +static inline int clamp_div255round(int prod) { + if (prod <= 0) { + return 0; + } else if (prod >= 255*255) { + return 255; + } else { + return SkDiv255Round(prod); + } +} - SkRasterPipeline_<256> p; +/////////////////////////////////////////////////////////////////////////////// - p.append(SkRasterPipeline::load_8888, &dst); - if (needs_swap) { - p.append(SkRasterPipeline::swap_rb); - } - p.append(SkRasterPipeline::move_src_dst); - p.append(SkRasterPipeline::load_8888, &src); - if (needs_swap) { - p.append(SkRasterPipeline::swap_rb); - } +// kClear_Mode, //!< [0, 0] +static SkPMColor clear_modeproc(SkPMColor src, SkPMColor dst) { + return 0; +} - SkBlendMode_AppendStagesNoClamp(fMode, &p); - if (aa) { - p.append(SkRasterPipeline::lerp_u8, &aa); - } - SkBlendMode_AppendClampIfNeeded(fMode, &p); +// kSrc_Mode, //!< [Sa, Sc] +static SkPMColor src_modeproc(SkPMColor src, SkPMColor dst) { + return src; +} + +// kDst_Mode, //!< [Da, Dc] +static SkPMColor dst_modeproc(SkPMColor src, SkPMColor dst) { + return dst; +} + +// kSrcOver_Mode, //!< [Sa + Da - Sa*Da, Sc + (1 - Sa)*Dc] +static SkPMColor srcover_modeproc(SkPMColor src, SkPMColor dst) { +#if 0 + // this is the old, more-correct way, but it doesn't guarantee that dst==255 + // will always stay opaque + return src + SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src))); +#else + // this is slightly faster, but more importantly guarantees that dst==255 + // will always stay opaque + return src + SkAlphaMulQ(dst, 256 - SkGetPackedA32(src)); +#endif +} - if (needs_swap) { - p.append(SkRasterPipeline::swap_rb); +// kDstOver_Mode, //!< [Sa + Da - Sa*Da, Dc + (1 - Da)*Sc] +static SkPMColor dstover_modeproc(SkPMColor src, SkPMColor dst) { + // this is the reverse of srcover, just flipping src and dst + // see srcover's comment about the 256 for opaqueness guarantees + return dst + SkAlphaMulQ(src, 256 - SkGetPackedA32(dst)); +} + +// kSrcIn_Mode, //!< [Sa * Da, Sc * Da] +static SkPMColor srcin_modeproc(SkPMColor src, SkPMColor dst) { + return SkAlphaMulQ(src, SkAlpha255To256(SkGetPackedA32(dst))); +} + +// kDstIn_Mode, //!< [Sa * Da, Sa * Dc] +static SkPMColor dstin_modeproc(SkPMColor src, SkPMColor dst) { + return SkAlphaMulQ(dst, SkAlpha255To256(SkGetPackedA32(src))); +} + +// kSrcOut_Mode, //!< [Sa * (1 - Da), Sc * (1 - Da)] +static SkPMColor srcout_modeproc(SkPMColor src, SkPMColor dst) { + return SkAlphaMulQ(src, SkAlpha255To256(255 - SkGetPackedA32(dst))); +} + +// kDstOut_Mode, //!< [Da * (1 - Sa), Dc * (1 - Sa)] +static SkPMColor dstout_modeproc(SkPMColor src, SkPMColor dst) { + return SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src))); +} + +// kSrcATop_Mode, //!< [Da, Sc * Da + (1 - Sa) * Dc] +static SkPMColor srcatop_modeproc(SkPMColor src, SkPMColor dst) { + unsigned sa = SkGetPackedA32(src); + unsigned da = SkGetPackedA32(dst); + unsigned isa = 255 - sa; + + return SkPackARGB32(da, + SkAlphaMulAlpha(da, SkGetPackedR32(src)) + + SkAlphaMulAlpha(isa, SkGetPackedR32(dst)), + SkAlphaMulAlpha(da, SkGetPackedG32(src)) + + SkAlphaMulAlpha(isa, SkGetPackedG32(dst)), + SkAlphaMulAlpha(da, SkGetPackedB32(src)) + + SkAlphaMulAlpha(isa, SkGetPackedB32(dst))); +} + +// kDstATop_Mode, //!< [Sa, Sa * Dc + Sc * (1 - Da)] +static SkPMColor dstatop_modeproc(SkPMColor src, SkPMColor dst) { + unsigned sa = SkGetPackedA32(src); + unsigned da = SkGetPackedA32(dst); + unsigned ida = 255 - da; + + return SkPackARGB32(sa, + SkAlphaMulAlpha(ida, SkGetPackedR32(src)) + + SkAlphaMulAlpha(sa, SkGetPackedR32(dst)), + SkAlphaMulAlpha(ida, SkGetPackedG32(src)) + + SkAlphaMulAlpha(sa, SkGetPackedG32(dst)), + SkAlphaMulAlpha(ida, SkGetPackedB32(src)) + + SkAlphaMulAlpha(sa, SkGetPackedB32(dst))); +} + +// kXor_Mode [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc] +static SkPMColor xor_modeproc(SkPMColor src, SkPMColor dst) { + unsigned sa = SkGetPackedA32(src); + unsigned da = SkGetPackedA32(dst); + unsigned isa = 255 - sa; + unsigned ida = 255 - da; + + return SkPackARGB32(sa + da - (SkAlphaMulAlpha(sa, da) << 1), + SkAlphaMulAlpha(ida, SkGetPackedR32(src)) + + SkAlphaMulAlpha(isa, SkGetPackedR32(dst)), + SkAlphaMulAlpha(ida, SkGetPackedG32(src)) + + SkAlphaMulAlpha(isa, SkGetPackedG32(dst)), + SkAlphaMulAlpha(ida, SkGetPackedB32(src)) + + SkAlphaMulAlpha(isa, SkGetPackedB32(dst))); +} + +/////////////////////////////////////////////////////////////////////////////// + +// kPlus_Mode +static SkPMColor plus_modeproc(SkPMColor src, SkPMColor dst) { + unsigned b = saturated_add(SkGetPackedB32(src), SkGetPackedB32(dst)); + unsigned g = saturated_add(SkGetPackedG32(src), SkGetPackedG32(dst)); + unsigned r = saturated_add(SkGetPackedR32(src), SkGetPackedR32(dst)); + unsigned a = saturated_add(SkGetPackedA32(src), SkGetPackedA32(dst)); + return SkPackARGB32(a, r, g, b); +} + +// kModulate_Mode +static SkPMColor modulate_modeproc(SkPMColor src, SkPMColor dst) { + int a = SkAlphaMulAlpha(SkGetPackedA32(src), SkGetPackedA32(dst)); + int r = SkAlphaMulAlpha(SkGetPackedR32(src), SkGetPackedR32(dst)); + int g = SkAlphaMulAlpha(SkGetPackedG32(src), SkGetPackedG32(dst)); + int b = SkAlphaMulAlpha(SkGetPackedB32(src), SkGetPackedB32(dst)); + return SkPackARGB32(a, r, g, b); +} + +static inline int srcover_byte(int a, int b) { + return a + b - SkAlphaMulAlpha(a, b); +} + +// kMultiply_Mode +// B(Cb, Cs) = Cb x Cs +// multiply uses its own version of blendfunc_byte because sa and da are not needed +static int blendfunc_multiply_byte(int sc, int dc, int sa, int da) { + return clamp_div255round(sc * (255 - da) + dc * (255 - sa) + sc * dc); +} + +static SkPMColor multiply_modeproc(SkPMColor src, SkPMColor dst) { + int sa = SkGetPackedA32(src); + int da = SkGetPackedA32(dst); + int a = srcover_byte(sa, da); + int r = blendfunc_multiply_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da); + int g = blendfunc_multiply_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da); + int b = blendfunc_multiply_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); + return SkPackARGB32(a, r, g, b); +} + +// kScreen_Mode +static SkPMColor screen_modeproc(SkPMColor src, SkPMColor dst) { + int a = srcover_byte(SkGetPackedA32(src), SkGetPackedA32(dst)); + int r = srcover_byte(SkGetPackedR32(src), SkGetPackedR32(dst)); + int g = srcover_byte(SkGetPackedG32(src), SkGetPackedG32(dst)); + int b = srcover_byte(SkGetPackedB32(src), SkGetPackedB32(dst)); + return SkPackARGB32(a, r, g, b); +} + +// kOverlay_Mode +static inline int overlay_byte(int sc, int dc, int sa, int da) { + int tmp = sc * (255 - da) + dc * (255 - sa); + int rc; + if (2 * dc <= da) { + rc = 2 * sc * dc; + } else { + rc = sa * da - 2 * (da - dc) * (sa - sc); + } + return clamp_div255round(rc + tmp); +} +static SkPMColor overlay_modeproc(SkPMColor src, SkPMColor dst) { + int sa = SkGetPackedA32(src); + int da = SkGetPackedA32(dst); + int a = srcover_byte(sa, da); + int r = overlay_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da); + int g = overlay_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da); + int b = overlay_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); + return SkPackARGB32(a, r, g, b); +} + +// kDarken_Mode +static inline int darken_byte(int sc, int dc, int sa, int da) { + int sd = sc * da; + int ds = dc * sa; + if (sd < ds) { + // srcover + return sc + dc - SkDiv255Round(ds); + } else { + // dstover + return dc + sc - SkDiv255Round(sd); + } +} +static SkPMColor darken_modeproc(SkPMColor src, SkPMColor dst) { + int sa = SkGetPackedA32(src); + int da = SkGetPackedA32(dst); + int a = srcover_byte(sa, da); + int r = darken_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da); + int g = darken_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da); + int b = darken_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); + return SkPackARGB32(a, r, g, b); +} + +// kLighten_Mode +static inline int lighten_byte(int sc, int dc, int sa, int da) { + int sd = sc * da; + int ds = dc * sa; + if (sd > ds) { + // srcover + return sc + dc - SkDiv255Round(ds); + } else { + // dstover + return dc + sc - SkDiv255Round(sd); + } +} +static SkPMColor lighten_modeproc(SkPMColor src, SkPMColor dst) { + int sa = SkGetPackedA32(src); + int da = SkGetPackedA32(dst); + int a = srcover_byte(sa, da); + int r = lighten_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da); + int g = lighten_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da); + int b = lighten_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); + return SkPackARGB32(a, r, g, b); +} + +// kColorDodge_Mode +static inline int colordodge_byte(int sc, int dc, int sa, int da) { + int diff = sa - sc; + int rc; + if (0 == dc) { + return SkAlphaMulAlpha(sc, 255 - da); + } else if (0 == diff) { + rc = sa * da + sc * (255 - da) + dc * (255 - sa); + } else { + diff = dc * sa / diff; + rc = sa * ((da < diff) ? da : diff) + sc * (255 - da) + dc * (255 - sa); + } + return clamp_div255round(rc); +} +static SkPMColor colordodge_modeproc(SkPMColor src, SkPMColor dst) { + int sa = SkGetPackedA32(src); + int da = SkGetPackedA32(dst); + int a = srcover_byte(sa, da); + int r = colordodge_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da); + int g = colordodge_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da); + int b = colordodge_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); + return SkPackARGB32(a, r, g, b); +} + +// kColorBurn_Mode +static inline int colorburn_byte(int sc, int dc, int sa, int da) { + int rc; + if (dc == da) { + rc = sa * da + sc * (255 - da) + dc * (255 - sa); + } else if (0 == sc) { + return SkAlphaMulAlpha(dc, 255 - sa); + } else { + int tmp = (da - dc) * sa / sc; + rc = sa * (da - ((da < tmp) ? da : tmp)) + + sc * (255 - da) + dc * (255 - sa); + } + return clamp_div255round(rc); +} +static SkPMColor colorburn_modeproc(SkPMColor src, SkPMColor dst) { + int sa = SkGetPackedA32(src); + int da = SkGetPackedA32(dst); + int a = srcover_byte(sa, da); + int r = colorburn_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da); + int g = colorburn_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da); + int b = colorburn_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); + return SkPackARGB32(a, r, g, b); +} + +// kHardLight_Mode +static inline int hardlight_byte(int sc, int dc, int sa, int da) { + int rc; + if (2 * sc <= sa) { + rc = 2 * sc * dc; + } else { + rc = sa * da - 2 * (da - dc) * (sa - sc); + } + return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa)); +} +static SkPMColor hardlight_modeproc(SkPMColor src, SkPMColor dst) { + int sa = SkGetPackedA32(src); + int da = SkGetPackedA32(dst); + int a = srcover_byte(sa, da); + int r = hardlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da); + int g = hardlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da); + int b = hardlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); + return SkPackARGB32(a, r, g, b); +} + +// returns 255 * sqrt(n/255) +static U8CPU sqrt_unit_byte(U8CPU n) { + return SkSqrtBits(n, 15+4); +} + +// kSoftLight_Mode +static inline int softlight_byte(int sc, int dc, int sa, int da) { + int m = da ? dc * 256 / da : 0; + int rc; + if (2 * sc <= sa) { + rc = dc * (sa + ((2 * sc - sa) * (256 - m) >> 8)); + } else if (4 * dc <= da) { + int tmp = (4 * m * (4 * m + 256) * (m - 256) >> 16) + 7 * m; + rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8); + } else { + int tmp = sqrt_unit_byte(m) - m; + rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8); + } + return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa)); +} +static SkPMColor softlight_modeproc(SkPMColor src, SkPMColor dst) { + int sa = SkGetPackedA32(src); + int da = SkGetPackedA32(dst); + int a = srcover_byte(sa, da); + int r = softlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da); + int g = softlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da); + int b = softlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); + return SkPackARGB32(a, r, g, b); +} + +// kDifference_Mode +static inline int difference_byte(int sc, int dc, int sa, int da) { + int tmp = SkMin32(sc * da, dc * sa); + return clamp_signed_byte(sc + dc - 2 * SkDiv255Round(tmp)); +} +static SkPMColor difference_modeproc(SkPMColor src, SkPMColor dst) { + int sa = SkGetPackedA32(src); + int da = SkGetPackedA32(dst); + int a = srcover_byte(sa, da); + int r = difference_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da); + int g = difference_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da); + int b = difference_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); + return SkPackARGB32(a, r, g, b); +} + +// kExclusion_Mode +static inline int exclusion_byte(int sc, int dc, int, int) { + // this equations is wacky, wait for SVG to confirm it + //int r = sc * da + dc * sa - 2 * sc * dc + sc * (255 - da) + dc * (255 - sa); + + // The above equation can be simplified as follows + int r = 255*(sc + dc) - 2 * sc * dc; + return clamp_div255round(r); +} +static SkPMColor exclusion_modeproc(SkPMColor src, SkPMColor dst) { + int sa = SkGetPackedA32(src); + int da = SkGetPackedA32(dst); + int a = srcover_byte(sa, da); + int r = exclusion_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da); + int g = exclusion_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da); + int b = exclusion_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); + return SkPackARGB32(a, r, g, b); +} + +// 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 int Lum(int r, int g, int b) +{ + return SkDiv255Round(r * 77 + g * 150 + b * 28); +} + +static inline int min2(int a, int b) { return a < b ? a : b; } +static inline int max2(int a, int b) { return a > b ? a : b; } +#define minimum(a, b, c) min2(min2(a, b), c) +#define maximum(a, b, c) max2(max2(a, b), c) + +static inline int Sat(int r, int g, int b) { + return maximum(r, g, b) - minimum(r, g, b); +} + +static inline void setSaturationComponents(int* Cmin, int* Cmid, int* Cmax, int s) { + if(*Cmax > *Cmin) { + *Cmid = SkMulDiv(*Cmid - *Cmin, s, *Cmax - *Cmin); + *Cmax = s; + } else { + *Cmax = 0; + *Cmid = 0; + } + + *Cmin = 0; +} + +static inline void SetSat(int* r, int* g, int* b, int 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); } - p.append(SkRasterPipeline::store_8888, &dst); - p.run(0, 0, count); + } 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(int* r, int* g, int* b, int a) { + int L = Lum(*r, *g, *b); + int n = minimum(*r, *g, *b); + int x = maximum(*r, *g, *b); + int denom; + if ((n < 0) && (denom = L - n)) { // Compute denom and make sure it's non zero + *r = L + SkMulDiv(*r - L, L, denom); + *g = L + SkMulDiv(*g - L, L, denom); + *b = L + SkMulDiv(*b - L, L, denom); + } + + if ((x > a) && (denom = x - L)) { // Compute denom and make sure it's non zero + int numer = a - L; + *r = L + SkMulDiv(*r - L, numer, denom); + *g = L + SkMulDiv(*g - L, numer, denom); + *b = L + SkMulDiv(*b - L, numer, denom); + } +} + +static inline void SetLum(int* r, int* g, int* b, int a, int l) { + int d = l - Lum(*r, *g, *b); + *r += d; + *g += d; + *b += d; + + clipColor(r, g, b, a); +} + +// non-separable blend modes are done in non-premultiplied alpha +#define blendfunc_nonsep_byte(sc, dc, sa, da, blendval) \ + clamp_div255round(sc * (255 - da) + dc * (255 - sa) + blendval) + +// kHue_Mode +// B(Cb, Cs) = SetLum(SetSat(Cs, Sat(Cb)), Lum(Cb)) +// Create a color with the hue of the source color and the saturation and luminosity of the backdrop color. +static SkPMColor hue_modeproc(SkPMColor src, SkPMColor dst) { + int sr = SkGetPackedR32(src); + int sg = SkGetPackedG32(src); + int sb = SkGetPackedB32(src); + int sa = SkGetPackedA32(src); + + int dr = SkGetPackedR32(dst); + int dg = SkGetPackedG32(dst); + int db = SkGetPackedB32(dst); + int da = SkGetPackedA32(dst); + int Sr, Sg, Sb; + + if(sa && da) { + Sr = sr * sa; + Sg = sg * sa; + Sb = sb * sa; + SetSat(&Sr, &Sg, &Sb, Sat(dr, dg, db) * sa); + SetLum(&Sr, &Sg, &Sb, sa * da, Lum(dr, dg, db) * sa); + } else { + Sr = 0; + Sg = 0; + Sb = 0; + } + + int a = srcover_byte(sa, da); + int r = blendfunc_nonsep_byte(sr, dr, sa, da, Sr); + int g = blendfunc_nonsep_byte(sg, dg, sa, da, Sg); + int b = blendfunc_nonsep_byte(sb, db, sa, da, Sb); + return SkPackARGB32(a, r, g, b); +} + +// kSaturation_Mode +// B(Cb, Cs) = SetLum(SetSat(Cb, Sat(Cs)), Lum(Cb)) +// Create a color with the saturation of the source color and the hue and luminosity of the backdrop color. +static SkPMColor saturation_modeproc(SkPMColor src, SkPMColor dst) { + int sr = SkGetPackedR32(src); + int sg = SkGetPackedG32(src); + int sb = SkGetPackedB32(src); + int sa = SkGetPackedA32(src); + + int dr = SkGetPackedR32(dst); + int dg = SkGetPackedG32(dst); + int db = SkGetPackedB32(dst); + int da = SkGetPackedA32(dst); + int Dr, Dg, Db; + + if(sa && da) { + Dr = dr * sa; + Dg = dg * sa; + Db = db * sa; + SetSat(&Dr, &Dg, &Db, Sat(sr, sg, sb) * da); + SetLum(&Dr, &Dg, &Db, sa * da, Lum(dr, dg, db) * sa); + } else { + Dr = 0; + Dg = 0; + Db = 0; + } + + int a = srcover_byte(sa, da); + int r = blendfunc_nonsep_byte(sr, dr, sa, da, Dr); + int g = blendfunc_nonsep_byte(sg, dg, sa, da, Dg); + int b = blendfunc_nonsep_byte(sb, db, sa, da, Db); + return SkPackARGB32(a, r, g, b); +} + +// kColor_Mode +// B(Cb, Cs) = SetLum(Cs, Lum(Cb)) +// Create a color with the hue and saturation of the source color and the luminosity of the backdrop color. +static SkPMColor color_modeproc(SkPMColor src, SkPMColor dst) { + int sr = SkGetPackedR32(src); + int sg = SkGetPackedG32(src); + int sb = SkGetPackedB32(src); + int sa = SkGetPackedA32(src); + + int dr = SkGetPackedR32(dst); + int dg = SkGetPackedG32(dst); + int db = SkGetPackedB32(dst); + int da = SkGetPackedA32(dst); + int Sr, Sg, Sb; + + if(sa && da) { + Sr = sr * da; + Sg = sg * da; + Sb = sb * da; + SetLum(&Sr, &Sg, &Sb, sa * da, Lum(dr, dg, db) * sa); + } else { + Sr = 0; + Sg = 0; + Sb = 0; + } + + int a = srcover_byte(sa, da); + int r = blendfunc_nonsep_byte(sr, dr, sa, da, Sr); + int g = blendfunc_nonsep_byte(sg, dg, sa, da, Sg); + int b = blendfunc_nonsep_byte(sb, db, sa, da, Sb); + return SkPackARGB32(a, r, g, b); +} + +// kLuminosity_Mode +// B(Cb, Cs) = SetLum(Cb, Lum(Cs)) +// Create a color with the luminosity of the source color and the hue and saturation of the backdrop color. +static SkPMColor luminosity_modeproc(SkPMColor src, SkPMColor dst) { + int sr = SkGetPackedR32(src); + int sg = SkGetPackedG32(src); + int sb = SkGetPackedB32(src); + int sa = SkGetPackedA32(src); + + int dr = SkGetPackedR32(dst); + int dg = SkGetPackedG32(dst); + int db = SkGetPackedB32(dst); + int da = SkGetPackedA32(dst); + int Dr, Dg, Db; + + if(sa && da) { + Dr = dr * sa; + Dg = dg * sa; + Db = db * sa; + SetLum(&Dr, &Dg, &Db, sa * da, Lum(sr, sg, sb) * da); + } else { + Dr = 0; + Dg = 0; + Db = 0; } -private: - const SkBlendMode fMode; + int a = srcover_byte(sa, da); + int r = blendfunc_nonsep_byte(sr, dr, sa, da, Dr); + int g = blendfunc_nonsep_byte(sg, dg, sa, da, Dg); + int b = blendfunc_nonsep_byte(sb, db, sa, da, Db); + return SkPackARGB32(a, r, g, b); +} - typedef SkXfermode INHERITED; +/////////////////////////////////////////////////////////////////////////////////////////////////// + +const SkXfermodeProc gProcs[] = { + clear_modeproc, + src_modeproc, + dst_modeproc, + srcover_modeproc, + dstover_modeproc, + srcin_modeproc, + dstin_modeproc, + srcout_modeproc, + dstout_modeproc, + srcatop_modeproc, + dstatop_modeproc, + xor_modeproc, + + plus_modeproc, + modulate_modeproc, + screen_modeproc, + overlay_modeproc, + darken_modeproc, + lighten_modeproc, + colordodge_modeproc, + colorburn_modeproc, + hardlight_modeproc, + softlight_modeproc, + difference_modeproc, + exclusion_modeproc, + multiply_modeproc, + hue_modeproc, + saturation_modeproc, + color_modeproc, + luminosity_modeproc, }; +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +void SkProcCoeffXfermode::xfer32(SkPMColor* SK_RESTRICT dst, + const SkPMColor* SK_RESTRICT src, int count, + const SkAlpha* SK_RESTRICT aa) const { + SkASSERT(dst && src && count >= 0); + + SkXfermodeProc proc = fProc; + + if (proc) { + if (nullptr == aa) { + for (int i = count - 1; i >= 0; --i) { + dst[i] = proc(src[i], dst[i]); + } + } else { + for (int i = count - 1; i >= 0; --i) { + unsigned a = aa[i]; + if (0 != a) { + SkPMColor dstC = dst[i]; + SkPMColor C = proc(src[i], dstC); + if (a != 0xFF) { + C = SkFourByteInterp(C, dstC, a); + } + dst[i] = C; + } + } + } + } +} + const char* SkBlendMode_Name(SkBlendMode mode) { SkASSERT((unsigned) mode <= (unsigned)SkBlendMode::kLastMode); const char* gModeStrings[] = { @@ -94,20 +712,30 @@ sk_sp<SkXfermode> SkXfermode::Make(SkBlendMode mode) { } const int COUNT_BLENDMODES = (int)SkBlendMode::kLastMode + 1; + SkASSERT(SK_ARRAY_COUNT(gProcs) == COUNT_BLENDMODES); static SkOnce once[COUNT_BLENDMODES]; static SkXfermode* cached[COUNT_BLENDMODES]; once[(int)mode]([mode] { + SkXfermodeProc proc = gProcs[(int)mode]; if (auto xfermode = SkOpts::create_xfermode(mode)) { cached[(int)mode] = xfermode; } else { - cached[(int)mode] = new SkProcCoeffXfermode(mode); + cached[(int)mode] = new SkProcCoeffXfermode(proc, mode); } }); return sk_ref_sp(cached[(int)mode]); } +SkXfermodeProc SkXfermode::GetProc(SkBlendMode mode) { + SkXfermodeProc proc = nullptr; + if ((unsigned)mode <= (unsigned)SkBlendMode::kLastMode) { + proc = gProcs[(unsigned)mode]; + } + return proc; +} + /////////////////////////////////////////////////////////////////////////////////////////////////// bool SkXfermode::IsOpaque(SkBlendMode mode, SrcColorOpacity opacityType) { |