• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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