|  | /* | 
|  | * Copyright 2006 The Android Open Source Project | 
|  | * | 
|  | * Use of this source code is governed by a BSD-style license that can be | 
|  | * found in the LICENSE file. | 
|  | */ | 
|  |  | 
|  | #ifndef SkXfermode_DEFINED | 
|  | #define SkXfermode_DEFINED | 
|  |  | 
|  | #include "SkFlattenable.h" | 
|  | #include "SkColor.h" | 
|  |  | 
|  | class GrFragmentProcessor; | 
|  | class GrTexture; | 
|  | class GrXPFactory; | 
|  | class SkString; | 
|  |  | 
|  | struct SkPM4f; | 
|  | typedef SkPM4f (*SkXfermodeProc4f)(const SkPM4f& src, const SkPM4f& dst); | 
|  |  | 
|  | /** \class SkXfermode | 
|  | * | 
|  | *  SkXfermode is the base class for objects that are called to implement custom | 
|  | *  "transfer-modes" in the drawing pipeline. The static function Create(Modes) | 
|  | *  can be called to return an instance of any of the predefined subclasses as | 
|  | *  specified in the Modes enum. When an SkXfermode is assigned to an SkPaint, | 
|  | *  then objects drawn with that paint have the xfermode applied. | 
|  | * | 
|  | *  All subclasses are required to be reentrant-safe : it must be legal to share | 
|  | *  the same instance between several threads. | 
|  | */ | 
|  | class SK_API SkXfermode : public SkFlattenable { | 
|  | public: | 
|  | virtual void xfer32(SkPMColor dst[], const SkPMColor src[], int count, | 
|  | const SkAlpha aa[]) const; | 
|  | virtual void xfer16(uint16_t dst[], const SkPMColor src[], int count, | 
|  | const SkAlpha aa[]) const; | 
|  | virtual void xferA8(SkAlpha dst[], const SkPMColor src[], int count, | 
|  | const SkAlpha aa[]) const; | 
|  |  | 
|  | /** Enum of possible coefficients to describe some xfermodes | 
|  | */ | 
|  | enum Coeff { | 
|  | kZero_Coeff,    /** 0 */ | 
|  | kOne_Coeff,     /** 1 */ | 
|  | kSC_Coeff,      /** src color */ | 
|  | kISC_Coeff,     /** inverse src color (i.e. 1 - sc) */ | 
|  | kDC_Coeff,      /** dst color */ | 
|  | kIDC_Coeff,     /** inverse dst color (i.e. 1 - dc) */ | 
|  | kSA_Coeff,      /** src alpha */ | 
|  | kISA_Coeff,     /** inverse src alpha (i.e. 1 - sa) */ | 
|  | kDA_Coeff,      /** dst alpha */ | 
|  | kIDA_Coeff,     /** inverse dst alpha (i.e. 1 - da) */ | 
|  |  | 
|  | kCoeffCount | 
|  | }; | 
|  |  | 
|  | /** List of predefined xfermodes. | 
|  | The algebra for the modes uses the following symbols: | 
|  | Sa, Sc  - source alpha and color | 
|  | Da, Dc - destination alpha and color (before compositing) | 
|  | [a, c] - Resulting (alpha, color) values | 
|  | For these equations, the colors are in premultiplied state. | 
|  | If no xfermode is specified, kSrcOver is assumed. | 
|  | The modes are ordered by those that can be expressed as a pair of Coeffs, followed by those | 
|  | that aren't Coeffs but have separable r,g,b computations, and finally | 
|  | those that are not separable. | 
|  | */ | 
|  | enum Mode { | 
|  | kClear_Mode,    //!< [0, 0] | 
|  | kSrc_Mode,      //!< [Sa, Sc] | 
|  | kDst_Mode,      //!< [Da, Dc] | 
|  | kSrcOver_Mode,  //!< [Sa + Da * (1 - Sa), Sc + Dc * (1 - Sa)] | 
|  | kDstOver_Mode,  //!< [Da + Sa * (1 - Da), Dc + Sc * (1 - Da)] | 
|  | kSrcIn_Mode,    //!< [Sa * Da, Sc * Da] | 
|  | kDstIn_Mode,    //!< [Da * Sa, Dc * Sa] | 
|  | kSrcOut_Mode,   //!< [Sa * (1 - Da), Sc * (1 - Da)] | 
|  | kDstOut_Mode,   //!< [Da * (1 - Sa), Dc * (1 - Sa)] | 
|  | kSrcATop_Mode,  //!< [Da, Sc * Da + Dc * (1 - Sa)] | 
|  | kDstATop_Mode,  //!< [Sa, Dc * Sa + Sc * (1 - Da)] | 
|  | kXor_Mode,      //!< [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + Dc * (1 - Sa)] | 
|  | kPlus_Mode,     //!< [Sa + Da, Sc + Dc] | 
|  | kModulate_Mode, // multiplies all components (= alpha and color) | 
|  |  | 
|  | // Following blend modes are defined in the CSS Compositing standard: | 
|  | // https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#blending | 
|  | kScreen_Mode, | 
|  | kLastCoeffMode = kScreen_Mode, | 
|  |  | 
|  | kOverlay_Mode, | 
|  | kDarken_Mode, | 
|  | kLighten_Mode, | 
|  | kColorDodge_Mode, | 
|  | kColorBurn_Mode, | 
|  | kHardLight_Mode, | 
|  | kSoftLight_Mode, | 
|  | kDifference_Mode, | 
|  | kExclusion_Mode, | 
|  | kMultiply_Mode, | 
|  | kLastSeparableMode = kMultiply_Mode, | 
|  |  | 
|  | kHue_Mode, | 
|  | kSaturation_Mode, | 
|  | kColor_Mode, | 
|  | kLuminosity_Mode, | 
|  | kLastMode = kLuminosity_Mode | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * Gets the name of the Mode as a string. | 
|  | */ | 
|  | static const char* ModeName(Mode); | 
|  |  | 
|  | /** | 
|  | *  If the xfermode is one of the modes in the Mode enum, then asMode() | 
|  | *  returns true and sets (if not null) mode accordingly. Otherwise it | 
|  | *  returns false and ignores the mode parameter. | 
|  | */ | 
|  | virtual bool asMode(Mode* mode) const; | 
|  |  | 
|  | /** | 
|  | *  The same as calling xfermode->asMode(mode), except that this also checks | 
|  | *  if the xfermode is NULL, and if so, treats it as kSrcOver_Mode. | 
|  | */ | 
|  | static bool AsMode(const SkXfermode*, Mode* mode); | 
|  | static bool AsMode(const sk_sp<SkXfermode>& xfer, Mode* mode) { | 
|  | return AsMode(xfer.get(), mode); | 
|  | } | 
|  |  | 
|  | /** | 
|  | *  Returns true if the xfermode claims to be the specified Mode. This works | 
|  | *  correctly even if the xfermode is NULL (which equates to kSrcOver.) Thus | 
|  | *  you can say this without checking for a null... | 
|  | * | 
|  | *  If (SkXfermode::IsMode(paint.getXfermode(), | 
|  | *                         SkXfermode::kDstOver_Mode)) { | 
|  | *      ... | 
|  | *  } | 
|  | */ | 
|  | static bool IsMode(const SkXfermode* xfer, Mode mode); | 
|  | static bool IsMode(const sk_sp<SkXfermode>& xfer, Mode mode) { | 
|  | return IsMode(xfer.get(), mode); | 
|  | } | 
|  |  | 
|  | /** Return an SkXfermode object for the specified mode. | 
|  | */ | 
|  | static sk_sp<SkXfermode> Make(Mode); | 
|  | #ifdef SK_SUPPORT_LEGACY_XFERMODE_PTR | 
|  | static SkXfermode* Create(Mode mode) { | 
|  | return Make(mode).release(); | 
|  | } | 
|  | SK_ATTR_DEPRECATED("use AsMode(...)") | 
|  | static bool IsMode(const SkXfermode* xfer, Mode* mode) { | 
|  | return AsMode(xfer, mode); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | /** Return a function pointer to a routine that applies the specified | 
|  | porter-duff transfer mode. | 
|  | */ | 
|  | static SkXfermodeProc GetProc(Mode mode); | 
|  | static SkXfermodeProc4f GetProc4f(Mode); | 
|  |  | 
|  | virtual SkXfermodeProc4f getProc4f() const; | 
|  |  | 
|  | /** | 
|  | *  If the specified mode can be represented by a pair of Coeff, then return | 
|  | *  true and set (if not NULL) the corresponding coeffs. If the mode is | 
|  | *  not representable as a pair of Coeffs, return false and ignore the | 
|  | *  src and dst parameters. | 
|  | */ | 
|  | static bool ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst); | 
|  |  | 
|  | /** | 
|  | * 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); | 
|  | static bool SupportsCoverageAsAlpha(const sk_sp<SkXfermode>& xfer) { | 
|  | return SupportsCoverageAsAlpha(xfer.get()); | 
|  | } | 
|  |  | 
|  | 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); | 
|  | static bool IsOpaque(const sk_sp<SkXfermode>& xfer, SrcColorOpacity opacityType) { | 
|  | return IsOpaque(xfer.get(), opacityType); | 
|  | } | 
|  |  | 
|  | #if SK_SUPPORT_GPU | 
|  | /** Used by the SkXfermodeImageFilter to blend two colors via a GrFragmentProcessor. | 
|  | The input to the returned FP is the src color. The dst color is | 
|  | provided by the dst param which becomes a child FP of the returned FP. | 
|  | It is legal for the function to return a null output. This indicates that | 
|  | the output of the blend is simply the src color. | 
|  | */ | 
|  | virtual sk_sp<GrFragmentProcessor> makeFragmentProcessorForImageFilter( | 
|  | sk_sp<GrFragmentProcessor> dst) const; | 
|  |  | 
|  | /** A subclass must implement this factory function to work with the GPU backend. | 
|  | The xfermode will return a factory for which the caller will get a ref. It is up | 
|  | to the caller to install it. XferProcessors cannot use a background texture. | 
|  | */ | 
|  | virtual sk_sp<GrXPFactory> asXPFactory() const; | 
|  | #endif | 
|  |  | 
|  | SK_TO_STRING_PUREVIRT() | 
|  | SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP() | 
|  | SK_DEFINE_FLATTENABLE_TYPE(SkXfermode) | 
|  |  | 
|  | enum D32Flags { | 
|  | kSrcIsOpaque_D32Flag  = 1 << 0, | 
|  | kSrcIsSingle_D32Flag  = 1 << 1, | 
|  | kDstIsSRGB_D32Flag    = 1 << 2, | 
|  | }; | 
|  | typedef void (*D32Proc)(const SkXfermode*, uint32_t dst[], const SkPM4f src[], | 
|  | int count, const SkAlpha coverage[]); | 
|  | static D32Proc GetD32Proc(SkXfermode*, uint32_t flags); | 
|  | static D32Proc GetD32Proc(const sk_sp<SkXfermode>& xfer, uint32_t flags) { | 
|  | return GetD32Proc(xfer.get(), flags); | 
|  | } | 
|  |  | 
|  | enum F16Flags { | 
|  | kSrcIsOpaque_F16Flag  = 1 << 0, | 
|  | kSrcIsSingle_F16Flag  = 1 << 1, | 
|  | }; | 
|  | typedef void (*F16Proc)(const SkXfermode*, uint64_t dst[], const SkPM4f src[], int count, | 
|  | const SkAlpha coverage[]); | 
|  | static F16Proc GetF16Proc(SkXfermode*, uint32_t flags); | 
|  | static F16Proc GetF16Proc(const sk_sp<SkXfermode>& xfer, uint32_t flags) { | 
|  | return GetF16Proc(xfer.get(), flags); | 
|  | } | 
|  |  | 
|  | enum LCDFlags { | 
|  | kSrcIsOpaque_LCDFlag    = 1 << 0,   // else src(s) may have alpha < 1 | 
|  | kSrcIsSingle_LCDFlag    = 1 << 1,   // else src[count] | 
|  | kDstIsSRGB_LCDFlag      = 1 << 2,   // else l32 or f16 | 
|  | }; | 
|  | typedef void (*LCD32Proc)(uint32_t* dst, const SkPM4f* src, int count, const uint16_t lcd[]); | 
|  | typedef void (*LCDF16Proc)(uint64_t* dst, const SkPM4f* src, int count, const uint16_t lcd[]); | 
|  | static LCD32Proc GetLCD32Proc(uint32_t flags); | 
|  | static LCDF16Proc GetLCDF16Proc(uint32_t) { return nullptr; } | 
|  |  | 
|  | protected: | 
|  | SkXfermode() {} | 
|  | /** The default implementation of xfer32/xfer16/xferA8 in turn call this | 
|  | method, 1 color at a time (upscaled to a SkPMColor). The default | 
|  | implementation of this method just returns dst. If performance is | 
|  | important, your subclass should override xfer32/xfer16/xferA8 directly. | 
|  |  | 
|  | This method will not be called directly by the client, so it need not | 
|  | be implemented if your subclass has overridden xfer32/xfer16/xferA8 | 
|  | */ | 
|  | virtual SkPMColor xferColor(SkPMColor src, SkPMColor dst) const; | 
|  |  | 
|  | virtual D32Proc onGetD32Proc(uint32_t flags) const; | 
|  | virtual F16Proc onGetF16Proc(uint32_t flags) const; | 
|  |  | 
|  | private: | 
|  | enum { | 
|  | kModeCount = kLastMode + 1 | 
|  | }; | 
|  |  | 
|  | typedef SkFlattenable INHERITED; | 
|  | }; | 
|  |  | 
|  | #endif |