Revert "use pipeline for non-opt xfermodes"
This reverts commit e93cf97175
.
Reason for revert: unblock Chrome roll
Original change's description:
> use pipeline for non-opt xfermodes
>
> Produces slightly different results for Hue, Saturation, Color, Luminosity,
> seemingly around the aa edging.
>
> Bug: skia:
> Change-Id: I6364818c9788863e5fad6d14cad4797d073dbea3
> Reviewed-on: https://skia-review.googlesource.com/19554
> Reviewed-by: Mike Klein <mtklein@google.com>
> Commit-Queue: Mike Reed <reed@google.com>
TBR=mtklein@google.com,fmalita@chromium.org,reed@google.com
Change-Id: Ib85a51753d21ce778fa5cfedd6b7d1b5b2b87096
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: skia:
Reviewed-on: https://skia-review.googlesource.com/19745
Reviewed-by: Mike Klein <mtklein@chromium.org>
Commit-Queue: Mike Klein <mtklein@chromium.org>
This commit is contained in:
parent
9e99b3de69
commit
4f8c695736
@ -345,6 +345,7 @@ skia_core_sources = [
|
||||
"$_src/core/SkWriteBuffer.cpp",
|
||||
"$_src/core/SkWriter32.cpp",
|
||||
"$_src/core/SkXfermode.cpp",
|
||||
"$_src/core/SkXfermode_proccoeff.h",
|
||||
"$_src/core/SkXfermodeInterpretation.cpp",
|
||||
"$_src/core/SkXfermodeInterpretation.h",
|
||||
"$_src/core/SkYUVPlanesCache.cpp",
|
||||
|
@ -169,6 +169,10 @@ SK_API SkPMColor SkPreMultiplyARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b);
|
||||
*/
|
||||
SK_API SkPMColor SkPreMultiplyColor(SkColor c);
|
||||
|
||||
/** Define a function pointer type for combining two premultiplied colors
|
||||
*/
|
||||
typedef SkPMColor (*SkXfermodeProc)(SkPMColor src, SkPMColor dst);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct SkPM4f;
|
||||
|
@ -15,10 +15,6 @@ class SkRasterPipeline;
|
||||
|
||||
bool SkBlendMode_SupportsCoverageAsAlpha(SkBlendMode);
|
||||
|
||||
static inline bool SkBlendMode_CaresAboutRBOrder(SkBlendMode mode) {
|
||||
return (mode > SkBlendMode::kLastSeparableMode);
|
||||
}
|
||||
|
||||
void SkBlendMode_AppendStagesNoClamp(SkBlendMode, SkRasterPipeline*);
|
||||
void SkBlendMode_AppendClampIfNeeded(SkBlendMode, SkRasterPipeline*);
|
||||
|
||||
|
@ -6,16 +6,16 @@
|
||||
*/
|
||||
|
||||
#include "SkBlendModePriv.h"
|
||||
#include "SkXfermode_proccoeff.h"
|
||||
#include "SkColorPriv.h"
|
||||
#include "SkMathPriv.h"
|
||||
#include "SkOnce.h"
|
||||
#include "SkOpts.h"
|
||||
#include "SkPM4f.h"
|
||||
#include "SkRasterPipeline.h"
|
||||
#include "SkReadBuffer.h"
|
||||
#include "SkString.h"
|
||||
#include "SkWriteBuffer.h"
|
||||
#include "SkXfermodePriv.h"
|
||||
#include "SkPM4f.h"
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
#include "GrFragmentProcessor.h"
|
||||
@ -24,50 +24,668 @@
|
||||
#include "effects/GrXfermodeFragmentProcessor.h"
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#define SkAlphaMulAlpha(a, b) SkMulDiv255Round(a, b)
|
||||
|
||||
class SkProcCoeffXfermode : public SkXfermode {
|
||||
public:
|
||||
SkProcCoeffXfermode(SkBlendMode mode) : fMode(mode) {}
|
||||
static inline unsigned saturated_add(unsigned a, unsigned b) {
|
||||
SkASSERT(a <= 255);
|
||||
SkASSERT(b <= 255);
|
||||
unsigned sum = a + b;
|
||||
if (sum > 255) {
|
||||
sum = 255;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
void xfer32(SkPMColor dst[], const SkPMColor src[], int count,
|
||||
const SkAlpha aa[]) const override {
|
||||
SkASSERT(dst && src && count >= 0);
|
||||
static inline int clamp_signed_byte(int n) {
|
||||
if (n < 0) {
|
||||
n = 0;
|
||||
} else if (n > 255) {
|
||||
n = 255;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
bool needs_swap = (kN32_SkColorType == kBGRA_8888_SkColorType) &&
|
||||
SkBlendMode_CaresAboutRBOrder(fMode);
|
||||
static inline int clamp_div255round(int prod) {
|
||||
if (prod <= 0) {
|
||||
return 0;
|
||||
} else if (prod >= 255*255) {
|
||||
return 255;
|
||||
} else {
|
||||
return SkDiv255Round(prod);
|
||||
}
|
||||
}
|
||||
|
||||
SkRasterPipeline_<256> p;
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
p.append(SkRasterPipeline::load_8888, &dst);
|
||||
if (needs_swap) {
|
||||
p.append(SkRasterPipeline::swap_rb);
|
||||
}
|
||||
p.append(SkRasterPipeline::move_src_dst);
|
||||
p.append(SkRasterPipeline::load_8888, &src);
|
||||
if (needs_swap) {
|
||||
p.append(SkRasterPipeline::swap_rb);
|
||||
}
|
||||
// kClear_Mode, //!< [0, 0]
|
||||
static SkPMColor clear_modeproc(SkPMColor src, SkPMColor dst) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
SkBlendMode_AppendStagesNoClamp(fMode, &p);
|
||||
if (aa) {
|
||||
p.append(SkRasterPipeline::lerp_u8, &aa);
|
||||
}
|
||||
SkBlendMode_AppendClampIfNeeded(fMode, &p);
|
||||
// kSrc_Mode, //!< [Sa, Sc]
|
||||
static SkPMColor src_modeproc(SkPMColor src, SkPMColor dst) {
|
||||
return src;
|
||||
}
|
||||
|
||||
if (needs_swap) {
|
||||
p.append(SkRasterPipeline::swap_rb);
|
||||
}
|
||||
p.append(SkRasterPipeline::store_8888, &dst);
|
||||
p.run(0, 0, count);
|
||||
// kDst_Mode, //!< [Da, Dc]
|
||||
static SkPMColor dst_modeproc(SkPMColor src, SkPMColor dst) {
|
||||
return dst;
|
||||
}
|
||||
|
||||
// kSrcOver_Mode, //!< [Sa + Da - Sa*Da, Sc + (1 - Sa)*Dc]
|
||||
static SkPMColor srcover_modeproc(SkPMColor src, SkPMColor dst) {
|
||||
#if 0
|
||||
// this is the old, more-correct way, but it doesn't guarantee that dst==255
|
||||
// will always stay opaque
|
||||
return src + SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
|
||||
#else
|
||||
// this is slightly faster, but more importantly guarantees that dst==255
|
||||
// will always stay opaque
|
||||
return src + SkAlphaMulQ(dst, 256 - SkGetPackedA32(src));
|
||||
#endif
|
||||
}
|
||||
|
||||
// kDstOver_Mode, //!< [Sa + Da - Sa*Da, Dc + (1 - Da)*Sc]
|
||||
static SkPMColor dstover_modeproc(SkPMColor src, SkPMColor dst) {
|
||||
// this is the reverse of srcover, just flipping src and dst
|
||||
// see srcover's comment about the 256 for opaqueness guarantees
|
||||
return dst + SkAlphaMulQ(src, 256 - SkGetPackedA32(dst));
|
||||
}
|
||||
|
||||
// kSrcIn_Mode, //!< [Sa * Da, Sc * Da]
|
||||
static SkPMColor srcin_modeproc(SkPMColor src, SkPMColor dst) {
|
||||
return SkAlphaMulQ(src, SkAlpha255To256(SkGetPackedA32(dst)));
|
||||
}
|
||||
|
||||
// kDstIn_Mode, //!< [Sa * Da, Sa * Dc]
|
||||
static SkPMColor dstin_modeproc(SkPMColor src, SkPMColor dst) {
|
||||
return SkAlphaMulQ(dst, SkAlpha255To256(SkGetPackedA32(src)));
|
||||
}
|
||||
|
||||
// kSrcOut_Mode, //!< [Sa * (1 - Da), Sc * (1 - Da)]
|
||||
static SkPMColor srcout_modeproc(SkPMColor src, SkPMColor dst) {
|
||||
return SkAlphaMulQ(src, SkAlpha255To256(255 - SkGetPackedA32(dst)));
|
||||
}
|
||||
|
||||
// kDstOut_Mode, //!< [Da * (1 - Sa), Dc * (1 - Sa)]
|
||||
static SkPMColor dstout_modeproc(SkPMColor src, SkPMColor dst) {
|
||||
return SkAlphaMulQ(dst, SkAlpha255To256(255 - SkGetPackedA32(src)));
|
||||
}
|
||||
|
||||
// kSrcATop_Mode, //!< [Da, Sc * Da + (1 - Sa) * Dc]
|
||||
static SkPMColor srcatop_modeproc(SkPMColor src, SkPMColor dst) {
|
||||
unsigned sa = SkGetPackedA32(src);
|
||||
unsigned da = SkGetPackedA32(dst);
|
||||
unsigned isa = 255 - sa;
|
||||
|
||||
return SkPackARGB32(da,
|
||||
SkAlphaMulAlpha(da, SkGetPackedR32(src)) +
|
||||
SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
|
||||
SkAlphaMulAlpha(da, SkGetPackedG32(src)) +
|
||||
SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
|
||||
SkAlphaMulAlpha(da, SkGetPackedB32(src)) +
|
||||
SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
|
||||
}
|
||||
|
||||
// kDstATop_Mode, //!< [Sa, Sa * Dc + Sc * (1 - Da)]
|
||||
static SkPMColor dstatop_modeproc(SkPMColor src, SkPMColor dst) {
|
||||
unsigned sa = SkGetPackedA32(src);
|
||||
unsigned da = SkGetPackedA32(dst);
|
||||
unsigned ida = 255 - da;
|
||||
|
||||
return SkPackARGB32(sa,
|
||||
SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
|
||||
SkAlphaMulAlpha(sa, SkGetPackedR32(dst)),
|
||||
SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
|
||||
SkAlphaMulAlpha(sa, SkGetPackedG32(dst)),
|
||||
SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
|
||||
SkAlphaMulAlpha(sa, SkGetPackedB32(dst)));
|
||||
}
|
||||
|
||||
// kXor_Mode [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc]
|
||||
static SkPMColor xor_modeproc(SkPMColor src, SkPMColor dst) {
|
||||
unsigned sa = SkGetPackedA32(src);
|
||||
unsigned da = SkGetPackedA32(dst);
|
||||
unsigned isa = 255 - sa;
|
||||
unsigned ida = 255 - da;
|
||||
|
||||
return SkPackARGB32(sa + da - (SkAlphaMulAlpha(sa, da) << 1),
|
||||
SkAlphaMulAlpha(ida, SkGetPackedR32(src)) +
|
||||
SkAlphaMulAlpha(isa, SkGetPackedR32(dst)),
|
||||
SkAlphaMulAlpha(ida, SkGetPackedG32(src)) +
|
||||
SkAlphaMulAlpha(isa, SkGetPackedG32(dst)),
|
||||
SkAlphaMulAlpha(ida, SkGetPackedB32(src)) +
|
||||
SkAlphaMulAlpha(isa, SkGetPackedB32(dst)));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// kPlus_Mode
|
||||
static SkPMColor plus_modeproc(SkPMColor src, SkPMColor dst) {
|
||||
unsigned b = saturated_add(SkGetPackedB32(src), SkGetPackedB32(dst));
|
||||
unsigned g = saturated_add(SkGetPackedG32(src), SkGetPackedG32(dst));
|
||||
unsigned r = saturated_add(SkGetPackedR32(src), SkGetPackedR32(dst));
|
||||
unsigned a = saturated_add(SkGetPackedA32(src), SkGetPackedA32(dst));
|
||||
return SkPackARGB32(a, r, g, b);
|
||||
}
|
||||
|
||||
// kModulate_Mode
|
||||
static SkPMColor modulate_modeproc(SkPMColor src, SkPMColor dst) {
|
||||
int a = SkAlphaMulAlpha(SkGetPackedA32(src), SkGetPackedA32(dst));
|
||||
int r = SkAlphaMulAlpha(SkGetPackedR32(src), SkGetPackedR32(dst));
|
||||
int g = SkAlphaMulAlpha(SkGetPackedG32(src), SkGetPackedG32(dst));
|
||||
int b = SkAlphaMulAlpha(SkGetPackedB32(src), SkGetPackedB32(dst));
|
||||
return SkPackARGB32(a, r, g, b);
|
||||
}
|
||||
|
||||
static inline int srcover_byte(int a, int b) {
|
||||
return a + b - SkAlphaMulAlpha(a, b);
|
||||
}
|
||||
|
||||
// kMultiply_Mode
|
||||
// B(Cb, Cs) = Cb x Cs
|
||||
// multiply uses its own version of blendfunc_byte because sa and da are not needed
|
||||
static int blendfunc_multiply_byte(int sc, int dc, int sa, int da) {
|
||||
return clamp_div255round(sc * (255 - da) + dc * (255 - sa) + sc * dc);
|
||||
}
|
||||
|
||||
static SkPMColor multiply_modeproc(SkPMColor src, SkPMColor dst) {
|
||||
int sa = SkGetPackedA32(src);
|
||||
int da = SkGetPackedA32(dst);
|
||||
int a = srcover_byte(sa, da);
|
||||
int r = blendfunc_multiply_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
|
||||
int g = blendfunc_multiply_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
|
||||
int b = blendfunc_multiply_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
|
||||
return SkPackARGB32(a, r, g, b);
|
||||
}
|
||||
|
||||
// kScreen_Mode
|
||||
static SkPMColor screen_modeproc(SkPMColor src, SkPMColor dst) {
|
||||
int a = srcover_byte(SkGetPackedA32(src), SkGetPackedA32(dst));
|
||||
int r = srcover_byte(SkGetPackedR32(src), SkGetPackedR32(dst));
|
||||
int g = srcover_byte(SkGetPackedG32(src), SkGetPackedG32(dst));
|
||||
int b = srcover_byte(SkGetPackedB32(src), SkGetPackedB32(dst));
|
||||
return SkPackARGB32(a, r, g, b);
|
||||
}
|
||||
|
||||
// kOverlay_Mode
|
||||
static inline int overlay_byte(int sc, int dc, int sa, int da) {
|
||||
int tmp = sc * (255 - da) + dc * (255 - sa);
|
||||
int rc;
|
||||
if (2 * dc <= da) {
|
||||
rc = 2 * sc * dc;
|
||||
} else {
|
||||
rc = sa * da - 2 * (da - dc) * (sa - sc);
|
||||
}
|
||||
return clamp_div255round(rc + tmp);
|
||||
}
|
||||
static SkPMColor overlay_modeproc(SkPMColor src, SkPMColor dst) {
|
||||
int sa = SkGetPackedA32(src);
|
||||
int da = SkGetPackedA32(dst);
|
||||
int a = srcover_byte(sa, da);
|
||||
int r = overlay_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
|
||||
int g = overlay_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
|
||||
int b = overlay_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
|
||||
return SkPackARGB32(a, r, g, b);
|
||||
}
|
||||
|
||||
// kDarken_Mode
|
||||
static inline int darken_byte(int sc, int dc, int sa, int da) {
|
||||
int sd = sc * da;
|
||||
int ds = dc * sa;
|
||||
if (sd < ds) {
|
||||
// srcover
|
||||
return sc + dc - SkDiv255Round(ds);
|
||||
} else {
|
||||
// dstover
|
||||
return dc + sc - SkDiv255Round(sd);
|
||||
}
|
||||
}
|
||||
static SkPMColor darken_modeproc(SkPMColor src, SkPMColor dst) {
|
||||
int sa = SkGetPackedA32(src);
|
||||
int da = SkGetPackedA32(dst);
|
||||
int a = srcover_byte(sa, da);
|
||||
int r = darken_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
|
||||
int g = darken_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
|
||||
int b = darken_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
|
||||
return SkPackARGB32(a, r, g, b);
|
||||
}
|
||||
|
||||
// kLighten_Mode
|
||||
static inline int lighten_byte(int sc, int dc, int sa, int da) {
|
||||
int sd = sc * da;
|
||||
int ds = dc * sa;
|
||||
if (sd > ds) {
|
||||
// srcover
|
||||
return sc + dc - SkDiv255Round(ds);
|
||||
} else {
|
||||
// dstover
|
||||
return dc + sc - SkDiv255Round(sd);
|
||||
}
|
||||
}
|
||||
static SkPMColor lighten_modeproc(SkPMColor src, SkPMColor dst) {
|
||||
int sa = SkGetPackedA32(src);
|
||||
int da = SkGetPackedA32(dst);
|
||||
int a = srcover_byte(sa, da);
|
||||
int r = lighten_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
|
||||
int g = lighten_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
|
||||
int b = lighten_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
|
||||
return SkPackARGB32(a, r, g, b);
|
||||
}
|
||||
|
||||
// kColorDodge_Mode
|
||||
static inline int colordodge_byte(int sc, int dc, int sa, int da) {
|
||||
int diff = sa - sc;
|
||||
int rc;
|
||||
if (0 == dc) {
|
||||
return SkAlphaMulAlpha(sc, 255 - da);
|
||||
} else if (0 == diff) {
|
||||
rc = sa * da + sc * (255 - da) + dc * (255 - sa);
|
||||
} else {
|
||||
diff = dc * sa / diff;
|
||||
rc = sa * ((da < diff) ? da : diff) + sc * (255 - da) + dc * (255 - sa);
|
||||
}
|
||||
return clamp_div255round(rc);
|
||||
}
|
||||
static SkPMColor colordodge_modeproc(SkPMColor src, SkPMColor dst) {
|
||||
int sa = SkGetPackedA32(src);
|
||||
int da = SkGetPackedA32(dst);
|
||||
int a = srcover_byte(sa, da);
|
||||
int r = colordodge_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
|
||||
int g = colordodge_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
|
||||
int b = colordodge_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
|
||||
return SkPackARGB32(a, r, g, b);
|
||||
}
|
||||
|
||||
// kColorBurn_Mode
|
||||
static inline int colorburn_byte(int sc, int dc, int sa, int da) {
|
||||
int rc;
|
||||
if (dc == da) {
|
||||
rc = sa * da + sc * (255 - da) + dc * (255 - sa);
|
||||
} else if (0 == sc) {
|
||||
return SkAlphaMulAlpha(dc, 255 - sa);
|
||||
} else {
|
||||
int tmp = (da - dc) * sa / sc;
|
||||
rc = sa * (da - ((da < tmp) ? da : tmp))
|
||||
+ sc * (255 - da) + dc * (255 - sa);
|
||||
}
|
||||
return clamp_div255round(rc);
|
||||
}
|
||||
static SkPMColor colorburn_modeproc(SkPMColor src, SkPMColor dst) {
|
||||
int sa = SkGetPackedA32(src);
|
||||
int da = SkGetPackedA32(dst);
|
||||
int a = srcover_byte(sa, da);
|
||||
int r = colorburn_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
|
||||
int g = colorburn_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
|
||||
int b = colorburn_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
|
||||
return SkPackARGB32(a, r, g, b);
|
||||
}
|
||||
|
||||
// kHardLight_Mode
|
||||
static inline int hardlight_byte(int sc, int dc, int sa, int da) {
|
||||
int rc;
|
||||
if (2 * sc <= sa) {
|
||||
rc = 2 * sc * dc;
|
||||
} else {
|
||||
rc = sa * da - 2 * (da - dc) * (sa - sc);
|
||||
}
|
||||
return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa));
|
||||
}
|
||||
static SkPMColor hardlight_modeproc(SkPMColor src, SkPMColor dst) {
|
||||
int sa = SkGetPackedA32(src);
|
||||
int da = SkGetPackedA32(dst);
|
||||
int a = srcover_byte(sa, da);
|
||||
int r = hardlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
|
||||
int g = hardlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
|
||||
int b = hardlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
|
||||
return SkPackARGB32(a, r, g, b);
|
||||
}
|
||||
|
||||
// returns 255 * sqrt(n/255)
|
||||
static U8CPU sqrt_unit_byte(U8CPU n) {
|
||||
return SkSqrtBits(n, 15+4);
|
||||
}
|
||||
|
||||
// kSoftLight_Mode
|
||||
static inline int softlight_byte(int sc, int dc, int sa, int da) {
|
||||
int m = da ? dc * 256 / da : 0;
|
||||
int rc;
|
||||
if (2 * sc <= sa) {
|
||||
rc = dc * (sa + ((2 * sc - sa) * (256 - m) >> 8));
|
||||
} else if (4 * dc <= da) {
|
||||
int tmp = (4 * m * (4 * m + 256) * (m - 256) >> 16) + 7 * m;
|
||||
rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8);
|
||||
} else {
|
||||
int tmp = sqrt_unit_byte(m) - m;
|
||||
rc = dc * sa + (da * (2 * sc - sa) * tmp >> 8);
|
||||
}
|
||||
return clamp_div255round(rc + sc * (255 - da) + dc * (255 - sa));
|
||||
}
|
||||
static SkPMColor softlight_modeproc(SkPMColor src, SkPMColor dst) {
|
||||
int sa = SkGetPackedA32(src);
|
||||
int da = SkGetPackedA32(dst);
|
||||
int a = srcover_byte(sa, da);
|
||||
int r = softlight_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
|
||||
int g = softlight_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
|
||||
int b = softlight_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
|
||||
return SkPackARGB32(a, r, g, b);
|
||||
}
|
||||
|
||||
// kDifference_Mode
|
||||
static inline int difference_byte(int sc, int dc, int sa, int da) {
|
||||
int tmp = SkMin32(sc * da, dc * sa);
|
||||
return clamp_signed_byte(sc + dc - 2 * SkDiv255Round(tmp));
|
||||
}
|
||||
static SkPMColor difference_modeproc(SkPMColor src, SkPMColor dst) {
|
||||
int sa = SkGetPackedA32(src);
|
||||
int da = SkGetPackedA32(dst);
|
||||
int a = srcover_byte(sa, da);
|
||||
int r = difference_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
|
||||
int g = difference_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
|
||||
int b = difference_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
|
||||
return SkPackARGB32(a, r, g, b);
|
||||
}
|
||||
|
||||
// kExclusion_Mode
|
||||
static inline int exclusion_byte(int sc, int dc, int, int) {
|
||||
// this equations is wacky, wait for SVG to confirm it
|
||||
//int r = sc * da + dc * sa - 2 * sc * dc + sc * (255 - da) + dc * (255 - sa);
|
||||
|
||||
// The above equation can be simplified as follows
|
||||
int r = 255*(sc + dc) - 2 * sc * dc;
|
||||
return clamp_div255round(r);
|
||||
}
|
||||
static SkPMColor exclusion_modeproc(SkPMColor src, SkPMColor dst) {
|
||||
int sa = SkGetPackedA32(src);
|
||||
int da = SkGetPackedA32(dst);
|
||||
int a = srcover_byte(sa, da);
|
||||
int r = exclusion_byte(SkGetPackedR32(src), SkGetPackedR32(dst), sa, da);
|
||||
int g = exclusion_byte(SkGetPackedG32(src), SkGetPackedG32(dst), sa, da);
|
||||
int b = exclusion_byte(SkGetPackedB32(src), SkGetPackedB32(dst), sa, da);
|
||||
return SkPackARGB32(a, r, g, b);
|
||||
}
|
||||
|
||||
// The CSS compositing spec introduces the following formulas:
|
||||
// (See https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#blendingnonseparable)
|
||||
// SkComputeLuminance is similar to this formula but it uses the new definition from Rec. 709
|
||||
// while PDF and CG uses the one from Rec. Rec. 601
|
||||
// See http://www.glennchan.info/articles/technical/hd-versus-sd-color-space/hd-versus-sd-color-space.htm
|
||||
static inline int Lum(int r, int g, int b)
|
||||
{
|
||||
return SkDiv255Round(r * 77 + g * 150 + b * 28);
|
||||
}
|
||||
|
||||
static inline int min2(int a, int b) { return a < b ? a : b; }
|
||||
static inline int max2(int a, int b) { return a > b ? a : b; }
|
||||
#define minimum(a, b, c) min2(min2(a, b), c)
|
||||
#define maximum(a, b, c) max2(max2(a, b), c)
|
||||
|
||||
static inline int Sat(int r, int g, int b) {
|
||||
return maximum(r, g, b) - minimum(r, g, b);
|
||||
}
|
||||
|
||||
static inline void setSaturationComponents(int* Cmin, int* Cmid, int* Cmax, int s) {
|
||||
if(*Cmax > *Cmin) {
|
||||
*Cmid = SkMulDiv(*Cmid - *Cmin, s, *Cmax - *Cmin);
|
||||
*Cmax = s;
|
||||
} else {
|
||||
*Cmax = 0;
|
||||
*Cmid = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
const SkBlendMode fMode;
|
||||
*Cmin = 0;
|
||||
}
|
||||
|
||||
typedef SkXfermode INHERITED;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void clipColor(int* r, int* g, int* b, int a) {
|
||||
int L = Lum(*r, *g, *b);
|
||||
int n = minimum(*r, *g, *b);
|
||||
int x = maximum(*r, *g, *b);
|
||||
int denom;
|
||||
if ((n < 0) && (denom = L - n)) { // Compute denom and make sure it's non zero
|
||||
*r = L + SkMulDiv(*r - L, L, denom);
|
||||
*g = L + SkMulDiv(*g - L, L, denom);
|
||||
*b = L + SkMulDiv(*b - L, L, denom);
|
||||
}
|
||||
|
||||
if ((x > a) && (denom = x - L)) { // Compute denom and make sure it's non zero
|
||||
int numer = a - L;
|
||||
*r = L + SkMulDiv(*r - L, numer, denom);
|
||||
*g = L + SkMulDiv(*g - L, numer, denom);
|
||||
*b = L + SkMulDiv(*b - L, numer, denom);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void SetLum(int* r, int* g, int* b, int a, int l) {
|
||||
int d = l - Lum(*r, *g, *b);
|
||||
*r += d;
|
||||
*g += d;
|
||||
*b += d;
|
||||
|
||||
clipColor(r, g, b, a);
|
||||
}
|
||||
|
||||
// non-separable blend modes are done in non-premultiplied alpha
|
||||
#define blendfunc_nonsep_byte(sc, dc, sa, da, blendval) \
|
||||
clamp_div255round(sc * (255 - da) + dc * (255 - sa) + blendval)
|
||||
|
||||
// kHue_Mode
|
||||
// B(Cb, Cs) = SetLum(SetSat(Cs, Sat(Cb)), Lum(Cb))
|
||||
// Create a color with the hue of the source color and the saturation and luminosity of the backdrop color.
|
||||
static SkPMColor hue_modeproc(SkPMColor src, SkPMColor dst) {
|
||||
int sr = SkGetPackedR32(src);
|
||||
int sg = SkGetPackedG32(src);
|
||||
int sb = SkGetPackedB32(src);
|
||||
int sa = SkGetPackedA32(src);
|
||||
|
||||
int dr = SkGetPackedR32(dst);
|
||||
int dg = SkGetPackedG32(dst);
|
||||
int db = SkGetPackedB32(dst);
|
||||
int da = SkGetPackedA32(dst);
|
||||
int Sr, Sg, Sb;
|
||||
|
||||
if(sa && da) {
|
||||
Sr = sr * sa;
|
||||
Sg = sg * sa;
|
||||
Sb = sb * sa;
|
||||
SetSat(&Sr, &Sg, &Sb, Sat(dr, dg, db) * sa);
|
||||
SetLum(&Sr, &Sg, &Sb, sa * da, Lum(dr, dg, db) * sa);
|
||||
} else {
|
||||
Sr = 0;
|
||||
Sg = 0;
|
||||
Sb = 0;
|
||||
}
|
||||
|
||||
int a = srcover_byte(sa, da);
|
||||
int r = blendfunc_nonsep_byte(sr, dr, sa, da, Sr);
|
||||
int g = blendfunc_nonsep_byte(sg, dg, sa, da, Sg);
|
||||
int b = blendfunc_nonsep_byte(sb, db, sa, da, Sb);
|
||||
return SkPackARGB32(a, r, g, b);
|
||||
}
|
||||
|
||||
// kSaturation_Mode
|
||||
// B(Cb, Cs) = SetLum(SetSat(Cb, Sat(Cs)), Lum(Cb))
|
||||
// Create a color with the saturation of the source color and the hue and luminosity of the backdrop color.
|
||||
static SkPMColor saturation_modeproc(SkPMColor src, SkPMColor dst) {
|
||||
int sr = SkGetPackedR32(src);
|
||||
int sg = SkGetPackedG32(src);
|
||||
int sb = SkGetPackedB32(src);
|
||||
int sa = SkGetPackedA32(src);
|
||||
|
||||
int dr = SkGetPackedR32(dst);
|
||||
int dg = SkGetPackedG32(dst);
|
||||
int db = SkGetPackedB32(dst);
|
||||
int da = SkGetPackedA32(dst);
|
||||
int Dr, Dg, Db;
|
||||
|
||||
if(sa && da) {
|
||||
Dr = dr * sa;
|
||||
Dg = dg * sa;
|
||||
Db = db * sa;
|
||||
SetSat(&Dr, &Dg, &Db, Sat(sr, sg, sb) * da);
|
||||
SetLum(&Dr, &Dg, &Db, sa * da, Lum(dr, dg, db) * sa);
|
||||
} else {
|
||||
Dr = 0;
|
||||
Dg = 0;
|
||||
Db = 0;
|
||||
}
|
||||
|
||||
int a = srcover_byte(sa, da);
|
||||
int r = blendfunc_nonsep_byte(sr, dr, sa, da, Dr);
|
||||
int g = blendfunc_nonsep_byte(sg, dg, sa, da, Dg);
|
||||
int b = blendfunc_nonsep_byte(sb, db, sa, da, Db);
|
||||
return SkPackARGB32(a, r, g, b);
|
||||
}
|
||||
|
||||
// kColor_Mode
|
||||
// B(Cb, Cs) = SetLum(Cs, Lum(Cb))
|
||||
// Create a color with the hue and saturation of the source color and the luminosity of the backdrop color.
|
||||
static SkPMColor color_modeproc(SkPMColor src, SkPMColor dst) {
|
||||
int sr = SkGetPackedR32(src);
|
||||
int sg = SkGetPackedG32(src);
|
||||
int sb = SkGetPackedB32(src);
|
||||
int sa = SkGetPackedA32(src);
|
||||
|
||||
int dr = SkGetPackedR32(dst);
|
||||
int dg = SkGetPackedG32(dst);
|
||||
int db = SkGetPackedB32(dst);
|
||||
int da = SkGetPackedA32(dst);
|
||||
int Sr, Sg, Sb;
|
||||
|
||||
if(sa && da) {
|
||||
Sr = sr * da;
|
||||
Sg = sg * da;
|
||||
Sb = sb * da;
|
||||
SetLum(&Sr, &Sg, &Sb, sa * da, Lum(dr, dg, db) * sa);
|
||||
} else {
|
||||
Sr = 0;
|
||||
Sg = 0;
|
||||
Sb = 0;
|
||||
}
|
||||
|
||||
int a = srcover_byte(sa, da);
|
||||
int r = blendfunc_nonsep_byte(sr, dr, sa, da, Sr);
|
||||
int g = blendfunc_nonsep_byte(sg, dg, sa, da, Sg);
|
||||
int b = blendfunc_nonsep_byte(sb, db, sa, da, Sb);
|
||||
return SkPackARGB32(a, r, g, b);
|
||||
}
|
||||
|
||||
// kLuminosity_Mode
|
||||
// B(Cb, Cs) = SetLum(Cb, Lum(Cs))
|
||||
// Create a color with the luminosity of the source color and the hue and saturation of the backdrop color.
|
||||
static SkPMColor luminosity_modeproc(SkPMColor src, SkPMColor dst) {
|
||||
int sr = SkGetPackedR32(src);
|
||||
int sg = SkGetPackedG32(src);
|
||||
int sb = SkGetPackedB32(src);
|
||||
int sa = SkGetPackedA32(src);
|
||||
|
||||
int dr = SkGetPackedR32(dst);
|
||||
int dg = SkGetPackedG32(dst);
|
||||
int db = SkGetPackedB32(dst);
|
||||
int da = SkGetPackedA32(dst);
|
||||
int Dr, Dg, Db;
|
||||
|
||||
if(sa && da) {
|
||||
Dr = dr * sa;
|
||||
Dg = dg * sa;
|
||||
Db = db * sa;
|
||||
SetLum(&Dr, &Dg, &Db, sa * da, Lum(sr, sg, sb) * da);
|
||||
} else {
|
||||
Dr = 0;
|
||||
Dg = 0;
|
||||
Db = 0;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const SkXfermodeProc gProcs[] = {
|
||||
clear_modeproc,
|
||||
src_modeproc,
|
||||
dst_modeproc,
|
||||
srcover_modeproc,
|
||||
dstover_modeproc,
|
||||
srcin_modeproc,
|
||||
dstin_modeproc,
|
||||
srcout_modeproc,
|
||||
dstout_modeproc,
|
||||
srcatop_modeproc,
|
||||
dstatop_modeproc,
|
||||
xor_modeproc,
|
||||
|
||||
plus_modeproc,
|
||||
modulate_modeproc,
|
||||
screen_modeproc,
|
||||
overlay_modeproc,
|
||||
darken_modeproc,
|
||||
lighten_modeproc,
|
||||
colordodge_modeproc,
|
||||
colorburn_modeproc,
|
||||
hardlight_modeproc,
|
||||
softlight_modeproc,
|
||||
difference_modeproc,
|
||||
exclusion_modeproc,
|
||||
multiply_modeproc,
|
||||
hue_modeproc,
|
||||
saturation_modeproc,
|
||||
color_modeproc,
|
||||
luminosity_modeproc,
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SkProcCoeffXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
|
||||
const SkPMColor* SK_RESTRICT src, int count,
|
||||
const SkAlpha* SK_RESTRICT aa) const {
|
||||
SkASSERT(dst && src && count >= 0);
|
||||
|
||||
SkXfermodeProc proc = fProc;
|
||||
|
||||
if (proc) {
|
||||
if (nullptr == aa) {
|
||||
for (int i = count - 1; i >= 0; --i) {
|
||||
dst[i] = proc(src[i], dst[i]);
|
||||
}
|
||||
} else {
|
||||
for (int i = count - 1; i >= 0; --i) {
|
||||
unsigned a = aa[i];
|
||||
if (0 != a) {
|
||||
SkPMColor dstC = dst[i];
|
||||
SkPMColor C = proc(src[i], dstC);
|
||||
if (a != 0xFF) {
|
||||
C = SkFourByteInterp(C, dstC, a);
|
||||
}
|
||||
dst[i] = C;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char* SkBlendMode_Name(SkBlendMode mode) {
|
||||
SkASSERT((unsigned) mode <= (unsigned)SkBlendMode::kLastMode);
|
||||
const char* gModeStrings[] = {
|
||||
@ -94,20 +712,30 @@ sk_sp<SkXfermode> SkXfermode::Make(SkBlendMode mode) {
|
||||
}
|
||||
|
||||
const int COUNT_BLENDMODES = (int)SkBlendMode::kLastMode + 1;
|
||||
SkASSERT(SK_ARRAY_COUNT(gProcs) == COUNT_BLENDMODES);
|
||||
|
||||
static SkOnce once[COUNT_BLENDMODES];
|
||||
static SkXfermode* cached[COUNT_BLENDMODES];
|
||||
|
||||
once[(int)mode]([mode] {
|
||||
SkXfermodeProc proc = gProcs[(int)mode];
|
||||
if (auto xfermode = SkOpts::create_xfermode(mode)) {
|
||||
cached[(int)mode] = xfermode;
|
||||
} else {
|
||||
cached[(int)mode] = new SkProcCoeffXfermode(mode);
|
||||
cached[(int)mode] = new SkProcCoeffXfermode(proc, mode);
|
||||
}
|
||||
});
|
||||
return sk_ref_sp(cached[(int)mode]);
|
||||
}
|
||||
|
||||
SkXfermodeProc SkXfermode::GetProc(SkBlendMode mode) {
|
||||
SkXfermodeProc proc = nullptr;
|
||||
if ((unsigned)mode <= (unsigned)SkBlendMode::kLastMode) {
|
||||
proc = gProcs[(unsigned)mode];
|
||||
}
|
||||
return proc;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool SkXfermode::IsOpaque(SkBlendMode mode, SrcColorOpacity opacityType) {
|
||||
|
@ -42,6 +42,8 @@ public:
|
||||
return xfer.get();
|
||||
}
|
||||
|
||||
static SkXfermodeProc GetProc(SkBlendMode);
|
||||
|
||||
enum SrcColorOpacity {
|
||||
// The src color is known to be opaque (alpha == 255)
|
||||
kOpaque_SrcColorOpacity = 0,
|
||||
|
39
src/core/SkXfermode_proccoeff.h
Normal file
39
src/core/SkXfermode_proccoeff.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2015 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkXfermode_proccoeff_DEFINED
|
||||
#define SkXfermode_proccoeff_DEFINED
|
||||
|
||||
#include "SkXfermodePriv.h"
|
||||
|
||||
#define CANNOT_USE_COEFF SkXfermode::Coeff(-1)
|
||||
|
||||
class SkProcCoeffXfermode : public SkXfermode {
|
||||
public:
|
||||
SkProcCoeffXfermode(SkXfermodeProc proc, SkBlendMode mode) {
|
||||
fMode = mode;
|
||||
fProc = proc;
|
||||
}
|
||||
|
||||
void xfer32(SkPMColor dst[], const SkPMColor src[], int count,
|
||||
const SkAlpha aa[]) const override;
|
||||
|
||||
protected:
|
||||
SkBlendMode getMode() const { return fMode; }
|
||||
|
||||
SkXfermodeProc getProc() const { return fProc; }
|
||||
|
||||
private:
|
||||
SkXfermodeProc fProc;
|
||||
SkBlendMode fMode;
|
||||
|
||||
friend class SkXfermode;
|
||||
|
||||
typedef SkXfermode INHERITED;
|
||||
};
|
||||
|
||||
#endif // #ifndef SkXfermode_proccoeff_DEFINED
|
@ -54,8 +54,8 @@ static SkColor xferColor(SkColor src, SkColor dst, SkBlendMode mode) {
|
||||
default: {
|
||||
SkPMColor pmS = SkPreMultiplyColor(src);
|
||||
SkPMColor pmD = SkPreMultiplyColor(dst);
|
||||
SkXfermode::Peek(mode)->xfer32(&pmD, &pmS, 1, nullptr);
|
||||
return SkUnPreMultiply::PMColorToColor(pmD);
|
||||
SkPMColor result = SkXfermode::GetProc(mode)(pmS, pmD);
|
||||
return SkUnPreMultiply::PMColorToColor(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user