blob: 94f49fac2615b3ccee42cc10ea8f0d3eb13260d8 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
reed@android.com8a1c16f2008-12-17 15:59:43 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2006 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00004 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00005 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#ifndef SkXfermode_DEFINED
11#define SkXfermode_DEFINED
12
13#include "SkFlattenable.h"
14#include "SkColor.h"
15
joshualittb0a8a372014-09-23 09:50:21 -070016class GrFragmentProcessor;
senorblanco@chromium.org86fc2662013-05-31 17:49:12 +000017class GrTexture;
egdaniel378092f2014-12-03 10:40:13 -080018class GrXPFactory;
robertphillips@google.comb83b6b42013-01-22 14:32:09 +000019class SkString;
20
reeddd9ffea2016-02-18 12:39:14 -080021struct SkPM4f;
22typedef SkPM4f (*SkXfermodeProc4f)(const SkPM4f& src, const SkPM4f& dst);
23
reed@android.com8a1c16f2008-12-17 15:59:43 +000024/** \class SkXfermode
reed@google.comfb6deed2013-10-10 17:35:58 +000025 *
26 * SkXfermode is the base class for objects that are called to implement custom
27 * "transfer-modes" in the drawing pipeline. The static function Create(Modes)
28 * can be called to return an instance of any of the predefined subclasses as
29 * specified in the Modes enum. When an SkXfermode is assigned to an SkPaint,
30 * then objects drawn with that paint have the xfermode applied.
31 *
32 * All subclasses are required to be reentrant-safe : it must be legal to share
33 * the same instance between several threads.
34 */
ctguil@chromium.org7ffb1b22011-03-15 21:27:08 +000035class SK_API SkXfermode : public SkFlattenable {
reed@android.com8a1c16f2008-12-17 15:59:43 +000036public:
reed@android.com8a1c16f2008-12-17 15:59:43 +000037 virtual void xfer32(SkPMColor dst[], const SkPMColor src[], int count,
reed@google.com30da7452012-12-17 19:55:24 +000038 const SkAlpha aa[]) const;
reed@android.com8a1c16f2008-12-17 15:59:43 +000039 virtual void xfer16(uint16_t dst[], const SkPMColor src[], int count,
reed@google.com30da7452012-12-17 19:55:24 +000040 const SkAlpha aa[]) const;
reed@android.com8a1c16f2008-12-17 15:59:43 +000041 virtual void xferA8(SkAlpha dst[], const SkPMColor src[], int count,
reed@google.com30da7452012-12-17 19:55:24 +000042 const SkAlpha aa[]) const;
tomhudson@google.com1447c6f2011-04-27 14:09:52 +000043
reed@android.comd252db02009-04-01 18:31:44 +000044 /** Enum of possible coefficients to describe some xfermodes
45 */
reed@android.com8a1c16f2008-12-17 15:59:43 +000046 enum Coeff {
reed@android.comd252db02009-04-01 18:31:44 +000047 kZero_Coeff, /** 0 */
48 kOne_Coeff, /** 1 */
49 kSC_Coeff, /** src color */
50 kISC_Coeff, /** inverse src color (i.e. 1 - sc) */
51 kDC_Coeff, /** dst color */
52 kIDC_Coeff, /** inverse dst color (i.e. 1 - dc) */
53 kSA_Coeff, /** src alpha */
54 kISA_Coeff, /** inverse src alpha (i.e. 1 - sa) */
55 kDA_Coeff, /** dst alpha */
56 kIDA_Coeff, /** inverse dst alpha (i.e. 1 - da) */
tomhudson@google.com1447c6f2011-04-27 14:09:52 +000057
reed@android.com8a1c16f2008-12-17 15:59:43 +000058 kCoeffCount
59 };
tomhudson@google.com1447c6f2011-04-27 14:09:52 +000060
reed@android.coma0f5d152009-06-22 17:38:10 +000061 /** List of predefined xfermodes.
62 The algebra for the modes uses the following symbols:
63 Sa, Sc - source alpha and color
64 Da, Dc - destination alpha and color (before compositing)
65 [a, c] - Resulting (alpha, color) values
66 For these equations, the colors are in premultiplied state.
67 If no xfermode is specified, kSrcOver is assumed.
bsalomon@google.com8da9bc72013-04-19 15:03:21 +000068 The modes are ordered by those that can be expressed as a pair of Coeffs, followed by those
69 that aren't Coeffs but have separable r,g,b computations, and finally
70 those that are not separable.
reed@android.coma0f5d152009-06-22 17:38:10 +000071 */
72 enum Mode {
73 kClear_Mode, //!< [0, 0]
74 kSrc_Mode, //!< [Sa, Sc]
75 kDst_Mode, //!< [Da, Dc]
pkasting129319f2015-10-29 08:41:15 -070076 kSrcOver_Mode, //!< [Sa + Da * (1 - Sa), Sc + Dc * (1 - Sa)]
77 kDstOver_Mode, //!< [Da + Sa * (1 - Da), Dc + Sc * (1 - Da)]
reed@android.coma0f5d152009-06-22 17:38:10 +000078 kSrcIn_Mode, //!< [Sa * Da, Sc * Da]
pkasting129319f2015-10-29 08:41:15 -070079 kDstIn_Mode, //!< [Da * Sa, Dc * Sa]
reed@android.coma0f5d152009-06-22 17:38:10 +000080 kSrcOut_Mode, //!< [Sa * (1 - Da), Sc * (1 - Da)]
81 kDstOut_Mode, //!< [Da * (1 - Sa), Dc * (1 - Sa)]
pkasting129319f2015-10-29 08:41:15 -070082 kSrcATop_Mode, //!< [Da, Sc * Da + Dc * (1 - Sa)]
83 kDstATop_Mode, //!< [Sa, Dc * Sa + Sc * (1 - Da)]
84 kXor_Mode, //!< [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + Dc * (1 - Sa)]
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +000085 kPlus_Mode, //!< [Sa + Da, Sc + Dc]
reed@google.com8d3cd7a2013-01-30 21:36:11 +000086 kModulate_Mode, // multiplies all components (= alpha and color)
rmistry@google.comfbfcd562012-08-23 18:09:54 +000087
skia.committer@gmail.com64334352013-03-06 07:01:46 +000088 // Following blend modes are defined in the CSS Compositing standard:
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +000089 // https://dvcs.w3.org/hg/FXTF/rawfile/tip/compositing/index.html#blending
bsalomon@google.comb0091b82013-04-15 15:16:47 +000090 kScreen_Mode,
bsalomon@google.com8da9bc72013-04-19 15:03:21 +000091 kLastCoeffMode = kScreen_Mode,
92
93 kOverlay_Mode,
reed@android.coma0f5d152009-06-22 17:38:10 +000094 kDarken_Mode,
95 kLighten_Mode,
96 kColorDodge_Mode,
97 kColorBurn_Mode,
98 kHardLight_Mode,
99 kSoftLight_Mode,
100 kDifference_Mode,
101 kExclusion_Mode,
reed@google.com25cfa692013-02-04 20:06:00 +0000102 kMultiply_Mode,
bsalomon@google.com8da9bc72013-04-19 15:03:21 +0000103 kLastSeparableMode = kMultiply_Mode,
reed@android.coma0f5d152009-06-22 17:38:10 +0000104
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000105 kHue_Mode,
106 kSaturation_Mode,
107 kColor_Mode,
108 kLuminosity_Mode,
commit-bot@chromium.orgb24f8932013-03-05 16:23:59 +0000109 kLastMode = kLuminosity_Mode
reed@android.coma0f5d152009-06-22 17:38:10 +0000110 };
skia.committer@gmail.com05a2ee02013-04-02 07:01:34 +0000111
commit-bot@chromium.orgd7aaf602013-04-01 12:51:34 +0000112 /**
113 * Gets the name of the Mode as a string.
114 */
115 static const char* ModeName(Mode);
reed@android.coma0f5d152009-06-22 17:38:10 +0000116
reed@google.comc0d4aa22011-04-13 21:12:04 +0000117 /**
118 * If the xfermode is one of the modes in the Mode enum, then asMode()
119 * returns true and sets (if not null) mode accordingly. Otherwise it
120 * returns false and ignores the mode parameter.
vandebo@chromium.org48543272011-02-08 19:28:07 +0000121 */
reed@google.com30da7452012-12-17 19:55:24 +0000122 virtual bool asMode(Mode* mode) const;
vandebo@chromium.org48543272011-02-08 19:28:07 +0000123
reed@google.com43c50c82011-04-14 15:50:52 +0000124 /**
125 * The same as calling xfermode->asMode(mode), except that this also checks
bsalomon@google.comf51c0132013-03-27 18:31:15 +0000126 * if the xfermode is NULL, and if so, treats it as kSrcOver_Mode.
reed@google.com43c50c82011-04-14 15:50:52 +0000127 */
reed@google.com30da7452012-12-17 19:55:24 +0000128 static bool AsMode(const SkXfermode*, Mode* mode);
reed@google.com43c50c82011-04-14 15:50:52 +0000129
mike@reedtribe.orge303fcf2011-11-17 02:16:43 +0000130 /**
131 * Returns true if the xfermode claims to be the specified Mode. This works
132 * correctly even if the xfermode is NULL (which equates to kSrcOver.) Thus
133 * you can say this without checking for a null...
134 *
135 * If (SkXfermode::IsMode(paint.getXfermode(),
136 * SkXfermode::kDstOver_Mode)) {
137 * ...
138 * }
139 */
reed@google.com30da7452012-12-17 19:55:24 +0000140 static bool IsMode(const SkXfermode* xfer, Mode mode);
mike@reedtribe.orge303fcf2011-11-17 02:16:43 +0000141
reed@android.coma0f5d152009-06-22 17:38:10 +0000142 /** Return an SkXfermode object for the specified mode.
143 */
144 static SkXfermode* Create(Mode mode);
145
146 /** Return a function pointer to a routine that applies the specified
147 porter-duff transfer mode.
148 */
149 static SkXfermodeProc GetProc(Mode mode);
reed31255652016-02-08 12:56:56 -0800150 static SkXfermodeProc4f GetProc4f(Mode);
reed@android.coma0f5d152009-06-22 17:38:10 +0000151
reed@google.comc0d4aa22011-04-13 21:12:04 +0000152 /**
reed@google.com43c50c82011-04-14 15:50:52 +0000153 * If the specified mode can be represented by a pair of Coeff, then return
154 * true and set (if not NULL) the corresponding coeffs. If the mode is
155 * not representable as a pair of Coeffs, return false and ignore the
156 * src and dst parameters.
reed@android.coma0f5d152009-06-22 17:38:10 +0000157 */
reed@google.com43c50c82011-04-14 15:50:52 +0000158 static bool ModeAsCoeff(Mode mode, Coeff* src, Coeff* dst);
reed@android.coma0f5d152009-06-22 17:38:10 +0000159
reed@google.com44699382013-10-31 17:28:30 +0000160 SK_ATTR_DEPRECATED("use AsMode(...)")
reed@google.com30da7452012-12-17 19:55:24 +0000161 static bool IsMode(const SkXfermode* xfer, Mode* mode) {
reed@google.com43c50c82011-04-14 15:50:52 +0000162 return AsMode(xfer, mode);
163 }
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000164
egdanieldcfb7cf2015-01-22 06:52:29 -0800165 /**
166 * Returns whether or not the xfer mode can support treating coverage as alpha
mtklein2766c002015-06-26 11:45:03 -0700167 */
egdanieldcfb7cf2015-01-22 06:52:29 -0800168 virtual bool supportsCoverageAsAlpha() const;
169
170 /**
171 * The same as calling xfermode->supportsCoverageAsAlpha(), except that this also checks if
172 * the xfermode is NULL, and if so, treats it as kSrcOver_Mode.
173 */
174 static bool SupportsCoverageAsAlpha(const SkXfermode* xfer);
175
176 enum SrcColorOpacity {
177 // The src color is known to be opaque (alpha == 255)
178 kOpaque_SrcColorOpacity = 0,
179 // The src color is known to be fully transparent (color == 0)
180 kTransparentBlack_SrcColorOpacity = 1,
181 // The src alpha is known to be fully transparent (alpha == 0)
182 kTransparentAlpha_SrcColorOpacity = 2,
183 // The src color opacity is unknown
184 kUnknown_SrcColorOpacity = 3
185 };
186
187 /**
188 * Returns whether or not the result of the draw with the xfer mode will be opaque or not. The
189 * input to this call is an enum describing known information about the opacity of the src color
190 * that will be given to the xfer mode.
191 */
192 virtual bool isOpaque(SrcColorOpacity opacityType) const;
193
194 /**
195 * The same as calling xfermode->isOpaque(...), except that this also checks if
196 * the xfermode is NULL, and if so, treats it as kSrcOver_Mode.
197 */
198 static bool IsOpaque(const SkXfermode* xfer, SrcColorOpacity opacityType);
199
robertphillips4f037942016-02-09 05:09:27 -0800200#if SK_SUPPORT_GPU
201 /** Used by the SkXfermodeImageFilter to blend two colors via a GrFragmentProcessor.
202 The input to the returned FP is the src color. The dst color is
203 provided by the dst param which becomes a child FP of the returned FP.
204 It is legal for the function to return a null output. This indicates that
bsalomonae4738f2015-09-15 15:33:27 -0700205 the output of the blend is simply the src color.
bsalomon@google.comf51c0132013-03-27 18:31:15 +0000206 */
robertphillips4f037942016-02-09 05:09:27 -0800207 virtual const GrFragmentProcessor* getFragmentProcessorForImageFilter(
208 const GrFragmentProcessor* dst) const;
bsalomon@google.comf51c0132013-03-27 18:31:15 +0000209
robertphillips4f037942016-02-09 05:09:27 -0800210 /** A subclass must implement this factory function to work with the GPU backend.
211 The xfermode will return a factory for which the caller will get a ref. It is up
212 to the caller to install it. XferProcessors cannot use a background texture.
egdanielc4b72722015-11-23 13:20:41 -0800213 */
robertphillips4f037942016-02-09 05:09:27 -0800214 virtual GrXPFactory* asXPFactory() const;
215#endif
bsalomon@google.comf51c0132013-03-27 18:31:15 +0000216
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +0000217 SK_TO_STRING_PUREVIRT()
djsollen@google.coma2ca41e2012-03-23 19:00:34 +0000218 SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP()
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000219 SK_DEFINE_FLATTENABLE_TYPE(SkXfermode)
220
reed395eabe2016-01-30 18:52:31 -0800221 enum PM4fFlags {
222 kSrcIsOpaque_PM4fFlag = 1 << 0,
223 kDstIsSRGB_PM4fFlag = 1 << 1,
224 };
225 struct PM4fState {
226 const SkXfermode* fXfer;
227 uint32_t fFlags;
228 };
229 typedef void (*PM4fProc1)(const PM4fState&, uint32_t dst[], const SkPM4f& src,
230 int count, const SkAlpha coverage[]);
231 typedef void (*PM4fProcN)(const PM4fState&, uint32_t dst[], const SkPM4f src[],
232 int count, const SkAlpha coverage[]);
reed31255652016-02-08 12:56:56 -0800233
reed395eabe2016-01-30 18:52:31 -0800234 static PM4fProc1 GetPM4fProc1(Mode, uint32_t flags);
235 static PM4fProcN GetPM4fProcN(Mode, uint32_t flags);
236 virtual PM4fProc1 getPM4fProc1(uint32_t flags) const;
237 virtual PM4fProcN getPM4fProcN(uint32_t flags) const;
238
reedd2ed6222016-02-09 09:14:59 -0800239 enum U64Flags {
240 kSrcIsOpaque_U64Flag = 1 << 0,
241 kDstIsFloat16_U64Flag = 1 << 1, // else U16 bit components
242 };
243 struct U64State {
244 const SkXfermode* fXfer;
245 uint32_t fFlags;
246 };
247 typedef void (*U64Proc1)(const U64State&, uint64_t dst[], const SkPM4f& src, int count,
248 const SkAlpha coverage[]);
249 typedef void (*U64ProcN)(const U64State&, uint64_t dst[], const SkPM4f src[], int count,
250 const SkAlpha coverage[]);
251 static U64Proc1 GetU64Proc1(Mode, uint32_t flags);
252 static U64ProcN GetU64ProcN(Mode, uint32_t flags);
253
reed4528c862016-02-18 08:16:33 -0800254 enum LCDFlags {
255 kSrcIsOpaque_LCDFlag = 1 << 0, // else src(s) may have alpha < 1
256 kSrcIsSingle_LCDFlag = 1 << 1, // else src[count]
257 kDstIsLinearInt_LCDFlag = 1 << 2, // else srgb/half-float
258 };
259 typedef void (*LCD32Proc)(uint32_t* dst, const SkPM4f* src, int count, const uint16_t lcd[]);
260 typedef void (*LCD64Proc)(uint64_t* dst, const SkPM4f* src, int count, const uint16_t lcd[]);
261 static LCD32Proc GetLCD32Proc(uint32_t flags);
262 static LCD64Proc GetLCD64Proc(uint32_t) { return nullptr; }
263
reed@android.com8a1c16f2008-12-17 15:59:43 +0000264protected:
commit-bot@chromium.orgbd0be252014-05-15 15:40:41 +0000265 SkXfermode() {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000266 /** The default implementation of xfer32/xfer16/xferA8 in turn call this
267 method, 1 color at a time (upscaled to a SkPMColor). The default
bsalomonae4738f2015-09-15 15:33:27 -0700268 implementation of this method just returns dst. If performance is
reed@android.com8a1c16f2008-12-17 15:59:43 +0000269 important, your subclass should override xfer32/xfer16/xferA8 directly.
tomhudson@google.com1447c6f2011-04-27 14:09:52 +0000270
reed@android.com8a1c16f2008-12-17 15:59:43 +0000271 This method will not be called directly by the client, so it need not
272 be implemented if your subclass has overridden xfer32/xfer16/xferA8
273 */
reed@google.com30da7452012-12-17 19:55:24 +0000274 virtual SkPMColor xferColor(SkPMColor src, SkPMColor dst) const;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000275
276private:
reed@android.coma0f5d152009-06-22 17:38:10 +0000277 enum {
278 kModeCount = kLastMode + 1
279 };
commit-bot@chromium.org86490572013-10-04 16:52:55 +0000280
reed@android.com8a1c16f2008-12-17 15:59:43 +0000281 typedef SkFlattenable INHERITED;
282};
283
reed@android.com8a1c16f2008-12-17 15:59:43 +0000284#endif