michael@0: # HG changeset patch michael@0: # User Rik Cabanier michael@0: # Date 1360273929 -46800 michael@0: # Node ID 3ac8edca3a03b3d22240b5a5b95ae3b5ada9877d michael@0: # Parent cbb67fe70b864b36165061e1fd3b083cd09af087 michael@0: Bug 836892 - Add new blending modes to SkXfermode. r=gw280 michael@0: michael@0: diff --git a/gfx/skia/include/core/SkXfermode.h b/gfx/skia/include/core/SkXfermode.h michael@0: --- a/gfx/skia/include/core/SkXfermode.h michael@0: +++ b/gfx/skia/include/core/SkXfermode.h michael@0: @@ -96,33 +96,37 @@ public: michael@0: kDstOut_Mode, //!< [Da * (1 - Sa), Dc * (1 - Sa)] michael@0: kSrcATop_Mode, //!< [Da, Sc * Da + (1 - Sa) * Dc] michael@0: kDstATop_Mode, //!< [Sa, Sa * Dc + Sc * (1 - Da)] michael@0: kXor_Mode, //!< [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc] michael@0: michael@0: // all remaining modes are defined in the SVG Compositing standard michael@0: // http://www.w3.org/TR/2009/WD-SVGCompositing-20090430/ michael@0: kPlus_Mode, michael@0: - kMultiply_Mode, michael@0: michael@0: // all above modes can be expressed as pair of src/dst Coeffs michael@0: kCoeffModesCnt, michael@0: michael@0: - kScreen_Mode = kCoeffModesCnt, michael@0: + kMultiply_Mode = kCoeffModesCnt, michael@0: + kScreen_Mode, michael@0: kOverlay_Mode, michael@0: kDarken_Mode, michael@0: kLighten_Mode, michael@0: kColorDodge_Mode, michael@0: kColorBurn_Mode, michael@0: kHardLight_Mode, michael@0: kSoftLight_Mode, michael@0: kDifference_Mode, michael@0: kExclusion_Mode, michael@0: + kHue_Mode, michael@0: + kSaturation_Mode, michael@0: + kColor_Mode, michael@0: + kLuminosity_Mode, michael@0: michael@0: - kLastMode = kExclusion_Mode michael@0: + kLastMode = kLuminosity_Mode michael@0: }; michael@0: michael@0: /** michael@0: * If the xfermode is one of the modes in the Mode enum, then asMode() michael@0: * returns true and sets (if not null) mode accordingly. Otherwise it michael@0: * returns false and ignores the mode parameter. michael@0: */ michael@0: virtual bool asMode(Mode* mode); michael@0: diff --git a/gfx/skia/src/core/SkXfermode.cpp b/gfx/skia/src/core/SkXfermode.cpp michael@0: --- a/gfx/skia/src/core/SkXfermode.cpp michael@0: +++ b/gfx/skia/src/core/SkXfermode.cpp michael@0: @@ -7,16 +7,18 @@ michael@0: */ michael@0: michael@0: michael@0: #include "SkXfermode.h" michael@0: #include "SkColorPriv.h" michael@0: #include "SkFlattenableBuffers.h" michael@0: #include "SkMathPriv.h" michael@0: michael@0: +#include michael@0: + michael@0: SK_DEFINE_INST_COUNT(SkXfermode) michael@0: michael@0: #define SkAlphaMulAlpha(a, b) SkMulDiv255Round(a, b) michael@0: michael@0: #if 0 michael@0: // idea for higher precision blends in xfer procs (and slightly faster) michael@0: // see DstATop as a probable caller michael@0: static U8CPU mulmuldiv255round(U8CPU a, U8CPU b, U8CPU c, U8CPU d) { michael@0: @@ -176,244 +178,439 @@ static SkPMColor xor_modeproc(SkPMColor michael@0: static SkPMColor plus_modeproc(SkPMColor src, SkPMColor dst) { michael@0: unsigned b = saturated_add(SkGetPackedB32(src), SkGetPackedB32(dst)); michael@0: unsigned g = saturated_add(SkGetPackedG32(src), SkGetPackedG32(dst)); michael@0: unsigned r = saturated_add(SkGetPackedR32(src), SkGetPackedR32(dst)); michael@0: unsigned a = saturated_add(SkGetPackedA32(src), SkGetPackedA32(dst)); michael@0: return SkPackARGB32(a, r, g, b); michael@0: } michael@0: michael@0: +static inline int srcover_byte(int a, int b) { michael@0: + return a + b - SkAlphaMulAlpha(a, b); michael@0: +} michael@0: + michael@0: +#define blendfunc_byte(sc, dc, sa, da, blendfunc) \ michael@0: + clamp_div255round(sc * (255 - da) + dc * (255 - sa) + blendfunc(sc, dc, sa, da)) michael@0: + michael@0: // kMultiply_Mode michael@0: +static inline int multiply_byte(int sc, int dc, int sa, int da) { michael@0: + return sc * dc; michael@0: +} michael@0: static SkPMColor multiply_modeproc(SkPMColor src, SkPMColor dst) { michael@0: - int a = SkAlphaMulAlpha(SkGetPackedA32(src), SkGetPackedA32(dst)); michael@0: - int r = SkAlphaMulAlpha(SkGetPackedR32(src), SkGetPackedR32(dst)); michael@0: - int g = SkAlphaMulAlpha(SkGetPackedG32(src), SkGetPackedG32(dst)); michael@0: - int b = SkAlphaMulAlpha(SkGetPackedB32(src), SkGetPackedB32(dst)); michael@0: + int sa = SkGetPackedA32(src); michael@0: + int da = SkGetPackedA32(dst); michael@0: + int a = srcover_byte(sa, da); michael@0: + int r = blendfunc_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da, multiply_byte); michael@0: + int g = blendfunc_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da, multiply_byte); michael@0: + int b = blendfunc_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da, multiply_byte); michael@0: return SkPackARGB32(a, r, g, b); michael@0: } michael@0: michael@0: // kScreen_Mode michael@0: -static inline int srcover_byte(int a, int b) { michael@0: - return a + b - SkAlphaMulAlpha(a, b); michael@0: +static inline int screen_byte(int sc, int dc, int sa, int da) { michael@0: + return sc * da + sa * dc - sc * dc; michael@0: } michael@0: static SkPMColor screen_modeproc(SkPMColor src, SkPMColor dst) { michael@0: - int a = srcover_byte(SkGetPackedA32(src), SkGetPackedA32(dst)); michael@0: - int r = srcover_byte(SkGetPackedR32(src), SkGetPackedR32(dst)); michael@0: - int g = srcover_byte(SkGetPackedG32(src), SkGetPackedG32(dst)); michael@0: - int b = srcover_byte(SkGetPackedB32(src), SkGetPackedB32(dst)); michael@0: + int sa = SkGetPackedA32(src); michael@0: + int da = SkGetPackedA32(dst); michael@0: + int a = srcover_byte(sa, da); michael@0: + int r = blendfunc_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da, screen_byte); michael@0: + int g = blendfunc_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da, screen_byte); michael@0: + int b = blendfunc_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da, screen_byte); michael@0: + return SkPackARGB32(a, r, g, b); michael@0: +} michael@0: + michael@0: +// kHardLight_Mode michael@0: +static inline int hardlight_byte(int sc, int dc, int sa, int da) { michael@0: + if(!sa || !da) michael@0: + return sc * da; michael@0: + float Sc = (float)sc/sa; michael@0: + float Dc = (float)dc/da; michael@0: + if(Sc <= 0.5) michael@0: + Sc *= 2 * Dc; michael@0: + else michael@0: + Sc = -1 + 2 * Sc + 2 * Dc - 2 * Sc * Dc; michael@0: + michael@0: + return Sc * sa * da; michael@0: +} michael@0: +static SkPMColor hardlight_modeproc(SkPMColor src, SkPMColor dst) { michael@0: + int sa = SkGetPackedA32(src); michael@0: + int da = SkGetPackedA32(dst); michael@0: + int a = srcover_byte(sa, da); michael@0: + int r = blendfunc_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da, hardlight_byte); michael@0: + int g = blendfunc_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da, hardlight_byte); michael@0: + int b = blendfunc_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da, hardlight_byte); michael@0: return SkPackARGB32(a, r, g, b); michael@0: } michael@0: michael@0: // kOverlay_Mode michael@0: static inline int overlay_byte(int sc, int dc, int sa, int da) { michael@0: - int tmp = sc * (255 - da) + dc * (255 - sa); michael@0: - int rc; michael@0: - if (2 * dc <= da) { michael@0: - rc = 2 * sc * dc; michael@0: - } else { michael@0: - rc = sa * da - 2 * (da - dc) * (sa - sc); michael@0: - } michael@0: - return clamp_div255round(rc + tmp); michael@0: + return hardlight_byte(dc, sc, da, sa); michael@0: } michael@0: static SkPMColor overlay_modeproc(SkPMColor src, SkPMColor dst) { michael@0: int sa = SkGetPackedA32(src); michael@0: int da = SkGetPackedA32(dst); michael@0: int a = srcover_byte(sa, da); michael@0: - int r = overlay_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da); michael@0: - int g = overlay_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da); michael@0: - int b = overlay_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); michael@0: + int r = blendfunc_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da, overlay_byte); michael@0: + int g = blendfunc_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da, overlay_byte); michael@0: + int b = blendfunc_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da, overlay_byte); michael@0: return SkPackARGB32(a, r, g, b); michael@0: } michael@0: michael@0: // kDarken_Mode michael@0: static inline int darken_byte(int sc, int dc, int sa, int da) { michael@0: - int sd = sc * da; michael@0: - int ds = dc * sa; michael@0: - if (sd < ds) { michael@0: - // srcover michael@0: - return sc + dc - SkDiv255Round(ds); michael@0: - } else { michael@0: - // dstover michael@0: - return dc + sc - SkDiv255Round(sd); michael@0: - } michael@0: + return SkMin32(sc * da, sa * dc); michael@0: } michael@0: static SkPMColor darken_modeproc(SkPMColor src, SkPMColor dst) { michael@0: int sa = SkGetPackedA32(src); michael@0: int da = SkGetPackedA32(dst); michael@0: int a = srcover_byte(sa, da); michael@0: - int r = darken_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da); michael@0: - int g = darken_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da); michael@0: - int b = darken_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); michael@0: + int r = blendfunc_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da, darken_byte); michael@0: + int g = blendfunc_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da, darken_byte); michael@0: + int b = blendfunc_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da, darken_byte); michael@0: return SkPackARGB32(a, r, g, b); michael@0: } michael@0: michael@0: // kLighten_Mode michael@0: static inline int lighten_byte(int sc, int dc, int sa, int da) { michael@0: - int sd = sc * da; michael@0: - int ds = dc * sa; michael@0: - if (sd > ds) { michael@0: - // srcover michael@0: - return sc + dc - SkDiv255Round(ds); michael@0: - } else { michael@0: - // dstover michael@0: - return dc + sc - SkDiv255Round(sd); michael@0: - } michael@0: + return SkMax32(sc * da, sa * dc); michael@0: } michael@0: static SkPMColor lighten_modeproc(SkPMColor src, SkPMColor dst) { michael@0: int sa = SkGetPackedA32(src); michael@0: int da = SkGetPackedA32(dst); michael@0: int a = srcover_byte(sa, da); michael@0: - int r = lighten_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da); michael@0: - int g = lighten_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da); michael@0: - int b = lighten_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); michael@0: + int r = blendfunc_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da, lighten_byte); michael@0: + int g = blendfunc_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da, lighten_byte); michael@0: + int b = blendfunc_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da, lighten_byte); michael@0: return SkPackARGB32(a, r, g, b); michael@0: } michael@0: michael@0: // kColorDodge_Mode michael@0: static inline int colordodge_byte(int sc, int dc, int sa, int da) { michael@0: - int diff = sa - sc; michael@0: - int rc; michael@0: - if (0 == diff) { michael@0: - rc = sa * da + sc * (255 - da) + dc * (255 - sa); michael@0: - rc = SkDiv255Round(rc); michael@0: - } else { michael@0: - int tmp = (dc * sa << 15) / (da * diff); michael@0: - rc = SkDiv255Round(sa * da) * tmp >> 15; michael@0: - // don't clamp here, since we'll do it in our modeproc michael@0: - } michael@0: - return rc; michael@0: + if (dc == 0) michael@0: + return 0; michael@0: + // Avoid division by 0 michael@0: + if (sc == sa) michael@0: + return da * sa; michael@0: + michael@0: + return SkMin32(sa * da, sa * sa * dc / (sa - sc)); michael@0: } michael@0: static SkPMColor colordodge_modeproc(SkPMColor src, SkPMColor dst) { michael@0: - // added to avoid div-by-zero in colordodge_byte michael@0: - if (0 == dst) { michael@0: - return src; michael@0: - } michael@0: - michael@0: int sa = SkGetPackedA32(src); michael@0: int da = SkGetPackedA32(dst); michael@0: int a = srcover_byte(sa, da); michael@0: - int r = colordodge_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da); michael@0: - int g = colordodge_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da); michael@0: - int b = colordodge_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); michael@0: - r = clamp_max(r, a); michael@0: - g = clamp_max(g, a); michael@0: - b = clamp_max(b, a); michael@0: + int r = blendfunc_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da, colordodge_byte); michael@0: + int g = blendfunc_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da, colordodge_byte); michael@0: + int b = blendfunc_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da, colordodge_byte); michael@0: return SkPackARGB32(a, r, g, b); michael@0: } michael@0: michael@0: // kColorBurn_Mode michael@0: static inline int colorburn_byte(int sc, int dc, int sa, int da) { michael@0: - int rc; michael@0: - if (dc == da && 0 == sc) { michael@0: - rc = sa * da + dc * (255 - sa); michael@0: - } else if (0 == sc) { michael@0: - return SkAlphaMulAlpha(dc, 255 - sa); michael@0: - } else { michael@0: - int tmp = (sa * (da - dc) * 256) / (sc * da); michael@0: - if (tmp > 256) { michael@0: - tmp = 256; michael@0: - } michael@0: - int tmp2 = sa * da; michael@0: - rc = tmp2 - (tmp2 * tmp >> 8) + sc * (255 - da) + dc * (255 - sa); michael@0: - } michael@0: - return SkDiv255Round(rc); michael@0: + // Avoid division by 0 michael@0: + if(dc == da) michael@0: + return sa * da; michael@0: + if(sc == 0) michael@0: + return 0; michael@0: + michael@0: + return sa * da - SkMin32(sa * da, sa * sa * (da - dc) / sc); michael@0: } michael@0: static SkPMColor colorburn_modeproc(SkPMColor src, SkPMColor dst) { michael@0: - // added to avoid div-by-zero in colorburn_byte michael@0: - if (0 == dst) { michael@0: - return src; michael@0: - } michael@0: - michael@0: int sa = SkGetPackedA32(src); michael@0: int da = SkGetPackedA32(dst); michael@0: int a = srcover_byte(sa, da); michael@0: - int r = colorburn_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da); michael@0: - int g = colorburn_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da); michael@0: - int b = colorburn_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); michael@0: - return SkPackARGB32(a, r, g, b); michael@0: -} michael@0: - michael@0: -// kHardLight_Mode michael@0: -static inline int hardlight_byte(int sc, int dc, int sa, int da) { michael@0: - int rc; michael@0: - if (2 * sc <= sa) { michael@0: - rc = 2 * sc * dc; michael@0: - } else { michael@0: - rc = sa * da - 2 * (da - dc) * (sa - sc); michael@0: - } michael@0: - return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa)); michael@0: -} michael@0: -static SkPMColor hardlight_modeproc(SkPMColor src, SkPMColor dst) { michael@0: - int sa = SkGetPackedA32(src); michael@0: - int da = SkGetPackedA32(dst); michael@0: - int a = srcover_byte(sa, da); michael@0: - int r = hardlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da); michael@0: - int g = hardlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da); michael@0: - int b = hardlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); michael@0: + int r = blendfunc_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da, colorburn_byte); michael@0: + int g = blendfunc_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da, colorburn_byte); michael@0: + int b = blendfunc_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da, colorburn_byte); michael@0: return SkPackARGB32(a, r, g, b); michael@0: } michael@0: michael@0: // returns 255 * sqrt(n/255) michael@0: static U8CPU sqrt_unit_byte(U8CPU n) { michael@0: return SkSqrtBits(n, 15+4); michael@0: } michael@0: michael@0: // kSoftLight_Mode michael@0: static inline int softlight_byte(int sc, int dc, int sa, int da) { michael@0: int m = da ? dc * 256 / da : 0; michael@0: int rc; michael@0: - if (2 * sc <= sa) { michael@0: - rc = dc * (sa + ((2 * sc - sa) * (256 - m) >> 8)); michael@0: - } else if (4 * dc <= da) { michael@0: + if (2 * sc <= sa) michael@0: + return dc * (sa + ((2 * sc - sa) * (256 - m) >> 8)); michael@0: + michael@0: + if (4 * dc <= da) { michael@0: int tmp = (4 * m * (4 * m + 256) * (m - 256) >> 16) + 7 * m; michael@0: - rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8); michael@0: - } else { michael@0: - int tmp = sqrt_unit_byte(m) - m; michael@0: - rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8); michael@0: + return dc * sa + (da * (2 * sc - sa) * tmp >> 8); michael@0: } michael@0: - return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa)); michael@0: + int tmp = sqrt_unit_byte(m) - m; michael@0: + return rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8); michael@0: } michael@0: static SkPMColor softlight_modeproc(SkPMColor src, SkPMColor dst) { michael@0: int sa = SkGetPackedA32(src); michael@0: int da = SkGetPackedA32(dst); michael@0: int a = srcover_byte(sa, da); michael@0: - int r = softlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da); michael@0: - int g = softlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da); michael@0: - int b = softlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); michael@0: + int r = blendfunc_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da, softlight_byte); michael@0: + int g = blendfunc_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da, softlight_byte); michael@0: + int b = blendfunc_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da, softlight_byte); michael@0: return SkPackARGB32(a, r, g, b); michael@0: } michael@0: michael@0: // kDifference_Mode michael@0: static inline int difference_byte(int sc, int dc, int sa, int da) { michael@0: - int tmp = SkMin32(sc * da, dc * sa); michael@0: - return clamp_signed_byte(sc + dc - 2 * SkDiv255Round(tmp)); michael@0: + int tmp = dc * sa - sc * da; michael@0: + if(tmp<0) michael@0: + return - tmp; michael@0: + michael@0: + return tmp; michael@0: } michael@0: static SkPMColor difference_modeproc(SkPMColor src, SkPMColor dst) { michael@0: int sa = SkGetPackedA32(src); michael@0: int da = SkGetPackedA32(dst); michael@0: int a = srcover_byte(sa, da); michael@0: - int r = difference_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da); michael@0: - int g = difference_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da); michael@0: - int b = difference_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); michael@0: + int r = blendfunc_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da, difference_byte); michael@0: + int g = blendfunc_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da, difference_byte); michael@0: + int b = blendfunc_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da, difference_byte); michael@0: return SkPackARGB32(a, r, g, b); michael@0: } michael@0: michael@0: // kExclusion_Mode michael@0: static inline int exclusion_byte(int sc, int dc, int sa, int da) { michael@0: - // this equations is wacky, wait for SVG to confirm it michael@0: - int r = sc * da + dc * sa - 2 * sc * dc + sc * (255 - da) + dc * (255 - sa); michael@0: - return clamp_div255round(r); michael@0: + return sc * da + dc * sa - 2 * dc * sc; michael@0: } michael@0: static SkPMColor exclusion_modeproc(SkPMColor src, SkPMColor dst) { michael@0: int sa = SkGetPackedA32(src); michael@0: int da = SkGetPackedA32(dst); michael@0: int a = srcover_byte(sa, da); michael@0: - int r = exclusion_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da); michael@0: - int g = exclusion_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da); michael@0: - int b = exclusion_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da); michael@0: + int r = blendfunc_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da, exclusion_byte); michael@0: + int g = blendfunc_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da, exclusion_byte); michael@0: + int b = blendfunc_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da, exclusion_byte); michael@0: + return SkPackARGB32(a, r, g, b); michael@0: +} michael@0: + michael@0: +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// michael@0: +struct BlendColor { michael@0: + float r; michael@0: + float g; michael@0: + float b; michael@0: + michael@0: + BlendColor(): r(0), g(0), b(0) michael@0: + {} michael@0: +}; michael@0: + michael@0: +static inline float Lum(BlendColor C) michael@0: +{ michael@0: + return C.r * 0.3 + C.g * 0.59 + C.b* 0.11; michael@0: +} michael@0: + michael@0: +static inline float SkMinFloat(float a, float b) michael@0: +{ michael@0: + if (a > b) michael@0: + a = b; michael@0: + return a; michael@0: +} michael@0: + michael@0: +static inline float SkMaxFloat(float a, float b) michael@0: +{ michael@0: + if (a < b) michael@0: + a = b; michael@0: + return a; michael@0: +} michael@0: + michael@0: +#define minimum(C) SkMinFloat(SkMinFloat(C.r, C.g), C.b) michael@0: +#define maximum(C) SkMaxFloat(SkMaxFloat(C.r, C.g), C.b) michael@0: + michael@0: +static inline float Sat(BlendColor c) { michael@0: + return maximum(c) - minimum(c); michael@0: +} michael@0: + michael@0: +static inline void setSaturationComponents(float& Cmin, float& Cmid, float& Cmax, float s) { michael@0: + if(Cmax > Cmin) { michael@0: + Cmid = (((Cmid - Cmin) * s ) / (Cmax - Cmin)); michael@0: + Cmax = s; michael@0: + } else { michael@0: + Cmax = 0; michael@0: + Cmid = 0; michael@0: + } michael@0: + Cmin = 0; michael@0: +} michael@0: + michael@0: +static inline BlendColor SetSat(BlendColor C, float s) { michael@0: + if(C.r <= C.g) { michael@0: + if(C.g <= C.b) michael@0: + setSaturationComponents(C.r, C.g, C.b, s); michael@0: + else michael@0: + if(C.r <= C.b) michael@0: + setSaturationComponents(C.r, C.b, C.g, s); michael@0: + else michael@0: + setSaturationComponents(C.b, C.r, C.g, s); michael@0: + } else if(C.r <= C.b) michael@0: + setSaturationComponents(C.g, C.r, C.b, s); michael@0: + else michael@0: + if(C.g <= C.b) michael@0: + setSaturationComponents(C.g, C.b, C.r, s); michael@0: + else michael@0: + setSaturationComponents(C.b, C.g, C.r, s); michael@0: + michael@0: + return C; michael@0: +} michael@0: + michael@0: +static inline BlendColor clipColor(BlendColor C) { michael@0: + float L = Lum(C); michael@0: + float n = minimum(C); michael@0: + float x = maximum(C); michael@0: + if(n < 0) { michael@0: + C.r = L + (((C.r - L) * L) / (L - n)); michael@0: + C.g = L + (((C.g - L) * L) / (L - n)); michael@0: + C.b = L + (((C.b - L) * L) / (L - n)); michael@0: + } michael@0: + michael@0: + if(x > 1) { michael@0: + C.r = L + (((C.r - L) * (1 - L)) / (x - L)); michael@0: + C.g = L + (((C.g - L) * (1 - L)) / (x - L)); michael@0: + C.b = L + (((C.b - L) * (1 - L)) / (x - L)); michael@0: + } michael@0: + return C; michael@0: +} michael@0: + michael@0: +static inline BlendColor SetLum(BlendColor C, float l) { michael@0: + float d = l - Lum(C); michael@0: + C.r += d; michael@0: + C.g += d; michael@0: + C.b += d; michael@0: + michael@0: + return clipColor(C); michael@0: +} michael@0: + michael@0: +#define blendfunc_nonsep_byte(sc, dc, sa, da, blendval) \ michael@0: + clamp_div255round(sc * (255 - da) + dc * (255 - sa) + (int)(sa * da * blendval)) michael@0: + michael@0: +static SkPMColor hue_modeproc(SkPMColor src, SkPMColor dst) { michael@0: + int sr = SkGetPackedR32(src); michael@0: + int sg = SkGetPackedG32(src); michael@0: + int sb = SkGetPackedB32(src); michael@0: + int sa = SkGetPackedA32(src); michael@0: + michael@0: + int dr = SkGetPackedR32(dst); michael@0: + int dg = SkGetPackedG32(dst); michael@0: + int db = SkGetPackedB32(dst); michael@0: + int da = SkGetPackedA32(dst); michael@0: + michael@0: + BlendColor Cs; michael@0: + if(sa) { michael@0: + Cs.r = (float)sr / sa; michael@0: + Cs.g = (float)sg / sa; michael@0: + Cs.b = (float)sb / sa; michael@0: + BlendColor Cd; michael@0: + if(da) { michael@0: + Cd.r = (float)dr / da; michael@0: + Cd.g = (float)dg / da; michael@0: + Cd.b = (float)db / da; michael@0: + Cs = SetLum(SetSat(Cs, Sat(Cd)), Lum(Cd)); michael@0: + } michael@0: + } michael@0: + michael@0: + int a = srcover_byte(sa, da); michael@0: + int r = blendfunc_nonsep_byte(sr, dr, sa, da, Cs.r); michael@0: + int g = blendfunc_nonsep_byte(sg, dg, sa, da, Cs.g); michael@0: + int b = blendfunc_nonsep_byte(sb, db, sa, da, Cs.b); michael@0: + return SkPackARGB32(a, r, g, b); michael@0: +} michael@0: + michael@0: +static SkPMColor saturation_modeproc(SkPMColor src, SkPMColor dst) { michael@0: + int sr = SkGetPackedR32(src); michael@0: + int sg = SkGetPackedG32(src); michael@0: + int sb = SkGetPackedB32(src); michael@0: + int sa = SkGetPackedA32(src); michael@0: + michael@0: + int dr = SkGetPackedR32(dst); michael@0: + int dg = SkGetPackedG32(dst); michael@0: + int db = SkGetPackedB32(dst); michael@0: + int da = SkGetPackedA32(dst); michael@0: + michael@0: + BlendColor Cs; michael@0: + if(sa) { michael@0: + Cs.r = (float)sr / sa; michael@0: + Cs.g = (float)sg / sa; michael@0: + Cs.b = (float)sb / sa; michael@0: + BlendColor Cd; michael@0: + if(da) { michael@0: + Cd.r = (float)dr / da; michael@0: + Cd.g = (float)dg / da; michael@0: + Cd.b = (float)db / da; michael@0: + Cs = SetLum(SetSat(Cd, Sat(Cs)), Lum(Cd)); michael@0: + } michael@0: + } michael@0: + michael@0: + int a = srcover_byte(sa, da); michael@0: + int r = blendfunc_nonsep_byte(sr, dr, sa, da, Cs.r); michael@0: + int g = blendfunc_nonsep_byte(sg, dg, sa, da, Cs.g); michael@0: + int b = blendfunc_nonsep_byte(sb, db, sa, da, Cs.b); michael@0: + return SkPackARGB32(a, r, g, b); michael@0: +} michael@0: + michael@0: +static SkPMColor color_modeproc(SkPMColor src, SkPMColor dst) { michael@0: + int sr = SkGetPackedR32(src); michael@0: + int sg = SkGetPackedG32(src); michael@0: + int sb = SkGetPackedB32(src); michael@0: + int sa = SkGetPackedA32(src); michael@0: + michael@0: + int dr = SkGetPackedR32(dst); michael@0: + int dg = SkGetPackedG32(dst); michael@0: + int db = SkGetPackedB32(dst); michael@0: + int da = SkGetPackedA32(dst); michael@0: + michael@0: + BlendColor Cs; michael@0: + if(sa) { michael@0: + Cs.r = (float)sr / sa; michael@0: + Cs.g = (float)sg / sa; michael@0: + Cs.b = (float)sb / sa; michael@0: + BlendColor Cd; michael@0: + if(da) { michael@0: + Cd.r = (float)dr / da; michael@0: + Cd.g = (float)dg / da; michael@0: + Cd.b = (float)db / da; michael@0: + Cs = SetLum(Cs, Lum(Cd)); michael@0: + } michael@0: + } michael@0: + michael@0: + int a = srcover_byte(sa, da); michael@0: + int r = blendfunc_nonsep_byte(sr, dr, sa, da, Cs.r); michael@0: + int g = blendfunc_nonsep_byte(sg, dg, sa, da, Cs.g); michael@0: + int b = blendfunc_nonsep_byte(sb, db, sa, da, Cs.b); michael@0: + return SkPackARGB32(a, r, g, b); michael@0: +} michael@0: + michael@0: +static SkPMColor luminosity_modeproc(SkPMColor src, SkPMColor dst) { michael@0: + int sr = SkGetPackedR32(src); michael@0: + int sg = SkGetPackedG32(src); michael@0: + int sb = SkGetPackedB32(src); michael@0: + int sa = SkGetPackedA32(src); michael@0: + michael@0: + int dr = SkGetPackedR32(dst); michael@0: + int dg = SkGetPackedG32(dst); michael@0: + int db = SkGetPackedB32(dst); michael@0: + int da = SkGetPackedA32(dst); michael@0: + michael@0: + BlendColor Cs; michael@0: + if(sa) { michael@0: + Cs.r = (float)sr / sa; michael@0: + Cs.g = (float)sg / sa; michael@0: + Cs.b = (float)sb / sa; michael@0: + BlendColor Cd; michael@0: + if(da) { michael@0: + Cd.r = (float)dr / da; michael@0: + Cd.g = (float)dg / da; michael@0: + Cd.b = (float)db / da; michael@0: + Cs = SetLum(Cd, Lum(Cs)); michael@0: + } michael@0: + } michael@0: + michael@0: + int a = srcover_byte(sa, da); michael@0: + int r = blendfunc_nonsep_byte(sr, dr, sa, da, Cs.r); michael@0: + int g = blendfunc_nonsep_byte(sg, dg, sa, da, Cs.g); michael@0: + int b = blendfunc_nonsep_byte(sb, db, sa, da, Cs.b); michael@0: return SkPackARGB32(a, r, g, b); michael@0: } michael@0: michael@0: struct ProcCoeff { michael@0: SkXfermodeProc fProc; michael@0: SkXfermode::Coeff fSC; michael@0: SkXfermode::Coeff fDC; michael@0: }; michael@0: @@ -430,27 +627,31 @@ static const ProcCoeff gProcCoeffs[] = { michael@0: { dstin_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kSA_Coeff }, michael@0: { srcout_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kZero_Coeff }, michael@0: { dstout_modeproc, SkXfermode::kZero_Coeff, SkXfermode::kISA_Coeff }, michael@0: { srcatop_modeproc, SkXfermode::kDA_Coeff, SkXfermode::kISA_Coeff }, michael@0: { dstatop_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kSA_Coeff }, michael@0: { xor_modeproc, SkXfermode::kIDA_Coeff, SkXfermode::kISA_Coeff }, michael@0: michael@0: { plus_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kOne_Coeff }, michael@0: - { multiply_modeproc,SkXfermode::kZero_Coeff, SkXfermode::kSC_Coeff }, michael@0: + { multiply_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF}, michael@0: { screen_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, michael@0: { overlay_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, michael@0: { darken_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, michael@0: { lighten_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, michael@0: { colordodge_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, michael@0: { colorburn_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, michael@0: { hardlight_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, michael@0: { softlight_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, michael@0: { difference_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, michael@0: { exclusion_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, michael@0: + { hue_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, michael@0: + { saturation_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, michael@0: + { color_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, michael@0: + { luminosity_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF }, michael@0: }; michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: bool SkXfermode::asCoeff(Coeff* src, Coeff* dst) { michael@0: return false; michael@0: } michael@0: michael@0: @@ -1172,16 +1373,20 @@ static const Proc16Rec gModeProcs16[] = michael@0: { darken_modeproc16_0, darken_modeproc16_255, NULL }, // darken michael@0: { lighten_modeproc16_0, lighten_modeproc16_255, NULL }, // lighten michael@0: { NULL, NULL, NULL }, // colordodge michael@0: { NULL, NULL, NULL }, // colorburn michael@0: { NULL, NULL, NULL }, // hardlight michael@0: { NULL, NULL, NULL }, // softlight michael@0: { NULL, NULL, NULL }, // difference michael@0: { NULL, NULL, NULL }, // exclusion michael@0: + { NULL, NULL, NULL }, // hue michael@0: + { NULL, NULL, NULL }, // saturation michael@0: + { NULL, NULL, NULL }, // color michael@0: + { NULL, NULL, NULL }, // luminosity michael@0: }; michael@0: michael@0: SkXfermodeProc16 SkXfermode::GetProc16(Mode mode, SkColor srcColor) { michael@0: SkXfermodeProc16 proc16 = NULL; michael@0: if ((unsigned)mode < kModeCount) { michael@0: const Proc16Rec& rec = gModeProcs16[mode]; michael@0: unsigned a = SkColorGetA(srcColor); michael@0: