aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/SkXfermode.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/SkXfermode.cpp')
-rw-r--r--src/core/SkXfermode.cpp416
1 files changed, 37 insertions, 379 deletions
diff --git a/src/core/SkXfermode.cpp b/src/core/SkXfermode.cpp
index 02abe55f74..e6c10e7c4b 100644
--- a/src/core/SkXfermode.cpp
+++ b/src/core/SkXfermode.cpp
@@ -56,308 +56,6 @@ static inline int clamp_div255round(int prod) {
}
///////////////////////////////////////////////////////////////////////////////
-#include "SkNx.h"
-
-static Sk4f alpha(const Sk4f& color) { return Sk4f(color[3]); }
-static Sk4f inv_alpha(const Sk4f& color) { return Sk4f(1 - color[3]); }
-static Sk4f pin_1(const Sk4f& value) { return Sk4f::Min(value, Sk4f(1)); }
-
-static Sk4f color_alpha(const Sk4f& color, float newAlpha) {
- return Sk4f(color[0], color[1], color[2], newAlpha);
-}
-static Sk4f color_alpha(const Sk4f& color, const Sk4f& newAlpha) {
- return color_alpha(color, newAlpha[3]);
-}
-
-static Sk4f set_argb(float a, float r, float g, float b) {
- if (0 == SkPM4f::R) {
- return Sk4f(r, g, b, a);
- } else {
- return Sk4f(b, g, r, a);
- }
-}
-
-static Sk4f clear_4f(const Sk4f& s, const Sk4f& d) { return Sk4f(0); }
-static Sk4f src_4f(const Sk4f& s, const Sk4f& d) { return s; }
-static Sk4f dst_4f(const Sk4f& s, const Sk4f& d) { return d; }
-static Sk4f srcover_4f(const Sk4f& s, const Sk4f& d) { return s + inv_alpha(s) * d; }
-static Sk4f dstover_4f(const Sk4f& s, const Sk4f& d) { return d + inv_alpha(d) * s; }
-static Sk4f srcin_4f(const Sk4f& s, const Sk4f& d) { return s * alpha(d); }
-static Sk4f dstin_4f(const Sk4f& s, const Sk4f& d) { return d * alpha(s); }
-static Sk4f srcout_4f(const Sk4f& s, const Sk4f& d) { return s * inv_alpha(d); }
-static Sk4f dstout_4f(const Sk4f& s, const Sk4f& d) { return d * inv_alpha(s); }
-static Sk4f srcatop_4f(const Sk4f& s, const Sk4f& d) { return s * alpha(d) + d * inv_alpha(s); }
-static Sk4f dstatop_4f(const Sk4f& s, const Sk4f& d) { return d * alpha(s) + s * inv_alpha(d); }
-static Sk4f xor_4f(const Sk4f& s, const Sk4f& d) { return s * inv_alpha(d) + d * inv_alpha(s);}
-static Sk4f plus_4f(const Sk4f& s, const Sk4f& d) { return pin_1(s + d); }
-static Sk4f modulate_4f(const Sk4f& s, const Sk4f& d) { return s * d; }
-static Sk4f screen_4f(const Sk4f& s, const Sk4f& d) { return s + d - s * d; }
-
-static Sk4f multiply_4f(const Sk4f& s, const Sk4f& d) {
- return s * inv_alpha(d) + d * inv_alpha(s) + s * d;
-}
-
-static Sk4f overlay_4f(const Sk4f& s, const Sk4f& d) {
- Sk4f sa = alpha(s);
- Sk4f da = alpha(d);
- Sk4f two = Sk4f(2);
- Sk4f rc = (two * d <= da).thenElse(two * s * d,
- sa * da - two * (da - d) * (sa - s));
- return pin_1(s + d - s * da + color_alpha(rc - d * sa, 0));
-}
-
-static Sk4f hardlight_4f(const Sk4f& s, const Sk4f& d) {
- return overlay_4f(d, s);
-}
-
-static Sk4f darken_4f(const Sk4f& s, const Sk4f& d) {
- Sk4f sa = alpha(s);
- Sk4f da = alpha(d);
- return s + d - Sk4f::Max(s * da, d * sa);
-}
-
-static Sk4f lighten_4f(const Sk4f& s, const Sk4f& d) {
- Sk4f sa = alpha(s);
- Sk4f da = alpha(d);
- return s + d - Sk4f::Min(s * da, d * sa);
-}
-
-static Sk4f colordodge_4f(const Sk4f& s, const Sk4f& d) {
- Sk4f sa = alpha(s);
- Sk4f da = alpha(d);
- Sk4f isa = Sk4f(1) - sa;
- Sk4f ida = Sk4f(1) - da;
-
- Sk4f srcover = s + d * isa;
- Sk4f dstover = d + s * ida;
- Sk4f otherwise = sa * Sk4f::Min(da, (d * sa) / (sa - s)) + s * ida + d * isa;
-
- // Order matters here, preferring d==0 over s==sa.
- auto colors = (d == Sk4f(0)).thenElse(dstover,
- (s == sa).thenElse(srcover,
- otherwise));
- return color_alpha(colors, srcover);
-}
-
-static Sk4f colorburn_4f(const Sk4f& s, const Sk4f& d) {
- Sk4f sa = alpha(s);
- Sk4f da = alpha(d);
- Sk4f isa = Sk4f(1) - sa;
- Sk4f ida = Sk4f(1) - da;
-
- Sk4f srcover = s + d * isa;
- Sk4f dstover = d + s * ida;
- Sk4f otherwise = sa * (da - Sk4f::Min(da, (da - d) * sa / s)) + s * ida + d * isa;
-
- // Order matters here, preferring d==da over s==0.
- auto colors = (d == da).thenElse(dstover,
- (s == Sk4f(0)).thenElse(srcover,
- otherwise));
- return color_alpha(colors, srcover);
-}
-
-static Sk4f softlight_4f(const Sk4f& s, const Sk4f& d) {
- Sk4f sa = alpha(s);
- Sk4f da = alpha(d);
- Sk4f isa = Sk4f(1) - sa;
- Sk4f ida = Sk4f(1) - da;
-
- // Some common terms.
- Sk4f m = (da > Sk4f(0)).thenElse(d / da, Sk4f(0));
- Sk4f s2 = Sk4f(2) * s;
- Sk4f m4 = Sk4f(4) * m;
-
- // The logic forks three ways:
- // 1. dark src?
- // 2. light src, dark dst?
- // 3. light src, light dst?
- Sk4f darkSrc = d * (sa + (s2 - sa) * (Sk4f(1) - m)); // Used in case 1.
- Sk4f darkDst = (m4 * m4 + m4) * (m - Sk4f(1)) + Sk4f(7) * m; // Used in case 2.
- Sk4f liteDst = m.sqrt() - m; // Used in case 3.
- Sk4f liteSrc = d * sa + da * (s2 - sa) * (Sk4f(4) * d <= da).thenElse(darkDst,
- liteDst); // Case 2 or 3?
-
- return color_alpha(s * ida + d * isa + (s2 <= sa).thenElse(darkSrc, liteSrc), // Case 1 or 2/3?
- s + d * isa);
-}
-
-static Sk4f difference_4f(const Sk4f& s, const Sk4f& d) {
- Sk4f min = Sk4f::Min(s * alpha(d), d * alpha(s));
- return s + d - min - color_alpha(min, 0);
-}
-
-static Sk4f exclusion_4f(const Sk4f& s, const Sk4f& d) {
- Sk4f product = s * d;
- return s + d - product - color_alpha(product, 0);
-}
-
-////////////////////////////////////////////////////
-
-// The CSS compositing spec introduces the following formulas:
-// (See https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#blendingnonseparable)
-// SkComputeLuminance is similar to this formula but it uses the new definition from Rec. 709
-// while PDF and CG uses the one from Rec. Rec. 601
-// See http://www.glennchan.info/articles/technical/hd-versus-sd-color-space/hd-versus-sd-color-space.htm
-static inline float Lum(float r, float g, float b) {
- return r * 0.2126f + g * 0.7152f + b * 0.0722f;
-}
-
-static inline float max(float a, float b, float c) {
- return SkTMax(a, SkTMax(b, c));
-}
-
-static inline float min(float a, float b, float c) {
- return SkTMin(a, SkTMin(b, c));
-}
-
-static inline float Sat(float r, float g, float b) {
- return max(r, g, b) - min(r, g, b);
-}
-
-static inline void setSaturationComponents(float* Cmin, float* Cmid, float* Cmax, float s) {
- if(*Cmax > *Cmin) {
- *Cmid = (*Cmid - *Cmin) * s / (*Cmax - *Cmin);
- *Cmax = s;
- } else {
- *Cmax = 0;
- *Cmid = 0;
- }
- *Cmin = 0;
-}
-
-static inline void SetSat(float* r, float* g, float* b, float s) {
- if(*r <= *g) {
- if(*g <= *b) {
- setSaturationComponents(r, g, b, s);
- } else if(*r <= *b) {
- setSaturationComponents(r, b, g, s);
- } else {
- setSaturationComponents(b, r, g, s);
- }
- } else if(*r <= *b) {
- setSaturationComponents(g, r, b, s);
- } else if(*g <= *b) {
- setSaturationComponents(g, b, r, s);
- } else {
- setSaturationComponents(b, g, r, s);
- }
-}
-
-static inline void clipColor(float* r, float* g, float* b, float a) {
- float L = Lum(*r, *g, *b);
- float n = min(*r, *g, *b);
- float x = max(*r, *g, *b);
- float denom;
- if ((n < 0) && (denom = L - n)) { // Compute denom and make sure it's non zero
- float scale = L / denom;
- *r = L + (*r - L) * scale;
- *g = L + (*g - L) * scale;
- *b = L + (*b - L) * scale;
- }
-
- if ((x > a) && (denom = x - L)) { // Compute denom and make sure it's non zero
- float scale = (a - L) / denom;
- *r = L + (*r - L) * scale;
- *g = L + (*g - L) * scale;
- *b = L + (*b - L) * scale;
- }
-}
-
-static inline void SetLum(float* r, float* g, float* b, float a, float l) {
- float d = l - Lum(*r, *g, *b);
- *r += d;
- *g += d;
- *b += d;
- clipColor(r, g, b, a);
-}
-
-static Sk4f hue_4f(const Sk4f& s, const Sk4f& d) {
- float sa = s[SkPM4f::A];
- float sr = s[SkPM4f::R];
- float sg = s[SkPM4f::G];
- float sb = s[SkPM4f::B];
-
- float da = d[SkPM4f::A];
- float dr = d[SkPM4f::R];
- float dg = d[SkPM4f::G];
- float db = d[SkPM4f::B];
-
- float Sr = sr;
- float Sg = sg;
- float Sb = sb;
- SetSat(&Sr, &Sg, &Sb, Sat(dr, dg, db) * sa);
- SetLum(&Sr, &Sg, &Sb, sa * da, Lum(dr, dg, db) * sa);
-
- return color_alpha(s * inv_alpha(d) + d * inv_alpha(s) + set_argb(0, Sr, Sg, Sb),
- sa + da - sa * da);
-}
-
-static Sk4f saturation_4f(const Sk4f& s, const Sk4f& d) {
- float sa = s[SkPM4f::A];
- float sr = s[SkPM4f::R];
- float sg = s[SkPM4f::G];
- float sb = s[SkPM4f::B];
-
- float da = d[SkPM4f::A];
- float dr = d[SkPM4f::R];
- float dg = d[SkPM4f::G];
- float db = d[SkPM4f::B];
-
- float Dr = dr;
- float Dg = dg;
- float Db = db;
- SetSat(&Dr, &Dg, &Db, Sat(sr, sg, sb) * da);
- SetLum(&Dr, &Dg, &Db, sa * da, Lum(dr, dg, db) * sa);
-
- return color_alpha(s * inv_alpha(d) + d * inv_alpha(s) + set_argb(0, Dr, Dg, Db),
- sa + da - sa * da);
-}
-
-static Sk4f color_4f(const Sk4f& s, const Sk4f& d) {
- float sa = s[SkPM4f::A];
- float sr = s[SkPM4f::R];
- float sg = s[SkPM4f::G];
- float sb = s[SkPM4f::B];
-
- float da = d[SkPM4f::A];
- float dr = d[SkPM4f::R];
- float dg = d[SkPM4f::G];
- float db = d[SkPM4f::B];
-
- float Sr = sr;
- float Sg = sg;
- float Sb = sb;
- SetLum(&Sr, &Sg, &Sb, sa * da, Lum(dr, dg, db) * sa);
-
- Sk4f res = color_alpha(s * inv_alpha(d) + d * inv_alpha(s) + set_argb(0, Sr, Sg, Sb),
- sa + da - sa * da);
- // Can return tiny negative values ...
- return Sk4f::Max(res, Sk4f(0));
-}
-
-static Sk4f luminosity_4f(const Sk4f& s, const Sk4f& d) {
- float sa = s[SkPM4f::A];
- float sr = s[SkPM4f::R];
- float sg = s[SkPM4f::G];
- float sb = s[SkPM4f::B];
-
- float da = d[SkPM4f::A];
- float dr = d[SkPM4f::R];
- float dg = d[SkPM4f::G];
- float db = d[SkPM4f::B];
-
- float Dr = dr;
- float Dg = dg;
- float Db = db;
- SetLum(&Dr, &Dg, &Db, sa * da, Lum(sr, sg, sb) * da);
-
- Sk4f res = color_alpha(s * inv_alpha(d) + d * inv_alpha(s) + set_argb(0, Dr, Dg, Db),
- sa + da - sa * da);
- // Can return tiny negative values ...
- return Sk4f::Max(res, Sk4f(0));
-}
-
-///////////////////////////////////////////////////////////////////////////////
// kClear_Mode, //!< [0, 0]
static SkPMColor clear_modeproc(SkPMColor src, SkPMColor dst) {
@@ -924,71 +622,39 @@ static SkPMColor luminosity_modeproc(SkPMColor src, SkPMColor dst) {
///////////////////////////////////////////////////////////////////////////////////////////////////
-static SkPM4f as_pm4f(const Sk4f& x) {
- SkPM4f pm4;
- x.store(pm4.fVec);
- return pm4;
-}
-
-static Sk4f as_4f(const SkPM4f& pm4) {
- return Sk4f::Load(pm4.fVec);
-}
-
-static void assert_unit(const SkPM4f& r) {
-#ifdef SK_DEBUG
- const float eps = 0.00001f;
- const float min = 0 - eps;
- const float max = 1 + eps;
- for (int i = 0; i < 4; ++i) {
- SkASSERT(r.fVec[i] >= min && r.fVec[i] <= max);
- }
-#endif
-}
-
-template <Sk4f (blend)(const Sk4f&, const Sk4f&)> SkPM4f proc_4f(const SkPM4f& s, const SkPM4f& d) {
- assert_unit(s);
- assert_unit(d);
- SkPM4f r = as_pm4f(blend(as_4f(s), as_4f(d)));
- // Turn this assert off for now because srgb conversions may end up in rgb > a
- // assert_unit(r);
- return r;
-}
-
-const ProcCoeff gProcCoeffs[] = {
- { clear_modeproc, proc_4f<clear_4f> },
- { src_modeproc, proc_4f<src_4f> },
- { dst_modeproc, proc_4f<dst_4f> },
- { srcover_modeproc, proc_4f<srcover_4f> },
- { dstover_modeproc, proc_4f<dstover_4f> },
- { srcin_modeproc, proc_4f<srcin_4f> },
- { dstin_modeproc, proc_4f<dstin_4f> },
- { srcout_modeproc, proc_4f<srcout_4f> },
- { dstout_modeproc, proc_4f<dstout_4f> },
- { srcatop_modeproc, proc_4f<srcatop_4f> },
- { dstatop_modeproc, proc_4f<dstatop_4f> },
- { xor_modeproc, proc_4f<xor_4f> },
-
- { plus_modeproc, proc_4f<plus_4f> },
- { modulate_modeproc, proc_4f<modulate_4f> },
- { screen_modeproc, proc_4f<screen_4f> },
- { overlay_modeproc, proc_4f<overlay_4f> },
- { darken_modeproc, proc_4f<darken_4f> },
- { lighten_modeproc, proc_4f<lighten_4f> },
- { colordodge_modeproc, proc_4f<colordodge_4f> },
- { colorburn_modeproc, proc_4f<colorburn_4f> },
- { hardlight_modeproc, proc_4f<hardlight_4f> },
- { softlight_modeproc, proc_4f<softlight_4f> },
- { difference_modeproc, proc_4f<difference_4f> },
- { exclusion_modeproc, proc_4f<exclusion_4f> },
- { multiply_modeproc, proc_4f<multiply_4f> },
- { hue_modeproc, proc_4f<hue_4f> },
- { saturation_modeproc, proc_4f<saturation_4f> },
- { color_modeproc, proc_4f<color_4f> },
- { luminosity_modeproc, proc_4f<luminosity_4f> },
+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,
};
-///////////////////////////////////////////////////////////////////////////////
-
bool SkXfermode::asMode(SkBlendMode* mode) const {
return false;
}
@@ -1015,7 +681,7 @@ const GrXPFactory* SkXfermode::asXPFactory() const {
sk_sp<SkFlattenable> SkProcCoeffXfermode::CreateProc(SkReadBuffer& buffer) {
uint32_t mode32 = buffer.read32();
- if (!buffer.validate(mode32 < SK_ARRAY_COUNT(gProcCoeffs))) {
+ if (!buffer.validate(mode32 < SK_ARRAY_COUNT(gProcs))) {
return nullptr;
}
return SkXfermode::Make((SkBlendMode)mode32);
@@ -1115,17 +781,17 @@ sk_sp<SkXfermode> SkXfermode::Make(SkBlendMode mode) {
}
const int COUNT_BLENDMODES = (int)SkBlendMode::kLastMode + 1;
- SkASSERT(SK_ARRAY_COUNT(gProcCoeffs) == COUNT_BLENDMODES);
+ SkASSERT(SK_ARRAY_COUNT(gProcs) == COUNT_BLENDMODES);
static SkOnce once[COUNT_BLENDMODES];
static SkXfermode* cached[COUNT_BLENDMODES];
once[(int)mode]([mode] {
- ProcCoeff rec = gProcCoeffs[(int)mode];
- if (auto xfermode = SkOpts::create_xfermode(rec, mode)) {
+ SkXfermodeProc proc = gProcs[(int)mode];
+ if (auto xfermode = SkOpts::create_xfermode(proc, mode)) {
cached[(int)mode] = xfermode;
} else {
- cached[(int)mode] = new SkProcCoeffXfermode(rec, mode);
+ cached[(int)mode] = new SkProcCoeffXfermode(proc, mode);
}
});
return sk_ref_sp(cached[(int)mode]);
@@ -1134,15 +800,7 @@ sk_sp<SkXfermode> SkXfermode::Make(SkBlendMode mode) {
SkXfermodeProc SkXfermode::GetProc(SkBlendMode mode) {
SkXfermodeProc proc = nullptr;
if ((unsigned)mode <= (unsigned)SkBlendMode::kLastMode) {
- proc = gProcCoeffs[(unsigned)mode].fProc;
- }
- return proc;
-}
-
-SkXfermodeProc4f SkXfermode::GetProc4f(SkBlendMode mode) {
- SkXfermodeProc4f proc = nullptr;
- if ((unsigned)mode <= (unsigned)SkBlendMode::kLastMode) {
- proc = gProcCoeffs[(unsigned)mode].fProc4f;
+ proc = gProcs[(unsigned)mode];
}
return proc;
}