From dcfb7cf336cafffd8d149c908b615e1deaa3a49b Mon Sep 17 00:00:00 2001 From: egdaniel Date: Thu, 22 Jan 2015 06:52:29 -0800 Subject: [PATCH] Remove the need for asCoeff in SkXfermode. BUG=skia: Review URL: https://codereview.chromium.org/864833002 --- include/core/SkXfermode.h | 58 +++++++++++++++---------- src/core/SkDraw.cpp | 18 +------- src/core/SkPaintPriv.cpp | 69 +++++++----------------------- src/core/SkXfermode.cpp | 76 +++++++++++++++++++++++++-------- src/core/SkXfermode_proccoeff.h | 4 +- 5 files changed, 114 insertions(+), 111 deletions(-) diff --git a/include/core/SkXfermode.h b/include/core/SkXfermode.h index fc9ae21ac4..1dd01a2e1d 100644 --- a/include/core/SkXfermode.h +++ b/include/core/SkXfermode.h @@ -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 diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp index f69137f6b8..c42d3ef9ed 100644 --- a/src/core/SkDraw.cpp +++ b/src/core/SkDraw.cpp @@ -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 * diff --git a/src/core/SkPaintPriv.cpp b/src/core/SkPaintPriv.cpp index e82c4045aa..c6957cd1ca 100644 --- a/src/core/SkPaintPriv.cpp +++ b/src/core/SkPaintPriv.cpp @@ -13,65 +13,28 @@ #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::SrcColorOpacity opacityType = SkXfermode::kUnknown_SrcColorOpacity; - 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; + 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) { diff --git a/src/core/SkXfermode.cpp b/src/core/SkXfermode.cpp index ac1ebcccb0..08f760d205 100644 --- a/src/core/SkXfermode.cpp +++ b/src/core/SkXfermode.cpp @@ -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; } - if (dc) { - *dc = fDstCoeff; +} + +bool SkProcCoeffXfermode::isOpaque(SkXfermode::SrcColorOpacity opacityType) const { + if (CANNOT_USE_COEFF == fSrcCoeff) { + return false; } - return true; + + if (SkXfermode::kDA_Coeff == fSrcCoeff || SkXfermode::kDC_Coeff == fSrcCoeff || + SkXfermode::kIDA_Coeff == fSrcCoeff || SkXfermode::kIDC_Coeff == fSrcCoeff) { + return false; + } + + 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 diff --git a/src/core/SkXfermode_proccoeff.h b/src/core/SkXfermode_proccoeff.h index 88b4d34e63..8bd081157d 100644 --- a/src/core/SkXfermode_proccoeff.h +++ b/src/core/SkXfermode_proccoeff.h @@ -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**,