[External patch] Source-over support for SkLumaXfermode.
authorfmalita@google.com <fmalita@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Tue, 17 Sep 2013 13:09:16 +0000 (13:09 +0000)
committerfmalita@google.com <fmalita@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Tue, 17 Sep 2013 13:09:16 +0000 (13:09 +0000)
This is a patch by Andrei Parvu <parvu@adobe.com> (Adobe CLA signer).

Original CL/review: https://codereview.chromium.org/24078006/

GM:lumamode will need rebaselining after landing this.

---

  In order to use CSS luminance masking, we need to be able to create an
  instance of SkLumaXfermode which can receive a kSrcOver mode, and applies
  that mode after converting the source using the luminance-to-alpha
  coefficients.

BUG=289420
R=reed@google.com

Review URL: https://codereview.chromium.org/23710053

git-svn-id: http://skia.googlecode.com/svn/trunk@11312 2bbb7eff-a529-9590-31e7-b0007b416f81

bench/XfermodeBench.cpp
gm/lumamode.cpp
include/effects/SkLumaXfermode.h
src/effects/SkLumaXfermode.cpp
src/ports/SkGlobalInitialization_chromium.cpp
src/ports/SkGlobalInitialization_default.cpp

index aed4c3478cddd0b9b1218c2183d5129133d4ab9b..e9b3b95021ed5f1ed8ea9f4d4719d31938042651 100644 (file)
@@ -105,3 +105,4 @@ BENCH(SkXfermode::kLuminosity_Mode)
 
 BENCH(SkLumaMaskXfermode::Create(SkXfermode::kSrcIn_Mode), "SrcInLuma")
 BENCH(SkLumaMaskXfermode::Create(SkXfermode::kDstIn_Mode), "DstInLuma")
+BENCH(SkLumaMaskXfermode::Create(SkXfermode::kSrcOver_Mode), "SrcOverLuma")
index e6aed18bb4ba046e8acb348ba46733278f0cc301..dbf45411fb290c9ec65fd5b53bde00e29126f6bc 100644 (file)
@@ -76,6 +76,7 @@ public:
     LumaXfermodeGM() {
         fSrcInXfer.reset(SkLumaMaskXfermode::Create(SkXfermode::kSrcIn_Mode));
         fDstInXfer.reset(SkLumaMaskXfermode::Create(SkXfermode::kDstIn_Mode));
+        fSrcOverXfer.reset(SkLumaMaskXfermode::Create(SkXfermode::kSrcOver_Mode));
 
         SkColor  g1Colors[] = { kColor1, SkColorSetA(kColor1, 0x20) };
         SkColor  g2Colors[] = { kColor2, SkColorSetA(kColor2, 0x20) };
@@ -101,11 +102,11 @@ protected:
     }
 
     virtual SkISize onISize() SK_OVERRIDE {
-        return SkISize::Make(600, 420);
+        return SkISize::Make(800, 420);
     }
 
     virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
-        SkXfermode* modes[] = { NULL, fSrcInXfer, fDstInXfer };
+        SkXfermode* modes[] = { NULL, fSrcInXfer, fDstInXfer, fSrcOverXfer };
         struct {
             SkShader*   fShader1;
             SkShader*   fShader2;
@@ -120,6 +121,7 @@ protected:
         draw_label(canvas, "SrcOver", SkPoint::Make(gridStep, 20));
         draw_label(canvas, "SrcInLuma", SkPoint::Make(gridStep * 3, 20));
         draw_label(canvas, "DstInLuma", SkPoint::Make(gridStep * 5, 20));
+        draw_label(canvas, "SrcOverLuma", SkPoint::Make(gridStep * 7, 20));
         for (size_t i = 0; i < SK_ARRAY_COUNT(shaders); ++i) {
             canvas->save();
             canvas->translate(kInset, gridStep * i + 30);
@@ -137,7 +139,7 @@ protected:
 
 private:
     SkAutoTUnref<SkShader>   fGr1, fGr2;
-    SkAutoTUnref<SkXfermode> fSrcInXfer, fDstInXfer;
+    SkAutoTUnref<SkXfermode> fSrcInXfer, fDstInXfer, fSrcOverXfer;
 
     typedef skiagm::GM INHERITED;
 };
index 5bcd10eff1bca6fbe7ae2292c7f201c6ee6df5ef..b189328fdb1f36cec1249a5a772f7d321804ed30 100644 (file)
@@ -16,7 +16,7 @@
  *  http://www.w3.org/TR/css-masking/#MaskValues
  *
  *  The luminance-to-alpha function is applied before performing a standard
- *  SrcIn/DstIn xfer:
+ *  SrcIn/DstIn/SrcOver xfer:
  *
  *    luma(C) = (0.2125 * C.r + 0.7154 * C.g + 0.0721 * C.b) * C.a
  *
@@ -26,7 +26,7 @@ class SK_API SkLumaMaskXfermode : public SkXfermode {
 public:
     /** Return an SkLumaMaskXfermode object for the specified submode.
      *
-     *  Only kSrcIn_Mode and kDstIn_Mode are supported - for everything else,
+     *  Only kSrcIn_Mode, kDstIn_Mode kSrcOver_Mode are supported - for everything else,
      *  the factory returns NULL.
      */
     static SkXfermode* Create(SkXfermode::Mode);
@@ -37,6 +37,7 @@ public:
 
     SK_DEVELOPER_TO_STRING()
     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkLumaMaskXfermode)
+    SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP()
 
 #if SK_SUPPORT_GPU
     virtual bool asNewEffectOrCoeff(GrContext*, GrEffectRef**, Coeff*, Coeff*,
@@ -47,12 +48,14 @@ protected:
     SkLumaMaskXfermode(SkFlattenableReadBuffer&);
     virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;
 
-private:
     SkLumaMaskXfermode(SkXfermode::Mode);
 
+private:
     const SkXfermode::Mode fMode;
 
     typedef SkXfermode INHERITED;
+
+    virtual SkPMColor lumaProc(const SkPMColor a, const SkPMColor b) const;
 };
 
 #endif
index 88b0ddfbc341c3621df6f2e1836260dcc7616caa..a23e010366ead4e21cc6251ec75c80097994460d 100644 (file)
 #include "GrTBackendEffectFactory.h"
 #endif
 
-static inline SkPMColor luma_proc(const SkPMColor a, const SkPMColor b) {
+class SkLumaMaskXfermodeSrcOver : public SkLumaMaskXfermode {
+public:
+    SkLumaMaskXfermodeSrcOver();
+
+    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkLumaMaskXfermodeSrcOver)
+
+protected:
+    SkLumaMaskXfermodeSrcOver(SkFlattenableReadBuffer&);
+
+private:
+    typedef SkLumaMaskXfermode INHERITED;
+
+    virtual SkPMColor lumaProc(const SkPMColor a, const SkPMColor b) const;
+};
+
+SkPMColor SkLumaMaskXfermode::lumaProc(const SkPMColor a, const SkPMColor b) const {
     unsigned luma = SkComputeLuminance(SkGetPackedR32(b),
                                        SkGetPackedG32(b),
                                        SkGetPackedB32(b));
@@ -40,18 +55,22 @@ SkXfermode* SkLumaMaskXfermode::Create(SkXfermode::Mode mode) {
     if (kSrcIn_Mode == mode || kDstIn_Mode == mode) {
         return SkNEW_ARGS(SkLumaMaskXfermode, (mode));
     }
+    if (kSrcOver_Mode == mode) {
+        return SkNEW_ARGS(SkLumaMaskXfermodeSrcOver, ());
+    }
+
     return NULL;
 }
 
 SkLumaMaskXfermode::SkLumaMaskXfermode(SkXfermode::Mode mode)
     : fMode(mode) {
-    SkASSERT(kSrcIn_Mode == mode || kDstIn_Mode == mode);
+    SkASSERT(kSrcIn_Mode == mode || kDstIn_Mode == mode || kSrcOver_Mode == mode);
 }
 
 SkLumaMaskXfermode::SkLumaMaskXfermode(SkFlattenableReadBuffer& buffer)
     : INHERITED(buffer)
     , fMode((SkXfermode::Mode)buffer.readUInt()) {
-    SkASSERT(kSrcIn_Mode == fMode || kDstIn_Mode == fMode);
+    SkASSERT(kSrcIn_Mode == fMode || kDstIn_Mode == fMode || kSrcOver_Mode == fMode);
 }
 
 void SkLumaMaskXfermode::flatten(SkFlattenableWriteBuffer& buffer) const {
@@ -62,7 +81,7 @@ void SkLumaMaskXfermode::flatten(SkFlattenableWriteBuffer& buffer) const {
 SkPMColor SkLumaMaskXfermode::xferColor(SkPMColor src, SkPMColor dst) const {
     const SkPMColor* a = lumaOpA<SkPMColor>(fMode, &src, &dst);
     const SkPMColor* b = lumaOpB<SkPMColor>(fMode, &src, &dst);
-    return luma_proc(*a, *b);
+    return this->lumaProc(*a, *b);
 }
 
 void SkLumaMaskXfermode::xfer32(SkPMColor dst[], const SkPMColor src[],
@@ -74,7 +93,7 @@ void SkLumaMaskXfermode::xfer32(SkPMColor dst[], const SkPMColor src[],
         for (int i = 0; i < count; ++i) {
             unsigned cov = aa[i];
             if (cov) {
-                unsigned resC = luma_proc(a[i], b[i]);
+                unsigned resC = this->lumaProc(a[i], b[i]);
                 if (cov < 255) {
                     resC = SkFastFourByteInterp256(resC, dst[i],
                                                    SkAlpha255To256(cov));
@@ -84,7 +103,7 @@ void SkLumaMaskXfermode::xfer32(SkPMColor dst[], const SkPMColor src[],
         }
     } else {
         for (int i = 0; i < count; ++i) {
-            dst[i] = luma_proc(a[i], b[i]);
+            dst[i] = this->lumaProc(a[i], b[i]);
         }
     }
 }
@@ -92,10 +111,41 @@ void SkLumaMaskXfermode::xfer32(SkPMColor dst[], const SkPMColor src[],
 #ifdef SK_DEVELOPER
 void SkLumaMaskXfermode::toString(SkString* str) const {
     str->printf("SkLumaMaskXfermode: mode: %s",
-                fMode == kSrcIn_Mode ? "SRC_IN" : "DST_IN");
+                fMode == kSrcIn_Mode ? "SRC_IN" :
+                fMode == kDstIn_Mode ? "DST_IN" : "SRC_OVER");
 }
 #endif
 
+SkLumaMaskXfermodeSrcOver::SkLumaMaskXfermodeSrcOver() : SkLumaMaskXfermode(kSrcOver_Mode) {}
+
+SkLumaMaskXfermodeSrcOver::SkLumaMaskXfermodeSrcOver(SkFlattenableReadBuffer& buffer)
+    : INHERITED(buffer) {
+}
+
+SkPMColor SkLumaMaskXfermodeSrcOver::lumaProc(const SkPMColor a, const SkPMColor b) const {
+    unsigned luma = SkComputeLuminance(SkGetPackedR32(b),
+                                       SkGetPackedG32(b),
+                                       SkGetPackedB32(b));
+
+    unsigned oldAlpha = SkGetPackedA32(b);
+    unsigned newR = 0, newG = 0, newB = 0;
+
+    if (oldAlpha > 0) {
+        newR = SkGetPackedR32(b) * 255 / oldAlpha;
+        newG = SkGetPackedG32(b) * 255 / oldAlpha;
+        newB = SkGetPackedB32(b) * 255 / oldAlpha;
+    }
+
+    SkPMColor colorB = SkPremultiplyARGBInline(luma, newR, newG, newB);
+
+    return SkPMSrcOver(colorB, a);
+}
+
+SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkLumaMaskXfermode)
+    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLumaMaskXfermode)
+    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLumaMaskXfermodeSrcOver)
+SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
+
 #if SK_SUPPORT_GPU
 //////////////////////////////////////////////////////////////////////////////
 
@@ -174,7 +224,12 @@ void GrGLLumaMaskEffect::emitCode(GrGLShaderBuilder* builder,
                            SK_ITU_BT709_LUM_COEFF_G,
                            SK_ITU_BT709_LUM_COEFF_B,
                            opB);
-    builder->fsCodeAppendf("\t\t%s = %s * luma;\n", outputColor, opA);
+    if (SkXfermode::kSrcOver_Mode == lumaEffect.getMode()) {
+        builder->fsCodeAppendf("\t\tvec4 newB = %s;\n\t\tif (newB.a > 0.0) { newB *= luma / newB.a; }\n\t\tnewB.a = luma;\n", opB);
+        builder->fsCodeAppendf("\t\t%s = newB + %s * (1.0 - luma); \n", outputColor, opA);
+    } else {
+        builder->fsCodeAppendf("\t\t%s = %s * luma;\n", outputColor, opA);
+    }
 }
 
 GrGLEffect::EffectKey GrGLLumaMaskEffect::GenKey(const GrDrawEffect& drawEffect,
index ebdbffb7caa68825de5a7034bcb2118687d1de2c..6b25a4d6b0739551ed74266fdbaf4cdf7ea96c11 100644 (file)
@@ -25,12 +25,12 @@ void SkFlattenable::InitializeFlattenables() {
     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkCornerPathEffect)
     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkDashPathEffect)
     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLayerDrawLooper)
-    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLumaMaskXfermode)
     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkMallocPixelRef)
     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkMagnifierImageFilter)
 
     SkBlurMaskFilter::InitializeFlattenables();
     SkColorFilter::InitializeFlattenables();
     SkGradientShader::InitializeFlattenables();
+    SkLumaMaskXfermode::InitializeFlattenables();
     SkXfermode::InitializeFlattenables();
 }
index 21b15a6182a9cade155161ff48b01e9989f5d166..9a0d8dfbeacdc63fabfb377be418db1808b194ba 100644 (file)
@@ -88,7 +88,6 @@ void SkFlattenable::InitializeFlattenables() {
     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLayerDrawLooper)
     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLayerRasterizer)
     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLerpXfermode)
-    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLumaMaskXfermode)
     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPath1DPathEffect)
     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(Sk2DPathEffect)
     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLine2DPathEffect)
@@ -115,6 +114,7 @@ void SkFlattenable::InitializeFlattenables() {
     SkGradientShader::InitializeFlattenables();
     SkImages::InitializeFlattenables();
     SkLightingImageFilter::InitializeFlattenables();
+    SkLumaMaskXfermode::InitializeFlattenables();
     SkTableColorFilter::InitializeFlattenables();
     SkXfermode::InitializeFlattenables();
 }