2011-07-28 14:26:00 +00:00
|
|
|
|
2008-12-17 15:59:43 +00:00
|
|
|
/*
|
2011-07-28 14:26:00 +00:00
|
|
|
* Copyright 2006 The Android Open Source Project
|
2008-12-17 15:59:43 +00:00
|
|
|
*
|
2011-07-28 14:26:00 +00:00
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
2008-12-17 15:59:43 +00:00
|
|
|
*/
|
|
|
|
|
2011-07-28 14:26:00 +00:00
|
|
|
|
2008-12-17 15:59:43 +00:00
|
|
|
#include "SkXfermode.h"
|
2014-04-09 15:43:46 +00:00
|
|
|
#include "SkXfermode_opts_SSE2.h"
|
2013-10-09 14:39:46 +00:00
|
|
|
#include "SkXfermode_proccoeff.h"
|
2008-12-17 15:59:43 +00:00
|
|
|
#include "SkColorPriv.h"
|
2014-05-29 20:13:22 +00:00
|
|
|
#include "SkLazyPtr.h"
|
2012-08-07 21:35:13 +00:00
|
|
|
#include "SkMathPriv.h"
|
2014-03-28 20:04:11 +00:00
|
|
|
#include "SkReadBuffer.h"
|
2013-01-22 14:32:09 +00:00
|
|
|
#include "SkString.h"
|
2013-10-17 16:29:34 +00:00
|
|
|
#include "SkUtilsArm.h"
|
2014-03-28 20:04:11 +00:00
|
|
|
#include "SkWriteBuffer.h"
|
2013-10-17 16:29:34 +00:00
|
|
|
|
|
|
|
#if !SK_ARM_NEON_IS_NONE
|
|
|
|
#include "SkXfermode_opts_arm_neon.h"
|
|
|
|
#endif
|
2008-12-17 15:59:43 +00:00
|
|
|
|
|
|
|
#define SkAlphaMulAlpha(a, b) SkMulDiv255Round(a, b)
|
|
|
|
|
2009-01-15 14:38:33 +00:00
|
|
|
#if 0
|
2008-12-17 15:59:43 +00:00
|
|
|
// idea for higher precision blends in xfer procs (and slightly faster)
|
|
|
|
// see DstATop as a probable caller
|
|
|
|
static U8CPU mulmuldiv255round(U8CPU a, U8CPU b, U8CPU c, U8CPU d) {
|
|
|
|
SkASSERT(a <= 255);
|
|
|
|
SkASSERT(b <= 255);
|
|
|
|
SkASSERT(c <= 255);
|
|
|
|
SkASSERT(d <= 255);
|
|
|
|
unsigned prod = SkMulS16(a, b) + SkMulS16(c, d) + 128;
|
|
|
|
unsigned result = (prod + (prod >> 8)) >> 8;
|
|
|
|
SkASSERT(result <= 255);
|
|
|
|
return result;
|
|
|
|
}
|
2009-01-15 14:38:33 +00:00
|
|
|
#endif
|
2008-12-17 15:59:43 +00:00
|
|
|
|
2009-07-03 12:54:24 +00:00
|
|
|
static inline unsigned saturated_add(unsigned a, unsigned b) {
|
2009-04-24 12:43:40 +00:00
|
|
|
SkASSERT(a <= 255);
|
|
|
|
SkASSERT(b <= 255);
|
|
|
|
unsigned sum = a + b;
|
|
|
|
if (sum > 255) {
|
|
|
|
sum = 255;
|
|
|
|
}
|
|
|
|
return sum;
|
|
|
|
}
|
|
|
|
|
2009-07-03 12:54:24 +00:00
|
|
|
static inline int clamp_signed_byte(int n) {
|
2009-06-22 17:38:10 +00:00
|
|
|
if (n < 0) {
|
|
|
|
n = 0;
|
|
|
|
} else if (n > 255) {
|
|
|
|
n = 255;
|
|
|
|
}
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2009-07-03 12:54:24 +00:00
|
|
|
static inline int clamp_div255round(int prod) {
|
2009-06-22 17:38:10 +00:00
|
|
|
if (prod <= 0) {
|
|
|
|
return 0;
|
|
|
|
} else if (prod >= 255*255) {
|
|
|
|
return 255;
|
|
|
|
} else {
|
|
|
|
return SkDiv255Round(prod);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-17 15:59:43 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2011-02-08 19:28:07 +00:00
|
|
|
// kClear_Mode, //!< [0, 0]
|
|
|
|
static SkPMColor clear_modeproc(SkPMColor src, SkPMColor dst) {
|
|
|
|
return 0;
|
2008-12-17 15:59:43 +00:00
|
|
|
}
|
|
|
|
|
2011-02-08 19:28:07 +00:00
|
|
|
// kSrc_Mode, //!< [Sa, Sc]
|
|
|
|
static SkPMColor src_modeproc(SkPMColor src, SkPMColor dst) {
|
|
|
|
return src;
|
2008-12-17 15:59:43 +00:00
|
|
|
}
|
|
|
|
|
2011-02-08 19:28:07 +00:00
|
|
|
// kDst_Mode, //!< [Da, Dc]
|
|
|
|
static SkPMColor dst_modeproc(SkPMColor src, SkPMColor dst) {
|
|
|
|
return dst;
|
|
|
|
}
|
2008-12-17 15:59:43 +00:00
|
|
|
|
2011-04-27 14:09:52 +00:00
|
|
|
// kSrcOver_Mode, //!< [Sa + Da - Sa*Da, Sc + (1 - Sa)*Dc]
|
2011-02-08 19:28:07 +00:00
|
|
|
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
|
2008-12-17 15:59:43 +00:00
|
|
|
}
|
|
|
|
|
2011-02-08 19:28:07 +00:00
|
|
|
// 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));
|
|
|
|
}
|
2008-12-17 15:59:43 +00:00
|
|
|
|
2011-02-08 19:28:07 +00:00
|
|
|
// kSrcIn_Mode, //!< [Sa * Da, Sc * Da]
|
|
|
|
static SkPMColor srcin_modeproc(SkPMColor src, SkPMColor dst) {
|
|
|
|
return SkAlphaMulQ(src, SkAlpha255To256(SkGetPackedA32(dst)));
|
2008-12-17 15:59:43 +00:00
|
|
|
}
|
|
|
|
|
2011-02-08 19:28:07 +00:00
|
|
|
// kDstIn_Mode, //!< [Sa * Da, Sa * Dc]
|
|
|
|
static SkPMColor dstin_modeproc(SkPMColor src, SkPMColor dst) {
|
|
|
|
return SkAlphaMulQ(dst, SkAlpha255To256(SkGetPackedA32(src)));
|
2008-12-17 15:59:43 +00:00
|
|
|
}
|
|
|
|
|
2011-02-08 19:28:07 +00:00
|
|
|
// kSrcOut_Mode, //!< [Sa * (1 - Da), Sc * (1 - Da)]
|
|
|
|
static SkPMColor srcout_modeproc(SkPMColor src, SkPMColor dst) {
|
|
|
|
return SkAlphaMulQ(src, SkAlpha255To256(255 - SkGetPackedA32(dst)));
|
|
|
|
}
|
2008-12-17 15:59:43 +00:00
|
|
|
|
2011-02-08 19:28:07 +00:00
|
|
|
// kDstOut_Mode, //!< [Da * (1 - Sa), Dc * (1 - Sa)]
|
|
|
|
static SkPMColor dstout_modeproc(SkPMColor src, SkPMColor dst) {
|
|
|
|
return SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
|
2008-12-17 15:59:43 +00:00
|
|
|
}
|
|
|
|
|
2011-02-08 19:28:07 +00:00
|
|
|
// 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;
|
2008-12-17 15:59:43 +00:00
|
|
|
|
2011-02-08 19:28:07 +00:00
|
|
|
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)));
|
|
|
|
}
|
2008-12-17 15:59:43 +00:00
|
|
|
|
2011-02-08 19:28:07 +00:00
|
|
|
// 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;
|
2008-12-17 15:59:43 +00:00
|
|
|
|
2011-02-08 19:28:07 +00:00
|
|
|
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)));
|
2008-12-17 15:59:43 +00:00
|
|
|
}
|
|
|
|
|
2011-02-08 19:28:07 +00:00
|
|
|
// 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;
|
2008-12-17 15:59:43 +00:00
|
|
|
|
2011-02-08 19:28:07 +00:00
|
|
|
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)));
|
|
|
|
}
|
2008-12-17 15:59:43 +00:00
|
|
|
|
2011-02-08 19:28:07 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// 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);
|
2008-12-17 15:59:43 +00:00
|
|
|
}
|
|
|
|
|
2013-01-30 21:36:11 +00:00
|
|
|
// kModulate_Mode
|
|
|
|
static SkPMColor modulate_modeproc(SkPMColor src, SkPMColor dst) {
|
2011-02-08 19:28:07 +00:00
|
|
|
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);
|
|
|
|
}
|
2008-12-17 15:59:43 +00:00
|
|
|
|
2009-06-22 17:38:10 +00:00
|
|
|
static inline int srcover_byte(int a, int b) {
|
|
|
|
return a + b - SkAlphaMulAlpha(a, b);
|
|
|
|
}
|
2013-02-04 20:06:00 +00:00
|
|
|
|
|
|
|
// 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
|
2009-06-22 17:38:10 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2008-12-17 15:59:43 +00:00
|
|
|
static SkPMColor darken_modeproc(SkPMColor src, SkPMColor dst) {
|
2009-06-22 17:38:10 +00:00
|
|
|
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);
|
|
|
|
}
|
2008-12-17 15:59:43 +00:00
|
|
|
|
2009-06-22 17:38:10 +00:00
|
|
|
// 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);
|
|
|
|
}
|
2008-12-17 15:59:43 +00:00
|
|
|
|
2009-06-22 17:38:10 +00:00
|
|
|
// kColorDodge_Mode
|
|
|
|
static inline int colordodge_byte(int sc, int dc, int sa, int da) {
|
|
|
|
int diff = sa - sc;
|
|
|
|
int rc;
|
2013-03-21 12:40:08 +00:00
|
|
|
if (0 == dc) {
|
|
|
|
return SkAlphaMulAlpha(sc, 255 - da);
|
|
|
|
} else if (0 == diff) {
|
2009-06-22 17:38:10 +00:00
|
|
|
rc = sa * da + sc * (255 - da) + dc * (255 - sa);
|
|
|
|
} else {
|
2013-03-21 12:40:08 +00:00
|
|
|
diff = dc * sa / diff;
|
|
|
|
rc = sa * ((da < diff) ? da : diff) + sc * (255 - da) + dc * (255 - sa);
|
2009-06-22 17:38:10 +00:00
|
|
|
}
|
2013-03-21 12:40:08 +00:00
|
|
|
return clamp_div255round(rc);
|
2011-02-08 19:28:07 +00:00
|
|
|
}
|
|
|
|
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;
|
2013-03-21 12:40:08 +00:00
|
|
|
if (dc == da) {
|
|
|
|
rc = sa * da + sc * (255 - da) + dc * (255 - sa);
|
2011-02-08 19:28:07 +00:00
|
|
|
} else if (0 == sc) {
|
|
|
|
return SkAlphaMulAlpha(dc, 255 - sa);
|
|
|
|
} else {
|
2013-03-21 12:40:08 +00:00
|
|
|
int tmp = (da - dc) * sa / sc;
|
|
|
|
rc = sa * (da - ((da < tmp) ? da : tmp))
|
|
|
|
+ sc * (255 - da) + dc * (255 - sa);
|
2011-02-08 19:28:07 +00:00
|
|
|
}
|
2013-03-21 12:40:08 +00:00
|
|
|
return clamp_div255round(rc);
|
2011-02-08 19:28:07 +00:00
|
|
|
}
|
|
|
|
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
|
2013-07-15 12:20:36 +00:00
|
|
|
static inline int exclusion_byte(int sc, int dc, int, int) {
|
2011-02-08 19:28:07 +00:00
|
|
|
// this equations is wacky, wait for SVG to confirm it
|
2013-07-15 12:20:36 +00:00
|
|
|
//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;
|
2011-02-08 19:28:07 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2013-03-05 16:23:59 +00:00
|
|
|
// 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)
|
|
|
|
{
|
2013-03-21 12:40:08 +00:00
|
|
|
return SkDiv255Round(r * 77 + g * 150 + b * 28);
|
2013-03-05 16:23:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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; }
|
2013-03-06 07:01:46 +00:00
|
|
|
#define minimum(a, b, c) min2(min2(a, b), c)
|
|
|
|
#define maximum(a, b, c) max2(max2(a, b), c)
|
2013-03-05 16:23:59 +00:00
|
|
|
|
|
|
|
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) {
|
2013-03-07 15:31:58 +00:00
|
|
|
if(*Cmax > *Cmin) {
|
2013-03-21 12:40:08 +00:00
|
|
|
*Cmid = SkMulDiv(*Cmid - *Cmin, s, *Cmax - *Cmin);
|
2013-03-05 16:23:59 +00:00
|
|
|
*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);
|
|
|
|
}
|
|
|
|
} else if(*r <= *b) {
|
|
|
|
setSaturationComponents(g, r, b, s);
|
|
|
|
} else if(*g <= *b) {
|
|
|
|
setSaturationComponents(g, b, r, s);
|
|
|
|
} else {
|
|
|
|
setSaturationComponents(b, g, r, s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-21 12:40:08 +00:00
|
|
|
static inline void clipColor(int* r, int* g, int* b, int a) {
|
2013-03-05 16:23:59 +00:00
|
|
|
int L = Lum(*r, *g, *b);
|
|
|
|
int n = minimum(*r, *g, *b);
|
|
|
|
int x = maximum(*r, *g, *b);
|
2013-12-12 19:47:09 +00:00
|
|
|
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);
|
2013-03-05 16:23:59 +00:00
|
|
|
}
|
|
|
|
|
2013-12-12 19:47:09 +00:00
|
|
|
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);
|
2013-03-05 16:23:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-21 12:40:08 +00:00
|
|
|
static inline void SetLum(int* r, int* g, int* b, int a, int l) {
|
2013-03-05 16:23:59 +00:00
|
|
|
int d = l - Lum(*r, *g, *b);
|
|
|
|
*r += d;
|
|
|
|
*g += d;
|
|
|
|
*b += d;
|
|
|
|
|
2013-03-21 12:40:08 +00:00
|
|
|
clipColor(r, g, b, a);
|
2013-03-05 16:23:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// non-separable blend modes are done in non-premultiplied alpha
|
|
|
|
#define blendfunc_nonsep_byte(sc, dc, sa, da, blendval) \
|
2013-03-21 12:40:08 +00:00
|
|
|
clamp_div255round(sc * (255 - da) + dc * (255 - sa) + blendval)
|
2013-03-05 16:23:59 +00:00
|
|
|
|
|
|
|
// 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) {
|
2013-03-21 12:40:08 +00:00
|
|
|
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);
|
2013-03-05 16:23:59 +00:00
|
|
|
} 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))
|
2013-03-06 07:01:46 +00:00
|
|
|
// Create a color with the saturation of the source color and the hue and luminosity of the backdrop color.
|
2013-03-05 16:23:59 +00:00
|
|
|
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) {
|
2013-03-21 12:40:08 +00:00
|
|
|
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);
|
2013-03-05 16:23:59 +00:00
|
|
|
} 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))
|
2013-03-06 07:01:46 +00:00
|
|
|
// Create a color with the hue and saturation of the source color and the luminosity of the backdrop color.
|
2013-03-05 16:23:59 +00:00
|
|
|
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) {
|
2013-03-21 12:40:08 +00:00
|
|
|
Sr = sr * da;
|
|
|
|
Sg = sg * da;
|
|
|
|
Sb = sb * da;
|
|
|
|
SetLum(&Sr, &Sg, &Sb, sa * da, Lum(dr, dg, db) * sa);
|
2013-03-05 16:23:59 +00:00
|
|
|
} 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))
|
2013-03-06 07:01:46 +00:00
|
|
|
// Create a color with the luminosity of the source color and the hue and saturation of the backdrop color.
|
2013-03-05 16:23:59 +00:00
|
|
|
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) {
|
2013-03-21 12:40:08 +00:00
|
|
|
Dr = dr * sa;
|
|
|
|
Dg = dg * sa;
|
|
|
|
Db = db * sa;
|
|
|
|
SetLum(&Dr, &Dg, &Db, sa * da, Lum(sr, sg, sb) * da);
|
2013-03-05 16:23:59 +00:00
|
|
|
} 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);
|
|
|
|
}
|
|
|
|
|
2013-10-09 14:39:46 +00:00
|
|
|
const ProcCoeff gProcCoeffs[] = {
|
2011-02-08 19:28:07 +00:00
|
|
|
{ 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 },
|
|
|
|
|
2011-04-12 18:55:21 +00:00
|
|
|
{ plus_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kOne_Coeff },
|
2013-01-30 21:36:11 +00:00
|
|
|
{ modulate_modeproc,SkXfermode::kZero_Coeff, SkXfermode::kSC_Coeff },
|
2013-04-15 15:16:47 +00:00
|
|
|
{ screen_modeproc, SkXfermode::kOne_Coeff, SkXfermode::kISC_Coeff },
|
2011-02-08 19:28:07 +00:00
|
|
|
{ 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 },
|
2013-02-04 20:06:00 +00:00
|
|
|
{ multiply_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
|
2013-03-05 16:23:59 +00:00
|
|
|
{ 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 },
|
2011-02-08 19:28:07 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2012-12-17 19:55:24 +00:00
|
|
|
bool SkXfermode::asCoeff(Coeff* src, Coeff* dst) const {
|
2011-02-08 19:28:07 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-12-17 19:55:24 +00:00
|
|
|
bool SkXfermode::asMode(Mode* mode) const {
|
2011-04-13 21:12:04 +00:00
|
|
|
return false;
|
2011-02-08 19:28:07 +00:00
|
|
|
}
|
|
|
|
|
2014-07-08 13:52:35 +00:00
|
|
|
bool SkXfermode::asNewEffect(GrEffect** effect, GrTexture* background) const {
|
2013-10-23 18:41:36 +00:00
|
|
|
return false;
|
2013-03-27 18:31:15 +00:00
|
|
|
}
|
|
|
|
|
2013-03-29 19:22:36 +00:00
|
|
|
bool SkXfermode::AsNewEffectOrCoeff(SkXfermode* xfermode,
|
2014-07-08 13:52:35 +00:00
|
|
|
GrEffect** effect,
|
2013-03-29 19:22:36 +00:00
|
|
|
Coeff* src,
|
2013-05-31 17:49:12 +00:00
|
|
|
Coeff* dst,
|
|
|
|
GrTexture* background) {
|
2013-03-27 18:31:15 +00:00
|
|
|
if (NULL == xfermode) {
|
|
|
|
return ModeAsCoeff(kSrcOver_Mode, src, dst);
|
2013-10-23 18:41:36 +00:00
|
|
|
} else if (xfermode->asCoeff(src, dst)) {
|
|
|
|
return true;
|
2013-03-27 18:31:15 +00:00
|
|
|
} else {
|
2013-10-23 18:41:36 +00:00
|
|
|
return xfermode->asNewEffect(effect, background);
|
2013-03-27 18:31:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-17 19:55:24 +00:00
|
|
|
SkPMColor SkXfermode::xferColor(SkPMColor src, SkPMColor dst) const{
|
2011-02-08 19:28:07 +00:00
|
|
|
// no-op. subclasses should override this
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
2011-06-15 16:50:27 +00:00
|
|
|
void SkXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
|
|
|
|
const SkPMColor* SK_RESTRICT src, int count,
|
2012-12-17 19:55:24 +00:00
|
|
|
const SkAlpha* SK_RESTRICT aa) const {
|
2011-02-08 19:28:07 +00:00
|
|
|
SkASSERT(dst && src && count >= 0);
|
|
|
|
|
|
|
|
if (NULL == aa) {
|
|
|
|
for (int i = count - 1; i >= 0; --i) {
|
|
|
|
dst[i] = this->xferColor(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 = this->xferColor(src[i], dstC);
|
|
|
|
if (0xFF != a) {
|
|
|
|
C = SkFourByteInterp(C, dstC, a);
|
|
|
|
}
|
|
|
|
dst[i] = C;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-15 16:50:27 +00:00
|
|
|
void SkXfermode::xfer16(uint16_t* dst,
|
|
|
|
const SkPMColor* SK_RESTRICT src, int count,
|
2012-12-17 19:55:24 +00:00
|
|
|
const SkAlpha* SK_RESTRICT aa) const {
|
2011-02-08 19:28:07 +00:00
|
|
|
SkASSERT(dst && src && count >= 0);
|
|
|
|
|
|
|
|
if (NULL == aa) {
|
|
|
|
for (int i = count - 1; i >= 0; --i) {
|
|
|
|
SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
|
|
|
|
dst[i] = SkPixel32ToPixel16_ToU16(this->xferColor(src[i], dstC));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (int i = count - 1; i >= 0; --i) {
|
|
|
|
unsigned a = aa[i];
|
|
|
|
if (0 != a) {
|
|
|
|
SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
|
|
|
|
SkPMColor C = this->xferColor(src[i], dstC);
|
|
|
|
if (0xFF != a) {
|
|
|
|
C = SkFourByteInterp(C, dstC, a);
|
|
|
|
}
|
|
|
|
dst[i] = SkPixel32ToPixel16_ToU16(C);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-15 16:50:27 +00:00
|
|
|
void SkXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
|
2011-02-08 19:28:07 +00:00
|
|
|
const SkPMColor src[], int count,
|
2012-12-17 19:55:24 +00:00
|
|
|
const SkAlpha* SK_RESTRICT aa) const {
|
2011-02-08 19:28:07 +00:00
|
|
|
SkASSERT(dst && src && count >= 0);
|
|
|
|
|
|
|
|
if (NULL == aa) {
|
|
|
|
for (int i = count - 1; i >= 0; --i) {
|
|
|
|
SkPMColor res = this->xferColor(src[i], (dst[i] << SK_A32_SHIFT));
|
|
|
|
dst[i] = SkToU8(SkGetPackedA32(res));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (int i = count - 1; i >= 0; --i) {
|
|
|
|
unsigned a = aa[i];
|
|
|
|
if (0 != a) {
|
|
|
|
SkAlpha dstA = dst[i];
|
|
|
|
unsigned A = SkGetPackedA32(this->xferColor(src[i],
|
|
|
|
(SkPMColor)(dstA << SK_A32_SHIFT)));
|
|
|
|
if (0xFF != a) {
|
|
|
|
A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
|
|
|
|
}
|
|
|
|
dst[i] = SkToU8(A);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-29 19:22:36 +00:00
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
#if SK_SUPPORT_GPU
|
|
|
|
|
|
|
|
#include "GrEffect.h"
|
2013-10-02 13:04:56 +00:00
|
|
|
#include "GrCoordTransform.h"
|
2013-03-29 19:22:36 +00:00
|
|
|
#include "GrEffectUnitTest.h"
|
|
|
|
#include "GrTBackendEffectFactory.h"
|
|
|
|
#include "gl/GrGLEffect.h"
|
|
|
|
|
|
|
|
/**
|
2013-04-19 15:03:21 +00:00
|
|
|
* GrEffect that implements the all the separable xfer modes that cannot be expressed as Coeffs.
|
2013-03-29 19:22:36 +00:00
|
|
|
*/
|
2013-04-19 15:03:21 +00:00
|
|
|
class XferEffect : public GrEffect {
|
2013-03-29 19:22:36 +00:00
|
|
|
public:
|
2013-04-19 15:03:21 +00:00
|
|
|
static bool IsSupportedMode(SkXfermode::Mode mode) {
|
2013-04-22 21:05:48 +00:00
|
|
|
return mode > SkXfermode::kLastCoeffMode && mode <= SkXfermode::kLastMode;
|
2013-04-19 15:03:21 +00:00
|
|
|
}
|
|
|
|
|
2013-05-31 17:49:12 +00:00
|
|
|
static GrEffectRef* Create(SkXfermode::Mode mode, GrTexture* background) {
|
2013-04-19 15:03:21 +00:00
|
|
|
if (!IsSupportedMode(mode)) {
|
|
|
|
return NULL;
|
|
|
|
} else {
|
2013-05-31 17:49:12 +00:00
|
|
|
AutoEffectUnref effect(SkNEW_ARGS(XferEffect, (mode, background)));
|
2013-04-19 15:03:21 +00:00
|
|
|
return CreateEffectRef(effect);
|
|
|
|
}
|
2013-03-29 19:22:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void getConstantColorComponents(GrColor* color,
|
|
|
|
uint32_t* validFlags) const SK_OVERRIDE {
|
|
|
|
*validFlags = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
|
2013-04-19 15:03:21 +00:00
|
|
|
return GrTBackendEffectFactory<XferEffect>::getInstance();
|
2013-03-29 19:22:36 +00:00
|
|
|
}
|
|
|
|
|
2013-04-19 15:03:21 +00:00
|
|
|
static const char* Name() { return "XferEffect"; }
|
|
|
|
|
|
|
|
SkXfermode::Mode mode() const { return fMode; }
|
2013-05-31 17:49:12 +00:00
|
|
|
const GrTextureAccess& backgroundAccess() const { return fBackgroundAccess; }
|
2013-03-29 19:22:36 +00:00
|
|
|
|
|
|
|
class GLEffect : public GrGLEffect {
|
|
|
|
public:
|
|
|
|
GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
|
2013-10-02 13:04:56 +00:00
|
|
|
: GrGLEffect(factory) {
|
2013-03-29 19:22:36 +00:00
|
|
|
}
|
|
|
|
virtual void emitCode(GrGLShaderBuilder* builder,
|
|
|
|
const GrDrawEffect& drawEffect,
|
|
|
|
EffectKey key,
|
|
|
|
const char* outputColor,
|
|
|
|
const char* inputColor,
|
2013-10-02 13:04:56 +00:00
|
|
|
const TransformedCoordsArray& coords,
|
2013-03-29 19:22:36 +00:00
|
|
|
const TextureSamplerArray& samplers) SK_OVERRIDE {
|
2013-05-31 17:49:12 +00:00
|
|
|
SkXfermode::Mode mode = drawEffect.castEffect<XferEffect>().mode();
|
|
|
|
const GrTexture* backgroundTex = drawEffect.castEffect<XferEffect>().backgroundAccess().getTexture();
|
|
|
|
const char* dstColor;
|
|
|
|
if (backgroundTex) {
|
|
|
|
dstColor = "bgColor";
|
|
|
|
builder->fsCodeAppendf("\t\tvec4 %s = ", dstColor);
|
2013-10-02 13:04:56 +00:00
|
|
|
builder->fsAppendTextureLookup(samplers[0], coords[0].c_str(), coords[0].type());
|
2013-05-31 17:49:12 +00:00
|
|
|
builder->fsCodeAppendf(";\n");
|
|
|
|
} else {
|
|
|
|
dstColor = builder->dstColor();
|
|
|
|
}
|
2013-08-17 00:02:59 +00:00
|
|
|
SkASSERT(NULL != dstColor);
|
2013-04-19 15:03:21 +00:00
|
|
|
|
|
|
|
// We don't try to optimize for this case at all
|
2013-03-29 20:30:50 +00:00
|
|
|
if (NULL == inputColor) {
|
Express (GLSL expression, possibly known value) pairs as a class
Express (GLSL expression, possibly known value) pairs as a class
instead of two variables Introduces GrGLSLExpr<N> to encapsulate
the expression and possibly constant-folded value of the expression.
This simplifies passing of the expressions to functions.
Changes the shaders with following patterns:
{ // Stage 0: Linear Gradient
vec4 colorTemp = mix(uGradientStartColor_Stage0, uGradientEndColor_Stage0, clamp(vMatrixCoord_Stage0.x, 0.0, 1
colorTemp.rgb *= colorTemp.a;
- output_Stage0 = vec4((vColor) * (colorTemp));
+ output_Stage0 = (vColor * colorTemp);
+ }
Previously the vector cast was always added if constant folding was
effective, regardless of the term dimensions. Now the vector upcast is
not inserted in places where it is not needed, ie. when the binary
operator term is of the target dimension.
Also, some parentheses can be omitted. It is assumed that
GrGLSLExpr<N>("string") constructors construct a simple expression or
parenthesized expression.
Otherwise the shader code remains identical.
R=jvanverth@google.com, bsalomon@google.com, robertphillips@google.com
Author: kkinnunen@nvidia.com
Review URL: https://codereview.chromium.org/25048002
git-svn-id: http://skia.googlecode.com/svn/trunk@11690 2bbb7eff-a529-9590-31e7-b0007b416f81
2013-10-10 06:30:18 +00:00
|
|
|
builder->fsCodeAppendf("\t\tconst vec4 ones = vec4(1);\n");
|
2013-04-19 15:03:21 +00:00
|
|
|
inputColor = "ones";
|
|
|
|
}
|
2013-04-22 21:05:48 +00:00
|
|
|
builder->fsCodeAppendf("\t\t// SkXfermode::Mode: %s\n", SkXfermode::ModeName(mode));
|
|
|
|
|
2013-04-19 15:03:21 +00:00
|
|
|
// These all perform src-over on the alpha channel.
|
|
|
|
builder->fsCodeAppendf("\t\t%s.a = %s.a + (1.0 - %s.a) * %s.a;\n",
|
|
|
|
outputColor, inputColor, inputColor, dstColor);
|
|
|
|
|
2013-04-22 21:05:48 +00:00
|
|
|
switch (mode) {
|
2013-04-19 15:03:21 +00:00
|
|
|
case SkXfermode::kOverlay_Mode:
|
|
|
|
// Overlay is Hard-Light with the src and dst reversed
|
|
|
|
HardLight(builder, outputColor, dstColor, inputColor);
|
|
|
|
break;
|
|
|
|
case SkXfermode::kDarken_Mode:
|
|
|
|
builder->fsCodeAppendf("\t\t%s.rgb = min((1.0 - %s.a) * %s.rgb + %s.rgb, "
|
|
|
|
"(1.0 - %s.a) * %s.rgb + %s.rgb);\n",
|
|
|
|
outputColor,
|
|
|
|
inputColor, dstColor, inputColor,
|
|
|
|
dstColor, inputColor, dstColor);
|
|
|
|
break;
|
|
|
|
case SkXfermode::kLighten_Mode:
|
|
|
|
builder->fsCodeAppendf("\t\t%s.rgb = max((1.0 - %s.a) * %s.rgb + %s.rgb, "
|
|
|
|
"(1.0 - %s.a) * %s.rgb + %s.rgb);\n",
|
|
|
|
outputColor,
|
|
|
|
inputColor, dstColor, inputColor,
|
|
|
|
dstColor, inputColor, dstColor);
|
|
|
|
break;
|
|
|
|
case SkXfermode::kColorDodge_Mode:
|
|
|
|
ColorDodgeComponent(builder, outputColor, inputColor, dstColor, 'r');
|
|
|
|
ColorDodgeComponent(builder, outputColor, inputColor, dstColor, 'g');
|
|
|
|
ColorDodgeComponent(builder, outputColor, inputColor, dstColor, 'b');
|
|
|
|
break;
|
|
|
|
case SkXfermode::kColorBurn_Mode:
|
|
|
|
ColorBurnComponent(builder, outputColor, inputColor, dstColor, 'r');
|
|
|
|
ColorBurnComponent(builder, outputColor, inputColor, dstColor, 'g');
|
|
|
|
ColorBurnComponent(builder, outputColor, inputColor, dstColor, 'b');
|
|
|
|
break;
|
|
|
|
case SkXfermode::kHardLight_Mode:
|
|
|
|
HardLight(builder, outputColor, inputColor, dstColor);
|
|
|
|
break;
|
|
|
|
case SkXfermode::kSoftLight_Mode:
|
|
|
|
builder->fsCodeAppendf("\t\tif (0.0 == %s.a) {\n", dstColor);
|
|
|
|
builder->fsCodeAppendf("\t\t\t%s.rgba = %s;\n", outputColor, inputColor);
|
|
|
|
builder->fsCodeAppendf("\t\t} else {\n");
|
|
|
|
SoftLightComponentPosDstAlpha(builder, outputColor, inputColor, dstColor, 'r');
|
|
|
|
SoftLightComponentPosDstAlpha(builder, outputColor, inputColor, dstColor, 'g');
|
|
|
|
SoftLightComponentPosDstAlpha(builder, outputColor, inputColor, dstColor, 'b');
|
|
|
|
builder->fsCodeAppendf("\t\t}\n");
|
|
|
|
break;
|
|
|
|
case SkXfermode::kDifference_Mode:
|
|
|
|
builder->fsCodeAppendf("\t\t%s.rgb = %s.rgb + %s.rgb -"
|
2013-04-20 07:01:07 +00:00
|
|
|
"2.0 * min(%s.rgb * %s.a, %s.rgb * %s.a);\n",
|
2013-04-19 15:03:21 +00:00
|
|
|
outputColor, inputColor, dstColor, inputColor, dstColor,
|
|
|
|
dstColor, inputColor);
|
|
|
|
break;
|
|
|
|
case SkXfermode::kExclusion_Mode:
|
|
|
|
builder->fsCodeAppendf("\t\t%s.rgb = %s.rgb + %s.rgb - "
|
|
|
|
"2.0 * %s.rgb * %s.rgb;\n",
|
|
|
|
outputColor, dstColor, inputColor, dstColor, inputColor);
|
|
|
|
break;
|
|
|
|
case SkXfermode::kMultiply_Mode:
|
|
|
|
builder->fsCodeAppendf("\t\t%s.rgb = (1.0 - %s.a) * %s.rgb + "
|
|
|
|
"(1.0 - %s.a) * %s.rgb + "
|
|
|
|
"%s.rgb * %s.rgb;\n",
|
|
|
|
outputColor, inputColor, dstColor, dstColor, inputColor,
|
|
|
|
inputColor, dstColor);
|
|
|
|
break;
|
2013-04-22 21:05:48 +00:00
|
|
|
case SkXfermode::kHue_Mode: {
|
|
|
|
// SetLum(SetSat(S * Da, Sat(D * Sa)), Sa*Da, D*Sa) + (1 - Sa) * D + (1 - Da) * S
|
|
|
|
SkString setSat, setLum;
|
|
|
|
AddSatFunction(builder, &setSat);
|
|
|
|
AddLumFunction(builder, &setLum);
|
|
|
|
builder->fsCodeAppendf("\t\tvec4 dstSrcAlpha = %s * %s.a;\n",
|
|
|
|
dstColor, inputColor);
|
|
|
|
builder->fsCodeAppendf("\t\t%s.rgb = %s(%s(%s.rgb * %s.a, dstSrcAlpha.rgb), dstSrcAlpha.a, dstSrcAlpha.rgb);\n",
|
|
|
|
outputColor, setLum.c_str(), setSat.c_str(), inputColor,
|
|
|
|
dstColor);
|
|
|
|
builder->fsCodeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n",
|
|
|
|
outputColor, inputColor, dstColor, dstColor, inputColor);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SkXfermode::kSaturation_Mode: {
|
|
|
|
// SetLum(SetSat(D * Sa, Sat(S * Da)), Sa*Da, D*Sa)) + (1 - Sa) * D + (1 - Da) * S
|
|
|
|
SkString setSat, setLum;
|
|
|
|
AddSatFunction(builder, &setSat);
|
|
|
|
AddLumFunction(builder, &setLum);
|
|
|
|
builder->fsCodeAppendf("\t\tvec4 dstSrcAlpha = %s * %s.a;\n",
|
|
|
|
dstColor, inputColor);
|
|
|
|
builder->fsCodeAppendf("\t\t%s.rgb = %s(%s(dstSrcAlpha.rgb, %s.rgb * %s.a), dstSrcAlpha.a, dstSrcAlpha.rgb);\n",
|
|
|
|
outputColor, setLum.c_str(), setSat.c_str(), inputColor,
|
|
|
|
dstColor);
|
|
|
|
builder->fsCodeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n",
|
|
|
|
outputColor, inputColor, dstColor, dstColor, inputColor);
|
2013-04-19 15:03:21 +00:00
|
|
|
break;
|
2013-04-22 21:05:48 +00:00
|
|
|
}
|
|
|
|
case SkXfermode::kColor_Mode: {
|
|
|
|
// SetLum(S * Da, Sa* Da, D * Sa) + (1 - Sa) * D + (1 - Da) * S
|
|
|
|
SkString setLum;
|
|
|
|
AddLumFunction(builder, &setLum);
|
|
|
|
builder->fsCodeAppendf("\t\tvec4 srcDstAlpha = %s * %s.a;\n",
|
|
|
|
inputColor, dstColor);
|
|
|
|
builder->fsCodeAppendf("\t\t%s.rgb = %s(srcDstAlpha.rgb, srcDstAlpha.a, %s.rgb * %s.a);\n",
|
|
|
|
outputColor, setLum.c_str(), dstColor, inputColor);
|
|
|
|
builder->fsCodeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n",
|
|
|
|
outputColor, inputColor, dstColor, dstColor, inputColor);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SkXfermode::kLuminosity_Mode: {
|
|
|
|
// SetLum(D * Sa, Sa* Da, S * Da) + (1 - Sa) * D + (1 - Da) * S
|
|
|
|
SkString setLum;
|
|
|
|
AddLumFunction(builder, &setLum);
|
|
|
|
builder->fsCodeAppendf("\t\tvec4 srcDstAlpha = %s * %s.a;\n",
|
|
|
|
inputColor, dstColor);
|
|
|
|
builder->fsCodeAppendf("\t\t%s.rgb = %s(%s.rgb * %s.a, srcDstAlpha.a, srcDstAlpha.rgb);\n",
|
|
|
|
outputColor, setLum.c_str(), dstColor, inputColor);
|
|
|
|
builder->fsCodeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n",
|
|
|
|
outputColor, inputColor, dstColor, dstColor, inputColor);
|
|
|
|
break;
|
|
|
|
}
|
2013-04-19 15:03:21 +00:00
|
|
|
default:
|
2014-04-30 14:17:00 +00:00
|
|
|
SkFAIL("Unknown XferEffect mode.");
|
2013-04-19 15:03:21 +00:00
|
|
|
break;
|
2013-03-29 20:30:50 +00:00
|
|
|
}
|
2013-03-29 19:22:36 +00:00
|
|
|
}
|
|
|
|
|
2013-04-19 15:03:21 +00:00
|
|
|
static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
|
2014-04-07 17:13:10 +00:00
|
|
|
// The background may come from the dst or from a texture.
|
2014-07-07 18:54:23 +00:00
|
|
|
int numTextures = drawEffect.effect()->numTextures();
|
2014-04-07 17:13:10 +00:00
|
|
|
SkASSERT(numTextures <= 1);
|
|
|
|
return (drawEffect.castEffect<XferEffect>().mode() << 1) | numTextures;
|
2013-05-31 17:49:12 +00:00
|
|
|
}
|
2013-03-29 19:22:36 +00:00
|
|
|
|
|
|
|
private:
|
2013-04-19 15:03:21 +00:00
|
|
|
static void HardLight(GrGLShaderBuilder* builder,
|
|
|
|
const char* final,
|
|
|
|
const char* src,
|
|
|
|
const char* dst) {
|
2013-04-29 17:40:33 +00:00
|
|
|
static const char kComponents[] = {'r', 'g', 'b'};
|
|
|
|
for (size_t i = 0; i < SK_ARRAY_COUNT(kComponents); ++i) {
|
|
|
|
char component = kComponents[i];
|
|
|
|
builder->fsCodeAppendf("\t\tif (2.0 * %s.%c <= %s.a) {\n", src, component, src);
|
|
|
|
builder->fsCodeAppendf("\t\t\t%s.%c = 2.0 * %s.%c * %s.%c;\n", final, component, src, component, dst, component);
|
|
|
|
builder->fsCodeAppend("\t\t} else {\n");
|
|
|
|
builder->fsCodeAppendf("\t\t\t%s.%c = %s.a * %s.a - 2.0 * (%s.a - %s.%c) * (%s.a - %s.%c);\n",
|
|
|
|
final, component, src, dst, dst, dst, component, src, src, component);
|
|
|
|
builder->fsCodeAppend("\t\t}\n");
|
|
|
|
}
|
2013-04-19 15:03:21 +00:00
|
|
|
builder->fsCodeAppendf("\t\t%s.rgb += %s.rgb * (1.0 - %s.a) + %s.rgb * (1.0 - %s.a);\n",
|
|
|
|
final, src, dst, dst, src);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Does one component of color-dodge
|
|
|
|
static void ColorDodgeComponent(GrGLShaderBuilder* builder,
|
|
|
|
const char* final,
|
|
|
|
const char* src,
|
|
|
|
const char* dst,
|
|
|
|
const char component) {
|
|
|
|
builder->fsCodeAppendf("\t\tif (0.0 == %s.%c) {\n", dst, component);
|
2013-04-19 16:20:20 +00:00
|
|
|
builder->fsCodeAppendf("\t\t\t%s.%c = %s.%c * (1.0 - %s.a);\n",
|
2013-04-19 15:03:21 +00:00
|
|
|
final, component, src, component, dst);
|
|
|
|
builder->fsCodeAppend("\t\t} else {\n");
|
|
|
|
builder->fsCodeAppendf("\t\t\tfloat d = %s.a - %s.%c;\n", src, src, component);
|
2013-04-19 17:21:49 +00:00
|
|
|
builder->fsCodeAppend("\t\t\tif (0.0 == d) {\n");
|
2013-04-19 15:03:21 +00:00
|
|
|
builder->fsCodeAppendf("\t\t\t\t%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);\n",
|
|
|
|
final, component, src, dst, src, component, dst, dst, component,
|
|
|
|
src);
|
|
|
|
builder->fsCodeAppend("\t\t\t} else {\n");
|
|
|
|
builder->fsCodeAppendf("\t\t\t\td = min(%s.a, %s.%c * %s.a / d);\n",
|
|
|
|
dst, dst, component, src);
|
|
|
|
builder->fsCodeAppendf("\t\t\t\t%s.%c = d * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);\n",
|
|
|
|
final, component, src, src, component, dst, dst, component, src);
|
|
|
|
builder->fsCodeAppend("\t\t\t}\n");
|
|
|
|
builder->fsCodeAppend("\t\t}\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Does one component of color-burn
|
|
|
|
static void ColorBurnComponent(GrGLShaderBuilder* builder,
|
|
|
|
const char* final,
|
|
|
|
const char* src,
|
|
|
|
const char* dst,
|
|
|
|
const char component) {
|
|
|
|
builder->fsCodeAppendf("\t\tif (%s.a == %s.%c) {\n", dst, dst, component);
|
|
|
|
builder->fsCodeAppendf("\t\t\t%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);\n",
|
|
|
|
final, component, src, dst, src, component, dst, dst, component,
|
|
|
|
src);
|
|
|
|
builder->fsCodeAppendf("\t\t} else if (0.0 == %s.%c) {\n", src, component);
|
|
|
|
builder->fsCodeAppendf("\t\t\t%s.%c = %s.%c * (1.0 - %s.a);\n",
|
|
|
|
final, component, dst, component, src);
|
|
|
|
builder->fsCodeAppend("\t\t} else {\n");
|
|
|
|
builder->fsCodeAppendf("\t\t\tfloat d = max(0.0, %s.a - (%s.a - %s.%c) * %s.a / %s.%c);\n",
|
|
|
|
dst, dst, dst, component, src, src, component);
|
|
|
|
builder->fsCodeAppendf("\t\t\t%s.%c = %s.a * d + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);\n",
|
|
|
|
final, component, src, src, component, dst, dst, component, src);
|
|
|
|
builder->fsCodeAppend("\t\t}\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Does one component of soft-light. Caller should have already checked that dst alpha > 0.
|
|
|
|
static void SoftLightComponentPosDstAlpha(GrGLShaderBuilder* builder,
|
|
|
|
const char* final,
|
|
|
|
const char* src,
|
|
|
|
const char* dst,
|
|
|
|
const char component) {
|
|
|
|
// if (2S < Sa)
|
|
|
|
builder->fsCodeAppendf("\t\t\tif (2.0 * %s.%c <= %s.a) {\n", src, component, src);
|
|
|
|
// (D^2 (Sa-2 S))/Da+(1-Da) S+D (-Sa+2 S+1)
|
2013-04-19 18:10:50 +00:00
|
|
|
builder->fsCodeAppendf("\t\t\t\t%s.%c = (%s.%c*%s.%c*(%s.a - 2.0*%s.%c)) / %s.a + (1.0 - %s.a) * %s.%c + %s.%c*(-%s.a + 2.0*%s.%c + 1.0);\n",
|
2013-04-19 15:03:21 +00:00
|
|
|
final, component, dst, component, dst, component, src, src,
|
|
|
|
component, dst, dst, src, component, dst, component, src, src,
|
|
|
|
component);
|
|
|
|
// else if (4D < Da)
|
|
|
|
builder->fsCodeAppendf("\t\t\t} else if (4.0 * %s.%c <= %s.a) {\n",
|
|
|
|
dst, component, dst);
|
|
|
|
builder->fsCodeAppendf("\t\t\t\tfloat DSqd = %s.%c * %s.%c;\n",
|
|
|
|
dst, component, dst, component);
|
|
|
|
builder->fsCodeAppendf("\t\t\t\tfloat DCub = DSqd * %s.%c;\n", dst, component);
|
|
|
|
builder->fsCodeAppendf("\t\t\t\tfloat DaSqd = %s.a * %s.a;\n", dst, dst);
|
|
|
|
builder->fsCodeAppendf("\t\t\t\tfloat DaCub = DaSqd * %s.a;\n", dst);
|
|
|
|
// (Da^3 (-S)+Da^2 (S-D (3 Sa-6 S-1))+12 Da D^2 (Sa-2 S)-16 D^3 (Sa-2 S))/Da^2
|
2013-04-19 18:10:50 +00:00
|
|
|
builder->fsCodeAppendf("\t\t\t\t%s.%c = (-DaCub*%s.%c + DaSqd*(%s.%c - %s.%c * (3.0*%s.a - 6.0*%s.%c - 1.0)) + 12.0*%s.a*DSqd*(%s.a - 2.0*%s.%c) - 16.0*DCub * (%s.a - 2.0*%s.%c)) / DaSqd;\n",
|
2013-04-19 15:03:21 +00:00
|
|
|
final, component, src, component, src, component, dst, component,
|
|
|
|
src, src, component, dst, src, src, component, src, src,
|
|
|
|
component);
|
|
|
|
builder->fsCodeAppendf("\t\t\t} else {\n");
|
|
|
|
// -sqrt(Da * D) (Sa-2 S)-Da S+D (Sa-2 S+1)+S
|
2013-04-19 18:10:50 +00:00
|
|
|
builder->fsCodeAppendf("\t\t\t\t%s.%c = -sqrt(%s.a*%s.%c)*(%s.a - 2.0*%s.%c) - %s.a*%s.%c + %s.%c*(%s.a - 2.0*%s.%c + 1.0) + %s.%c;\n",
|
2013-04-19 15:03:21 +00:00
|
|
|
final, component, dst, dst, component, src, src, component, dst,
|
|
|
|
src, component, dst, component, src, src, component, src,
|
|
|
|
component);
|
|
|
|
builder->fsCodeAppendf("\t\t\t}\n");
|
|
|
|
}
|
|
|
|
|
2013-04-22 21:05:48 +00:00
|
|
|
// Adds a function that takes two colors and an alpha as input. It produces a color with the
|
|
|
|
// hue and saturation of the first color, the luminosity of the second color, and the input
|
|
|
|
// alpha. It has this signature:
|
|
|
|
// vec3 set_luminance(vec3 hueSatColor, float alpha, vec3 lumColor).
|
|
|
|
static void AddLumFunction(GrGLShaderBuilder* builder, SkString* setLumFunction) {
|
|
|
|
// Emit a helper that gets the luminance of a color.
|
|
|
|
SkString getFunction;
|
|
|
|
GrGLShaderVar getLumArgs[] = {
|
|
|
|
GrGLShaderVar("color", kVec3f_GrSLType),
|
|
|
|
};
|
|
|
|
SkString getLumBody("\treturn dot(vec3(0.3, 0.59, 0.11), color);\n");
|
2013-08-30 19:43:59 +00:00
|
|
|
builder->fsEmitFunction(kFloat_GrSLType,
|
|
|
|
"luminance",
|
|
|
|
SK_ARRAY_COUNT(getLumArgs), getLumArgs,
|
|
|
|
getLumBody.c_str(),
|
|
|
|
&getFunction);
|
2013-04-22 21:05:48 +00:00
|
|
|
|
|
|
|
// Emit the set luminance function.
|
|
|
|
GrGLShaderVar setLumArgs[] = {
|
|
|
|
GrGLShaderVar("hueSat", kVec3f_GrSLType),
|
|
|
|
GrGLShaderVar("alpha", kFloat_GrSLType),
|
|
|
|
GrGLShaderVar("lumColor", kVec3f_GrSLType),
|
|
|
|
};
|
|
|
|
SkString setLumBody;
|
|
|
|
setLumBody.printf("\tfloat diff = %s(lumColor - hueSat);\n", getFunction.c_str());
|
|
|
|
setLumBody.append("\tvec3 outColor = hueSat + diff;\n");
|
|
|
|
setLumBody.appendf("\tfloat outLum = %s(outColor);\n", getFunction.c_str());
|
|
|
|
setLumBody.append("\tfloat minComp = min(min(outColor.r, outColor.g), outColor.b);\n"
|
|
|
|
"\tfloat maxComp = max(max(outColor.r, outColor.g), outColor.b);\n"
|
|
|
|
"\tif (minComp < 0.0) {\n"
|
|
|
|
"\t\toutColor = outLum + ((outColor - vec3(outLum, outLum, outLum)) * outLum) / (outLum - minComp);\n"
|
|
|
|
"\t}\n"
|
|
|
|
"\tif (maxComp > alpha) {\n"
|
|
|
|
"\t\toutColor = outLum + ((outColor - vec3(outLum, outLum, outLum)) * (alpha - outLum)) / (maxComp - outLum);\n"
|
|
|
|
"\t}\n"
|
|
|
|
"\treturn outColor;\n");
|
2013-08-30 19:43:59 +00:00
|
|
|
builder->fsEmitFunction(kVec3f_GrSLType,
|
|
|
|
"set_luminance",
|
|
|
|
SK_ARRAY_COUNT(setLumArgs), setLumArgs,
|
|
|
|
setLumBody.c_str(),
|
|
|
|
setLumFunction);
|
2013-04-22 21:05:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Adds a function that creates a color with the hue and luminosity of one input color and
|
|
|
|
// the saturation of another color. It will have this signature:
|
|
|
|
// float set_saturation(vec3 hueLumColor, vec3 satColor)
|
|
|
|
static void AddSatFunction(GrGLShaderBuilder* builder, SkString* setSatFunction) {
|
|
|
|
// Emit a helper that gets the saturation of a color
|
|
|
|
SkString getFunction;
|
|
|
|
GrGLShaderVar getSatArgs[] = { GrGLShaderVar("color", kVec3f_GrSLType) };
|
|
|
|
SkString getSatBody;
|
|
|
|
getSatBody.printf("\treturn max(max(color.r, color.g), color.b) - "
|
|
|
|
"min(min(color.r, color.g), color.b);\n");
|
2013-08-30 19:43:59 +00:00
|
|
|
builder->fsEmitFunction(kFloat_GrSLType,
|
|
|
|
"saturation",
|
|
|
|
SK_ARRAY_COUNT(getSatArgs), getSatArgs,
|
|
|
|
getSatBody.c_str(),
|
|
|
|
&getFunction);
|
2013-04-22 21:05:48 +00:00
|
|
|
|
2013-04-29 17:36:14 +00:00
|
|
|
// Emit a helper that sets the saturation given sorted input channels. This used
|
|
|
|
// to use inout params for min, mid, and max components but that seems to cause
|
|
|
|
// problems on PowerVR drivers. So instead it returns a vec3 where r, g ,b are the
|
|
|
|
// adjusted min, mid, and max inputs, respectively.
|
2013-04-22 21:05:48 +00:00
|
|
|
SkString helperFunction;
|
|
|
|
GrGLShaderVar helperArgs[] = {
|
|
|
|
GrGLShaderVar("minComp", kFloat_GrSLType),
|
|
|
|
GrGLShaderVar("midComp", kFloat_GrSLType),
|
|
|
|
GrGLShaderVar("maxComp", kFloat_GrSLType),
|
|
|
|
GrGLShaderVar("sat", kFloat_GrSLType),
|
|
|
|
};
|
2013-04-29 17:36:14 +00:00
|
|
|
static const char kHelperBody[] = "\tif (minComp < maxComp) {\n"
|
|
|
|
"\t\tvec3 result;\n"
|
|
|
|
"\t\tresult.r = 0.0;\n"
|
|
|
|
"\t\tresult.g = sat * (midComp - minComp) / (maxComp - minComp);\n"
|
|
|
|
"\t\tresult.b = sat;\n"
|
|
|
|
"\t\treturn result;\n"
|
|
|
|
"\t} else {\n"
|
|
|
|
"\t\treturn vec3(0, 0, 0);\n"
|
|
|
|
"\t}\n";
|
2013-08-30 19:43:59 +00:00
|
|
|
builder->fsEmitFunction(kVec3f_GrSLType,
|
|
|
|
"set_saturation_helper",
|
|
|
|
SK_ARRAY_COUNT(helperArgs), helperArgs,
|
|
|
|
kHelperBody,
|
|
|
|
&helperFunction);
|
2013-04-22 21:05:48 +00:00
|
|
|
|
|
|
|
GrGLShaderVar setSatArgs[] = {
|
|
|
|
GrGLShaderVar("hueLumColor", kVec3f_GrSLType),
|
|
|
|
GrGLShaderVar("satColor", kVec3f_GrSLType),
|
|
|
|
};
|
|
|
|
const char* helpFunc = helperFunction.c_str();
|
|
|
|
SkString setSatBody;
|
|
|
|
setSatBody.appendf("\tfloat sat = %s(satColor);\n"
|
|
|
|
"\tif (hueLumColor.r <= hueLumColor.g) {\n"
|
|
|
|
"\t\tif (hueLumColor.g <= hueLumColor.b) {\n"
|
2013-04-29 17:36:14 +00:00
|
|
|
"\t\t\thueLumColor.rgb = %s(hueLumColor.r, hueLumColor.g, hueLumColor.b, sat);\n"
|
2013-04-25 00:40:41 +00:00
|
|
|
"\t\t} else if (hueLumColor.r <= hueLumColor.b) {\n"
|
2013-04-29 17:36:14 +00:00
|
|
|
"\t\t\thueLumColor.rbg = %s(hueLumColor.r, hueLumColor.b, hueLumColor.g, sat);\n"
|
2013-04-25 00:40:41 +00:00
|
|
|
"\t\t} else {\n"
|
2013-04-29 17:36:14 +00:00
|
|
|
"\t\t\thueLumColor.brg = %s(hueLumColor.b, hueLumColor.r, hueLumColor.g, sat);\n"
|
2013-04-22 21:05:48 +00:00
|
|
|
"\t\t}\n"
|
|
|
|
"\t} else if (hueLumColor.r <= hueLumColor.b) {\n"
|
2013-04-29 17:36:14 +00:00
|
|
|
"\t\thueLumColor.grb = %s(hueLumColor.g, hueLumColor.r, hueLumColor.b, sat);\n"
|
2013-04-22 21:05:48 +00:00
|
|
|
"\t} else if (hueLumColor.g <= hueLumColor.b) {\n"
|
2013-04-29 17:36:14 +00:00
|
|
|
"\t\thueLumColor.gbr = %s(hueLumColor.g, hueLumColor.b, hueLumColor.r, sat);\n"
|
2013-04-22 21:05:48 +00:00
|
|
|
"\t} else {\n"
|
2013-04-29 17:36:14 +00:00
|
|
|
"\t\thueLumColor.bgr = %s(hueLumColor.b, hueLumColor.g, hueLumColor.r, sat);\n"
|
2013-04-22 21:05:48 +00:00
|
|
|
"\t}\n"
|
2013-04-29 17:36:14 +00:00
|
|
|
"\treturn hueLumColor;\n",
|
2013-04-25 00:40:41 +00:00
|
|
|
getFunction.c_str(), helpFunc, helpFunc, helpFunc, helpFunc,
|
|
|
|
helpFunc, helpFunc);
|
2013-08-30 19:43:59 +00:00
|
|
|
builder->fsEmitFunction(kVec3f_GrSLType,
|
|
|
|
"set_saturation",
|
|
|
|
SK_ARRAY_COUNT(setSatArgs), setSatArgs,
|
|
|
|
setSatBody.c_str(),
|
|
|
|
setSatFunction);
|
2013-04-22 21:05:48 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2013-03-29 19:22:36 +00:00
|
|
|
typedef GrGLEffect INHERITED;
|
|
|
|
};
|
|
|
|
|
|
|
|
GR_DECLARE_EFFECT_TEST;
|
|
|
|
|
|
|
|
private:
|
2013-05-31 17:49:12 +00:00
|
|
|
XferEffect(SkXfermode::Mode mode, GrTexture* background)
|
|
|
|
: fMode(mode) {
|
|
|
|
if (background) {
|
2013-10-02 13:04:56 +00:00
|
|
|
fBackgroundTransform.reset(kLocal_GrCoordSet, background);
|
|
|
|
this->addCoordTransform(&fBackgroundTransform);
|
2013-05-31 17:49:12 +00:00
|
|
|
fBackgroundAccess.reset(background);
|
|
|
|
this->addTextureAccess(&fBackgroundAccess);
|
|
|
|
} else {
|
|
|
|
this->setWillReadDstColor();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
|
|
|
|
const XferEffect& s = CastEffect<XferEffect>(other);
|
|
|
|
return fMode == s.fMode &&
|
|
|
|
fBackgroundAccess.getTexture() == s.fBackgroundAccess.getTexture();
|
|
|
|
}
|
2013-04-20 07:01:07 +00:00
|
|
|
|
2013-04-19 15:03:21 +00:00
|
|
|
SkXfermode::Mode fMode;
|
2013-10-02 13:04:56 +00:00
|
|
|
GrCoordTransform fBackgroundTransform;
|
2013-05-31 17:49:12 +00:00
|
|
|
GrTextureAccess fBackgroundAccess;
|
2013-03-29 19:22:36 +00:00
|
|
|
|
|
|
|
typedef GrEffect INHERITED;
|
|
|
|
};
|
|
|
|
|
2013-04-19 15:03:21 +00:00
|
|
|
GR_DEFINE_EFFECT_TEST(XferEffect);
|
2013-09-09 20:09:12 +00:00
|
|
|
GrEffectRef* XferEffect::TestCreate(SkRandom* rand,
|
2013-04-19 15:03:21 +00:00
|
|
|
GrContext*,
|
|
|
|
const GrDrawTargetCaps&,
|
|
|
|
GrTexture*[]) {
|
2013-04-29 17:40:33 +00:00
|
|
|
int mode = rand->nextRangeU(SkXfermode::kLastCoeffMode + 1, SkXfermode::kLastSeparableMode);
|
2013-04-26 07:00:58 +00:00
|
|
|
|
2013-10-24 13:33:32 +00:00
|
|
|
AutoEffectUnref gEffect(SkNEW_ARGS(XferEffect, (static_cast<SkXfermode::Mode>(mode), NULL)));
|
2013-03-29 19:22:36 +00:00
|
|
|
return CreateEffectRef(gEffect);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2011-02-08 19:28:07 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2009-06-22 17:38:10 +00:00
|
|
|
|
2014-01-30 18:58:24 +00:00
|
|
|
SkProcCoeffXfermode::SkProcCoeffXfermode(SkReadBuffer& buffer) : INHERITED(buffer) {
|
2013-11-21 21:05:06 +00:00
|
|
|
uint32_t mode32 = buffer.read32() % SK_ARRAY_COUNT(gProcCoeffs);
|
|
|
|
if (mode32 >= SK_ARRAY_COUNT(gProcCoeffs)) {
|
|
|
|
// out of range, just set to something harmless
|
|
|
|
mode32 = SkXfermode::kSrcOut_Mode;
|
|
|
|
}
|
|
|
|
fMode = (SkXfermode::Mode)mode32;
|
2013-11-22 07:02:24 +00:00
|
|
|
|
2013-11-21 21:05:06 +00:00
|
|
|
const ProcCoeff& rec = gProcCoeffs[fMode];
|
2014-04-17 15:19:32 +00:00
|
|
|
fProc = rec.fProc;
|
2013-11-21 21:05:06 +00:00
|
|
|
// these may be valid, or may be CANNOT_USE_COEFF
|
|
|
|
fSrcCoeff = rec.fSC;
|
|
|
|
fDstCoeff = rec.fDC;
|
|
|
|
}
|
|
|
|
|
2013-10-09 14:39:46 +00:00
|
|
|
bool SkProcCoeffXfermode::asMode(Mode* mode) const {
|
|
|
|
if (mode) {
|
|
|
|
*mode = fMode;
|
2011-02-08 19:28:07 +00:00
|
|
|
}
|
2013-10-09 14:39:46 +00:00
|
|
|
return true;
|
|
|
|
}
|
2011-04-13 21:12:04 +00:00
|
|
|
|
2013-10-09 14:39:46 +00:00
|
|
|
bool SkProcCoeffXfermode::asCoeff(Coeff* sc, Coeff* dc) const {
|
|
|
|
if (CANNOT_USE_COEFF == fSrcCoeff) {
|
|
|
|
return false;
|
2011-04-13 21:12:04 +00:00
|
|
|
}
|
|
|
|
|
2013-10-09 14:39:46 +00:00
|
|
|
if (sc) {
|
|
|
|
*sc = fSrcCoeff;
|
|
|
|
}
|
|
|
|
if (dc) {
|
|
|
|
*dc = fDstCoeff;
|
2013-10-08 16:47:22 +00:00
|
|
|
}
|
2013-10-09 14:39:46 +00:00
|
|
|
return true;
|
|
|
|
}
|
2013-10-08 16:59:53 +00:00
|
|
|
|
2014-04-17 15:19:32 +00:00
|
|
|
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);
|
2014-04-18 03:03:54 +00:00
|
|
|
|
2014-04-17 15:19:32 +00:00
|
|
|
SkXfermodeProc proc = fProc;
|
2014-04-18 03:03:54 +00:00
|
|
|
|
2014-04-17 15:19:32 +00:00
|
|
|
if (NULL != proc) {
|
|
|
|
if (NULL == 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SkProcCoeffXfermode::xfer16(uint16_t* SK_RESTRICT dst,
|
|
|
|
const SkPMColor* SK_RESTRICT src, int count,
|
|
|
|
const SkAlpha* SK_RESTRICT aa) const {
|
|
|
|
SkASSERT(dst && src && count >= 0);
|
2014-04-18 03:03:54 +00:00
|
|
|
|
2014-04-17 15:19:32 +00:00
|
|
|
SkXfermodeProc proc = fProc;
|
2014-04-18 03:03:54 +00:00
|
|
|
|
2014-04-17 15:19:32 +00:00
|
|
|
if (NULL != proc) {
|
|
|
|
if (NULL == aa) {
|
|
|
|
for (int i = count - 1; i >= 0; --i) {
|
|
|
|
SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
|
|
|
|
dst[i] = SkPixel32ToPixel16_ToU16(proc(src[i], dstC));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (int i = count - 1; i >= 0; --i) {
|
|
|
|
unsigned a = aa[i];
|
|
|
|
if (0 != a) {
|
|
|
|
SkPMColor dstC = SkPixel16ToPixel32(dst[i]);
|
|
|
|
SkPMColor C = proc(src[i], dstC);
|
|
|
|
if (0xFF != a) {
|
|
|
|
C = SkFourByteInterp(C, dstC, a);
|
|
|
|
}
|
|
|
|
dst[i] = SkPixel32ToPixel16_ToU16(C);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SkProcCoeffXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
|
|
|
|
const SkPMColor* SK_RESTRICT src, int count,
|
|
|
|
const SkAlpha* SK_RESTRICT aa) const {
|
|
|
|
SkASSERT(dst && src && count >= 0);
|
2014-04-18 03:03:54 +00:00
|
|
|
|
2014-04-17 15:19:32 +00:00
|
|
|
SkXfermodeProc proc = fProc;
|
2014-04-18 03:03:54 +00:00
|
|
|
|
2014-04-17 15:19:32 +00:00
|
|
|
if (NULL != proc) {
|
|
|
|
if (NULL == aa) {
|
|
|
|
for (int i = count - 1; i >= 0; --i) {
|
|
|
|
SkPMColor res = proc(src[i], dst[i] << SK_A32_SHIFT);
|
|
|
|
dst[i] = SkToU8(SkGetPackedA32(res));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (int i = count - 1; i >= 0; --i) {
|
|
|
|
unsigned a = aa[i];
|
|
|
|
if (0 != a) {
|
|
|
|
SkAlpha dstA = dst[i];
|
|
|
|
SkPMColor res = proc(src[i], dstA << SK_A32_SHIFT);
|
|
|
|
unsigned A = SkGetPackedA32(res);
|
|
|
|
if (0xFF != a) {
|
|
|
|
A = SkAlphaBlend(A, dstA, SkAlpha255To256(a));
|
|
|
|
}
|
|
|
|
dst[i] = SkToU8(A);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-08 16:59:53 +00:00
|
|
|
#if SK_SUPPORT_GPU
|
2013-10-23 18:41:36 +00:00
|
|
|
bool SkProcCoeffXfermode::asNewEffect(GrEffectRef** effect,
|
|
|
|
GrTexture* background) const {
|
2013-10-09 14:39:46 +00:00
|
|
|
if (XferEffect::IsSupportedMode(fMode)) {
|
|
|
|
if (NULL != effect) {
|
|
|
|
*effect = XferEffect::Create(fMode, background);
|
|
|
|
SkASSERT(NULL != *effect);
|
2013-10-08 16:59:53 +00:00
|
|
|
}
|
2013-10-09 14:39:46 +00:00
|
|
|
return true;
|
2013-03-27 18:31:15 +00:00
|
|
|
}
|
2013-10-09 14:39:46 +00:00
|
|
|
return false;
|
|
|
|
}
|
2013-03-29 19:22:36 +00:00
|
|
|
#endif
|
2013-03-27 18:31:15 +00:00
|
|
|
|
2014-01-30 18:58:24 +00:00
|
|
|
void SkProcCoeffXfermode::flatten(SkWriteBuffer& buffer) const {
|
2013-10-09 14:39:46 +00:00
|
|
|
this->INHERITED::flatten(buffer);
|
|
|
|
buffer.write32(fMode);
|
|
|
|
}
|
2009-04-24 12:43:40 +00:00
|
|
|
|
2013-04-01 12:51:34 +00:00
|
|
|
const char* SkXfermode::ModeName(Mode mode) {
|
|
|
|
SkASSERT((unsigned) mode <= (unsigned)kLastMode);
|
|
|
|
const char* gModeStrings[] = {
|
2013-01-22 14:32:09 +00:00
|
|
|
"Clear", "Src", "Dst", "SrcOver", "DstOver", "SrcIn", "DstIn",
|
|
|
|
"SrcOut", "DstOut", "SrcATop", "DstATop", "Xor", "Plus",
|
2013-01-30 21:36:11 +00:00
|
|
|
"Modulate", "Screen", "Overlay", "Darken", "Lighten", "ColorDodge",
|
2013-04-01 12:51:34 +00:00
|
|
|
"ColorBurn", "HardLight", "SoftLight", "Difference", "Exclusion",
|
|
|
|
"Multiply", "Hue", "Saturation", "Color", "Luminosity"
|
2013-01-22 14:32:09 +00:00
|
|
|
};
|
2013-04-01 12:51:34 +00:00
|
|
|
return gModeStrings[mode];
|
|
|
|
SK_COMPILE_ASSERT(SK_ARRAY_COUNT(gModeStrings) == kLastMode + 1, mode_count);
|
|
|
|
}
|
|
|
|
|
2014-03-13 18:02:17 +00:00
|
|
|
#ifndef SK_IGNORE_TO_STRING
|
2013-04-01 12:51:34 +00:00
|
|
|
void SkProcCoeffXfermode::toString(SkString* str) const {
|
|
|
|
str->append("SkProcCoeffXfermode: ");
|
2013-01-22 14:32:09 +00:00
|
|
|
|
|
|
|
str->append("mode: ");
|
2013-04-01 12:51:34 +00:00
|
|
|
str->append(ModeName(fMode));
|
2013-01-22 14:32:09 +00:00
|
|
|
|
|
|
|
static const char* gCoeffStrings[kCoeffCount] = {
|
2013-01-23 07:06:17 +00:00
|
|
|
"Zero", "One", "SC", "ISC", "DC", "IDC", "SA", "ISA", "DA", "IDA"
|
2013-01-22 14:32:09 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
str->append(" src: ");
|
|
|
|
if (CANNOT_USE_COEFF == fSrcCoeff) {
|
|
|
|
str->append("can't use");
|
|
|
|
} else {
|
|
|
|
str->append(gCoeffStrings[fSrcCoeff]);
|
|
|
|
}
|
|
|
|
|
|
|
|
str->append(" dst: ");
|
|
|
|
if (CANNOT_USE_COEFF == fDstCoeff) {
|
|
|
|
str->append("can't use");
|
|
|
|
} else {
|
|
|
|
str->append(gCoeffStrings[fDstCoeff]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-12-17 15:59:43 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
class SkClearXfermode : public SkProcCoeffXfermode {
|
|
|
|
public:
|
2014-02-20 20:40:19 +00:00
|
|
|
static SkClearXfermode* Create(const ProcCoeff& rec) {
|
|
|
|
return SkNEW_ARGS(SkClearXfermode, (rec));
|
|
|
|
}
|
2008-12-17 15:59:43 +00:00
|
|
|
|
2012-12-17 19:55:24 +00:00
|
|
|
virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
|
|
|
|
virtual void xferA8(SkAlpha*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
|
2008-12-17 15:59:43 +00:00
|
|
|
|
2014-03-13 18:02:17 +00:00
|
|
|
SK_TO_STRING_OVERRIDE()
|
2012-03-26 17:57:35 +00:00
|
|
|
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkClearXfermode)
|
2011-04-27 14:09:52 +00:00
|
|
|
|
|
|
|
private:
|
2014-02-20 20:40:19 +00:00
|
|
|
SkClearXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kClear_Mode) {}
|
2014-01-30 18:58:24 +00:00
|
|
|
SkClearXfermode(SkReadBuffer& buffer)
|
2011-04-27 14:09:52 +00:00
|
|
|
: SkProcCoeffXfermode(buffer) {}
|
|
|
|
|
2013-01-22 14:32:09 +00:00
|
|
|
typedef SkProcCoeffXfermode INHERITED;
|
2008-12-17 15:59:43 +00:00
|
|
|
};
|
|
|
|
|
2011-11-28 15:26:14 +00:00
|
|
|
void SkClearXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
|
|
|
|
const SkPMColor* SK_RESTRICT, int count,
|
2012-12-17 19:55:24 +00:00
|
|
|
const SkAlpha* SK_RESTRICT aa) const {
|
2011-11-28 15:26:14 +00:00
|
|
|
SkASSERT(dst && count >= 0);
|
2008-12-17 15:59:43 +00:00
|
|
|
|
2011-11-28 15:26:14 +00:00
|
|
|
if (NULL == aa) {
|
|
|
|
memset(dst, 0, count << 2);
|
|
|
|
} else {
|
|
|
|
for (int i = count - 1; i >= 0; --i) {
|
|
|
|
unsigned a = aa[i];
|
|
|
|
if (0xFF == a) {
|
|
|
|
dst[i] = 0;
|
|
|
|
} else if (a != 0) {
|
|
|
|
dst[i] = SkAlphaMulQ(dst[i], SkAlpha255To256(255 - a));
|
2008-12-17 15:59:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-11-28 15:26:14 +00:00
|
|
|
}
|
|
|
|
void SkClearXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
|
|
|
|
const SkPMColor* SK_RESTRICT, int count,
|
2012-12-17 19:55:24 +00:00
|
|
|
const SkAlpha* SK_RESTRICT aa) const {
|
2011-11-28 15:26:14 +00:00
|
|
|
SkASSERT(dst && count >= 0);
|
2008-12-17 15:59:43 +00:00
|
|
|
|
2011-11-28 15:26:14 +00:00
|
|
|
if (NULL == aa) {
|
|
|
|
memset(dst, 0, count);
|
|
|
|
} else {
|
|
|
|
for (int i = count - 1; i >= 0; --i) {
|
|
|
|
unsigned a = aa[i];
|
|
|
|
if (0xFF == a) {
|
|
|
|
dst[i] = 0;
|
|
|
|
} else if (0 != a) {
|
|
|
|
dst[i] = SkAlphaMulAlpha(dst[i], 255 - a);
|
2008-12-17 15:59:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-11-28 15:26:14 +00:00
|
|
|
}
|
2011-04-27 14:09:52 +00:00
|
|
|
|
2014-03-13 18:02:17 +00:00
|
|
|
#ifndef SK_IGNORE_TO_STRING
|
2013-01-22 14:32:09 +00:00
|
|
|
void SkClearXfermode::toString(SkString* str) const {
|
|
|
|
this->INHERITED::toString(str);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2011-11-28 15:26:14 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
class SkSrcXfermode : public SkProcCoeffXfermode {
|
|
|
|
public:
|
2014-02-20 20:40:19 +00:00
|
|
|
static SkSrcXfermode* Create(const ProcCoeff& rec) {
|
|
|
|
return SkNEW_ARGS(SkSrcXfermode, (rec));
|
|
|
|
}
|
2011-11-28 15:26:14 +00:00
|
|
|
|
2012-12-17 19:55:24 +00:00
|
|
|
virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
|
|
|
|
virtual void xferA8(SkAlpha*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
|
2008-12-17 15:59:43 +00:00
|
|
|
|
2014-03-13 18:02:17 +00:00
|
|
|
SK_TO_STRING_OVERRIDE()
|
2012-03-26 17:57:35 +00:00
|
|
|
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkSrcXfermode)
|
2011-04-27 14:09:52 +00:00
|
|
|
|
|
|
|
private:
|
2014-02-20 20:40:19 +00:00
|
|
|
SkSrcXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kSrc_Mode) {}
|
2014-01-30 18:58:24 +00:00
|
|
|
SkSrcXfermode(SkReadBuffer& buffer)
|
2011-04-27 14:09:52 +00:00
|
|
|
: SkProcCoeffXfermode(buffer) {}
|
|
|
|
|
2013-01-22 14:32:09 +00:00
|
|
|
typedef SkProcCoeffXfermode INHERITED;
|
2008-12-17 15:59:43 +00:00
|
|
|
};
|
|
|
|
|
2011-11-28 15:26:14 +00:00
|
|
|
void SkSrcXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
|
|
|
|
const SkPMColor* SK_RESTRICT src, int count,
|
2012-12-17 19:55:24 +00:00
|
|
|
const SkAlpha* SK_RESTRICT aa) const {
|
2011-11-28 15:26:14 +00:00
|
|
|
SkASSERT(dst && src && count >= 0);
|
2011-04-27 14:09:52 +00:00
|
|
|
|
2011-11-28 15:26:14 +00:00
|
|
|
if (NULL == aa) {
|
|
|
|
memcpy(dst, src, count << 2);
|
|
|
|
} else {
|
|
|
|
for (int i = count - 1; i >= 0; --i) {
|
|
|
|
unsigned a = aa[i];
|
|
|
|
if (a == 0xFF) {
|
|
|
|
dst[i] = src[i];
|
|
|
|
} else if (a != 0) {
|
|
|
|
dst[i] = SkFourByteInterp(src[i], dst[i], a);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SkSrcXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
|
|
|
|
const SkPMColor* SK_RESTRICT src, int count,
|
2012-12-17 19:55:24 +00:00
|
|
|
const SkAlpha* SK_RESTRICT aa) const {
|
2011-11-28 15:26:14 +00:00
|
|
|
SkASSERT(dst && src && count >= 0);
|
2011-04-27 14:09:52 +00:00
|
|
|
|
2011-11-28 15:26:14 +00:00
|
|
|
if (NULL == aa) {
|
|
|
|
for (int i = count - 1; i >= 0; --i) {
|
|
|
|
dst[i] = SkToU8(SkGetPackedA32(src[i]));
|
2008-12-17 15:59:43 +00:00
|
|
|
}
|
2011-11-28 15:26:14 +00:00
|
|
|
} else {
|
|
|
|
for (int i = count - 1; i >= 0; --i) {
|
|
|
|
unsigned a = aa[i];
|
|
|
|
if (0 != a) {
|
|
|
|
unsigned srcA = SkGetPackedA32(src[i]);
|
|
|
|
if (a == 0xFF) {
|
|
|
|
dst[i] = SkToU8(srcA);
|
|
|
|
} else {
|
|
|
|
dst[i] = SkToU8(SkAlphaBlend(srcA, dst[i], a));
|
|
|
|
}
|
|
|
|
}
|
2008-12-17 15:59:43 +00:00
|
|
|
}
|
|
|
|
}
|
2011-11-28 15:26:14 +00:00
|
|
|
}
|
2014-03-13 18:02:17 +00:00
|
|
|
#ifndef SK_IGNORE_TO_STRING
|
2013-01-22 14:32:09 +00:00
|
|
|
void SkSrcXfermode::toString(SkString* str) const {
|
|
|
|
this->INHERITED::toString(str);
|
|
|
|
}
|
|
|
|
#endif
|
2011-04-27 14:09:52 +00:00
|
|
|
|
2012-12-17 19:55:24 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2011-11-28 15:26:14 +00:00
|
|
|
|
|
|
|
class SkDstInXfermode : public SkProcCoeffXfermode {
|
|
|
|
public:
|
2014-02-20 20:40:19 +00:00
|
|
|
static SkDstInXfermode* Create(const ProcCoeff& rec) {
|
|
|
|
return SkNEW_ARGS(SkDstInXfermode, (rec));
|
|
|
|
}
|
2011-11-28 15:26:14 +00:00
|
|
|
|
2012-12-17 19:55:24 +00:00
|
|
|
virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
|
2011-04-27 14:09:52 +00:00
|
|
|
|
2014-03-13 18:02:17 +00:00
|
|
|
SK_TO_STRING_OVERRIDE()
|
2012-03-26 17:57:35 +00:00
|
|
|
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDstInXfermode)
|
2011-04-27 14:09:52 +00:00
|
|
|
|
|
|
|
private:
|
2014-02-20 20:40:19 +00:00
|
|
|
SkDstInXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstIn_Mode) {}
|
2014-01-30 18:58:24 +00:00
|
|
|
SkDstInXfermode(SkReadBuffer& buffer) : INHERITED(buffer) {}
|
2011-04-27 14:09:52 +00:00
|
|
|
|
2008-12-17 15:59:43 +00:00
|
|
|
typedef SkProcCoeffXfermode INHERITED;
|
|
|
|
};
|
|
|
|
|
2011-11-28 15:26:14 +00:00
|
|
|
void SkDstInXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
|
|
|
|
const SkPMColor* SK_RESTRICT src, int count,
|
2012-12-17 19:55:24 +00:00
|
|
|
const SkAlpha* SK_RESTRICT aa) const {
|
2011-11-28 15:26:14 +00:00
|
|
|
SkASSERT(dst && src);
|
2011-04-27 14:09:52 +00:00
|
|
|
|
2011-11-28 15:26:14 +00:00
|
|
|
if (count <= 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (NULL != aa) {
|
|
|
|
return this->INHERITED::xfer32(dst, src, count, aa);
|
|
|
|
}
|
2011-04-27 14:09:52 +00:00
|
|
|
|
2011-11-28 15:26:14 +00:00
|
|
|
do {
|
|
|
|
unsigned a = SkGetPackedA32(*src);
|
|
|
|
*dst = SkAlphaMulQ(*dst, SkAlpha255To256(a));
|
|
|
|
dst++;
|
|
|
|
src++;
|
|
|
|
} while (--count != 0);
|
|
|
|
}
|
2011-04-27 14:09:52 +00:00
|
|
|
|
2014-03-13 18:02:17 +00:00
|
|
|
#ifndef SK_IGNORE_TO_STRING
|
2013-01-22 14:32:09 +00:00
|
|
|
void SkDstInXfermode::toString(SkString* str) const {
|
|
|
|
this->INHERITED::toString(str);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2012-12-17 19:55:24 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2011-04-27 14:09:52 +00:00
|
|
|
|
2011-11-28 15:26:14 +00:00
|
|
|
class SkDstOutXfermode : public SkProcCoeffXfermode {
|
|
|
|
public:
|
2014-02-20 20:40:19 +00:00
|
|
|
static SkDstOutXfermode* Create(const ProcCoeff& rec) {
|
|
|
|
return SkNEW_ARGS(SkDstOutXfermode, (rec));
|
|
|
|
}
|
2011-11-28 15:26:14 +00:00
|
|
|
|
2012-12-17 19:55:24 +00:00
|
|
|
virtual void xfer32(SkPMColor*, const SkPMColor*, int, const SkAlpha*) const SK_OVERRIDE;
|
2011-04-27 14:09:52 +00:00
|
|
|
|
2014-03-13 18:02:17 +00:00
|
|
|
SK_TO_STRING_OVERRIDE()
|
2012-03-26 17:57:35 +00:00
|
|
|
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDstOutXfermode)
|
2011-04-27 14:09:52 +00:00
|
|
|
|
|
|
|
private:
|
2014-02-20 20:40:19 +00:00
|
|
|
SkDstOutXfermode(const ProcCoeff& rec) : SkProcCoeffXfermode(rec, kDstOut_Mode) {}
|
2014-01-30 18:58:24 +00:00
|
|
|
SkDstOutXfermode(SkReadBuffer& buffer)
|
2011-04-27 14:09:52 +00:00
|
|
|
: INHERITED(buffer) {}
|
|
|
|
|
2008-12-17 15:59:43 +00:00
|
|
|
typedef SkProcCoeffXfermode INHERITED;
|
|
|
|
};
|
|
|
|
|
2011-11-28 15:26:14 +00:00
|
|
|
void SkDstOutXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
|
|
|
|
const SkPMColor* SK_RESTRICT src, int count,
|
2012-12-17 19:55:24 +00:00
|
|
|
const SkAlpha* SK_RESTRICT aa) const {
|
2011-11-28 15:26:14 +00:00
|
|
|
SkASSERT(dst && src);
|
|
|
|
|
|
|
|
if (count <= 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (NULL != aa) {
|
|
|
|
return this->INHERITED::xfer32(dst, src, count, aa);
|
|
|
|
}
|
|
|
|
|
|
|
|
do {
|
|
|
|
unsigned a = SkGetPackedA32(*src);
|
|
|
|
*dst = SkAlphaMulQ(*dst, SkAlpha255To256(255 - a));
|
|
|
|
dst++;
|
|
|
|
src++;
|
|
|
|
} while (--count != 0);
|
|
|
|
}
|
|
|
|
|
2014-03-13 18:02:17 +00:00
|
|
|
#ifndef SK_IGNORE_TO_STRING
|
2013-01-22 14:32:09 +00:00
|
|
|
void SkDstOutXfermode::toString(SkString* str) const {
|
|
|
|
this->INHERITED::toString(str);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-12-17 15:59:43 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2014-05-29 20:13:22 +00:00
|
|
|
extern SkProcCoeffXfermode* SkPlatformXfermodeFactory(const ProcCoeff& rec, SkXfermode::Mode mode);
|
2013-12-06 11:32:27 +00:00
|
|
|
extern SkXfermodeProc SkPlatformXfermodeProcFactory(SkXfermode::Mode mode);
|
2013-10-09 14:39:46 +00:00
|
|
|
|
2014-05-29 20:13:22 +00:00
|
|
|
// Technically, can't be static and passed as a template parameter. So we use anonymous namespace.
|
|
|
|
namespace {
|
|
|
|
SkXfermode* create_mode(int iMode) {
|
|
|
|
SkXfermode::Mode mode = (SkXfermode::Mode)iMode;
|
2014-03-28 20:04:11 +00:00
|
|
|
|
|
|
|
ProcCoeff rec = gProcCoeffs[mode];
|
|
|
|
SkXfermodeProc pp = SkPlatformXfermodeProcFactory(mode);
|
|
|
|
if (pp != NULL) {
|
|
|
|
rec.fProc = pp;
|
|
|
|
}
|
|
|
|
|
|
|
|
SkXfermode* xfer = NULL;
|
|
|
|
// check if we have a platform optim for that
|
|
|
|
SkProcCoeffXfermode* xfm = SkPlatformXfermodeFactory(rec, mode);
|
|
|
|
if (xfm != NULL) {
|
|
|
|
xfer = xfm;
|
|
|
|
} else {
|
|
|
|
// All modes can in theory be represented by the ProcCoeff rec, since
|
|
|
|
// it contains function ptrs. However, a few modes are both simple and
|
|
|
|
// commonly used, so we call those out for their own subclasses here.
|
|
|
|
switch (mode) {
|
|
|
|
case SkXfermode::kClear_Mode:
|
|
|
|
xfer = SkClearXfermode::Create(rec);
|
|
|
|
break;
|
|
|
|
case SkXfermode::kSrc_Mode:
|
|
|
|
xfer = SkSrcXfermode::Create(rec);
|
|
|
|
break;
|
|
|
|
case SkXfermode::kSrcOver_Mode:
|
|
|
|
SkASSERT(false); // should not land here
|
|
|
|
break;
|
|
|
|
case SkXfermode::kDstIn_Mode:
|
|
|
|
xfer = SkDstInXfermode::Create(rec);
|
|
|
|
break;
|
|
|
|
case SkXfermode::kDstOut_Mode:
|
|
|
|
xfer = SkDstOutXfermode::Create(rec);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// no special-case, just rely in the rec and its function-ptrs
|
|
|
|
xfer = SkProcCoeffXfermode::Create(rec, mode);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-05-29 20:13:22 +00:00
|
|
|
return xfer;
|
2014-03-28 20:04:11 +00:00
|
|
|
}
|
2014-05-29 20:13:22 +00:00
|
|
|
} // namespace
|
|
|
|
|
2014-03-28 20:04:11 +00:00
|
|
|
|
2009-06-22 17:38:10 +00:00
|
|
|
SkXfermode* SkXfermode::Create(Mode mode) {
|
|
|
|
SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
|
2008-12-17 15:59:43 +00:00
|
|
|
|
2013-10-04 16:52:55 +00:00
|
|
|
if ((unsigned)mode >= kModeCount) {
|
|
|
|
// report error
|
|
|
|
return NULL;
|
|
|
|
}
|
2011-04-13 21:12:04 +00:00
|
|
|
|
2014-05-29 20:13:22 +00:00
|
|
|
// Skia's "default" mode is srcover. NULL in SkPaint is interpreted as srcover
|
2013-10-04 16:52:55 +00:00
|
|
|
// so we can just return NULL from the factory.
|
|
|
|
if (kSrcOver_Mode == mode) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-05-29 20:13:22 +00:00
|
|
|
SK_DECLARE_STATIC_LAZY_PTR_ARRAY(SkXfermode, cached, kModeCount, create_mode);
|
|
|
|
return SkSafeRef(cached[mode]);
|
2008-12-17 15:59:43 +00:00
|
|
|
}
|
|
|
|
|
2011-04-14 15:50:52 +00:00
|
|
|
SkXfermodeProc SkXfermode::GetProc(Mode mode) {
|
|
|
|
SkXfermodeProc proc = NULL;
|
|
|
|
if ((unsigned)mode < kModeCount) {
|
|
|
|
proc = gProcCoeffs[mode].fProc;
|
|
|
|
}
|
|
|
|
return proc;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SkXfermode::ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst) {
|
|
|
|
SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == kModeCount);
|
2011-04-27 14:09:52 +00:00
|
|
|
|
2011-04-14 15:50:52 +00:00
|
|
|
if ((unsigned)mode >= (unsigned)kModeCount) {
|
|
|
|
// illegal mode parameter
|
|
|
|
return false;
|
|
|
|
}
|
2011-04-27 14:09:52 +00:00
|
|
|
|
2011-04-14 15:50:52 +00:00
|
|
|
const ProcCoeff& rec = gProcCoeffs[mode];
|
2011-04-27 14:09:52 +00:00
|
|
|
|
2011-04-14 15:50:52 +00:00
|
|
|
if (CANNOT_USE_COEFF == rec.fSC) {
|
|
|
|
return false;
|
|
|
|
}
|
2011-04-27 14:09:52 +00:00
|
|
|
|
2011-04-14 15:50:52 +00:00
|
|
|
SkASSERT(CANNOT_USE_COEFF != rec.fDC);
|
|
|
|
if (src) {
|
|
|
|
*src = rec.fSC;
|
|
|
|
}
|
|
|
|
if (dst) {
|
|
|
|
*dst = rec.fDC;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-12-17 19:55:24 +00:00
|
|
|
bool SkXfermode::AsMode(const SkXfermode* xfer, Mode* mode) {
|
2008-12-17 15:59:43 +00:00
|
|
|
if (NULL == xfer) {
|
|
|
|
if (mode) {
|
|
|
|
*mode = kSrcOver_Mode;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2011-04-13 21:12:04 +00:00
|
|
|
return xfer->asMode(mode);
|
2008-12-17 15:59:43 +00:00
|
|
|
}
|
|
|
|
|
2012-12-17 19:55:24 +00:00
|
|
|
bool SkXfermode::AsCoeff(const SkXfermode* xfer, Coeff* src, Coeff* dst) {
|
2011-04-14 15:50:52 +00:00
|
|
|
if (NULL == xfer) {
|
|
|
|
return ModeAsCoeff(kSrcOver_Mode, src, dst);
|
2008-12-17 15:59:43 +00:00
|
|
|
}
|
2011-04-14 15:50:52 +00:00
|
|
|
return xfer->asCoeff(src, dst);
|
2008-12-17 15:59:43 +00:00
|
|
|
}
|
|
|
|
|
2012-12-17 19:55:24 +00:00
|
|
|
bool SkXfermode::IsMode(const SkXfermode* xfer, Mode mode) {
|
2011-11-17 02:16:43 +00:00
|
|
|
// if xfer==null then the mode is srcover
|
|
|
|
Mode m = kSrcOver_Mode;
|
|
|
|
if (xfer && !xfer->asMode(&m)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return mode == m;
|
|
|
|
}
|
|
|
|
|
2008-12-17 15:59:43 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
//////////// 16bit xfermode procs
|
|
|
|
|
|
|
|
#ifdef SK_DEBUG
|
|
|
|
static bool require_255(SkPMColor src) { return SkGetPackedA32(src) == 0xFF; }
|
|
|
|
static bool require_0(SkPMColor src) { return SkGetPackedA32(src) == 0; }
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static uint16_t src_modeproc16_255(SkPMColor src, uint16_t dst) {
|
|
|
|
SkASSERT(require_255(src));
|
|
|
|
return SkPixel32ToPixel16(src);
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint16_t dst_modeproc16(SkPMColor src, uint16_t dst) {
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint16_t srcover_modeproc16_0(SkPMColor src, uint16_t dst) {
|
|
|
|
SkASSERT(require_0(src));
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint16_t srcover_modeproc16_255(SkPMColor src, uint16_t dst) {
|
|
|
|
SkASSERT(require_255(src));
|
|
|
|
return SkPixel32ToPixel16(src);
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint16_t dstover_modeproc16_0(SkPMColor src, uint16_t dst) {
|
|
|
|
SkASSERT(require_0(src));
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint16_t dstover_modeproc16_255(SkPMColor src, uint16_t dst) {
|
|
|
|
SkASSERT(require_255(src));
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint16_t srcin_modeproc16_255(SkPMColor src, uint16_t dst) {
|
|
|
|
SkASSERT(require_255(src));
|
|
|
|
return SkPixel32ToPixel16(src);
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint16_t dstin_modeproc16_255(SkPMColor src, uint16_t dst) {
|
|
|
|
SkASSERT(require_255(src));
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint16_t dstout_modeproc16_0(SkPMColor src, uint16_t dst) {
|
|
|
|
SkASSERT(require_0(src));
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint16_t srcatop_modeproc16(SkPMColor src, uint16_t dst) {
|
|
|
|
unsigned isa = 255 - SkGetPackedA32(src);
|
2011-04-27 14:09:52 +00:00
|
|
|
|
2008-12-17 15:59:43 +00:00
|
|
|
return SkPackRGB16(
|
|
|
|
SkPacked32ToR16(src) + SkAlphaMulAlpha(SkGetPackedR16(dst), isa),
|
|
|
|
SkPacked32ToG16(src) + SkAlphaMulAlpha(SkGetPackedG16(dst), isa),
|
|
|
|
SkPacked32ToB16(src) + SkAlphaMulAlpha(SkGetPackedB16(dst), isa));
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint16_t srcatop_modeproc16_0(SkPMColor src, uint16_t dst) {
|
|
|
|
SkASSERT(require_0(src));
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint16_t srcatop_modeproc16_255(SkPMColor src, uint16_t dst) {
|
|
|
|
SkASSERT(require_255(src));
|
|
|
|
return SkPixel32ToPixel16(src);
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint16_t dstatop_modeproc16_255(SkPMColor src, uint16_t dst) {
|
|
|
|
SkASSERT(require_255(src));
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*********
|
|
|
|
darken and lighten boil down to this.
|
|
|
|
|
|
|
|
darken = (1 - Sa) * Dc + min(Sc, Dc)
|
|
|
|
lighten = (1 - Sa) * Dc + max(Sc, Dc)
|
|
|
|
|
|
|
|
if (Sa == 0) these become
|
|
|
|
darken = Dc + min(0, Dc) = 0
|
|
|
|
lighten = Dc + max(0, Dc) = Dc
|
|
|
|
|
|
|
|
if (Sa == 1) these become
|
|
|
|
darken = min(Sc, Dc)
|
|
|
|
lighten = max(Sc, Dc)
|
|
|
|
*/
|
|
|
|
|
|
|
|
static uint16_t darken_modeproc16_0(SkPMColor src, uint16_t dst) {
|
|
|
|
SkASSERT(require_0(src));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint16_t darken_modeproc16_255(SkPMColor src, uint16_t dst) {
|
|
|
|
SkASSERT(require_255(src));
|
|
|
|
unsigned r = SkFastMin32(SkPacked32ToR16(src), SkGetPackedR16(dst));
|
|
|
|
unsigned g = SkFastMin32(SkPacked32ToG16(src), SkGetPackedG16(dst));
|
|
|
|
unsigned b = SkFastMin32(SkPacked32ToB16(src), SkGetPackedB16(dst));
|
|
|
|
return SkPackRGB16(r, g, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint16_t lighten_modeproc16_0(SkPMColor src, uint16_t dst) {
|
|
|
|
SkASSERT(require_0(src));
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint16_t lighten_modeproc16_255(SkPMColor src, uint16_t dst) {
|
|
|
|
SkASSERT(require_255(src));
|
|
|
|
unsigned r = SkMax32(SkPacked32ToR16(src), SkGetPackedR16(dst));
|
|
|
|
unsigned g = SkMax32(SkPacked32ToG16(src), SkGetPackedG16(dst));
|
|
|
|
unsigned b = SkMax32(SkPacked32ToB16(src), SkGetPackedB16(dst));
|
|
|
|
return SkPackRGB16(r, g, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Proc16Rec {
|
|
|
|
SkXfermodeProc16 fProc16_0;
|
|
|
|
SkXfermodeProc16 fProc16_255;
|
|
|
|
SkXfermodeProc16 fProc16_General;
|
|
|
|
};
|
|
|
|
|
2009-06-22 17:38:10 +00:00
|
|
|
static const Proc16Rec gModeProcs16[] = {
|
2008-12-17 15:59:43 +00:00
|
|
|
{ NULL, NULL, NULL }, // CLEAR
|
|
|
|
{ NULL, src_modeproc16_255, NULL },
|
|
|
|
{ dst_modeproc16, dst_modeproc16, dst_modeproc16 },
|
|
|
|
{ srcover_modeproc16_0, srcover_modeproc16_255, NULL },
|
|
|
|
{ dstover_modeproc16_0, dstover_modeproc16_255, NULL },
|
|
|
|
{ NULL, srcin_modeproc16_255, NULL },
|
|
|
|
{ NULL, dstin_modeproc16_255, NULL },
|
|
|
|
{ NULL, NULL, NULL },// SRC_OUT
|
|
|
|
{ dstout_modeproc16_0, NULL, NULL },
|
|
|
|
{ srcatop_modeproc16_0, srcatop_modeproc16_255, srcatop_modeproc16 },
|
|
|
|
{ NULL, dstatop_modeproc16_255, NULL },
|
|
|
|
{ NULL, NULL, NULL }, // XOR
|
2009-06-22 17:38:10 +00:00
|
|
|
|
|
|
|
{ NULL, NULL, NULL }, // plus
|
2013-01-30 21:36:11 +00:00
|
|
|
{ NULL, NULL, NULL }, // modulate
|
2009-06-22 17:38:10 +00:00
|
|
|
{ NULL, NULL, NULL }, // screen
|
|
|
|
{ NULL, NULL, NULL }, // overlay
|
|
|
|
{ darken_modeproc16_0, darken_modeproc16_255, NULL }, // darken
|
|
|
|
{ lighten_modeproc16_0, lighten_modeproc16_255, NULL }, // lighten
|
|
|
|
{ NULL, NULL, NULL }, // colordodge
|
|
|
|
{ NULL, NULL, NULL }, // colorburn
|
|
|
|
{ NULL, NULL, NULL }, // hardlight
|
|
|
|
{ NULL, NULL, NULL }, // softlight
|
|
|
|
{ NULL, NULL, NULL }, // difference
|
|
|
|
{ NULL, NULL, NULL }, // exclusion
|
2013-03-05 16:23:59 +00:00
|
|
|
{ NULL, NULL, NULL }, // multiply
|
|
|
|
{ NULL, NULL, NULL }, // hue
|
|
|
|
{ NULL, NULL, NULL }, // saturation
|
|
|
|
{ NULL, NULL, NULL }, // color
|
|
|
|
{ NULL, NULL, NULL }, // luminosity
|
2008-12-17 15:59:43 +00:00
|
|
|
};
|
|
|
|
|
2009-06-22 17:38:10 +00:00
|
|
|
SkXfermodeProc16 SkXfermode::GetProc16(Mode mode, SkColor srcColor) {
|
2008-12-17 15:59:43 +00:00
|
|
|
SkXfermodeProc16 proc16 = NULL;
|
2009-06-22 17:38:10 +00:00
|
|
|
if ((unsigned)mode < kModeCount) {
|
|
|
|
const Proc16Rec& rec = gModeProcs16[mode];
|
2008-12-17 15:59:43 +00:00
|
|
|
unsigned a = SkColorGetA(srcColor);
|
|
|
|
|
|
|
|
if (0 == a) {
|
|
|
|
proc16 = rec.fProc16_0;
|
|
|
|
} else if (255 == a) {
|
|
|
|
proc16 = rec.fProc16_255;
|
|
|
|
} else {
|
|
|
|
proc16 = rec.fProc16_General;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return proc16;
|
|
|
|
}
|
|
|
|
|
2011-12-15 14:16:43 +00:00
|
|
|
SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkXfermode)
|
|
|
|
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkProcCoeffXfermode)
|
|
|
|
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkClearXfermode)
|
|
|
|
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSrcXfermode)
|
|
|
|
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDstInXfermode)
|
|
|
|
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDstOutXfermode)
|
2013-10-17 16:29:34 +00:00
|
|
|
#if !SK_ARM_NEON_IS_NONE
|
|
|
|
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkNEONProcCoeffXfermode)
|
|
|
|
#endif
|
2014-04-11 12:52:44 +00:00
|
|
|
#if defined(SK_CPU_X86) && !defined(SK_BUILD_FOR_IOS)
|
2014-04-09 15:43:46 +00:00
|
|
|
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSSE2ProcCoeffXfermode)
|
2014-04-09 16:50:55 +00:00
|
|
|
#endif
|
2011-12-15 14:16:43 +00:00
|
|
|
SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
|