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 SkGradientShader_DEFINED 9 #define SkGradientShader_DEFINED 10 11 #include "include/core/SkColorSpace.h" 12 #include "include/core/SkRefCnt.h" 13 #include "include/core/SkShader.h" 14 #include "include/core/SkTileMode.h" 15 16 /** \class SkGradientShader 17 18 SkGradientShader hosts factories for creating subclasses of SkShader that 19 render linear and radial gradients. In general, degenerate cases should not 20 produce surprising results, but there are several types of degeneracies: 21 22 * A linear gradient made from the same two points. 23 * A radial gradient with a radius of zero. 24 * A sweep gradient where the start and end angle are the same. 25 * A two point conical gradient where the two centers and the two radii are 26 the same. 27 28 For any degenerate gradient with a decal tile mode, it will draw empty since the interpolating 29 region is zero area and the outer region is discarded by the decal mode. 30 31 For any degenerate gradient with a repeat or mirror tile mode, it will draw a solid color that 32 is the average gradient color, since infinitely many repetitions of the gradients will fill the 33 shape. 34 35 For a clamped gradient, every type is well-defined at the limit except for linear gradients. The 36 radial gradient with zero radius becomes the last color. The sweep gradient draws the sector 37 from 0 to the provided angle with the first color, with a hardstop switching to the last color. 38 When the provided angle is 0, this is just the solid last color again. Similarly, the two point 39 conical gradient becomes a circle filled with the first color, sized to the provided radius, 40 with a hardstop switching to the last color. When the two radii are both zero, this is just the 41 solid last color. 42 43 As a linear gradient approaches the degenerate case, its shader will approach the appearance of 44 two half planes, each filled by the first and last colors of the gradient. The planes will be 45 oriented perpendicular to the vector between the two defining points of the gradient. However, 46 once they become the same point, Skia cannot reconstruct what that expected orientation is. To 47 provide a stable and predictable color in this case, Skia just uses the last color as a solid 48 fill to be similar to many of the other degenerate gradients' behaviors in clamp mode. 49 */ 50 class SK_API SkGradientShader { 51 public: 52 enum Flags { 53 /** By default gradients will interpolate their colors in unpremul space 54 * and then premultiply each of the results. By setting this flag, the 55 * gradients will premultiply their colors first, and then interpolate 56 * between them. 57 * example: https://fiddle.skia.org/c/@GradientShader_MakeLinear 58 */ 59 kInterpolateColorsInPremul_Flag = 1 << 0, 60 }; 61 62 struct Interpolation { 63 enum class InPremul : bool { kNo = false, kYes = true }; 64 65 enum class ColorSpace : uint8_t { 66 // Default Skia behavior: interpolate in the color space of the destination surface 67 kDestination, 68 69 // https://www.w3.org/TR/css-color-4/#interpolation-space 70 kSRGBLinear, 71 kLab, 72 kOKLab, 73 kLCH, 74 kOKLCH, 75 kSRGB, 76 kHSL, 77 kHWB, 78 79 kLastColorSpace = kHWB, 80 }; 81 static constexpr int kColorSpaceCount = static_cast<int>(ColorSpace::kLastColorSpace) + 1; 82 83 enum class HueMethod : uint8_t { 84 // https://www.w3.org/TR/css-color-4/#hue-interpolation 85 kShorter, 86 kLonger, 87 kIncreasing, 88 kDecreasing, 89 90 kLastHueMethod = kDecreasing, 91 }; 92 static constexpr int kHueMethodCount = static_cast<int>(HueMethod::kLastHueMethod) + 1; 93 94 InPremul fInPremul = InPremul::kNo; 95 96 /* 97 * NOTE: Do not use fColorSpace or fHueMethod (yet). These features are in development and 98 * incomplete. This comment (and RELEASE_NOTES.txt) will be updated once the features are 99 * ready to be used. 100 */ 101 ColorSpace fColorSpace = ColorSpace::kDestination; 102 HueMethod fHueMethod = HueMethod::kShorter; // Only relevant for LCH, OKLCH, HSL, or HWB 103 FromFlagsInterpolation104 static Interpolation FromFlags(uint32_t flags) { 105 return {flags & kInterpolateColorsInPremul_Flag ? InPremul::kYes : InPremul::kNo, 106 ColorSpace::kDestination, 107 HueMethod::kShorter}; 108 } 109 }; 110 111 /** Returns a shader that generates a linear gradient between the two specified points. 112 <p /> 113 @param pts The start and end points for the gradient. 114 @param colors The array[count] of colors, to be distributed between the two points 115 @param pos May be NULL. array[count] of SkScalars, or NULL, of the relative position of 116 each corresponding color in the colors array. If this is NULL, 117 the the colors are distributed evenly between the start and end point. 118 If this is not null, the values must lie between 0.0 and 1.0, and be 119 strictly increasing. If the first value is not 0.0, then an additional 120 color stop is added at position 0.0, with the same color as colors[0]. 121 If the the last value is not 1.0, then an additional color stop is added 122 at position 1.0, with the same color as colors[count - 1]. 123 @param count Must be >=2. The number of colors (and pos if not NULL) entries. 124 @param mode The tiling mode 125 126 example: https://fiddle.skia.org/c/@GradientShader_MakeLinear 127 */ 128 static sk_sp<SkShader> MakeLinear(const SkPoint pts[2], 129 const SkColor colors[], const SkScalar pos[], int count, 130 SkTileMode mode, 131 uint32_t flags = 0, const SkMatrix* localMatrix = nullptr); 132 133 /** Returns a shader that generates a linear gradient between the two specified points. 134 <p /> 135 @param pts The start and end points for the gradient. 136 @param colors The array[count] of colors, to be distributed between the two points 137 @param pos May be NULL. array[count] of SkScalars, or NULL, of the relative position of 138 each corresponding color in the colors array. If this is NULL, 139 the the colors are distributed evenly between the start and end point. 140 If this is not null, the values must lie between 0.0 and 1.0, and be 141 strictly increasing. If the first value is not 0.0, then an additional 142 color stop is added at position 0.0, with the same color as colors[0]. 143 If the the last value is not 1.0, then an additional color stop is added 144 at position 1.0, with the same color as colors[count - 1]. 145 @param count Must be >=2. The number of colors (and pos if not NULL) entries. 146 @param mode The tiling mode 147 148 example: https://fiddle.skia.org/c/@GradientShader_MakeLinear 149 */ 150 static sk_sp<SkShader> MakeLinear(const SkPoint pts[2], 151 const SkColor4f colors[], sk_sp<SkColorSpace> colorSpace, 152 const SkScalar pos[], int count, SkTileMode mode, 153 const Interpolation& interpolation, 154 const SkMatrix* localMatrix); 155 static sk_sp<SkShader> MakeLinear(const SkPoint pts[2], 156 const SkColor4f colors[], sk_sp<SkColorSpace> colorSpace, 157 const SkScalar pos[], int count, SkTileMode mode, 158 uint32_t flags = 0, const SkMatrix* localMatrix = nullptr) { 159 return MakeLinear(pts, colors, std::move(colorSpace), pos, count, mode, 160 Interpolation::FromFlags(flags), localMatrix); 161 } 162 163 /** Returns a shader that generates a radial gradient given the center and radius. 164 <p /> 165 @param center The center of the circle for this gradient 166 @param radius Must be positive. The radius of the circle for this gradient 167 @param colors The array[count] of colors, to be distributed between the center and edge of the circle 168 @param pos May be NULL. The array[count] of SkScalars, or NULL, of the relative position of 169 each corresponding color in the colors array. If this is NULL, 170 the the colors are distributed evenly between the center and edge of the circle. 171 If this is not null, the values must lie between 0.0 and 1.0, and be 172 strictly increasing. If the first value is not 0.0, then an additional 173 color stop is added at position 0.0, with the same color as colors[0]. 174 If the the last value is not 1.0, then an additional color stop is added 175 at position 1.0, with the same color as colors[count - 1]. 176 @param count Must be >= 2. The number of colors (and pos if not NULL) entries 177 @param mode The tiling mode 178 */ 179 static sk_sp<SkShader> MakeRadial(const SkPoint& center, SkScalar radius, 180 const SkColor colors[], const SkScalar pos[], int count, 181 SkTileMode mode, 182 uint32_t flags = 0, const SkMatrix* localMatrix = nullptr); 183 184 /** Returns a shader that generates a radial gradient given the center and radius. 185 <p /> 186 @param center The center of the circle for this gradient 187 @param radius Must be positive. The radius of the circle for this gradient 188 @param colors The array[count] of colors, to be distributed between the center and edge of the circle 189 @param pos May be NULL. The array[count] of SkScalars, or NULL, of the relative position of 190 each corresponding color in the colors array. If this is NULL, 191 the the colors are distributed evenly between the center and edge of the circle. 192 If this is not null, the values must lie between 0.0 and 1.0, and be 193 strictly increasing. If the first value is not 0.0, then an additional 194 color stop is added at position 0.0, with the same color as colors[0]. 195 If the the last value is not 1.0, then an additional color stop is added 196 at position 1.0, with the same color as colors[count - 1]. 197 @param count Must be >= 2. The number of colors (and pos if not NULL) entries 198 @param mode The tiling mode 199 */ 200 static sk_sp<SkShader> MakeRadial(const SkPoint& center, SkScalar radius, 201 const SkColor4f colors[], sk_sp<SkColorSpace> colorSpace, 202 const SkScalar pos[], int count, SkTileMode mode, 203 const Interpolation& interpolation, 204 const SkMatrix* localMatrix); 205 static sk_sp<SkShader> MakeRadial(const SkPoint& center, SkScalar radius, 206 const SkColor4f colors[], sk_sp<SkColorSpace> colorSpace, 207 const SkScalar pos[], int count, SkTileMode mode, 208 uint32_t flags = 0, const SkMatrix* localMatrix = nullptr) { 209 return MakeRadial(center, radius, colors, std::move(colorSpace), pos, count, mode, 210 Interpolation::FromFlags(flags), localMatrix); 211 } 212 213 /** 214 * Returns a shader that generates a conical gradient given two circles, or 215 * returns NULL if the inputs are invalid. The gradient interprets the 216 * two circles according to the following HTML spec. 217 * http://dev.w3.org/html5/2dcontext/#dom-context-2d-createradialgradient 218 */ 219 static sk_sp<SkShader> MakeTwoPointConical(const SkPoint& start, SkScalar startRadius, 220 const SkPoint& end, SkScalar endRadius, 221 const SkColor colors[], const SkScalar pos[], 222 int count, SkTileMode mode, 223 uint32_t flags = 0, 224 const SkMatrix* localMatrix = nullptr); 225 226 /** 227 * Returns a shader that generates a conical gradient given two circles, or 228 * returns NULL if the inputs are invalid. The gradient interprets the 229 * two circles according to the following HTML spec. 230 * http://dev.w3.org/html5/2dcontext/#dom-context-2d-createradialgradient 231 */ 232 static sk_sp<SkShader> MakeTwoPointConical(const SkPoint& start, SkScalar startRadius, 233 const SkPoint& end, SkScalar endRadius, 234 const SkColor4f colors[], 235 sk_sp<SkColorSpace> colorSpace, const SkScalar pos[], 236 int count, SkTileMode mode, 237 const Interpolation& interpolation, 238 const SkMatrix* localMatrix); 239 static sk_sp<SkShader> MakeTwoPointConical(const SkPoint& start, SkScalar startRadius, 240 const SkPoint& end, SkScalar endRadius, 241 const SkColor4f colors[], 242 sk_sp<SkColorSpace> colorSpace, const SkScalar pos[], 243 int count, SkTileMode mode, 244 uint32_t flags = 0, 245 const SkMatrix* localMatrix = nullptr) { 246 return MakeTwoPointConical(start, startRadius, end, endRadius, colors, 247 std::move(colorSpace), pos, count, mode, 248 Interpolation::FromFlags(flags), localMatrix); 249 } 250 251 /** Returns a shader that generates a sweep gradient given a center. 252 253 The shader accepts negative angles and angles larger than 360, draws 254 between 0 and 360 degrees, similar to the CSS conic-gradient 255 semantics. 0 degrees means horizontal positive x axis. The start angle 256 must be less than the end angle, otherwise a null pointer is 257 returned. If color stops do not contain 0 and 1 but are within this 258 range, the respective outer color stop is repeated for 0 and 1. Color 259 stops less than 0 are clamped to 0, and greater than 1 are clamped to 1. 260 <p /> 261 @param cx The X coordinate of the center of the sweep 262 @param cx The Y coordinate of the center of the sweep 263 @param colors The array[count] of colors, to be distributed around the center, within 264 the gradient angle range. 265 @param pos May be NULL. The array[count] of SkScalars, or NULL, of the relative 266 position of each corresponding color in the colors array. If this is 267 NULL, then the colors are distributed evenly within the angular range. 268 If this is not null, the values must lie between 0.0 and 1.0, and be 269 strictly increasing. If the first value is not 0.0, then an additional 270 color stop is added at position 0.0, with the same color as colors[0]. 271 If the the last value is not 1.0, then an additional color stop is added 272 at position 1.0, with the same color as colors[count - 1]. 273 @param count Must be >= 2. The number of colors (and pos if not NULL) entries 274 @param mode Tiling mode: controls drawing outside of the gradient angular range. 275 @param startAngle Start of the angular range, corresponding to pos == 0. 276 @param endAngle End of the angular range, corresponding to pos == 1. 277 */ 278 static sk_sp<SkShader> MakeSweep(SkScalar cx, SkScalar cy, 279 const SkColor colors[], const SkScalar pos[], int count, 280 SkTileMode mode, 281 SkScalar startAngle, SkScalar endAngle, 282 uint32_t flags, const SkMatrix* localMatrix); 283 static sk_sp<SkShader> MakeSweep(SkScalar cx, SkScalar cy, 284 const SkColor colors[], const SkScalar pos[], int count, 285 uint32_t flags = 0, const SkMatrix* localMatrix = nullptr) { 286 return MakeSweep(cx, cy, colors, pos, count, SkTileMode::kClamp, 0, 360, flags, 287 localMatrix); 288 } 289 290 /** Returns a shader that generates a sweep gradient given a center. 291 292 The shader accepts negative angles and angles larger than 360, draws 293 between 0 and 360 degrees, similar to the CSS conic-gradient 294 semantics. 0 degrees means horizontal positive x axis. The start angle 295 must be less than the end angle, otherwise a null pointer is 296 returned. If color stops do not contain 0 and 1 but are within this 297 range, the respective outer color stop is repeated for 0 and 1. Color 298 stops less than 0 are clamped to 0, and greater than 1 are clamped to 1. 299 <p /> 300 @param cx The X coordinate of the center of the sweep 301 @param cx The Y coordinate of the center of the sweep 302 @param colors The array[count] of colors, to be distributed around the center, within 303 the gradient angle range. 304 @param pos May be NULL. The array[count] of SkScalars, or NULL, of the relative 305 position of each corresponding color in the colors array. If this is 306 NULL, then the colors are distributed evenly within the angular range. 307 If this is not null, the values must lie between 0.0 and 1.0, and be 308 strictly increasing. If the first value is not 0.0, then an additional 309 color stop is added at position 0.0, with the same color as colors[0]. 310 If the the last value is not 1.0, then an additional color stop is added 311 at position 1.0, with the same color as colors[count - 1]. 312 @param count Must be >= 2. The number of colors (and pos if not NULL) entries 313 @param mode Tiling mode: controls drawing outside of the gradient angular range. 314 @param startAngle Start of the angular range, corresponding to pos == 0. 315 @param endAngle End of the angular range, corresponding to pos == 1. 316 */ 317 static sk_sp<SkShader> MakeSweep(SkScalar cx, SkScalar cy, 318 const SkColor4f colors[], sk_sp<SkColorSpace> colorSpace, 319 const SkScalar pos[], int count, 320 SkTileMode mode, 321 SkScalar startAngle, SkScalar endAngle, 322 const Interpolation& interpolation, 323 const SkMatrix* localMatrix); MakeSweep(SkScalar cx,SkScalar cy,const SkColor4f colors[],sk_sp<SkColorSpace> colorSpace,const SkScalar pos[],int count,SkTileMode mode,SkScalar startAngle,SkScalar endAngle,uint32_t flags,const SkMatrix * localMatrix)324 static sk_sp<SkShader> MakeSweep(SkScalar cx, SkScalar cy, 325 const SkColor4f colors[], sk_sp<SkColorSpace> colorSpace, 326 const SkScalar pos[], int count, 327 SkTileMode mode, 328 SkScalar startAngle, SkScalar endAngle, 329 uint32_t flags, const SkMatrix* localMatrix) { 330 return MakeSweep(cx, cy, colors, std::move(colorSpace), pos, count, mode, startAngle, 331 endAngle, Interpolation::FromFlags(flags), localMatrix); 332 } 333 static sk_sp<SkShader> MakeSweep(SkScalar cx, SkScalar cy, 334 const SkColor4f colors[], sk_sp<SkColorSpace> colorSpace, 335 const SkScalar pos[], int count, 336 uint32_t flags = 0, const SkMatrix* localMatrix = nullptr) { 337 return MakeSweep(cx, cy, colors, std::move(colorSpace), pos, count, SkTileMode::kClamp, 338 0, 360, flags, localMatrix); 339 } 340 }; 341 342 #endif 343