2011-07-28 14:26:00 +00:00
|
|
|
|
2008-12-17 15:59:43 +00:00
|
|
|
/*
|
2011-07-28 14:26:00 +00:00
|
|
|
* Copyright 2006 The Android Open Source Project
|
2008-12-17 15:59:43 +00:00
|
|
|
*
|
2011-07-28 14:26:00 +00:00
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
2008-12-17 15:59:43 +00:00
|
|
|
*/
|
|
|
|
|
2011-07-28 14:26:00 +00:00
|
|
|
|
2008-12-17 15:59:43 +00:00
|
|
|
#ifndef SkXfermode_DEFINED
|
|
|
|
#define SkXfermode_DEFINED
|
|
|
|
|
|
|
|
#include "SkFlattenable.h"
|
|
|
|
#include "SkColor.h"
|
|
|
|
|
2014-09-23 16:50:21 +00:00
|
|
|
class GrFragmentProcessor;
|
2013-05-31 17:49:12 +00:00
|
|
|
class GrTexture;
|
2014-12-03 18:40:13 +00:00
|
|
|
class GrXPFactory;
|
2013-01-22 14:32:09 +00:00
|
|
|
class SkString;
|
|
|
|
|
2008-12-17 15:59:43 +00:00
|
|
|
/** \class SkXfermode
|
2013-10-10 17:35:58 +00:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
2011-03-15 21:27:08 +00:00
|
|
|
class SK_API SkXfermode : public SkFlattenable {
|
2008-12-17 15:59:43 +00:00
|
|
|
public:
|
|
|
|
virtual void xfer32(SkPMColor dst[], const SkPMColor src[], int count,
|
2012-12-17 19:55:24 +00:00
|
|
|
const SkAlpha aa[]) const;
|
2008-12-17 15:59:43 +00:00
|
|
|
virtual void xfer16(uint16_t dst[], const SkPMColor src[], int count,
|
2012-12-17 19:55:24 +00:00
|
|
|
const SkAlpha aa[]) const;
|
2008-12-17 15:59:43 +00:00
|
|
|
virtual void xferA8(SkAlpha dst[], const SkPMColor src[], int count,
|
2012-12-17 19:55:24 +00:00
|
|
|
const SkAlpha aa[]) const;
|
2011-04-27 14:09:52 +00:00
|
|
|
|
2009-04-01 18:31:44 +00:00
|
|
|
/** Enum of possible coefficients to describe some xfermodes
|
|
|
|
*/
|
2008-12-17 15:59:43 +00:00
|
|
|
enum Coeff {
|
2009-04-01 18:31:44 +00:00
|
|
|
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) */
|
2011-04-27 14:09:52 +00:00
|
|
|
|
2008-12-17 15:59:43 +00:00
|
|
|
kCoeffCount
|
|
|
|
};
|
2011-04-27 14:09:52 +00:00
|
|
|
|
2009-06-22 17:38:10 +00:00
|
|
|
/** 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.
|
2013-04-19 15:03:21 +00:00
|
|
|
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.
|
2009-06-22 17:38:10 +00:00
|
|
|
*/
|
|
|
|
enum Mode {
|
|
|
|
kClear_Mode, //!< [0, 0]
|
|
|
|
kSrc_Mode, //!< [Sa, Sc]
|
|
|
|
kDst_Mode, //!< [Da, Dc]
|
2015-10-29 15:41:15 +00:00
|
|
|
kSrcOver_Mode, //!< [Sa + Da * (1 - Sa), Sc + Dc * (1 - Sa)]
|
|
|
|
kDstOver_Mode, //!< [Da + Sa * (1 - Da), Dc + Sc * (1 - Da)]
|
2009-06-22 17:38:10 +00:00
|
|
|
kSrcIn_Mode, //!< [Sa * Da, Sc * Da]
|
2015-10-29 15:41:15 +00:00
|
|
|
kDstIn_Mode, //!< [Da * Sa, Dc * Sa]
|
2009-06-22 17:38:10 +00:00
|
|
|
kSrcOut_Mode, //!< [Sa * (1 - Da), Sc * (1 - Da)]
|
|
|
|
kDstOut_Mode, //!< [Da * (1 - Sa), Dc * (1 - Sa)]
|
2015-10-29 15:41:15 +00:00
|
|
|
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)]
|
2013-03-05 16:23:59 +00:00
|
|
|
kPlus_Mode, //!< [Sa + Da, Sc + Dc]
|
2013-01-30 21:36:11 +00:00
|
|
|
kModulate_Mode, // multiplies all components (= alpha and color)
|
2012-08-23 18:09:54 +00:00
|
|
|
|
2013-03-06 07:01:46 +00:00
|
|
|
// Following blend modes are defined in the CSS Compositing standard:
|
2013-03-05 16:23:59 +00:00
|
|
|
// https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#blending
|
2013-04-15 15:16:47 +00:00
|
|
|
kScreen_Mode,
|
2013-04-19 15:03:21 +00:00
|
|
|
kLastCoeffMode = kScreen_Mode,
|
|
|
|
|
|
|
|
kOverlay_Mode,
|
2009-06-22 17:38:10 +00:00
|
|
|
kDarken_Mode,
|
|
|
|
kLighten_Mode,
|
|
|
|
kColorDodge_Mode,
|
|
|
|
kColorBurn_Mode,
|
|
|
|
kHardLight_Mode,
|
|
|
|
kSoftLight_Mode,
|
|
|
|
kDifference_Mode,
|
|
|
|
kExclusion_Mode,
|
2013-02-04 20:06:00 +00:00
|
|
|
kMultiply_Mode,
|
2013-04-19 15:03:21 +00:00
|
|
|
kLastSeparableMode = kMultiply_Mode,
|
2009-06-22 17:38:10 +00:00
|
|
|
|
2013-03-05 16:23:59 +00:00
|
|
|
kHue_Mode,
|
|
|
|
kSaturation_Mode,
|
|
|
|
kColor_Mode,
|
|
|
|
kLuminosity_Mode,
|
|
|
|
kLastMode = kLuminosity_Mode
|
2009-06-22 17:38:10 +00:00
|
|
|
};
|
2013-04-02 07:01:34 +00:00
|
|
|
|
2013-04-01 12:51:34 +00:00
|
|
|
/**
|
|
|
|
* Gets the name of the Mode as a string.
|
|
|
|
*/
|
|
|
|
static const char* ModeName(Mode);
|
2009-06-22 17:38:10 +00:00
|
|
|
|
2011-04-13 21:12:04 +00:00
|
|
|
/**
|
|
|
|
* 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.
|
2011-02-08 19:28:07 +00:00
|
|
|
*/
|
2012-12-17 19:55:24 +00:00
|
|
|
virtual bool asMode(Mode* mode) const;
|
2011-02-08 19:28:07 +00:00
|
|
|
|
2011-04-14 15:50:52 +00:00
|
|
|
/**
|
|
|
|
* The same as calling xfermode->asMode(mode), except that this also checks
|
2013-03-27 18:31:15 +00:00
|
|
|
* if the xfermode is NULL, and if so, treats it as kSrcOver_Mode.
|
2011-04-14 15:50:52 +00:00
|
|
|
*/
|
2012-12-17 19:55:24 +00:00
|
|
|
static bool AsMode(const SkXfermode*, Mode* mode);
|
2011-04-14 15:50:52 +00:00
|
|
|
|
2011-11-17 02:16:43 +00:00
|
|
|
/**
|
|
|
|
* 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)) {
|
|
|
|
* ...
|
|
|
|
* }
|
|
|
|
*/
|
2012-12-17 19:55:24 +00:00
|
|
|
static bool IsMode(const SkXfermode* xfer, Mode mode);
|
2011-11-17 02:16:43 +00:00
|
|
|
|
2009-06-22 17:38:10 +00:00
|
|
|
/** Return an SkXfermode object for the specified mode.
|
|
|
|
*/
|
|
|
|
static SkXfermode* Create(Mode mode);
|
|
|
|
|
|
|
|
/** Return a function pointer to a routine that applies the specified
|
|
|
|
porter-duff transfer mode.
|
|
|
|
*/
|
|
|
|
static SkXfermodeProc GetProc(Mode mode);
|
|
|
|
|
2011-04-13 21:12:04 +00:00
|
|
|
/**
|
2011-04-14 15:50:52 +00:00
|
|
|
* 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.
|
2009-06-22 17:38:10 +00:00
|
|
|
*/
|
2011-04-14 15:50:52 +00:00
|
|
|
static bool ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst);
|
2009-06-22 17:38:10 +00:00
|
|
|
|
2013-10-31 17:28:30 +00:00
|
|
|
SK_ATTR_DEPRECATED("use AsMode(...)")
|
2012-12-17 19:55:24 +00:00
|
|
|
static bool IsMode(const SkXfermode* xfer, Mode* mode) {
|
2011-04-14 15:50:52 +00:00
|
|
|
return AsMode(xfer, mode);
|
|
|
|
}
|
2011-04-27 14:09:52 +00:00
|
|
|
|
2015-01-22 14:52:29 +00:00
|
|
|
/**
|
|
|
|
* Returns whether or not the xfer mode can support treating coverage as alpha
|
2015-06-26 18:45:03 +00:00
|
|
|
*/
|
2015-01-22 14:52:29 +00:00
|
|
|
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);
|
|
|
|
|
2015-09-15 22:33:27 +00:00
|
|
|
/** Used to do in-shader blending between two colors computed in the shader 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. If the params are
|
|
|
|
null then this is just a query of whether the SkXfermode could support this functionality.
|
|
|
|
It is legal for the function to succeed but return a null output. This indicates that
|
|
|
|
the output of the blend is simply the src color.
|
2013-03-27 18:31:15 +00:00
|
|
|
*/
|
2015-10-06 15:40:50 +00:00
|
|
|
virtual bool asFragmentProcessor(const GrFragmentProcessor** output,
|
2015-09-15 22:33:27 +00:00
|
|
|
const GrFragmentProcessor* dst) const;
|
2013-03-27 18:31:15 +00:00
|
|
|
|
2014-12-03 18:40:13 +00:00
|
|
|
/** A subclass may implement this factory function to work with the GPU backend. It is legal
|
2015-11-23 21:20:41 +00:00
|
|
|
to call this with xpf NULL to simply test the return value. If xpf is non-NULL then the
|
|
|
|
xfermode may optionally allocate a factory to return to the caller as *xpf. The caller
|
|
|
|
will install it and own a ref to it. Since the xfermode may or may not assign *xpf, the
|
|
|
|
caller should set *xpf to NULL beforehand. XferProcessors cannot use a background texture.
|
|
|
|
*/
|
2015-11-20 23:12:59 +00:00
|
|
|
virtual bool asXPFactory(GrXPFactory** xpf) const;
|
2014-12-03 18:40:13 +00:00
|
|
|
|
2015-01-20 18:19:22 +00:00
|
|
|
/** Returns true if the xfermode can be expressed as an xfer processor factory (xpFactory).
|
2015-11-23 21:20:41 +00:00
|
|
|
This helper calls the asXPFactory() virtual. If the xfermode is NULL, it is treated as
|
|
|
|
kSrcOver_Mode. It is legal to call this with xpf param NULL to simply test the return value.
|
|
|
|
*/
|
|
|
|
static inline bool AsXPFactory(SkXfermode* xfermode, GrXPFactory** xpf) {
|
|
|
|
if (nullptr == xfermode) {
|
|
|
|
if (xpf) {
|
|
|
|
*xpf = nullptr;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return xfermode->asXPFactory(xpf);
|
|
|
|
}
|
2013-03-27 18:31:15 +00:00
|
|
|
|
2014-03-13 18:02:17 +00:00
|
|
|
SK_TO_STRING_PUREVIRT()
|
2012-03-23 19:00:34 +00:00
|
|
|
SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP()
|
2013-10-23 17:06:21 +00:00
|
|
|
SK_DEFINE_FLATTENABLE_TYPE(SkXfermode)
|
|
|
|
|
2016-01-31 02:52:31 +00:00
|
|
|
enum PM4fFlags {
|
|
|
|
kSrcIsOpaque_PM4fFlag = 1 << 0,
|
|
|
|
kDstIsSRGB_PM4fFlag = 1 << 1,
|
|
|
|
};
|
|
|
|
struct PM4fState {
|
|
|
|
const SkXfermode* fXfer;
|
|
|
|
uint32_t fFlags;
|
|
|
|
};
|
|
|
|
typedef void (*PM4fProc1)(const PM4fState&, uint32_t dst[], const SkPM4f& src,
|
|
|
|
int count, const SkAlpha coverage[]);
|
|
|
|
typedef void (*PM4fProcN)(const PM4fState&, uint32_t dst[], const SkPM4f src[],
|
|
|
|
int count, const SkAlpha coverage[]);
|
|
|
|
static PM4fProc1 GetPM4fProc1(Mode, uint32_t flags);
|
|
|
|
static PM4fProcN GetPM4fProcN(Mode, uint32_t flags);
|
|
|
|
virtual PM4fProc1 getPM4fProc1(uint32_t flags) const;
|
|
|
|
virtual PM4fProcN getPM4fProcN(uint32_t flags) const;
|
|
|
|
|
2008-12-17 15:59:43 +00:00
|
|
|
protected:
|
2014-05-15 15:40:41 +00:00
|
|
|
SkXfermode() {}
|
2008-12-17 15:59:43 +00:00
|
|
|
/** The default implementation of xfer32/xfer16/xferA8 in turn call this
|
|
|
|
method, 1 color at a time (upscaled to a SkPMColor). The default
|
2015-09-15 22:33:27 +00:00
|
|
|
implementation of this method just returns dst. If performance is
|
2008-12-17 15:59:43 +00:00
|
|
|
important, your subclass should override xfer32/xfer16/xferA8 directly.
|
2011-04-27 14:09:52 +00:00
|
|
|
|
2008-12-17 15:59:43 +00:00
|
|
|
This method will not be called directly by the client, so it need not
|
|
|
|
be implemented if your subclass has overridden xfer32/xfer16/xferA8
|
|
|
|
*/
|
2012-12-17 19:55:24 +00:00
|
|
|
virtual SkPMColor xferColor(SkPMColor src, SkPMColor dst) const;
|
2008-12-17 15:59:43 +00:00
|
|
|
|
|
|
|
private:
|
2009-06-22 17:38:10 +00:00
|
|
|
enum {
|
|
|
|
kModeCount = kLastMode + 1
|
|
|
|
};
|
2013-10-04 16:52:55 +00:00
|
|
|
|
2008-12-17 15:59:43 +00:00
|
|
|
typedef SkFlattenable INHERITED;
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|