Added support for non-separable blending modes.
Fixed scalar issue from https://codereview.appspot.com/7346044
Review URL: https://chromiumcodereview.appspot.com/12393049
git-svn-id: http://skia.googlecode.com/svn/trunk@7984 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/core/SkXfermode.cpp b/src/core/SkXfermode.cpp
index c0a825c..ddcccec 100644
--- a/src/core/SkXfermode.cpp
+++ b/src/core/SkXfermode.cpp
@@ -431,6 +431,233 @@
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 (r * 77 + g * 151 + b * 28) >> 8;
+}
+
+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 = (((*Cmid - *Cmin) * s ) / (*Cmax - *Cmin));
+ *Cmax = s;
+ } else {
+ *Cmax = 0;
+ *Cmid = 0;
+ }
+
+ *Cmin = 0;
+}
+
+static inline void SetSat(int* r, int* g, int* b, int s) {
+ if(*r <= *g) {
+ if(*g <= *b) {
+ setSaturationComponents(r, g, b, s);
+ } else if(*r <= *b) {
+ setSaturationComponents(r, b, g, s);
+ } else {
+ setSaturationComponents(b, r, g, s);
+ }
+ } 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 L = Lum(*r, *g, *b);
+ int n = minimum(*r, *g, *b);
+ int x = maximum(*r, *g, *b);
+ if(n < 0) {
+ *r = L + (((*r - L) * L) / (L - n));
+ *g = L + (((*g - L) * L) / (L - n));
+ *b = L + (((*b - L) * L) / (L - n));
+ }
+
+ if(x > 255) {
+ *r = L + (((*r - L) * (255 - L)) / (x - L));
+ *g = L + (((*g - L) * (255 - L)) / (x - L));
+ *b = L + (((*b - L) * (255 - L)) / (x - L));
+ }
+}
+
+static inline void SetLum(int* r, int* g, int* b, int l) {
+ int d = l - Lum(*r, *g, *b);
+ *r += d;
+ *g += d;
+ *b += d;
+
+ clipColor(r, g, b);
+}
+
+// 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) + clamp_div255round(sa * da) * 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 = SkMulDiv255Round(sr, sa);
+ Sg = SkMulDiv255Round(sg, sa);
+ Sb = SkMulDiv255Round(sb, sa);
+ int Dr = SkMulDiv255Round(dr, da);
+ int Dg = SkMulDiv255Round(dg, da);
+ int Db = SkMulDiv255Round(db, da);
+ SetSat(&Sr, &Sg, &Sb, Sat(Dr, Dg, Db));
+ SetLum(&Sr, &Sg, &Sb, Lum(Dr, Dg, Db));
+ } 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) {
+ int Sr = SkMulDiv255Round(sr, sa);
+ int Sg = SkMulDiv255Round(sg, sa);
+ int Sb = SkMulDiv255Round(sb, sa);
+ Dr = SkMulDiv255Round(dr, da);
+ Dg = SkMulDiv255Round(dg, da);
+ Db = SkMulDiv255Round(db, da);
+ int LumD = Lum(Dr, Dg, Db);
+ SetSat(&Dr, &Dg, &Db, Sat(Sr, Sg, Sb));
+ SetLum(&Dr, &Dg, &Db, LumD);
+ } 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 = SkMulDiv255Round(sr, sa);
+ Sg = SkMulDiv255Round(sg, sa);
+ Sb = SkMulDiv255Round(sb, sa);
+ int Dr = SkMulDiv255Round(dr, da);
+ int Dg = SkMulDiv255Round(dg, da);
+ int Db = SkMulDiv255Round(db, da);
+ SetLum(&Sr, &Sg, &Sb, Lum(Dr, Dg, Db));
+ } 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) {
+ int Sr = SkMulDiv255Round(sr, sa);
+ int Sg = SkMulDiv255Round(sg, sa);
+ int Sb = SkMulDiv255Round(sb, sa);
+ Dr = SkMulDiv255Round(dr, da);
+ Dg = SkMulDiv255Round(dg, da);
+ Db = SkMulDiv255Round(db, da);
+ SetLum(&Dr, &Dg, &Db, Lum(Sr, Sg, Sb));
+ } 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);
+}
+
+
struct ProcCoeff {
SkXfermodeProc fProc;
SkXfermode::Coeff fSC;
@@ -466,6 +693,10 @@
{ difference_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ exclusion_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
{ multiply_modeproc, CANNOT_USE_COEFF, CANNOT_USE_COEFF },
+ { 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 },
};
///////////////////////////////////////////////////////////////////////////////
@@ -1264,6 +1495,11 @@
{ NULL, NULL, NULL }, // softlight
{ NULL, NULL, NULL }, // difference
{ NULL, NULL, NULL }, // exclusion
+ { NULL, NULL, NULL }, // multiply
+ { NULL, NULL, NULL }, // hue
+ { NULL, NULL, NULL }, // saturation
+ { NULL, NULL, NULL }, // color
+ { NULL, NULL, NULL }, // luminosity
};
SkXfermodeProc16 SkXfermode::GetProc16(Mode mode, SkColor srcColor) {
diff --git a/src/pdf/SkPDFGraphicState.cpp b/src/pdf/SkPDFGraphicState.cpp
index 558deb7..580d7e9 100644
--- a/src/pdf/SkPDFGraphicState.cpp
+++ b/src/pdf/SkPDFGraphicState.cpp
@@ -14,7 +14,9 @@
static const char* blend_mode_from_xfermode(SkXfermode::Mode mode) {
switch (mode) {
case SkXfermode::kSrcOver_Mode: return "Normal";
- case SkXfermode::kModulate_Mode: return "Multiply";
+ // kModulate is not really like multipy but similar most of the time.
+ case SkXfermode::kModulate_Mode:
+ case SkXfermode::kMultiply_Mode: return "Multiply";
case SkXfermode::kScreen_Mode: return "Screen";
case SkXfermode::kOverlay_Mode: return "Overlay";
case SkXfermode::kDarken_Mode: return "Darken";
@@ -25,6 +27,10 @@
case SkXfermode::kSoftLight_Mode: return "SoftLight";
case SkXfermode::kDifference_Mode: return "Difference";
case SkXfermode::kExclusion_Mode: return "Exclusion";
+ case SkXfermode::kHue_Mode: return "Hue";
+ case SkXfermode::kSaturation_Mode: return "Saturation";
+ case SkXfermode::kColor_Mode: return "Color";
+ case SkXfermode::kLuminosity_Mode: return "Luminosity";
// These are handled in SkPDFDevice::setUpContentEntry.
case SkXfermode::kClear_Mode:
@@ -42,7 +48,6 @@
case SkXfermode::kDstATop_Mode:
case SkXfermode::kXor_Mode:
case SkXfermode::kPlus_Mode:
- case SkXfermode::kMultiply_Mode:
return NULL;
}
return NULL;