blob: 076ecf5460df9698021913279f6d13f5e3280179 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2006 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
epoger@google.comec3ed6a2011-07-28 14:26:00 +00008
reed@android.com8a1c16f2008-12-17 15:59:43 +00009#ifndef SkShader_DEFINED
10#define SkShader_DEFINED
11
12#include "SkBitmap.h"
13#include "SkFlattenable.h"
14#include "SkMask.h"
15#include "SkMatrix.h"
16#include "SkPaint.h"
17
18class SkPath;
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +000019class SkPicture;
rileya@google.com03c1c352012-07-20 20:02:43 +000020class GrContext;
bsalomon@google.com0ac6af42013-01-16 15:16:18 +000021class GrEffectRef;
reed@android.com8a1c16f2008-12-17 15:59:43 +000022
23/** \class SkShader
reed@google.comad917992011-04-11 19:01:12 +000024 *
reed@google.com880dc472012-05-11 14:47:03 +000025 * Shaders specify the source color(s) for what is being drawn. If a paint
26 * has no shader, then the paint's color is used. If the paint has a
27 * shader, then the shader's color(s) are use instead, but they are
28 * modulated by the paint's alpha. This makes it easy to create a shader
29 * once (e.g. bitmap tiling or gradient) and then change its transparency
30 * w/o having to modify the original shader... only the paint's alpha needs
31 * to be modified.
reed@google.comad917992011-04-11 19:01:12 +000032 */
ctguil@chromium.org7ffb1b22011-03-15 21:27:08 +000033class SK_API SkShader : public SkFlattenable {
reed@android.com8a1c16f2008-12-17 15:59:43 +000034public:
robertphillips@google.com0456e0b2012-06-27 14:03:26 +000035 SK_DECLARE_INST_COUNT(SkShader)
36
37 SkShader();
reed@android.com8a1c16f2008-12-17 15:59:43 +000038 virtual ~SkShader();
39
reed@google.comad917992011-04-11 19:01:12 +000040 /**
bsalomon@google.comf94b3a42012-10-31 18:09:01 +000041 * Returns true if the local matrix is not an identity matrix.
reed@google.comad917992011-04-11 19:01:12 +000042 */
bsalomon@google.comf94b3a42012-10-31 18:09:01 +000043 bool hasLocalMatrix() const { return !fLocalMatrix.isIdentity(); }
44
45 /**
46 * Returns the local matrix.
47 */
48 const SkMatrix& getLocalMatrix() const { return fLocalMatrix; }
reed@google.comad917992011-04-11 19:01:12 +000049
50 /**
51 * Set the shader's local matrix.
52 * @param localM The shader's new local matrix.
53 */
bsalomon@google.comf94b3a42012-10-31 18:09:01 +000054 void setLocalMatrix(const SkMatrix& localM) { fLocalMatrix = localM; }
reed@google.comad917992011-04-11 19:01:12 +000055
56 /**
57 * Reset the shader's local matrix to identity.
58 */
bsalomon@google.comf94b3a42012-10-31 18:09:01 +000059 void resetLocalMatrix() { fLocalMatrix.reset(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +000060
61 enum TileMode {
reed@google.com0beaba52012-03-16 14:38:06 +000062 /** replicate the edge color if the shader draws outside of its
63 * original bounds
64 */
65 kClamp_TileMode,
66
67 /** repeat the shader's image horizontally and vertically */
68 kRepeat_TileMode,
69
70 /** repeat the shader's image horizontally and vertically, alternating
71 * mirror images so that adjacent images always seam
72 */
73 kMirror_TileMode,
74
75#if 0
76 /** only draw within the original domain, return 0 everywhere else */
77 kDecal_TileMode,
78#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000079
80 kTileModeCount
81 };
82
83 // override these in your subclass
84
85 enum Flags {
86 //!< set if all of the colors will be opaque
reed@android.com3c9b2a42009-08-27 19:28:37 +000087 kOpaqueAlpha_Flag = 0x01,
reed@android.com5119bdb2009-06-12 21:27:03 +000088
reed@android.com8a1c16f2008-12-17 15:59:43 +000089 //! set if this shader's shadeSpan16() method can be called
reed@android.com3c9b2a42009-08-27 19:28:37 +000090 kHasSpan16_Flag = 0x02,
reed@android.com5119bdb2009-06-12 21:27:03 +000091
reed@android.com8a1c16f2008-12-17 15:59:43 +000092 /** Set this bit if the shader's native data type is instrinsically 16
93 bit, meaning that calling the 32bit shadeSpan() entry point will
94 mean the the impl has to up-sample 16bit data into 32bit. Used as a
95 a means of clearing a dither request if the it will have no effect
96 */
reed@android.com5119bdb2009-06-12 21:27:03 +000097 kIntrinsicly16_Flag = 0x04,
98
99 /** set (after setContext) if the spans only vary in X (const in Y).
100 e.g. an Nx1 bitmap that is being tiled in Y, or a linear-gradient
reed@android.com3c9b2a42009-08-27 19:28:37 +0000101 that varies from left-to-right. This flag specifies this for
102 shadeSpan().
reed@android.com5119bdb2009-06-12 21:27:03 +0000103 */
reed@android.com3c9b2a42009-08-27 19:28:37 +0000104 kConstInY32_Flag = 0x08,
reed@google.com7c2f27d2011-03-07 19:29:00 +0000105
reed@android.com3c9b2a42009-08-27 19:28:37 +0000106 /** same as kConstInY32_Flag, but is set if this is true for shadeSpan16
107 which may not always be the case, since shadeSpan16 may be
108 predithered, which would mean it was not const in Y, even though
109 the 32bit shadeSpan() would be const.
110 */
111 kConstInY16_Flag = 0x10
reed@android.com8a1c16f2008-12-17 15:59:43 +0000112 };
113
reed@google.comad917992011-04-11 19:01:12 +0000114 /**
115 * Called sometimes before drawing with this shader. Return the type of
116 * alpha your shader will return. The default implementation returns 0.
117 * Your subclass should override if it can (even sometimes) report a
118 * non-zero value, since that will enable various blitters to perform
119 * faster.
120 */
reed@android.com8a1c16f2008-12-17 15:59:43 +0000121 virtual uint32_t getFlags() { return 0; }
122
reed@google.comad917992011-04-11 19:01:12 +0000123 /**
junov@chromium.orgb6e16192011-12-09 15:48:03 +0000124 * Returns true if the shader is guaranteed to produce only opaque
125 * colors, subject to the SkPaint using the shader to apply an opaque
126 * alpha value. Subclasses should override this to allow some
127 * optimizations. isOpaque() can be called at any time, unlike getFlags,
128 * which only works properly when the context is set.
129 */
130 virtual bool isOpaque() const { return false; }
131
132 /**
reed@google.comad917992011-04-11 19:01:12 +0000133 * Return the alpha associated with the data returned by shadeSpan16(). If
134 * kHasSpan16_Flag is not set, this value is meaningless.
135 */
reed@android.com8a1c16f2008-12-17 15:59:43 +0000136 virtual uint8_t getSpan16Alpha() const { return fPaintAlpha; }
reed@google.com7c2f27d2011-03-07 19:29:00 +0000137
reed@google.comad917992011-04-11 19:01:12 +0000138 /**
139 * Called once before drawing, with the current paint and device matrix.
140 * Return true if your shader supports these parameters, or false if not.
reed@google.coma641f3f2012-12-13 22:16:30 +0000141 * If false is returned, nothing will be drawn. If true is returned, then
142 * a balancing call to endContext() will be made before the next call to
143 * setContext.
144 *
145 * Subclasses should be sure to call their INHERITED::setContext() if they
146 * override this method.
reed@google.comad917992011-04-11 19:01:12 +0000147 */
reed@android.com3c9b2a42009-08-27 19:28:37 +0000148 virtual bool setContext(const SkBitmap& device, const SkPaint& paint,
149 const SkMatrix& matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000150
reed@google.comad917992011-04-11 19:01:12 +0000151 /**
reed@google.coma641f3f2012-12-13 22:16:30 +0000152 * Assuming setContext returned true, endContext() will be called when
153 * the draw using the shader has completed. It is an error for setContext
154 * to be called twice w/o an intervening call to endContext().
155 *
156 * Subclasses should be sure to call their INHERITED::endContext() if they
157 * override this method.
158 */
159 virtual void endContext();
160
robertphillips@google.com441a0052012-12-14 13:55:06 +0000161 SkDEBUGCODE(bool setContextHasBeenCalled() const { return SkToBool(fInSetContext); })
reed@google.coma641f3f2012-12-13 22:16:30 +0000162
163 /**
reed@google.comad917992011-04-11 19:01:12 +0000164 * Called for each span of the object being drawn. Your subclass should
165 * set the appropriate colors (with premultiplied alpha) that correspond
166 * to the specified device coordinates.
167 */
reed@android.com3c9b2a42009-08-27 19:28:37 +0000168 virtual void shadeSpan(int x, int y, SkPMColor[], int count) = 0;
reed@google.comad917992011-04-11 19:01:12 +0000169
reed@google.com3bafe742012-10-12 18:56:18 +0000170 typedef void (*ShadeProc)(void* ctx, int x, int y, SkPMColor[], int count);
171 virtual ShadeProc asAShadeProc(void** ctx);
172
reed@google.comad917992011-04-11 19:01:12 +0000173 /**
174 * Called only for 16bit devices when getFlags() returns
175 * kOpaqueAlphaFlag | kHasSpan16_Flag
176 */
reed@android.com3c9b2a42009-08-27 19:28:37 +0000177 virtual void shadeSpan16(int x, int y, uint16_t[], int count);
reed@google.comad917992011-04-11 19:01:12 +0000178
179 /**
180 * Similar to shadeSpan, but only returns the alpha-channel for a span.
181 * The default implementation calls shadeSpan() and then extracts the alpha
182 * values from the returned colors.
183 */
reed@android.com3c9b2a42009-08-27 19:28:37 +0000184 virtual void shadeSpanAlpha(int x, int y, uint8_t alpha[], int count);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000185
reed@google.comad917992011-04-11 19:01:12 +0000186 /**
187 * Helper function that returns true if this shader's shadeSpan16() method
188 * can be called.
189 */
reed@android.com3c9b2a42009-08-27 19:28:37 +0000190 bool canCallShadeSpan16() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000191 return SkShader::CanCallShadeSpan16(this->getFlags());
192 }
193
reed@google.comad917992011-04-11 19:01:12 +0000194 /**
195 * Helper to check the flags to know if it is legal to call shadeSpan16()
196 */
reed@android.com8a1c16f2008-12-17 15:59:43 +0000197 static bool CanCallShadeSpan16(uint32_t flags) {
198 return (flags & kHasSpan16_Flag) != 0;
199 }
200
reed@google.comad917992011-04-11 19:01:12 +0000201 /**
reed@android.comf2b98d62010-12-20 18:26:13 +0000202 Gives method bitmap should be read to implement a shader.
203 Also determines number and interpretation of "extra" parameters returned
204 by asABitmap
205 */
206 enum BitmapType {
207 kNone_BitmapType, //<! Shader is not represented as a bitmap
reed@google.com7c2f27d2011-03-07 19:29:00 +0000208 kDefault_BitmapType,//<! Access bitmap using local coords transformed
reed@android.comf2b98d62010-12-20 18:26:13 +0000209 // by matrix. No extras
reed@google.com7c2f27d2011-03-07 19:29:00 +0000210 kRadial_BitmapType, //<! Access bitmap by transforming local coordinates
211 // by the matrix and taking the distance of result
212 // from (0,0) as bitmap column. Bitmap is 1 pixel
reed@android.comf2b98d62010-12-20 18:26:13 +0000213 // tall. No extras
reed@google.com7c2f27d2011-03-07 19:29:00 +0000214 kSweep_BitmapType, //<! Access bitmap by transforming local coordinates
reed@android.comf2b98d62010-12-20 18:26:13 +0000215 // by the matrix and taking the angle of result
216 // to (0,0) as bitmap x coord, where angle = 0 is
reed@google.com7c2f27d2011-03-07 19:29:00 +0000217 // bitmap left edge of bitmap = 2pi is the
reed@android.comf2b98d62010-12-20 18:26:13 +0000218 // right edge. Bitmap is 1 pixel tall. No extras
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000219 kTwoPointRadial_BitmapType,
reed@google.com7c2f27d2011-03-07 19:29:00 +0000220 //<! Matrix transforms to space where (0,0) is
reed@android.comf2b98d62010-12-20 18:26:13 +0000221 // the center of the starting circle. The second
reed@google.com7c2f27d2011-03-07 19:29:00 +0000222 // circle will be centered (x, 0) where x may be
223 // 0. The post-matrix space is normalized such
reed@android.comf2b98d62010-12-20 18:26:13 +0000224 // that 1 is the second radius - first radius.
225 // Three extra parameters are returned:
reed@google.com7c2f27d2011-03-07 19:29:00 +0000226 // 0: x-offset of second circle center
reed@android.comf2b98d62010-12-20 18:26:13 +0000227 // to first.
reed@google.com7c2f27d2011-03-07 19:29:00 +0000228 // 1: radius of first circle in post-matrix
reed@android.comf2b98d62010-12-20 18:26:13 +0000229 // space
230 // 2: the second radius minus the first radius
reed@google.com7c2f27d2011-03-07 19:29:00 +0000231 // in pre-transformed space.
rileya@google.com3e332582012-07-03 13:43:35 +0000232 kTwoPointConical_BitmapType,
233 //<! Matrix transforms to space where (0,0) is
234 // the center of the starting circle. The second
235 // circle will be centered (x, 0) where x may be
236 // 0.
237 // Three extra parameters are returned:
238 // 0: x-offset of second circle center
239 // to first.
240 // 1: radius of first circle
241 // 2: the second radius minus the first radius
rileya@google.com22e57f92012-07-19 15:16:19 +0000242 kLinear_BitmapType, //<! Access bitmap using local coords transformed
243 // by matrix. No extras
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000244
rileya@google.com22e57f92012-07-19 15:16:19 +0000245 kLast_BitmapType = kLinear_BitmapType
reed@android.comf2b98d62010-12-20 18:26:13 +0000246 };
reed@android.com8a1c16f2008-12-17 15:59:43 +0000247 /** Optional methods for shaders that can pretend to be a bitmap/texture
reed@google.com7c2f27d2011-03-07 19:29:00 +0000248 to play along with opengl. Default just returns kNone_BitmapType and
reed@android.comf2b98d62010-12-20 18:26:13 +0000249 ignores the out parameters.
250
251 @param outTexture if non-NULL will be the bitmap representing the shader
252 after return.
253 @param outMatrix if non-NULL will be the matrix to apply to vertices
254 to access the bitmap after return.
255 @param xy if non-NULL will be the tile modes that should be
256 used to access the bitmap after return.
257 @param twoPointRadialParams Two extra return values needed for two point
258 radial bitmaps. The first is the x-offset of
259 the second point and the second is the radius
260 about the first point.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000261 */
reed@android.comf2b98d62010-12-20 18:26:13 +0000262 virtual BitmapType asABitmap(SkBitmap* outTexture, SkMatrix* outMatrix,
rileya@google.com91f319c2012-07-25 17:18:31 +0000263 TileMode xy[2]) const;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000264
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000265 /**
266 * If the shader subclass can be represented as a gradient, asAGradient
267 * returns the matching GradientType enum (or kNone_GradientType if it
268 * cannot). Also, if info is not null, asAGradient populates info with
269 * the relevant (see below) parameters for the gradient. fColorCount
270 * is both an input and output parameter. On input, it indicates how
271 * many entries in fColors and fColorOffsets can be used, if they are
272 * non-NULL. After asAGradient has run, fColorCount indicates how
273 * many color-offset pairs there are in the gradient. If there is
274 * insufficient space to store all of the color-offset pairs, fColors
275 * and fColorOffsets will not be altered. fColorOffsets specifies
276 * where on the range of 0 to 1 to transition to the given color.
277 * The meaning of fPoint and fRadius is dependant on the type of gradient.
278 *
279 * None:
280 * info is ignored.
281 * Color:
282 * fColorOffsets[0] is meaningless.
283 * Linear:
284 * fPoint[0] and fPoint[1] are the end-points of the gradient
285 * Radial:
286 * fPoint[0] and fRadius[0] are the center and radius
287 * Radial2:
288 * fPoint[0] and fRadius[0] are the center and radius of the 1st circle
289 * fPoint[1] and fRadius[1] are the center and radius of the 2nd circle
290 * Sweep:
291 * fPoint[0] is the center of the sweep.
292 */
293
294 enum GradientType {
295 kNone_GradientType,
296 kColor_GradientType,
297 kLinear_GradientType,
298 kRadial_GradientType,
299 kRadial2_GradientType,
300 kSweep_GradientType,
reed@google.com83226972012-06-07 20:26:47 +0000301 kConical_GradientType,
302 kLast_GradientType = kConical_GradientType
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000303 };
304
305 struct GradientInfo {
306 int fColorCount; //!< In-out parameter, specifies passed size
307 // of fColors/fColorOffsets on input, and
308 // actual number of colors/offsets on
309 // output.
310 SkColor* fColors; //!< The colors in the gradient.
311 SkScalar* fColorOffsets; //!< The unit offset for color transitions.
312 SkPoint fPoint[2]; //!< Type specific, see above.
313 SkScalar fRadius[2]; //!< Type specific, see above.
314 TileMode fTileMode; //!< The tile mode used.
reed@google.com3d3a8602013-05-24 14:58:44 +0000315 uint32_t fGradientFlags; //!< see SkGradientShader::Flags
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000316 };
317
318 virtual GradientType asAGradient(GradientInfo* info) const;
319
rileya@google.com03c1c352012-07-20 20:02:43 +0000320 /**
commit-bot@chromium.org91a798f2013-09-06 15:31:06 +0000321 * If the shader subclass has a GrEffect implementation, this resturns the effect to install.
322 * The incoming color to the effect has r=g=b=a all extracted from the SkPaint's alpha.
323 * The output color should be the computed SkShader premul color modulated by the incoming
324 * color. The GrContext may be used by the effect to create textures. The GPU device does not
325 * call setContext. Instead we pass the SkPaint here in case the shader needs paint info.
rileya@google.com03c1c352012-07-20 20:02:43 +0000326 */
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000327 virtual GrEffectRef* asNewEffect(GrContext* context, const SkPaint& paint) const;
rileya@google.com03c1c352012-07-20 20:02:43 +0000328
reed@android.com8a1c16f2008-12-17 15:59:43 +0000329 //////////////////////////////////////////////////////////////////////////
330 // Factory methods for stock shaders
331
332 /** Call this to create a new shader that will draw with the specified bitmap.
reed@google.com99c114e2012-05-03 20:14:26 +0000333 *
334 * If the bitmap cannot be used (e.g. has no pixels, or its dimensions
335 * exceed implementation limits (currently at 64K - 1)) then SkEmptyShader
336 * may be returned.
337 *
commit-bot@chromium.org91246b92013-12-05 15:43:19 +0000338 * If the src is kA8_Config then that mask will be colorized using the color on
339 * the paint.
340 *
reed@google.com99c114e2012-05-03 20:14:26 +0000341 * @param src The bitmap to use inside the shader
342 * @param tmx The tiling mode to use when sampling the bitmap in the x-direction.
343 * @param tmy The tiling mode to use when sampling the bitmap in the y-direction.
344 * @return Returns a new shader object. Note: this function never returns null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000345 */
346 static SkShader* CreateBitmapShader(const SkBitmap& src,
347 TileMode tmx, TileMode tmy);
348
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000349 /** Call this to create a new shader that will draw with the specified picture.
350 *
351 * @param src The picture to use inside the shader (if not NULL, its ref count
352 * is incremented).
353 * @param tmx The tiling mode to use when sampling the bitmap in the x-direction.
354 * @param tmy The tiling mode to use when sampling the bitmap in the y-direction.
355 * @return Returns a new shader object. Note: this function never returns null.
356 */
357 static SkShader* CreatePictureShader(SkPicture* src, TileMode tmx, TileMode tmy);
358
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +0000359 SK_TO_STRING_VIRT()
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000360 SK_DEFINE_FLATTENABLE_TYPE(SkShader)
361
reed@android.com8a1c16f2008-12-17 15:59:43 +0000362protected:
363 enum MatrixClass {
364 kLinear_MatrixClass, // no perspective
365 kFixedStepInX_MatrixClass, // fast perspective, need to call fixedStepInX() each scanline
366 kPerspective_MatrixClass // slow perspective, need to mappoints each pixel
367 };
368 static MatrixClass ComputeMatrixClass(const SkMatrix&);
369
370 // These can be called by your subclass after setContext() has been called
371 uint8_t getPaintAlpha() const { return fPaintAlpha; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000372 const SkMatrix& getTotalInverse() const { return fTotalInverse; }
373 MatrixClass getInverseClass() const { return (MatrixClass)fTotalInverseClass; }
374
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000375 SkShader(SkReadBuffer& );
376 virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000377private:
bsalomon@google.comf94b3a42012-10-31 18:09:01 +0000378 SkMatrix fLocalMatrix;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000379 SkMatrix fTotalInverse;
380 uint8_t fPaintAlpha;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000381 uint8_t fTotalInverseClass;
reed@google.coma641f3f2012-12-13 22:16:30 +0000382 SkDEBUGCODE(SkBool8 fInSetContext;)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000383
reed@android.com8a1c16f2008-12-17 15:59:43 +0000384 typedef SkFlattenable INHERITED;
385};
386
387#endif