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/SkShader.h"
12
13/** \class SkGradientShader
14
15    SkGradientShader hosts factories for creating subclasses of SkShader that
16    render linear and radial gradients. In general, degenerate cases should not
17    produce surprising results, but there are several types of degeneracies:
18
19     * A linear gradient made from the same two points.
20     * A radial gradient with a radius of zero.
21     * A sweep gradient where the start and end angle are the same.
22     * A two point conical gradient where the two centers and the two radii are
23       the same.
24
25    For any degenerate gradient with a decal tile mode, it will draw empty since the interpolating
26    region is zero area and the outer region is discarded by the decal mode.
27
28    For any degenerate gradient with a repeat or mirror tile mode, it will draw a solid color that
29    is the average gradient color, since infinitely many repetitions of the gradients will fill the
30    shape.
31
32    For a clamped gradient, every type is well-defined at the limit except for linear gradients. The
33    radial gradient with zero radius becomes the last color. The sweep gradient draws the sector
34    from 0 to the provided angle with the first color, with a hardstop switching to the last color.
35    When the provided angle is 0, this is just the solid last color again. Similarly, the two point
36    conical gradient becomes a circle filled with the first color, sized to the provided radius,
37    with a hardstop switching to the last color. When the two radii are both zero, this is just the
38    solid last color.
39
40    As a linear gradient approaches the degenerate case, its shader will approach the appearance of
41    two half planes, each filled by the first and last colors of the gradient. The planes will be
42    oriented perpendicular to the vector between the two defining points of the gradient. However,
43    once they become the same point, Skia cannot reconstruct what that expected orientation is. To
44    provide a stable and predictable color in this case, Skia just uses the last color as a solid
45    fill to be similar to many of the other degenerate gradients' behaviors in clamp mode.
46*/
47class SK_API SkGradientShader {
48public:
49    enum Flags {
50        /** By default gradients will interpolate their colors in unpremul space
51         *  and then premultiply each of the results. By setting this flag, the
52         *  gradients will premultiply their colors first, and then interpolate
53         *  between them.
54         *  example: https://fiddle.skia.org/c/@GradientShader_MakeLinear
55         */
56        kInterpolateColorsInPremul_Flag = 1 << 0,
57    };
58
59    /** Returns a shader that generates a linear gradient between the two specified points.
60        <p />
61        @param  pts     The start and end points for the gradient.
62        @param  colors  The array[count] of colors, to be distributed between the two points
63        @param  pos     May be NULL. array[count] of SkScalars, or NULL, of the relative position of
64                        each corresponding color in the colors array. If this is NULL,
65                        the the colors are distributed evenly between the start and end point.
66                        If this is not null, the values must begin with 0, end with 1.0, and
67                        intermediate values must be strictly increasing.
68        @param  count   Must be >=2. The number of colors (and pos if not NULL) entries.
69        @param  mode    The tiling mode
70
71        example: https://fiddle.skia.org/c/@GradientShader_MakeLinear
72    */
73    static sk_sp<SkShader> MakeLinear(const SkPoint pts[2],
74                                      const SkColor colors[], const SkScalar pos[], int count,
75                                      SkTileMode mode,
76                                      uint32_t flags, const SkMatrix* localMatrix);
77    static sk_sp<SkShader> MakeLinear(const SkPoint pts[2],
78                                      const SkColor colors[], const SkScalar pos[], int count,
79                                      SkTileMode mode) {
80        return MakeLinear(pts, colors, pos, count, mode, 0, nullptr);
81    }
82
83    /** Returns a shader that generates a linear gradient between the two specified points.
84        <p />
85        @param  pts     The start and end points for the gradient.
86        @param  colors  The array[count] of colors, to be distributed between the two points
87        @param  pos     May be NULL. array[count] of SkScalars, or NULL, of the relative position of
88                        each corresponding color in the colors array. If this is NULL,
89                        the the colors are distributed evenly between the start and end point.
90                        If this is not null, the values must begin with 0, end with 1.0, and
91                        intermediate values must be strictly increasing.
92        @param  count   Must be >=2. The number of colors (and pos if not NULL) entries.
93        @param  mode    The tiling mode
94
95        example: https://fiddle.skia.org/c/@GradientShader_MakeLinear
96    */
97    static sk_sp<SkShader> MakeLinear(const SkPoint pts[2],
98                                      const SkColor4f colors[], sk_sp<SkColorSpace> colorSpace,
99                                      const SkScalar pos[], int count, SkTileMode mode,
100                                      uint32_t flags, const SkMatrix* localMatrix);
101    static sk_sp<SkShader> MakeLinear(const SkPoint pts[2],
102                                      const SkColor4f colors[], sk_sp<SkColorSpace> colorSpace,
103                                      const SkScalar pos[], int count, SkTileMode mode) {
104        return MakeLinear(pts, colors, std::move(colorSpace), pos, count, mode, 0, nullptr);
105    }
106
107    /** Returns a shader that generates a radial gradient given the center and radius.
108        <p />
109        @param  center  The center of the circle for this gradient
110        @param  radius  Must be positive. The radius of the circle for this gradient
111        @param  colors  The array[count] of colors, to be distributed between the center and edge of the circle
112        @param  pos     May be NULL. The array[count] of SkScalars, or NULL, of the relative position of
113                        each corresponding color in the colors array. If this is NULL,
114                        the the colors are distributed evenly between the center and edge of the circle.
115                        If this is not null, the values must begin with 0, end with 1.0, and
116                        intermediate values must be strictly increasing.
117        @param  count   Must be >= 2. The number of colors (and pos if not NULL) entries
118        @param  mode    The tiling mode
119    */
120    static sk_sp<SkShader> MakeRadial(const SkPoint& center, SkScalar radius,
121                                      const SkColor colors[], const SkScalar pos[], int count,
122                                      SkTileMode mode,
123                                      uint32_t flags, const SkMatrix* localMatrix);
124    static sk_sp<SkShader> MakeRadial(const SkPoint& center, SkScalar radius,
125                                      const SkColor colors[], const SkScalar pos[], int count,
126                                      SkTileMode mode) {
127        return MakeRadial(center, radius, colors, pos, count, mode, 0, nullptr);
128    }
129
130    /** Returns a shader that generates a radial gradient given the center and radius.
131        <p />
132        @param  center  The center of the circle for this gradient
133        @param  radius  Must be positive. The radius of the circle for this gradient
134        @param  colors  The array[count] of colors, to be distributed between the center and edge of the circle
135        @param  pos     May be NULL. The array[count] of SkScalars, or NULL, of the relative position of
136                        each corresponding color in the colors array. If this is NULL,
137                        the the colors are distributed evenly between the center and edge of the circle.
138                        If this is not null, the values must begin with 0, end with 1.0, and
139                        intermediate values must be strictly increasing.
140        @param  count   Must be >= 2. The number of colors (and pos if not NULL) entries
141        @param  mode    The tiling mode
142    */
143    static sk_sp<SkShader> MakeRadial(const SkPoint& center, SkScalar radius,
144                                      const SkColor4f colors[], sk_sp<SkColorSpace> colorSpace,
145                                      const SkScalar pos[], int count, SkTileMode mode,
146                                      uint32_t flags, const SkMatrix* localMatrix);
147    static sk_sp<SkShader> MakeRadial(const SkPoint& center, SkScalar radius,
148                                      const SkColor4f colors[], sk_sp<SkColorSpace> colorSpace,
149                                      const SkScalar pos[], int count, SkTileMode mode) {
150        return MakeRadial(center, radius, colors, std::move(colorSpace), pos, count, mode,
151                          0, nullptr);
152    }
153
154    /**
155     *  Returns a shader that generates a conical gradient given two circles, or
156     *  returns NULL if the inputs are invalid. The gradient interprets the
157     *  two circles according to the following HTML spec.
158     *  http://dev.w3.org/html5/2dcontext/#dom-context-2d-createradialgradient
159     */
160    static sk_sp<SkShader> MakeTwoPointConical(const SkPoint& start, SkScalar startRadius,
161                                               const SkPoint& end, SkScalar endRadius,
162                                               const SkColor colors[], const SkScalar pos[],
163                                               int count, SkTileMode mode,
164                                               uint32_t flags, const SkMatrix* localMatrix);
165    static sk_sp<SkShader> MakeTwoPointConical(const SkPoint& start, SkScalar startRadius,
166                                               const SkPoint& end, SkScalar endRadius,
167                                               const SkColor colors[], const SkScalar pos[],
168                                               int count, SkTileMode mode) {
169        return MakeTwoPointConical(start, startRadius, end, endRadius, colors, pos, count, mode,
170                                   0, nullptr);
171    }
172
173    /**
174     *  Returns a shader that generates a conical gradient given two circles, or
175     *  returns NULL if the inputs are invalid. The gradient interprets the
176     *  two circles according to the following HTML spec.
177     *  http://dev.w3.org/html5/2dcontext/#dom-context-2d-createradialgradient
178     */
179    static sk_sp<SkShader> MakeTwoPointConical(const SkPoint& start, SkScalar startRadius,
180                                               const SkPoint& end, SkScalar endRadius,
181                                               const SkColor4f colors[],
182                                               sk_sp<SkColorSpace> colorSpace, const SkScalar pos[],
183                                               int count, SkTileMode mode,
184                                               uint32_t flags, const SkMatrix* localMatrix);
185    static sk_sp<SkShader> MakeTwoPointConical(const SkPoint& start, SkScalar startRadius,
186                                               const SkPoint& end, SkScalar endRadius,
187                                               const SkColor4f colors[],
188                                               sk_sp<SkColorSpace> colorSpace, const SkScalar pos[],
189                                               int count, SkTileMode mode) {
190        return MakeTwoPointConical(start, startRadius, end, endRadius, colors,
191                                   std::move(colorSpace), pos, count, mode, 0, nullptr);
192    }
193
194    /** Returns a shader that generates a sweep gradient given a center.
195        <p />
196        @param  cx         The X coordinate of the center of the sweep
197        @param  cx         The Y coordinate of the center of the sweep
198        @param  colors     The array[count] of colors, to be distributed around the center, within
199                           the gradient angle range.
200        @param  pos        May be NULL. The array[count] of SkScalars, or NULL, of the relative
201                           position of each corresponding color in the colors array. If this is
202                           NULL, then the colors are distributed evenly within the angular range.
203                           If this is not null, the values must begin with 0, end with 1.0, and
204                           intermediate values must be strictly increasing.
205        @param  count      Must be >= 2. The number of colors (and pos if not NULL) entries
206        @param  mode       Tiling mode: controls drawing outside of the gradient angular range.
207        @param  startAngle Start of the angular range, corresponding to pos == 0.
208        @param  endAngle   End of the angular range, corresponding to pos == 1.
209    */
210    static sk_sp<SkShader> MakeSweep(SkScalar cx, SkScalar cy,
211                                     const SkColor colors[], const SkScalar pos[], int count,
212                                     SkTileMode mode,
213                                     SkScalar startAngle, SkScalar endAngle,
214                                     uint32_t flags, const SkMatrix* localMatrix);
215    static sk_sp<SkShader> MakeSweep(SkScalar cx, SkScalar cy,
216                                     const SkColor colors[], const SkScalar pos[], int count,
217                                     uint32_t flags, const SkMatrix* localMatrix) {
218        return MakeSweep(cx, cy, colors, pos, count, SkTileMode::kClamp, 0, 360, flags,
219                         localMatrix);
220    }
221    static sk_sp<SkShader> MakeSweep(SkScalar cx, SkScalar cy,
222                                     const SkColor colors[], const SkScalar pos[], int count) {
223        return MakeSweep(cx, cy, colors, pos, count, 0, nullptr);
224    }
225
226    /** Returns a shader that generates a sweep gradient given a center.
227        <p />
228        @param  cx         The X coordinate of the center of the sweep
229        @param  cx         The Y coordinate of the center of the sweep
230        @param  colors     The array[count] of colors, to be distributed around the center, within
231                           the gradient angle range.
232        @param  pos        May be NULL. The array[count] of SkScalars, or NULL, of the relative
233                           position of each corresponding color in the colors array. If this is
234                           NULL, then the colors are distributed evenly within the angular range.
235                           If this is not null, the values must begin with 0, end with 1.0, and
236                           intermediate values must be strictly increasing.
237        @param  count      Must be >= 2. The number of colors (and pos if not NULL) entries
238        @param  mode       Tiling mode: controls drawing outside of the gradient angular range.
239        @param  startAngle Start of the angular range, corresponding to pos == 0.
240        @param  endAngle   End of the angular range, corresponding to pos == 1.
241    */
242    static sk_sp<SkShader> MakeSweep(SkScalar cx, SkScalar cy,
243                                     const SkColor4f colors[], sk_sp<SkColorSpace> colorSpace,
244                                     const SkScalar pos[], int count,
245                                     SkTileMode mode,
246                                     SkScalar startAngle, SkScalar endAngle,
247                                     uint32_t flags, const SkMatrix* localMatrix);
248    static sk_sp<SkShader> MakeSweep(SkScalar cx, SkScalar cy,
249                                     const SkColor4f colors[], sk_sp<SkColorSpace> colorSpace,
250                                     const SkScalar pos[], int count,
251                                     uint32_t flags, const SkMatrix* localMatrix) {
252        return MakeSweep(cx, cy, colors, std::move(colorSpace), pos, count,
253                         SkTileMode::kClamp, 0, 360, flags, localMatrix);
254    }
255    static sk_sp<SkShader> MakeSweep(SkScalar cx, SkScalar cy,
256                                     const SkColor4f colors[], sk_sp<SkColorSpace> colorSpace,
257                                     const SkScalar pos[], int count) {
258        return MakeSweep(cx, cy, colors, std::move(colorSpace), pos, count, 0, nullptr);
259    }
260
261    static void RegisterFlattenables();
262};
263
264#endif
265