Added support for non-separable blending modes.
authorcommit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Tue, 5 Mar 2013 16:23:59 +0000 (16:23 +0000)
committercommit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Tue, 5 Mar 2013 16:23:59 +0000 (16:23 +0000)
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

gm/xfermodes.cpp
include/core/SkXfermode.h
src/core/SkXfermode.cpp
src/pdf/SkPDFGraphicState.cpp

index a5baeb9..65f53bf 100644 (file)
@@ -114,6 +114,10 @@ protected:
             { SkXfermode::kDifference_Mode,   "Difference"    },
             { SkXfermode::kExclusion_Mode,    "Exclusion"     },
             { SkXfermode::kMultiply_Mode,     "Multiply"      },
+            { SkXfermode::kHue_Mode,          "Hue"           },
+            { SkXfermode::kSaturation_Mode,   "Saturation"    },
+            { SkXfermode::kColor_Mode,        "Color"         },
+            { SkXfermode::kLuminosity_Mode,   "Luminosity"    },
         };
 
         const SkScalar w = SkIntToScalar(W);
index 27a6bf3..54946fd 100644 (file)
@@ -99,15 +99,14 @@ public:
         kSrcATop_Mode,  //!< [Da, Sc * Da + (1 - Sa) * Dc]
         kDstATop_Mode,  //!< [Sa, Sa * Dc + Sc * (1 - Da)]
         kXor_Mode,      //!< [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc]
-
-        // all remaining modes are defined in the SVG Compositing standard
-        // http://www.w3.org/TR/2009/WD-SVGCompositing-20090430/
-        kPlus_Mode,
+        kPlus_Mode,     //!< [Sa + Da, Sc + Dc]
         kModulate_Mode, // multiplies all components (= alpha and color)
 
         // all above modes can be expressed as pair of src/dst Coeffs
         kCoeffModesCnt,
 
+        // Following blend modes are defined in the CSS Compositing standard: 
+        // https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#blending
         kScreen_Mode = kCoeffModesCnt,
         kOverlay_Mode,
         kDarken_Mode,
@@ -120,7 +119,12 @@ public:
         kExclusion_Mode,
         kMultiply_Mode,
 
-        kLastMode = kMultiply_Mode
+        kHue_Mode,
+        kSaturation_Mode,
+        kColor_Mode,
+        kLuminosity_Mode,
+
+        kLastMode = kLuminosity_Mode
     };
 
     /**
index c0a825c..ddcccec 100644 (file)
@@ -431,6 +431,233 @@ static SkPMColor exclusion_modeproc(SkPMColor src, SkPMColor dst) {
     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 @@ static const ProcCoeff gProcCoeffs[] = {
     { 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 @@ static const Proc16Rec gModeProcs16[] = {
     { 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) {
index 558deb7..580d7e9 100644 (file)
@@ -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 @@ static const char* blend_mode_from_xfermode(SkXfermode::Mode mode) {
         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 @@ static const char* blend_mode_from_xfermode(SkXfermode::Mode mode) {
         case SkXfermode::kDstATop_Mode:
         case SkXfermode::kXor_Mode:
         case SkXfermode::kPlus_Mode:
-        case SkXfermode::kMultiply_Mode:
             return NULL;
     }
     return NULL;