michael@0: michael@0: /* michael@0: * Copyright 2006 The Android Open Source Project michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: michael@0: #ifndef SkXfermode_DEFINED michael@0: #define SkXfermode_DEFINED michael@0: michael@0: #include "SkFlattenable.h" michael@0: #include "SkColor.h" michael@0: michael@0: class GrEffectRef; michael@0: class GrTexture; michael@0: class SkString; michael@0: michael@0: /** \class SkXfermode michael@0: * michael@0: * SkXfermode is the base class for objects that are called to implement custom michael@0: * "transfer-modes" in the drawing pipeline. The static function Create(Modes) michael@0: * can be called to return an instance of any of the predefined subclasses as michael@0: * specified in the Modes enum. When an SkXfermode is assigned to an SkPaint, michael@0: * then objects drawn with that paint have the xfermode applied. michael@0: * michael@0: * All subclasses are required to be reentrant-safe : it must be legal to share michael@0: * the same instance between several threads. michael@0: */ michael@0: class SK_API SkXfermode : public SkFlattenable { michael@0: public: michael@0: SK_DECLARE_INST_COUNT(SkXfermode) michael@0: michael@0: virtual void xfer32(SkPMColor dst[], const SkPMColor src[], int count, michael@0: const SkAlpha aa[]) const; michael@0: virtual void xfer16(uint16_t dst[], const SkPMColor src[], int count, michael@0: const SkAlpha aa[]) const; michael@0: virtual void xferA8(SkAlpha dst[], const SkPMColor src[], int count, michael@0: const SkAlpha aa[]) const; michael@0: michael@0: /** Enum of possible coefficients to describe some xfermodes michael@0: */ michael@0: enum Coeff { michael@0: kZero_Coeff, /** 0 */ michael@0: kOne_Coeff, /** 1 */ michael@0: kSC_Coeff, /** src color */ michael@0: kISC_Coeff, /** inverse src color (i.e. 1 - sc) */ michael@0: kDC_Coeff, /** dst color */ michael@0: kIDC_Coeff, /** inverse dst color (i.e. 1 - dc) */ michael@0: kSA_Coeff, /** src alpha */ michael@0: kISA_Coeff, /** inverse src alpha (i.e. 1 - sa) */ michael@0: kDA_Coeff, /** dst alpha */ michael@0: kIDA_Coeff, /** inverse dst alpha (i.e. 1 - da) */ michael@0: michael@0: kCoeffCount michael@0: }; michael@0: michael@0: /** If the xfermode can be expressed as an equation using the coefficients michael@0: in Coeff, then asCoeff() returns true, and sets (if not null) src and michael@0: dst accordingly. michael@0: michael@0: result = src_coeff * src_color + dst_coeff * dst_color; michael@0: michael@0: As examples, here are some of the porterduff coefficients michael@0: michael@0: MODE SRC_COEFF DST_COEFF michael@0: clear zero zero michael@0: src one zero michael@0: dst zero one michael@0: srcover one isa michael@0: dstover ida one michael@0: */ michael@0: virtual bool asCoeff(Coeff* src, Coeff* dst) const; michael@0: michael@0: /** michael@0: * The same as calling xfermode->asCoeff(..), except that this also checks michael@0: * if the xfermode is NULL, and if so, treats it as kSrcOver_Mode. michael@0: */ michael@0: static bool AsCoeff(const SkXfermode*, Coeff* src, Coeff* dst); michael@0: michael@0: /** List of predefined xfermodes. michael@0: The algebra for the modes uses the following symbols: michael@0: Sa, Sc - source alpha and color michael@0: Da, Dc - destination alpha and color (before compositing) michael@0: [a, c] - Resulting (alpha, color) values michael@0: For these equations, the colors are in premultiplied state. michael@0: If no xfermode is specified, kSrcOver is assumed. michael@0: The modes are ordered by those that can be expressed as a pair of Coeffs, followed by those michael@0: that aren't Coeffs but have separable r,g,b computations, and finally michael@0: those that are not separable. michael@0: */ michael@0: enum Mode { michael@0: kClear_Mode, //!< [0, 0] michael@0: kSrc_Mode, //!< [Sa, Sc] michael@0: kDst_Mode, //!< [Da, Dc] michael@0: kSrcOver_Mode, //!< [Sa + Da - Sa*Da, Rc = Sc + (1 - Sa)*Dc] michael@0: kDstOver_Mode, //!< [Sa + Da - Sa*Da, Rc = Dc + (1 - Da)*Sc] michael@0: kSrcIn_Mode, //!< [Sa * Da, Sc * Da] michael@0: kDstIn_Mode, //!< [Sa * Da, Sa * Dc] michael@0: kSrcOut_Mode, //!< [Sa * (1 - Da), Sc * (1 - Da)] michael@0: kDstOut_Mode, //!< [Da * (1 - Sa), Dc * (1 - Sa)] michael@0: kSrcATop_Mode, //!< [Da, Sc * Da + (1 - Sa) * Dc] michael@0: kDstATop_Mode, //!< [Sa, Sa * Dc + Sc * (1 - Da)] michael@0: kXor_Mode, //!< [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc] michael@0: kPlus_Mode, //!< [Sa + Da, Sc + Dc] michael@0: kModulate_Mode, // multiplies all components (= alpha and color) michael@0: michael@0: // Following blend modes are defined in the CSS Compositing standard: michael@0: // https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#blending michael@0: kScreen_Mode, michael@0: kLastCoeffMode = kScreen_Mode, michael@0: michael@0: kOverlay_Mode, michael@0: kDarken_Mode, michael@0: kLighten_Mode, michael@0: kColorDodge_Mode, michael@0: kColorBurn_Mode, michael@0: kHardLight_Mode, michael@0: kSoftLight_Mode, michael@0: kDifference_Mode, michael@0: kExclusion_Mode, michael@0: kMultiply_Mode, michael@0: kLastSeparableMode = kMultiply_Mode, michael@0: michael@0: kHue_Mode, michael@0: kSaturation_Mode, michael@0: kColor_Mode, michael@0: kLuminosity_Mode, michael@0: kLastMode = kLuminosity_Mode michael@0: }; michael@0: michael@0: /** michael@0: * Gets the name of the Mode as a string. michael@0: */ michael@0: static const char* ModeName(Mode); michael@0: michael@0: /** michael@0: * If the xfermode is one of the modes in the Mode enum, then asMode() michael@0: * returns true and sets (if not null) mode accordingly. Otherwise it michael@0: * returns false and ignores the mode parameter. michael@0: */ michael@0: virtual bool asMode(Mode* mode) const; michael@0: michael@0: /** michael@0: * The same as calling xfermode->asMode(mode), except that this also checks michael@0: * if the xfermode is NULL, and if so, treats it as kSrcOver_Mode. michael@0: */ michael@0: static bool AsMode(const SkXfermode*, Mode* mode); michael@0: michael@0: /** michael@0: * Returns true if the xfermode claims to be the specified Mode. This works michael@0: * correctly even if the xfermode is NULL (which equates to kSrcOver.) Thus michael@0: * you can say this without checking for a null... michael@0: * michael@0: * If (SkXfermode::IsMode(paint.getXfermode(), michael@0: * SkXfermode::kDstOver_Mode)) { michael@0: * ... michael@0: * } michael@0: */ michael@0: static bool IsMode(const SkXfermode* xfer, Mode mode); michael@0: michael@0: /** Return an SkXfermode object for the specified mode. michael@0: */ michael@0: static SkXfermode* Create(Mode mode); michael@0: michael@0: /** Return a function pointer to a routine that applies the specified michael@0: porter-duff transfer mode. michael@0: */ michael@0: static SkXfermodeProc GetProc(Mode mode); michael@0: michael@0: /** Return a function pointer to a routine that applies the specified michael@0: porter-duff transfer mode and srcColor to a 16bit device color. Note, michael@0: if the mode+srcColor might return a non-opaque color, then there is not michael@0: 16bit proc, and this will return NULL. michael@0: */ michael@0: static SkXfermodeProc16 GetProc16(Mode mode, SkColor srcColor); michael@0: michael@0: /** michael@0: * If the specified mode can be represented by a pair of Coeff, then return michael@0: * true and set (if not NULL) the corresponding coeffs. If the mode is michael@0: * not representable as a pair of Coeffs, return false and ignore the michael@0: * src and dst parameters. michael@0: */ michael@0: static bool ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst); michael@0: michael@0: SK_ATTR_DEPRECATED("use AsMode(...)") michael@0: static bool IsMode(const SkXfermode* xfer, Mode* mode) { michael@0: return AsMode(xfer, mode); michael@0: } michael@0: michael@0: /** A subclass may implement this factory function to work with the GPU backend. It is legal michael@0: to call this with all params NULL to simply test the return value. If effect is non-NULL michael@0: then the xfermode may optionally allocate an effect to return and the caller as *effect. michael@0: The caller will install it and own a ref to it. Since the xfermode may or may not assign michael@0: *effect, the caller should set *effect to NULL beforehand. background specifies the michael@0: texture to use as the background for compositing, and should be accessed in the effect's michael@0: fragment shader. If NULL, the effect should request access to destination color michael@0: (setWillReadDstColor()), and use that in the fragment shader (builder->dstColor()). michael@0: */ michael@0: virtual bool asNewEffect(GrEffectRef** effect, GrTexture* background = NULL) const; michael@0: michael@0: /** Returns true if the xfermode can be expressed as coeffs (src, dst), or as an effect michael@0: (effect). This helper calls the asCoeff() and asNewEffect() virtuals. If the xfermode is michael@0: NULL, it is treated as kSrcOver_Mode. It is legal to call this with all params NULL to michael@0: simply test the return value. effect, src, and dst must all be NULL or all non-NULL. michael@0: */ michael@0: static bool AsNewEffectOrCoeff(SkXfermode*, michael@0: GrEffectRef** effect, michael@0: Coeff* src, michael@0: Coeff* dst, michael@0: GrTexture* background = NULL); michael@0: michael@0: SK_TO_STRING_PUREVIRT() michael@0: SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP() michael@0: SK_DEFINE_FLATTENABLE_TYPE(SkXfermode) michael@0: michael@0: protected: michael@0: SkXfermode(SkReadBuffer& rb) : SkFlattenable(rb) {} michael@0: michael@0: /** The default implementation of xfer32/xfer16/xferA8 in turn call this michael@0: method, 1 color at a time (upscaled to a SkPMColor). The default michael@0: implmentation of this method just returns dst. If performance is michael@0: important, your subclass should override xfer32/xfer16/xferA8 directly. michael@0: michael@0: This method will not be called directly by the client, so it need not michael@0: be implemented if your subclass has overridden xfer32/xfer16/xferA8 michael@0: */ michael@0: virtual SkPMColor xferColor(SkPMColor src, SkPMColor dst) const; michael@0: michael@0: #ifdef SK_SUPPORT_LEGACY_PUBLICEFFECTCONSTRUCTORS michael@0: public: michael@0: #endif michael@0: SkXfermode() {} michael@0: michael@0: private: michael@0: enum { michael@0: kModeCount = kLastMode + 1 michael@0: }; michael@0: michael@0: friend class SkGraphics; michael@0: static void Term(); michael@0: michael@0: typedef SkFlattenable INHERITED; michael@0: }; michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: /** \class SkProcXfermode michael@0: michael@0: SkProcXfermode is a xfermode that applies the specified proc to its colors. michael@0: This class is not exported to java. michael@0: */ michael@0: class SkProcXfermode : public SkXfermode { michael@0: public: michael@0: static SkProcXfermode* Create(SkXfermodeProc proc) { michael@0: return SkNEW_ARGS(SkProcXfermode, (proc)); michael@0: } michael@0: michael@0: // overrides from SkXfermode michael@0: virtual void xfer32(SkPMColor dst[], const SkPMColor src[], int count, michael@0: const SkAlpha aa[]) const SK_OVERRIDE; michael@0: virtual void xfer16(uint16_t dst[], const SkPMColor src[], int count, michael@0: const SkAlpha aa[]) const SK_OVERRIDE; michael@0: virtual void xferA8(SkAlpha dst[], const SkPMColor src[], int count, michael@0: const SkAlpha aa[]) const SK_OVERRIDE; michael@0: michael@0: SK_TO_STRING_OVERRIDE() michael@0: SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkProcXfermode) michael@0: michael@0: protected: michael@0: SkProcXfermode(SkReadBuffer&); michael@0: virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE; michael@0: michael@0: // allow subclasses to update this after we unflatten michael@0: void setProc(SkXfermodeProc proc) { michael@0: fProc = proc; michael@0: } michael@0: michael@0: SkXfermodeProc getProc() const { michael@0: return fProc; michael@0: } michael@0: michael@0: #ifdef SK_SUPPORT_LEGACY_PUBLICEFFECTCONSTRUCTORS michael@0: public: michael@0: #endif michael@0: SkProcXfermode(SkXfermodeProc proc) : fProc(proc) {} michael@0: michael@0: private: michael@0: SkXfermodeProc fProc; michael@0: michael@0: typedef SkXfermode INHERITED; michael@0: }; michael@0: michael@0: #endif