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