reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 1 | /* |
epoger@google.com | ec3ed6a | 2011-07-28 14:26:00 +0000 | [diff] [blame] | 2 | * Copyright 2006 The Android Open Source Project |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 3 | * |
epoger@google.com | ec3ed6a | 2011-07-28 14:26:00 +0000 | [diff] [blame] | 4 | * Use of this source code is governed by a BSD-style license that can be |
| 5 | * found in the LICENSE file. |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 6 | */ |
| 7 | |
| 8 | #ifndef SkShader_DEFINED |
| 9 | #define SkShader_DEFINED |
| 10 | |
Mike Reed | 75ae421 | 2018-01-23 11:24:08 -0500 | [diff] [blame] | 11 | #include "SkBlendMode.h" |
Mike Reed | e602f39 | 2018-02-06 10:17:08 -0500 | [diff] [blame^] | 12 | #include "SkColor.h" |
Mike Klein | 987de5b | 2016-11-17 10:47:39 -0500 | [diff] [blame] | 13 | #include "SkFilterQuality.h" |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 14 | #include "SkFlattenable.h" |
fmalita | d0c4e09 | 2016-02-22 17:19:04 -0800 | [diff] [blame] | 15 | #include "SkImageInfo.h" |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 16 | #include "SkMatrix.h" |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 17 | |
Herb Derby | 83e939b | 2017-02-07 14:25:11 -0500 | [diff] [blame] | 18 | class SkArenaAlloc; |
Mike Reed | 75ae421 | 2018-01-23 11:24:08 -0500 | [diff] [blame] | 19 | class SkBitmap; |
reed | 3061af4 | 2016-01-07 15:47:29 -0800 | [diff] [blame] | 20 | class SkColorFilter; |
reed | 0ccc62d | 2016-05-04 13:09:39 -0700 | [diff] [blame] | 21 | class SkColorSpace; |
Matt Sarett | 6cc6ae75 | 2017-04-18 18:29:12 -0400 | [diff] [blame] | 22 | class SkColorSpaceXformer; |
reed | f1ac182 | 2016-08-01 11:24:14 -0700 | [diff] [blame] | 23 | class SkImage; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 24 | class SkPath; |
commit-bot@chromium.org | c5d9bb0 | 2014-04-08 15:19:34 +0000 | [diff] [blame] | 25 | class SkPicture; |
Mike Klein | b0d10e0 | 2016-11-12 10:29:26 -0500 | [diff] [blame] | 26 | class SkRasterPipeline; |
rileya@google.com | 03c1c35 | 2012-07-20 20:02:43 +0000 | [diff] [blame] | 27 | class GrContext; |
joshualitt | b0a8a37 | 2014-09-23 09:50:21 -0700 | [diff] [blame] | 28 | class GrFragmentProcessor; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 29 | |
| 30 | /** \class SkShader |
reed@google.com | ad91799 | 2011-04-11 19:01:12 +0000 | [diff] [blame] | 31 | * |
reed@google.com | 880dc47 | 2012-05-11 14:47:03 +0000 | [diff] [blame] | 32 | * Shaders specify the source color(s) for what is being drawn. If a paint |
| 33 | * has no shader, then the paint's color is used. If the paint has a |
| 34 | * shader, then the shader's color(s) are use instead, but they are |
| 35 | * modulated by the paint's alpha. This makes it easy to create a shader |
| 36 | * once (e.g. bitmap tiling or gradient) and then change its transparency |
| 37 | * w/o having to modify the original shader... only the paint's alpha needs |
| 38 | * to be modified. |
reed@google.com | ad91799 | 2011-04-11 19:01:12 +0000 | [diff] [blame] | 39 | */ |
ctguil@chromium.org | 7ffb1b2 | 2011-03-15 21:27:08 +0000 | [diff] [blame] | 40 | class SK_API SkShader : public SkFlattenable { |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 41 | public: |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 42 | enum TileMode { |
reed@google.com | 0beaba5 | 2012-03-16 14:38:06 +0000 | [diff] [blame] | 43 | /** replicate the edge color if the shader draws outside of its |
| 44 | * original bounds |
| 45 | */ |
| 46 | kClamp_TileMode, |
| 47 | |
| 48 | /** repeat the shader's image horizontally and vertically */ |
| 49 | kRepeat_TileMode, |
| 50 | |
| 51 | /** repeat the shader's image horizontally and vertically, alternating |
| 52 | * mirror images so that adjacent images always seam |
| 53 | */ |
| 54 | kMirror_TileMode, |
| 55 | |
| 56 | #if 0 |
| 57 | /** only draw within the original domain, return 0 everywhere else */ |
| 58 | kDecal_TileMode, |
| 59 | #endif |
reed | 19c25f1 | 2015-03-15 14:01:21 -0700 | [diff] [blame] | 60 | }; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 61 | |
reed | 19c25f1 | 2015-03-15 14:01:21 -0700 | [diff] [blame] | 62 | enum { |
| 63 | kTileModeCount = kMirror_TileMode + 1 |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 64 | }; |
| 65 | |
Florin Malita | 4aed138 | 2017-05-25 10:38:07 -0400 | [diff] [blame] | 66 | /** |
| 67 | * Returns the local matrix. |
| 68 | * |
| 69 | * FIXME: This can be incorrect for a Shader with its own local matrix |
| 70 | * that is also wrapped via CreateLocalMatrixShader. |
| 71 | */ |
| 72 | const SkMatrix& getLocalMatrix() const; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 73 | |
reed@google.com | ad91799 | 2011-04-11 19:01:12 +0000 | [diff] [blame] | 74 | /** |
junov@chromium.org | b6e1619 | 2011-12-09 15:48:03 +0000 | [diff] [blame] | 75 | * Returns true if the shader is guaranteed to produce only opaque |
| 76 | * colors, subject to the SkPaint using the shader to apply an opaque |
| 77 | * alpha value. Subclasses should override this to allow some |
commit-bot@chromium.org | 87fcd95 | 2014-04-23 19:10:51 +0000 | [diff] [blame] | 78 | * optimizations. |
junov@chromium.org | b6e1619 | 2011-12-09 15:48:03 +0000 | [diff] [blame] | 79 | */ |
| 80 | virtual bool isOpaque() const { return false; } |
| 81 | |
Mike Reed | 627778d | 2016-09-28 17:13:38 -0400 | [diff] [blame] | 82 | #ifdef SK_SUPPORT_LEGACY_SHADER_ISABITMAP |
reed@google.com | ad91799 | 2011-04-11 19:01:12 +0000 | [diff] [blame] | 83 | /** |
reed | 0f0af23 | 2015-09-08 11:02:04 -0700 | [diff] [blame] | 84 | * Returns true if this shader is just a bitmap, and if not null, returns the bitmap, |
| 85 | * localMatrix, and tilemodes. If this is not a bitmap, returns false and ignores the |
| 86 | * out-parameters. |
reed@android.com | f2b98d6 | 2010-12-20 18:26:13 +0000 | [diff] [blame] | 87 | */ |
Florin Malita | 4aed138 | 2017-05-25 10:38:07 -0400 | [diff] [blame] | 88 | bool isABitmap(SkBitmap* outTexture, SkMatrix* outMatrix, TileMode xy[2]) const; |
reed | 0f0af23 | 2015-09-08 11:02:04 -0700 | [diff] [blame] | 89 | |
reed | f582282 | 2015-08-19 11:46:38 -0700 | [diff] [blame] | 90 | bool isABitmap() const { |
| 91 | return this->isABitmap(nullptr, nullptr, nullptr); |
| 92 | } |
Mike Reed | 627778d | 2016-09-28 17:13:38 -0400 | [diff] [blame] | 93 | #endif |
reed | f582282 | 2015-08-19 11:46:38 -0700 | [diff] [blame] | 94 | |
vandebo@chromium.org | d3ae779 | 2011-02-24 00:21:06 +0000 | [diff] [blame] | 95 | /** |
reed | f1ac182 | 2016-08-01 11:24:14 -0700 | [diff] [blame] | 96 | * Iff this shader is backed by a single SkImage, return its ptr (the caller must ref this |
| 97 | * if they want to keep it longer than the lifetime of the shader). If not, return nullptr. |
| 98 | */ |
Florin Malita | 4aed138 | 2017-05-25 10:38:07 -0400 | [diff] [blame] | 99 | SkImage* isAImage(SkMatrix* localMatrix, TileMode xy[2]) const; |
reed | f1ac182 | 2016-08-01 11:24:14 -0700 | [diff] [blame] | 100 | |
| 101 | bool isAImage() const { |
| 102 | return this->isAImage(nullptr, nullptr) != nullptr; |
| 103 | } |
| 104 | |
| 105 | /** |
vandebo@chromium.org | d3ae779 | 2011-02-24 00:21:06 +0000 | [diff] [blame] | 106 | * If the shader subclass can be represented as a gradient, asAGradient |
| 107 | * returns the matching GradientType enum (or kNone_GradientType if it |
| 108 | * cannot). Also, if info is not null, asAGradient populates info with |
| 109 | * the relevant (see below) parameters for the gradient. fColorCount |
| 110 | * is both an input and output parameter. On input, it indicates how |
| 111 | * many entries in fColors and fColorOffsets can be used, if they are |
| 112 | * non-NULL. After asAGradient has run, fColorCount indicates how |
| 113 | * many color-offset pairs there are in the gradient. If there is |
| 114 | * insufficient space to store all of the color-offset pairs, fColors |
| 115 | * and fColorOffsets will not be altered. fColorOffsets specifies |
| 116 | * where on the range of 0 to 1 to transition to the given color. |
| 117 | * The meaning of fPoint and fRadius is dependant on the type of gradient. |
| 118 | * |
| 119 | * None: |
| 120 | * info is ignored. |
| 121 | * Color: |
| 122 | * fColorOffsets[0] is meaningless. |
| 123 | * Linear: |
| 124 | * fPoint[0] and fPoint[1] are the end-points of the gradient |
| 125 | * Radial: |
| 126 | * fPoint[0] and fRadius[0] are the center and radius |
reed | 71a6cbf | 2015-05-04 08:32:51 -0700 | [diff] [blame] | 127 | * Conical: |
vandebo@chromium.org | d3ae779 | 2011-02-24 00:21:06 +0000 | [diff] [blame] | 128 | * fPoint[0] and fRadius[0] are the center and radius of the 1st circle |
| 129 | * fPoint[1] and fRadius[1] are the center and radius of the 2nd circle |
| 130 | * Sweep: |
| 131 | * fPoint[0] is the center of the sweep. |
| 132 | */ |
| 133 | |
| 134 | enum GradientType { |
| 135 | kNone_GradientType, |
| 136 | kColor_GradientType, |
| 137 | kLinear_GradientType, |
| 138 | kRadial_GradientType, |
vandebo@chromium.org | d3ae779 | 2011-02-24 00:21:06 +0000 | [diff] [blame] | 139 | kSweep_GradientType, |
reed@google.com | 8322697 | 2012-06-07 20:26:47 +0000 | [diff] [blame] | 140 | kConical_GradientType, |
| 141 | kLast_GradientType = kConical_GradientType |
vandebo@chromium.org | d3ae779 | 2011-02-24 00:21:06 +0000 | [diff] [blame] | 142 | }; |
| 143 | |
| 144 | struct GradientInfo { |
| 145 | int fColorCount; //!< In-out parameter, specifies passed size |
| 146 | // of fColors/fColorOffsets on input, and |
| 147 | // actual number of colors/offsets on |
| 148 | // output. |
| 149 | SkColor* fColors; //!< The colors in the gradient. |
| 150 | SkScalar* fColorOffsets; //!< The unit offset for color transitions. |
| 151 | SkPoint fPoint[2]; //!< Type specific, see above. |
| 152 | SkScalar fRadius[2]; //!< Type specific, see above. |
| 153 | TileMode fTileMode; //!< The tile mode used. |
reed@google.com | 3d3a860 | 2013-05-24 14:58:44 +0000 | [diff] [blame] | 154 | uint32_t fGradientFlags; //!< see SkGradientShader::Flags |
vandebo@chromium.org | d3ae779 | 2011-02-24 00:21:06 +0000 | [diff] [blame] | 155 | }; |
| 156 | |
| 157 | virtual GradientType asAGradient(GradientInfo* info) const; |
| 158 | |
Mike Reed | a6aaa30 | 2017-06-09 10:29:40 -0400 | [diff] [blame] | 159 | #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK |
Florin Malita | d93e11c | 2017-05-24 21:15:46 +0000 | [diff] [blame] | 160 | struct ComposeRec { |
| 161 | const SkShader* fShaderA; |
| 162 | const SkShader* fShaderB; |
| 163 | SkBlendMode fBlendMode; |
| 164 | }; |
Florin Malita | d93e11c | 2017-05-24 21:15:46 +0000 | [diff] [blame] | 165 | virtual bool asACompose(ComposeRec*) const { return false; } |
Mike Reed | a6aaa30 | 2017-06-09 10:29:40 -0400 | [diff] [blame] | 166 | #endif |
Florin Malita | d93e11c | 2017-05-24 21:15:46 +0000 | [diff] [blame] | 167 | |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 168 | ////////////////////////////////////////////////////////////////////////// |
reed | f880e45 | 2015-12-30 13:39:41 -0800 | [diff] [blame] | 169 | // Methods to create combinations or variants of shaders |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 170 | |
commit-bot@chromium.org | ce56d96 | 2014-05-05 18:39:18 +0000 | [diff] [blame] | 171 | /** |
reed | f880e45 | 2015-12-30 13:39:41 -0800 | [diff] [blame] | 172 | * Return a shader that will apply the specified localMatrix to this shader. |
| 173 | * The specified matrix will be applied before any matrix associated with this shader. |
| 174 | */ |
reed | 150835e | 2016-03-10 06:36:49 -0800 | [diff] [blame] | 175 | sk_sp<SkShader> makeWithLocalMatrix(const SkMatrix&) const; |
reed | 3061af4 | 2016-01-07 15:47:29 -0800 | [diff] [blame] | 176 | |
| 177 | /** |
| 178 | * Create a new shader that produces the same colors as invoking this shader and then applying |
| 179 | * the colorfilter. |
| 180 | */ |
reed | d053ce9 | 2016-03-22 10:17:23 -0700 | [diff] [blame] | 181 | sk_sp<SkShader> makeWithColorFilter(sk_sp<SkColorFilter>) const; |
reed | a2b340f | 2016-02-10 08:53:15 -0800 | [diff] [blame] | 182 | |
reed | f880e45 | 2015-12-30 13:39:41 -0800 | [diff] [blame] | 183 | ////////////////////////////////////////////////////////////////////////// |
| 184 | // Factory methods for stock shaders |
Mike Klein | b0d10e0 | 2016-11-12 10:29:26 -0500 | [diff] [blame] | 185 | |
reed | f880e45 | 2015-12-30 13:39:41 -0800 | [diff] [blame] | 186 | /** |
commit-bot@chromium.org | ce56d96 | 2014-05-05 18:39:18 +0000 | [diff] [blame] | 187 | * Call this to create a new "empty" shader, that will not draw anything. |
| 188 | */ |
reed | 8a21c9f | 2016-03-08 18:50:00 -0800 | [diff] [blame] | 189 | static sk_sp<SkShader> MakeEmptyShader(); |
commit-bot@chromium.org | ce56d96 | 2014-05-05 18:39:18 +0000 | [diff] [blame] | 190 | |
reed | 8367b8c | 2014-08-22 08:30:20 -0700 | [diff] [blame] | 191 | /** |
| 192 | * Call this to create a new shader that just draws the specified color. This should always |
| 193 | * draw the same as a paint with this color (and no shader). |
| 194 | */ |
reed | 8a21c9f | 2016-03-08 18:50:00 -0800 | [diff] [blame] | 195 | static sk_sp<SkShader> MakeColorShader(SkColor); |
reed | 8367b8c | 2014-08-22 08:30:20 -0700 | [diff] [blame] | 196 | |
reed | 0ccc62d | 2016-05-04 13:09:39 -0700 | [diff] [blame] | 197 | /** |
| 198 | * Create a shader that draws the specified color (in the specified colorspace). |
| 199 | * |
| 200 | * This works around the limitation that SkPaint::setColor() only takes byte values, and does |
| 201 | * not support specific colorspaces. |
| 202 | */ |
| 203 | static sk_sp<SkShader> MakeColorShader(const SkColor4f&, sk_sp<SkColorSpace>); |
| 204 | |
Mike Reed | 01b2b83 | 2017-06-09 10:51:52 -0400 | [diff] [blame] | 205 | /** |
| 206 | * Compose two shaders together, using two operators: mode and lerp. The resulting colors |
| 207 | * are computed by first combining the src and dst shaders using mode, and then linearly |
| 208 | * interpolating between the dst and result colors using lerp. |
| 209 | * |
| 210 | * result = dst * (1 - lerp) + (src (mode) dst) * lerp |
| 211 | * |
| 212 | * If either shader is nullptr, then this returns nullptr. |
| 213 | * If lerp is NaN then this returns nullptr, otherwise lerp is clamped to [0..1]. |
| 214 | */ |
| 215 | static sk_sp<SkShader> MakeCompose(sk_sp<SkShader> dst, sk_sp<SkShader> src, |
| 216 | SkBlendMode mode, float lerp = 1); |
| 217 | |
| 218 | /* |
| 219 | * DEPRECATED: call MakeCompose. |
| 220 | */ |
| 221 | static sk_sp<SkShader> MakeComposeShader(sk_sp<SkShader> dst, sk_sp<SkShader> src, |
| 222 | SkBlendMode mode) { |
| 223 | return MakeCompose(std::move(dst), std::move(src), mode, 1); |
| 224 | } |
| 225 | |
| 226 | /** |
| 227 | * Compose two shaders together using a weighted average. |
| 228 | * |
| 229 | * result = dst * (1 - lerp) + src * lerp |
| 230 | * |
| 231 | * If either shader is nullptr, then this returns nullptr. |
| 232 | * If lerp is NaN then this returns nullptr, otherwise lerp is clamped to [0..1]. |
| 233 | */ |
| 234 | static sk_sp<SkShader> MakeMixer(sk_sp<SkShader> dst, sk_sp<SkShader> src, float lerp) { |
| 235 | return MakeCompose(std::move(dst), std::move(src), SkBlendMode::kSrc, lerp); |
| 236 | } |
Mike Reed | 7d954ad | 2016-10-28 15:42:34 -0400 | [diff] [blame] | 237 | |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 238 | /** Call this to create a new shader that will draw with the specified bitmap. |
reed@google.com | 99c114e | 2012-05-03 20:14:26 +0000 | [diff] [blame] | 239 | * |
| 240 | * If the bitmap cannot be used (e.g. has no pixels, or its dimensions |
| 241 | * exceed implementation limits (currently at 64K - 1)) then SkEmptyShader |
| 242 | * may be returned. |
| 243 | * |
commit-bot@chromium.org | 91246b9 | 2013-12-05 15:43:19 +0000 | [diff] [blame] | 244 | * If the src is kA8_Config then that mask will be colorized using the color on |
| 245 | * the paint. |
| 246 | * |
reed@google.com | 99c114e | 2012-05-03 20:14:26 +0000 | [diff] [blame] | 247 | * @param src The bitmap to use inside the shader |
| 248 | * @param tmx The tiling mode to use when sampling the bitmap in the x-direction. |
| 249 | * @param tmy The tiling mode to use when sampling the bitmap in the y-direction. |
| 250 | * @return Returns a new shader object. Note: this function never returns null. |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 251 | */ |
reed | 8a21c9f | 2016-03-08 18:50:00 -0800 | [diff] [blame] | 252 | static sk_sp<SkShader> MakeBitmapShader(const SkBitmap& src, TileMode tmx, TileMode tmy, |
| 253 | const SkMatrix* localMatrix = nullptr); |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 254 | |
halcanary | a5f46e1 | 2015-09-08 07:12:25 -0700 | [diff] [blame] | 255 | // NOTE: You can create an SkImage Shader with SkImage::newShader(). |
| 256 | |
commit-bot@chromium.org | c5d9bb0 | 2014-04-08 15:19:34 +0000 | [diff] [blame] | 257 | /** Call this to create a new shader that will draw with the specified picture. |
| 258 | * |
| 259 | * @param src The picture to use inside the shader (if not NULL, its ref count |
commit-bot@chromium.org | 855e88e | 2014-04-21 19:33:12 +0000 | [diff] [blame] | 260 | * is incremented). The SkPicture must not be changed after |
| 261 | * successfully creating a picture shader. |
commit-bot@chromium.org | c5d9bb0 | 2014-04-08 15:19:34 +0000 | [diff] [blame] | 262 | * @param tmx The tiling mode to use when sampling the bitmap in the x-direction. |
| 263 | * @param tmy The tiling mode to use when sampling the bitmap in the y-direction. |
fmalita | b5f7826 | 2014-08-06 13:07:15 -0700 | [diff] [blame] | 264 | * @param tile The tile rectangle in picture coordinates: this represents the subset |
| 265 | * (or superset) of the picture used when building a tile. It is not |
| 266 | * affected by localMatrix and does not imply scaling (only translation |
| 267 | * and cropping). If null, the tile rect is considered equal to the picture |
| 268 | * bounds. |
commit-bot@chromium.org | c5d9bb0 | 2014-04-08 15:19:34 +0000 | [diff] [blame] | 269 | * @return Returns a new shader object. Note: this function never returns null. |
| 270 | */ |
reed | 7fb4f8b | 2016-03-11 04:33:52 -0800 | [diff] [blame] | 271 | static sk_sp<SkShader> MakePictureShader(sk_sp<SkPicture> src, TileMode tmx, TileMode tmy, |
reed | 8a21c9f | 2016-03-08 18:50:00 -0800 | [diff] [blame] | 272 | const SkMatrix* localMatrix, const SkRect* tile); |
commit-bot@chromium.org | c5d9bb0 | 2014-04-08 15:19:34 +0000 | [diff] [blame] | 273 | |
Florin Malita | d93e11c | 2017-05-24 21:15:46 +0000 | [diff] [blame] | 274 | /** |
| 275 | * If this shader can be represented by another shader + a localMatrix, return that shader and |
| 276 | * the localMatrix. If not, return nullptr and ignore the localMatrix parameter. |
| 277 | */ |
Florin Malita | 4aed138 | 2017-05-25 10:38:07 -0400 | [diff] [blame] | 278 | // TODO: clean up clients, move to SkShaderBase. |
Florin Malita | d93e11c | 2017-05-24 21:15:46 +0000 | [diff] [blame] | 279 | virtual sk_sp<SkShader> makeAsALocalMatrixShader(SkMatrix* localMatrix) const; |
| 280 | |
commit-bot@chromium.org | ce56d96 | 2014-05-05 18:39:18 +0000 | [diff] [blame] | 281 | private: |
Florin Malita | f7beee7 | 2017-05-26 12:54:32 -0400 | [diff] [blame] | 282 | SkShader() = default; |
| 283 | friend class SkShaderBase; |
| 284 | |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 285 | typedef SkFlattenable INHERITED; |
| 286 | }; |
| 287 | |
| 288 | #endif |