Remove the need for asCoeff in SkXfermode.
authoregdaniel <egdaniel@google.com>
Thu, 22 Jan 2015 14:52:29 +0000 (06:52 -0800)
committerCommit bot <commit-bot@chromium.org>
Thu, 22 Jan 2015 14:52:29 +0000 (06:52 -0800)
BUG=skia:

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

include/core/SkXfermode.h
src/core/SkDraw.cpp
src/core/SkPaintPriv.cpp
src/core/SkXfermode.cpp
src/core/SkXfermode_proccoeff.h

index fc9ae21..1dd01a2 100644 (file)
@@ -57,29 +57,6 @@ public:
         kCoeffCount
     };
 
-    /** If the xfermode can be expressed as an equation using the coefficients
-        in Coeff, then asCoeff() returns true, and sets (if not null) src and
-        dst accordingly.
-
-            result = src_coeff * src_color + dst_coeff * dst_color;
-
-        As examples, here are some of the porterduff coefficients
-
-        MODE        SRC_COEFF       DST_COEFF
-        clear       zero            zero
-        src         one             zero
-        dst         zero            one
-        srcover     one             isa
-        dstover     ida             one
-     */
-    virtual bool asCoeff(Coeff* src, Coeff* dst) const;
-
-    /**
-     *  The same as calling xfermode->asCoeff(..), except that this also checks
-     *  if the xfermode is NULL, and if so, treats it as kSrcOver_Mode.
-     */
-    static bool AsCoeff(const SkXfermode*, Coeff* src, Coeff* dst);
-
     /** List of predefined xfermodes.
         The algebra for the modes uses the following symbols:
         Sa, Sc  - source alpha and color
@@ -190,6 +167,41 @@ public:
         return AsMode(xfer, mode);
     }
 
+    /**
+     * Returns whether or not the xfer mode can support treating coverage as alpha
+     */    
+    virtual bool supportsCoverageAsAlpha() const;
+
+    /**
+     *  The same as calling xfermode->supportsCoverageAsAlpha(), except that this also checks if
+     *  the xfermode is NULL, and if so, treats it as kSrcOver_Mode.
+     */
+    static bool SupportsCoverageAsAlpha(const SkXfermode* xfer);
+
+    enum SrcColorOpacity {
+        // The src color is known to be opaque (alpha == 255)
+        kOpaque_SrcColorOpacity = 0,
+        // The src color is known to be fully transparent (color == 0)
+        kTransparentBlack_SrcColorOpacity = 1,
+        // The src alpha is known to be fully transparent (alpha == 0)
+        kTransparentAlpha_SrcColorOpacity = 2,
+        // The src color opacity is unknown
+        kUnknown_SrcColorOpacity = 3
+    };
+
+    /**
+     * Returns whether or not the result of the draw with the xfer mode will be opaque or not. The
+     * input to this call is an enum describing known information about the opacity of the src color
+     * that will be given to the xfer mode.
+     */
+    virtual bool isOpaque(SrcColorOpacity opacityType) const;
+
+    /**
+     *  The same as calling xfermode->isOpaque(...), except that this also checks if
+     *  the xfermode is NULL, and if so, treats it as kSrcOver_Mode.
+     */
+    static bool IsOpaque(const SkXfermode* xfer, SrcColorOpacity opacityType);
+
     /** Implemented by a subclass to support use as an image filter in the GPU backend. When used as
         an image filter the xfer mode blends the source color against a background texture rather
         than the destination. It is implemented as a fragment processor. This can be called with
index f69137f..c42d3ef 100644 (file)
@@ -936,22 +936,6 @@ static SkScalar fast_len(const SkVector& vec) {
     return x + SkScalarHalf(y);
 }
 
-static bool xfermodeSupportsCoverageAsAlpha(SkXfermode* xfer) {
-    SkXfermode::Coeff dc;
-    if (!SkXfermode::AsCoeff(xfer, NULL, &dc)) {
-        return false;
-    }
-
-    switch (dc) {
-        case SkXfermode::kOne_Coeff:
-        case SkXfermode::kISA_Coeff:
-        case SkXfermode::kISC_Coeff:
-            return true;
-        default:
-            return false;
-    }
-}
-
 bool SkDrawTreatAAStrokeAsHairline(SkScalar strokeWidth, const SkMatrix& matrix,
                                    SkScalar* coverage) {
     SkASSERT(strokeWidth > 0);
@@ -1063,7 +1047,7 @@ void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint,
         if (SkDrawTreatAsHairline(origPaint, *matrix, &coverage)) {
             if (SK_Scalar1 == coverage) {
                 paint.writable()->setStrokeWidth(0);
-            } else if (xfermodeSupportsCoverageAsAlpha(origPaint.getXfermode())) {
+            } else if (SkXfermode::SupportsCoverageAsAlpha(origPaint.getXfermode())) {
                 U8CPU newAlpha;
 #if 0
                 newAlpha = SkToU8(SkScalarRoundToInt(coverage *
index e82c404..c6957cd 100644 (file)
 #include "SkShader.h"
 
 bool isPaintOpaque(const SkPaint* paint, SkPaintBitmapOpacity contentType) {
-    // TODO: SkXfermode should have a virtual isOpaque method, which would
-    // make it possible to test modes that do not have a Coeff representation.
-
     if (!paint) {
         return contentType != kUnknown_SkPaintBitmapOpacity;
     }
-
-    SkXfermode::Coeff srcCoeff, dstCoeff;
-    if (SkXfermode::AsCoeff(paint->getXfermode(), &srcCoeff, &dstCoeff)){
-        if (SkXfermode::kDA_Coeff == srcCoeff || SkXfermode::kDC_Coeff == srcCoeff ||
-            SkXfermode::kIDA_Coeff == srcCoeff || SkXfermode::kIDC_Coeff == srcCoeff) {
-            return false;
-        }
-        switch (dstCoeff) {
-        case SkXfermode::kZero_Coeff:
-            return true;
-        case SkXfermode::kISA_Coeff:
-            if (paint->getAlpha() != 255) {
-                break;
-            }
-            if (contentType == kUnknown_SkPaintBitmapOpacity) {
-                break;
-            } else if (paint->getShader() && !paint->getShader()->isOpaque()) {
-                break;
-            }
-            if (paint->getColorFilter() &&
-                ((paint->getColorFilter()->getFlags() &
-                SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
-                break;
-            }
-            return true;
-        case SkXfermode::kSA_Coeff:
-            if (paint->getAlpha() != 0) {
-                break;
-            }
-            if (paint->getColorFilter() &&
-                ((paint->getColorFilter()->getFlags() &
-                SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
-                break;
-            }
-            return true;
-        case SkXfermode::kSC_Coeff:
-            if (paint->getColor() != 0) { // all components must be 0
-                break;
-            }
-            if (contentType != kNoBitmap_SkPaintBitmapOpacity || paint->getShader()) {
-                break;
-            }
-            if (paint->getColorFilter() && (
-                (paint->getColorFilter()->getFlags() &
-                SkColorFilter::kAlphaUnchanged_Flag) == 0)) {
-                break;
-            }
-            return true;
-        default:
-            break;
+    SkXfermode::SrcColorOpacity opacityType = SkXfermode::kUnknown_SrcColorOpacity;
+
+    if (!paint->getColorFilter() ||
+        ((paint->getColorFilter()->getFlags() &
+          SkColorFilter::kAlphaUnchanged_Flag) != 0)) {
+        if (0xff == paint->getAlpha() &&
+            contentType != kUnknown_SkPaintBitmapOpacity &&
+            (!paint->getShader() || paint->getShader()->isOpaque())) {
+            opacityType = SkXfermode::kOpaque_SrcColorOpacity;
+        } else if (0 == paint->getColor() &&
+                   contentType == kNoBitmap_SkPaintBitmapOpacity &&
+                   !paint->getShader()) {
+            opacityType = SkXfermode::kTransparentBlack_SrcColorOpacity;
+        } else if (0 == paint->getAlpha()) {
+            opacityType = SkXfermode::kTransparentAlpha_SrcColorOpacity;
         }
     }
-    return false;
+
+    return SkXfermode::IsOpaque(paint->getXfermode(), opacityType);
 }
 
 bool isPaintOpaque(const SkPaint* paint, const SkBitmap* bmpReplacesShader) {
index ac1ebcc..08f760d 100644 (file)
@@ -667,10 +667,6 @@ const ProcCoeff gProcCoeffs[] = {
 
 ///////////////////////////////////////////////////////////////////////////////
 
-bool SkXfermode::asCoeff(Coeff* src, Coeff* dst) const {
-    return false;
-}
-
 bool SkXfermode::asMode(Mode* mode) const {
     return false;
 }
@@ -783,6 +779,14 @@ void SkXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
     }
 }
 
+bool SkXfermode::supportsCoverageAsAlpha() const {
+    return false;
+}
+
+bool SkXfermode::isOpaque(SkXfermode::SrcColorOpacity opacityType) const {
+    return false;
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -805,18 +809,45 @@ bool SkProcCoeffXfermode::asMode(Mode* mode) const {
     return true;
 }
 
-bool SkProcCoeffXfermode::asCoeff(Coeff* sc, Coeff* dc) const {
+bool SkProcCoeffXfermode::supportsCoverageAsAlpha() const {
     if (CANNOT_USE_COEFF == fSrcCoeff) {
         return false;
     }
 
-    if (sc) {
-        *sc = fSrcCoeff;
+    switch (fDstCoeff) {
+        case SkXfermode::kOne_Coeff:
+        case SkXfermode::kISA_Coeff:
+        case SkXfermode::kISC_Coeff:
+            return true;
+        default:
+            return false;
+    }
+}
+
+bool SkProcCoeffXfermode::isOpaque(SkXfermode::SrcColorOpacity opacityType) const {
+    if (CANNOT_USE_COEFF == fSrcCoeff) {
+        return false;
     }
-    if (dc) {
-        *dc = fDstCoeff;
+   
+    if (SkXfermode::kDA_Coeff == fSrcCoeff || SkXfermode::kDC_Coeff == fSrcCoeff ||
+        SkXfermode::kIDA_Coeff == fSrcCoeff || SkXfermode::kIDC_Coeff == fSrcCoeff) {
+        return false;
     }
-    return true;
+        
+    switch (fDstCoeff) {
+        case SkXfermode::kZero_Coeff:
+            return true;
+        case SkXfermode::kISA_Coeff:
+            return SkXfermode::kOpaque_SrcColorOpacity == opacityType;
+        case SkXfermode::kSA_Coeff:
+            return SkXfermode::kTransparentBlack_SrcColorOpacity == opacityType ||
+                   SkXfermode::kTransparentAlpha_SrcColorOpacity == opacityType;
+        case SkXfermode::kSC_Coeff:
+            return SkXfermode::kTransparentBlack_SrcColorOpacity == opacityType;
+        default:
+            return false;
+    }
+
 }
 
 void SkProcCoeffXfermode::xfer32(SkPMColor* SK_RESTRICT dst,
@@ -1309,13 +1340,6 @@ bool SkXfermode::AsMode(const SkXfermode* xfer, Mode* mode) {
     return xfer->asMode(mode);
 }
 
-bool SkXfermode::AsCoeff(const SkXfermode* xfer, Coeff* src, Coeff* dst) {
-    if (NULL == xfer) {
-        return ModeAsCoeff(kSrcOver_Mode, src, dst);
-    }
-    return xfer->asCoeff(src, dst);
-}
-
 bool SkXfermode::IsMode(const SkXfermode* xfer, Mode mode) {
     // if xfer==null then the mode is srcover
     Mode m = kSrcOver_Mode;
@@ -1325,6 +1349,24 @@ bool SkXfermode::IsMode(const SkXfermode* xfer, Mode mode) {
     return mode == m;
 }
 
+bool SkXfermode::SupportsCoverageAsAlpha(const SkXfermode* xfer) {
+    // if xfer is NULL we treat it as srcOver which always supports coverageAsAlpha
+    if (!xfer) {
+        return true;
+    }
+
+    return xfer->supportsCoverageAsAlpha();
+}
+
+bool SkXfermode::IsOpaque(const SkXfermode* xfer, SrcColorOpacity opacityType) {
+    // if xfer is NULL we treat it as srcOver which is opaque if our src is opaque
+    if (!xfer) {
+        return SkXfermode::kOpaque_SrcColorOpacity == opacityType;
+    }
+
+    return xfer->isOpaque(opacityType);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 //////////// 16bit xfermode procs
 
index 88b4d34..8bd0811 100644 (file)
@@ -32,7 +32,9 @@ public:
 
     bool asMode(Mode* mode) const SK_OVERRIDE;
 
-    bool asCoeff(Coeff* sc, Coeff* dc) const SK_OVERRIDE;
+    bool supportsCoverageAsAlpha() const SK_OVERRIDE;
+
+    bool isOpaque(SkXfermode::SrcColorOpacity opacityType) const SK_OVERRIDE;
 
 #if SK_SUPPORT_GPU
     virtual bool asFragmentProcessor(GrFragmentProcessor**,