Index: src/core/SkXfermode.cpp |
=================================================================== |
--- src/core/SkXfermode.cpp (revision 7962) |
+++ src/core/SkXfermode.cpp (working copy) |
@@ -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) { |