blob: 4af8f78bfbaa9ca8523b3262870081fbd10ace65 [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
commit-bot@chromium.org9c9005a2014-04-28 14:55:39 +000037 SkShader(const SkMatrix* localMatrix = NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +000038 virtual ~SkShader();
39
reed@google.comad917992011-04-11 19:01:12 +000040 /**
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +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
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +000099 /** set if the spans only vary in X (const in Y).
reed@android.com5119bdb2009-06-12 21:27:03 +0000100 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 /**
junov@chromium.orgb6e16192011-12-09 15:48:03 +0000115 * Returns true if the shader is guaranteed to produce only opaque
116 * colors, subject to the SkPaint using the shader to apply an opaque
117 * alpha value. Subclasses should override this to allow some
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000118 * optimizations.
junov@chromium.orgb6e16192011-12-09 15:48:03 +0000119 */
120 virtual bool isOpaque() const { return false; }
121
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000122 class Context : public ::SkNoncopyable {
123 public:
124 Context(const SkShader& shader, const SkBitmap& device,
125 const SkPaint& paint, const SkMatrix& matrix);
126
127 virtual ~Context();
128
129 /**
130 * Called sometimes before drawing with this shader. Return the type of
131 * alpha your shader will return. The default implementation returns 0.
132 * Your subclass should override if it can (even sometimes) report a
133 * non-zero value, since that will enable various blitters to perform
134 * faster.
135 */
136 virtual uint32_t getFlags() const { return 0; }
137
138 /**
139 * Return the alpha associated with the data returned by shadeSpan16(). If
140 * kHasSpan16_Flag is not set, this value is meaningless.
141 */
142 virtual uint8_t getSpan16Alpha() const { return fPaintAlpha; }
143
144 /**
145 * Called for each span of the object being drawn. Your subclass should
146 * set the appropriate colors (with premultiplied alpha) that correspond
147 * to the specified device coordinates.
148 */
149 virtual void shadeSpan(int x, int y, SkPMColor[], int count) = 0;
150
151 typedef void (*ShadeProc)(void* ctx, int x, int y, SkPMColor[], int count);
152 virtual ShadeProc asAShadeProc(void** ctx);
153
154 /**
155 * Called only for 16bit devices when getFlags() returns
156 * kOpaqueAlphaFlag | kHasSpan16_Flag
157 */
158 virtual void shadeSpan16(int x, int y, uint16_t[], int count);
159
160 /**
161 * Similar to shadeSpan, but only returns the alpha-channel for a span.
162 * The default implementation calls shadeSpan() and then extracts the alpha
163 * values from the returned colors.
164 */
165 virtual void shadeSpanAlpha(int x, int y, uint8_t alpha[], int count);
166
167 /**
168 * Helper function that returns true if this shader's shadeSpan16() method
169 * can be called.
170 */
171 bool canCallShadeSpan16() {
172 return SkShader::CanCallShadeSpan16(this->getFlags());
173 }
174
175 protected:
176 // Reference to shader, so we don't have to dupe information.
177 const SkShader& fShader;
178
179 enum MatrixClass {
180 kLinear_MatrixClass, // no perspective
181 kFixedStepInX_MatrixClass, // fast perspective, need to call fixedStepInX() each
182 // scanline
183 kPerspective_MatrixClass // slow perspective, need to mappoints each pixel
184 };
185 static MatrixClass ComputeMatrixClass(const SkMatrix&);
186
187 uint8_t getPaintAlpha() const { return fPaintAlpha; }
188 const SkMatrix& getTotalInverse() const { return fTotalInverse; }
189 MatrixClass getInverseClass() const { return (MatrixClass)fTotalInverseClass; }
190
191 private:
192 SkMatrix fTotalInverse;
193 uint8_t fPaintAlpha;
194 uint8_t fTotalInverseClass;
195
196 typedef SkNoncopyable INHERITED;
197 };
reed@google.com7c2f27d2011-03-07 19:29:00 +0000198
reed@google.comad917992011-04-11 19:01:12 +0000199 /**
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000200 * Subclasses should be sure to call their INHERITED::validContext() if
201 * they override this method.
reed@google.comad917992011-04-11 19:01:12 +0000202 */
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000203 virtual bool validContext(const SkBitmap& device, const SkPaint& paint,
204 const SkMatrix& matrix, SkMatrix* totalInverse = NULL) const;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000205
reed@google.comad917992011-04-11 19:01:12 +0000206 /**
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000207 * Create the actual object that does the shading.
208 * Returns NULL if validContext() returns false.
209 * Size of storage must be >= contextSize.
reed@google.coma641f3f2012-12-13 22:16:30 +0000210 */
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000211 virtual Context* createContext(const SkBitmap& device,
212 const SkPaint& paint,
213 const SkMatrix& matrix,
214 void* storage) const = 0;
reed@google.coma641f3f2012-12-13 22:16:30 +0000215
216 /**
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000217 * Return the size of a Context returned by createContext.
reed@google.comad917992011-04-11 19:01:12 +0000218 */
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000219 virtual size_t contextSize() const = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000220
reed@google.comad917992011-04-11 19:01:12 +0000221 /**
222 * Helper to check the flags to know if it is legal to call shadeSpan16()
223 */
reed@android.com8a1c16f2008-12-17 15:59:43 +0000224 static bool CanCallShadeSpan16(uint32_t flags) {
225 return (flags & kHasSpan16_Flag) != 0;
226 }
227
reed@google.comad917992011-04-11 19:01:12 +0000228 /**
reed@android.comf2b98d62010-12-20 18:26:13 +0000229 Gives method bitmap should be read to implement a shader.
230 Also determines number and interpretation of "extra" parameters returned
231 by asABitmap
232 */
233 enum BitmapType {
234 kNone_BitmapType, //<! Shader is not represented as a bitmap
reed@google.com7c2f27d2011-03-07 19:29:00 +0000235 kDefault_BitmapType,//<! Access bitmap using local coords transformed
reed@android.comf2b98d62010-12-20 18:26:13 +0000236 // by matrix. No extras
reed@google.com7c2f27d2011-03-07 19:29:00 +0000237 kRadial_BitmapType, //<! Access bitmap by transforming local coordinates
238 // by the matrix and taking the distance of result
239 // from (0,0) as bitmap column. Bitmap is 1 pixel
reed@android.comf2b98d62010-12-20 18:26:13 +0000240 // tall. No extras
reed@google.com7c2f27d2011-03-07 19:29:00 +0000241 kSweep_BitmapType, //<! Access bitmap by transforming local coordinates
reed@android.comf2b98d62010-12-20 18:26:13 +0000242 // by the matrix and taking the angle of result
243 // to (0,0) as bitmap x coord, where angle = 0 is
reed@google.com7c2f27d2011-03-07 19:29:00 +0000244 // bitmap left edge of bitmap = 2pi is the
reed@android.comf2b98d62010-12-20 18:26:13 +0000245 // right edge. Bitmap is 1 pixel tall. No extras
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000246 kTwoPointRadial_BitmapType,
reed@google.com7c2f27d2011-03-07 19:29:00 +0000247 //<! Matrix transforms to space where (0,0) is
reed@android.comf2b98d62010-12-20 18:26:13 +0000248 // the center of the starting circle. The second
reed@google.com7c2f27d2011-03-07 19:29:00 +0000249 // circle will be centered (x, 0) where x may be
250 // 0. The post-matrix space is normalized such
reed@android.comf2b98d62010-12-20 18:26:13 +0000251 // that 1 is the second radius - first radius.
252 // Three extra parameters are returned:
reed@google.com7c2f27d2011-03-07 19:29:00 +0000253 // 0: x-offset of second circle center
reed@android.comf2b98d62010-12-20 18:26:13 +0000254 // to first.
reed@google.com7c2f27d2011-03-07 19:29:00 +0000255 // 1: radius of first circle in post-matrix
reed@android.comf2b98d62010-12-20 18:26:13 +0000256 // space
257 // 2: the second radius minus the first radius
reed@google.com7c2f27d2011-03-07 19:29:00 +0000258 // in pre-transformed space.
rileya@google.com3e332582012-07-03 13:43:35 +0000259 kTwoPointConical_BitmapType,
260 //<! Matrix transforms to space where (0,0) is
261 // the center of the starting circle. The second
262 // circle will be centered (x, 0) where x may be
263 // 0.
264 // Three extra parameters are returned:
265 // 0: x-offset of second circle center
266 // to first.
267 // 1: radius of first circle
268 // 2: the second radius minus the first radius
rileya@google.com22e57f92012-07-19 15:16:19 +0000269 kLinear_BitmapType, //<! Access bitmap using local coords transformed
270 // by matrix. No extras
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000271
rileya@google.com22e57f92012-07-19 15:16:19 +0000272 kLast_BitmapType = kLinear_BitmapType
reed@android.comf2b98d62010-12-20 18:26:13 +0000273 };
reed@android.com8a1c16f2008-12-17 15:59:43 +0000274 /** Optional methods for shaders that can pretend to be a bitmap/texture
reed@google.com7c2f27d2011-03-07 19:29:00 +0000275 to play along with opengl. Default just returns kNone_BitmapType and
reed@android.comf2b98d62010-12-20 18:26:13 +0000276 ignores the out parameters.
277
278 @param outTexture if non-NULL will be the bitmap representing the shader
279 after return.
280 @param outMatrix if non-NULL will be the matrix to apply to vertices
281 to access the bitmap after return.
282 @param xy if non-NULL will be the tile modes that should be
283 used to access the bitmap after return.
284 @param twoPointRadialParams Two extra return values needed for two point
285 radial bitmaps. The first is the x-offset of
286 the second point and the second is the radius
287 about the first point.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000288 */
reed@android.comf2b98d62010-12-20 18:26:13 +0000289 virtual BitmapType asABitmap(SkBitmap* outTexture, SkMatrix* outMatrix,
rileya@google.com91f319c2012-07-25 17:18:31 +0000290 TileMode xy[2]) const;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000291
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000292 /**
293 * If the shader subclass can be represented as a gradient, asAGradient
294 * returns the matching GradientType enum (or kNone_GradientType if it
295 * cannot). Also, if info is not null, asAGradient populates info with
296 * the relevant (see below) parameters for the gradient. fColorCount
297 * is both an input and output parameter. On input, it indicates how
298 * many entries in fColors and fColorOffsets can be used, if they are
299 * non-NULL. After asAGradient has run, fColorCount indicates how
300 * many color-offset pairs there are in the gradient. If there is
301 * insufficient space to store all of the color-offset pairs, fColors
302 * and fColorOffsets will not be altered. fColorOffsets specifies
303 * where on the range of 0 to 1 to transition to the given color.
304 * The meaning of fPoint and fRadius is dependant on the type of gradient.
305 *
306 * None:
307 * info is ignored.
308 * Color:
309 * fColorOffsets[0] is meaningless.
310 * Linear:
311 * fPoint[0] and fPoint[1] are the end-points of the gradient
312 * Radial:
313 * fPoint[0] and fRadius[0] are the center and radius
314 * Radial2:
315 * fPoint[0] and fRadius[0] are the center and radius of the 1st circle
316 * fPoint[1] and fRadius[1] are the center and radius of the 2nd circle
317 * Sweep:
318 * fPoint[0] is the center of the sweep.
319 */
320
321 enum GradientType {
322 kNone_GradientType,
323 kColor_GradientType,
324 kLinear_GradientType,
325 kRadial_GradientType,
326 kRadial2_GradientType,
327 kSweep_GradientType,
reed@google.com83226972012-06-07 20:26:47 +0000328 kConical_GradientType,
329 kLast_GradientType = kConical_GradientType
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000330 };
331
332 struct GradientInfo {
333 int fColorCount; //!< In-out parameter, specifies passed size
334 // of fColors/fColorOffsets on input, and
335 // actual number of colors/offsets on
336 // output.
337 SkColor* fColors; //!< The colors in the gradient.
338 SkScalar* fColorOffsets; //!< The unit offset for color transitions.
339 SkPoint fPoint[2]; //!< Type specific, see above.
340 SkScalar fRadius[2]; //!< Type specific, see above.
341 TileMode fTileMode; //!< The tile mode used.
reed@google.com3d3a8602013-05-24 14:58:44 +0000342 uint32_t fGradientFlags; //!< see SkGradientShader::Flags
vandebo@chromium.orgd3ae7792011-02-24 00:21:06 +0000343 };
344
345 virtual GradientType asAGradient(GradientInfo* info) const;
346
rileya@google.com03c1c352012-07-20 20:02:43 +0000347 /**
commit-bot@chromium.org91a798f2013-09-06 15:31:06 +0000348 * If the shader subclass has a GrEffect implementation, this resturns the effect to install.
349 * The incoming color to the effect has r=g=b=a all extracted from the SkPaint's alpha.
350 * The output color should be the computed SkShader premul color modulated by the incoming
351 * color. The GrContext may be used by the effect to create textures. The GPU device does not
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000352 * call createContext. Instead we pass the SkPaint here in case the shader needs paint info.
rileya@google.com03c1c352012-07-20 20:02:43 +0000353 */
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000354 virtual GrEffectRef* asNewEffect(GrContext* context, const SkPaint& paint) const;
rileya@google.com03c1c352012-07-20 20:02:43 +0000355
reed@android.com8a1c16f2008-12-17 15:59:43 +0000356 //////////////////////////////////////////////////////////////////////////
357 // Factory methods for stock shaders
358
359 /** Call this to create a new shader that will draw with the specified bitmap.
reed@google.com99c114e2012-05-03 20:14:26 +0000360 *
361 * If the bitmap cannot be used (e.g. has no pixels, or its dimensions
362 * exceed implementation limits (currently at 64K - 1)) then SkEmptyShader
363 * may be returned.
364 *
commit-bot@chromium.org91246b92013-12-05 15:43:19 +0000365 * If the src is kA8_Config then that mask will be colorized using the color on
366 * the paint.
367 *
reed@google.com99c114e2012-05-03 20:14:26 +0000368 * @param src The bitmap to use inside the shader
369 * @param tmx The tiling mode to use when sampling the bitmap in the x-direction.
370 * @param tmy The tiling mode to use when sampling the bitmap in the y-direction.
371 * @return Returns a new shader object. Note: this function never returns null.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000372 */
373 static SkShader* CreateBitmapShader(const SkBitmap& src,
commit-bot@chromium.org9c9005a2014-04-28 14:55:39 +0000374 TileMode tmx, TileMode tmy,
375 const SkMatrix* localMatrix = NULL);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000376
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000377 /** Call this to create a new shader that will draw with the specified picture.
378 *
379 * @param src The picture to use inside the shader (if not NULL, its ref count
commit-bot@chromium.org855e88e2014-04-21 19:33:12 +0000380 * is incremented). The SkPicture must not be changed after
381 * successfully creating a picture shader.
382 * FIXME: src cannot be const due to SkCanvas::drawPicture
commit-bot@chromium.orgc5d9bb02014-04-08 15:19:34 +0000383 * @param tmx The tiling mode to use when sampling the bitmap in the x-direction.
384 * @param tmy The tiling mode to use when sampling the bitmap in the y-direction.
385 * @return Returns a new shader object. Note: this function never returns null.
386 */
387 static SkShader* CreatePictureShader(SkPicture* src, TileMode tmx, TileMode tmy);
388
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +0000389 SK_TO_STRING_VIRT()
commit-bot@chromium.orgc0b7e102013-10-23 17:06:21 +0000390 SK_DEFINE_FLATTENABLE_TYPE(SkShader)
391
reed@android.com8a1c16f2008-12-17 15:59:43 +0000392protected:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000393
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000394 SkShader(SkReadBuffer& );
395 virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000396
reed@android.com8a1c16f2008-12-17 15:59:43 +0000397private:
bsalomon@google.comf94b3a42012-10-31 18:09:01 +0000398 SkMatrix fLocalMatrix;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000399
400 bool computeTotalInverse(const SkMatrix& matrix, SkMatrix* totalInverse) const;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000401
reed@android.com8a1c16f2008-12-17 15:59:43 +0000402 typedef SkFlattenable INHERITED;
403};
404
405#endif