Skip to main content

skia_safe/effects/
gradient_shader.rs

1#![allow(deprecated)]
2
3use crate::{
4    gradient, scalar, shaders, Color, Color4f, ColorSpace, Matrix, Point, Shader, TileMode,
5};
6
7pub use gradient::{interpolation, Colors as GradientColors, Gradient, Interpolation};
8
9impl From<Flags> for Interpolation {
10    fn from(flags: Flags) -> Self {
11        let in_premul = if flags.contains(Flags::INTERPOLATE_COLORS_IN_PREMUL) {
12            interpolation::InPremul::Yes
13        } else {
14            interpolation::InPremul::No
15        };
16        Self {
17            in_premul,
18            color_space: interpolation::ColorSpace::Destination,
19            hue_method: interpolation::HueMethod::Shorter,
20        }
21    }
22}
23
24impl Shader {
25    #[deprecated(
26        since = "0.93.0",
27        note = "Use gradient::shaders::linear_gradient() instead"
28    )]
29    pub fn linear_gradient<'a>(
30        points: (impl Into<Point>, impl Into<Point>),
31        colors: impl Into<GradientShaderColors<'a>>,
32        pos: impl Into<Option<&'a [scalar]>>,
33        mode: TileMode,
34        flags: impl Into<Option<Flags>>,
35        local_matrix: impl Into<Option<&'a Matrix>>,
36    ) -> Option<Self> {
37        linear(points, colors, pos, mode, flags, local_matrix)
38    }
39
40    #[deprecated(
41        since = "0.93.0",
42        note = "Use gradient::shaders::linear_gradient() instead"
43    )]
44    pub fn linear_gradient_with_interpolation<'a>(
45        points: (impl Into<Point>, impl Into<Point>),
46        colors: (&'a [Color4f], impl Into<Option<ColorSpace>>),
47        pos: impl Into<Option<&'a [scalar]>>,
48        mode: TileMode,
49        interpolation: impl Into<Interpolation>,
50        local_matrix: impl Into<Option<&'a Matrix>>,
51    ) -> Option<Self> {
52        linear_with_interpolation(points, colors, pos, mode, interpolation, local_matrix)
53    }
54
55    #[deprecated(
56        since = "0.93.0",
57        note = "Use gradient::shaders::radial_gradient() instead"
58    )]
59    pub fn radial_gradient<'a>(
60        center: impl Into<Point>,
61        radius: scalar,
62        colors: impl Into<GradientShaderColors<'a>>,
63        pos: impl Into<Option<&'a [scalar]>>,
64        mode: TileMode,
65        flags: impl Into<Option<self::Flags>>,
66        local_matrix: impl Into<Option<&'a Matrix>>,
67    ) -> Option<Self> {
68        radial(center, radius, colors, pos, mode, flags, local_matrix)
69    }
70
71    #[deprecated(
72        since = "0.93.0",
73        note = "Use gradient::shaders::radial_gradient() instead"
74    )]
75    #[allow(clippy::too_many_arguments)]
76    pub fn radial_gradient_with_interpolation<'a>(
77        center_and_radius: (impl Into<Point>, scalar),
78        colors: (&'a [Color4f], impl Into<Option<ColorSpace>>),
79        pos: impl Into<Option<&'a [scalar]>>,
80        mode: TileMode,
81        interpolation: impl Into<Interpolation>,
82        local_matrix: impl Into<Option<&'a Matrix>>,
83    ) -> Option<Shader> {
84        radial_with_interpolation(
85            center_and_radius,
86            colors,
87            pos,
88            mode,
89            interpolation,
90            local_matrix,
91        )
92    }
93
94    #[deprecated(
95        since = "0.93.0",
96        note = "Use gradient::shaders::two_point_conical_gradient() instead"
97    )]
98    #[allow(clippy::too_many_arguments)]
99    pub fn two_point_conical_gradient<'a>(
100        start: impl Into<Point>,
101        start_radius: scalar,
102        end: impl Into<Point>,
103        end_radius: scalar,
104        colors: impl Into<GradientShaderColors<'a>>,
105        pos: impl Into<Option<&'a [scalar]>>,
106        mode: TileMode,
107        flags: impl Into<Option<self::Flags>>,
108        local_matrix: impl Into<Option<&'a Matrix>>,
109    ) -> Option<Self> {
110        two_point_conical(
111            start,
112            start_radius,
113            end,
114            end_radius,
115            colors,
116            pos,
117            mode,
118            flags,
119            local_matrix,
120        )
121    }
122
123    #[deprecated(
124        since = "0.93.0",
125        note = "Use gradient::shaders::two_point_conical_gradient() instead"
126    )]
127    pub fn two_point_conical_gradient_with_interpolation<'a>(
128        start_and_radius: (impl Into<Point>, scalar),
129        end_and_radius: (impl Into<Point>, scalar),
130        colors: (&'a [Color4f], impl Into<Option<ColorSpace>>),
131        pos: impl Into<Option<&'a [scalar]>>,
132        mode: TileMode,
133        interpolation: impl Into<Interpolation>,
134        local_matrix: impl Into<Option<&'a Matrix>>,
135    ) -> Option<Shader> {
136        two_point_conical_with_interpolation(
137            start_and_radius,
138            end_and_radius,
139            colors,
140            pos,
141            mode,
142            interpolation,
143            local_matrix,
144        )
145    }
146
147    #[deprecated(
148        since = "0.93.0",
149        note = "Use gradient::shaders::sweep_gradient() instead"
150    )]
151    pub fn sweep_gradient<'a>(
152        center: impl Into<Point>,
153        colors: impl Into<GradientShaderColors<'a>>,
154        pos: impl Into<Option<&'a [scalar]>>,
155        mode: TileMode,
156        angles: impl Into<Option<(scalar, scalar)>>,
157        flags: impl Into<Option<self::Flags>>,
158        local_matrix: impl Into<Option<&'a Matrix>>,
159    ) -> Option<Self> {
160        sweep(center, colors, pos, mode, angles, flags, local_matrix)
161    }
162
163    #[deprecated(
164        since = "0.93.0",
165        note = "Use gradient::shaders::sweep_gradient() instead"
166    )]
167    pub fn sweep_gradient_with_interpolation<'a>(
168        center: impl Into<Point>,
169        colors: (&'a [Color4f], impl Into<Option<ColorSpace>>),
170        pos: impl Into<Option<&'a [scalar]>>,
171        mode: TileMode,
172        angles: impl Into<Option<(scalar, scalar)>>,
173        interpolation: impl Into<Interpolation>,
174        local_matrix: impl Into<Option<&'a Matrix>>,
175    ) -> Option<Shader> {
176        sweep_with_interpolation(
177            center,
178            colors,
179            pos,
180            mode,
181            angles,
182            interpolation,
183            local_matrix,
184        )
185    }
186}
187
188bitflags! {
189    #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
190    pub struct Flags: u32 {
191        const INTERPOLATE_COLORS_IN_PREMUL = 1 << 0;
192    }
193}
194
195impl Default for self::Flags {
196    fn default() -> Self {
197        Self::empty()
198    }
199}
200
201pub fn linear<'a>(
202    points: (impl Into<Point>, impl Into<Point>),
203    colors: impl Into<GradientShaderColors<'a>>,
204    pos: impl Into<Option<&'a [scalar]>>,
205    mode: TileMode,
206    flags: impl Into<Option<Flags>>,
207    local_matrix: impl Into<Option<&'a Matrix>>,
208) -> Option<Shader> {
209    let colors = colors.into();
210    let pos = pos.into();
211    let flags = flags.into().unwrap_or_default();
212
213    match colors {
214        GradientShaderColors::Colors(colors) => {
215            // Convert Color to Color4f
216            let colors4f: Vec<Color4f> = colors.iter().map(|c| Color4f::from(*c)).collect();
217            let grad_colors = GradientColors::new(&colors4f, pos, mode, None);
218            let grad = Gradient::new(grad_colors, flags);
219            shaders::linear_gradient(points, &grad, local_matrix)
220        }
221        GradientShaderColors::ColorsInSpace(colors, color_space) => linear_with_interpolation(
222            points,
223            (colors, color_space),
224            pos,
225            mode,
226            flags,
227            local_matrix,
228        ),
229    }
230}
231
232pub fn linear_with_interpolation<'a>(
233    points: (impl Into<Point>, impl Into<Point>),
234    (colors, color_space): (&'a [Color4f], impl Into<Option<ColorSpace>>),
235    pos: impl Into<Option<&'a [scalar]>>,
236    mode: TileMode,
237    interpolation: impl Into<Interpolation>,
238    local_matrix: impl Into<Option<&'a Matrix>>,
239) -> Option<Shader> {
240    let pos = pos.into();
241    let color_space = color_space.into();
242    let grad_colors = GradientColors::new(colors, pos, mode, color_space);
243    let grad = Gradient::new(grad_colors, interpolation);
244    shaders::linear_gradient(points, &grad, local_matrix)
245}
246
247pub fn radial<'a>(
248    center: impl Into<Point>,
249    radius: scalar,
250    colors: impl Into<GradientShaderColors<'a>>,
251    pos: impl Into<Option<&'a [scalar]>>,
252    mode: TileMode,
253    flags: impl Into<Option<self::Flags>>,
254    local_matrix: impl Into<Option<&'a Matrix>>,
255) -> Option<Shader> {
256    let colors = colors.into();
257    let pos = pos.into();
258    let flags = flags.into().unwrap_or_default();
259
260    match colors {
261        GradientShaderColors::Colors(colors) => {
262            let colors4f: Vec<Color4f> = colors.iter().map(|c| Color4f::from(*c)).collect();
263            let grad_colors = GradientColors::new(&colors4f, pos, mode, None);
264            let grad = Gradient::new(grad_colors, flags);
265            shaders::radial_gradient((center, radius), &grad, local_matrix)
266        }
267        GradientShaderColors::ColorsInSpace(colors, color_space) => radial_with_interpolation(
268            (center, radius),
269            (colors, color_space),
270            pos,
271            mode,
272            flags,
273            local_matrix,
274        ),
275    }
276}
277
278pub fn radial_with_interpolation<'a>(
279    (center, radius): (impl Into<Point>, scalar),
280    (colors, color_space): (&'a [Color4f], impl Into<Option<ColorSpace>>),
281    pos: impl Into<Option<&'a [scalar]>>,
282    mode: TileMode,
283    interpolation: impl Into<Interpolation>,
284    local_matrix: impl Into<Option<&'a Matrix>>,
285) -> Option<Shader> {
286    let pos = pos.into();
287    let color_space = color_space.into();
288    let grad_colors = GradientColors::new(colors, pos, mode, color_space);
289    let grad = Gradient::new(grad_colors, interpolation);
290    shaders::radial_gradient((center, radius), &grad, local_matrix)
291}
292
293#[allow(clippy::too_many_arguments)]
294pub fn two_point_conical<'a>(
295    start: impl Into<Point>,
296    start_radius: scalar,
297    end: impl Into<Point>,
298    end_radius: scalar,
299    colors: impl Into<GradientShaderColors<'a>>,
300    pos: impl Into<Option<&'a [scalar]>>,
301    mode: TileMode,
302    flags: impl Into<Option<self::Flags>>,
303    local_matrix: impl Into<Option<&'a Matrix>>,
304) -> Option<Shader> {
305    let colors = colors.into();
306    let pos = pos.into();
307    let flags = flags.into().unwrap_or_default();
308
309    match colors {
310        GradientShaderColors::Colors(colors) => {
311            let colors4f: Vec<Color4f> = colors.iter().map(|c| Color4f::from(*c)).collect();
312            let grad_colors = GradientColors::new(&colors4f, pos, mode, None);
313            let grad = Gradient::new(grad_colors, flags);
314            shaders::two_point_conical_gradient(
315                (start, start_radius),
316                (end, end_radius),
317                &grad,
318                local_matrix,
319            )
320        }
321        GradientShaderColors::ColorsInSpace(colors, color_space) => {
322            two_point_conical_with_interpolation(
323                (start, start_radius),
324                (end, end_radius),
325                (colors, color_space),
326                pos,
327                mode,
328                flags,
329                local_matrix,
330            )
331        }
332    }
333}
334
335pub fn two_point_conical_with_interpolation<'a>(
336    (start, start_radius): (impl Into<Point>, scalar),
337    (end, end_radius): (impl Into<Point>, scalar),
338    (colors, color_space): (&'a [Color4f], impl Into<Option<ColorSpace>>),
339    pos: impl Into<Option<&'a [scalar]>>,
340    mode: TileMode,
341    interpolation: impl Into<Interpolation>,
342    local_matrix: impl Into<Option<&'a Matrix>>,
343) -> Option<Shader> {
344    let pos = pos.into();
345    let color_space = color_space.into();
346    let grad_colors = GradientColors::new(colors, pos, mode, color_space);
347    let grad = Gradient::new(grad_colors, interpolation);
348    shaders::two_point_conical_gradient(
349        (start, start_radius),
350        (end, end_radius),
351        &grad,
352        local_matrix,
353    )
354}
355
356pub fn sweep<'a>(
357    center: impl Into<Point>,
358    colors: impl Into<GradientShaderColors<'a>>,
359    pos: impl Into<Option<&'a [scalar]>>,
360    mode: TileMode,
361    angles: impl Into<Option<(scalar, scalar)>>,
362    flags: impl Into<Option<self::Flags>>,
363    local_matrix: impl Into<Option<&'a Matrix>>,
364) -> Option<Shader> {
365    let colors = colors.into();
366    let pos = pos.into();
367    let angles = angles.into();
368    let flags = flags.into().unwrap_or_default();
369
370    let (start_angle, end_angle) = (
371        angles.map(|a| a.0).unwrap_or(0.0),
372        angles.map(|a| a.1).unwrap_or(360.0),
373    );
374
375    match colors {
376        GradientShaderColors::Colors(colors) => {
377            let colors4f: Vec<Color4f> = colors.iter().map(|c| Color4f::from(*c)).collect();
378            let grad_colors = GradientColors::new(&colors4f, pos, mode, None);
379            let grad = Gradient::new(grad_colors, flags);
380            shaders::sweep_gradient(center, (start_angle, end_angle), &grad, local_matrix)
381        }
382        GradientShaderColors::ColorsInSpace(colors, color_space) => sweep_with_interpolation(
383            center,
384            (colors, color_space),
385            pos,
386            mode,
387            angles,
388            flags,
389            local_matrix,
390        ),
391    }
392}
393
394pub fn sweep_with_interpolation<'a>(
395    center: impl Into<Point>,
396    (colors, color_space): (&'a [Color4f], impl Into<Option<ColorSpace>>),
397    pos: impl Into<Option<&'a [scalar]>>,
398    mode: TileMode,
399    angles: impl Into<Option<(scalar, scalar)>>,
400    interpolation: impl Into<Interpolation>,
401    local_matrix: impl Into<Option<&'a Matrix>>,
402) -> Option<Shader> {
403    let pos = pos.into();
404    let angles = angles.into();
405    let color_space = color_space.into();
406
407    let (start_angle, end_angle) = (
408        angles.map(|a| a.0).unwrap_or(0.0),
409        angles.map(|a| a.1).unwrap_or(360.0),
410    );
411
412    let grad_colors = GradientColors::new(colors, pos, mode, color_space);
413    let grad = Gradient::new(grad_colors, interpolation);
414    shaders::sweep_gradient(center, (start_angle, end_angle), &grad, local_matrix)
415}
416
417/// Type that represents either a slice of [`Color`], or a slice of [`Color4f`] and a color space.
418/// Whenever this type is expected, it's either possible to directly pass a `&[Color]` , or
419/// a tuple of type `(&[Color4f], &ColorSpace)`.
420#[derive(Debug)]
421pub enum GradientShaderColors<'a> {
422    Colors(&'a [Color]),
423    ColorsInSpace(&'a [Color4f], Option<ColorSpace>),
424}
425
426impl GradientShaderColors<'_> {
427    pub fn len(&self) -> usize {
428        match self {
429            GradientShaderColors::Colors(colors) => colors.len(),
430            GradientShaderColors::ColorsInSpace(colors, _) => colors.len(),
431        }
432    }
433
434    // to keep clippy happy.
435    pub fn is_empty(&self) -> bool {
436        self.len() == 0
437    }
438}
439
440impl<'a> From<&'a [Color]> for GradientShaderColors<'a> {
441    fn from(colors: &'a [Color]) -> Self {
442        GradientShaderColors::<'a>::Colors(colors)
443    }
444}
445
446impl<'a> From<(&'a [Color4f], ColorSpace)> for GradientShaderColors<'a> {
447    fn from(c: (&'a [Color4f], ColorSpace)) -> Self {
448        GradientShaderColors::<'a>::ColorsInSpace(c.0, Some(c.1))
449    }
450}
451
452impl<'a> From<(&'a [Color4f], Option<ColorSpace>)> for GradientShaderColors<'a> {
453    fn from(c: (&'a [Color4f], Option<ColorSpace>)) -> Self {
454        GradientShaderColors::<'a>::ColorsInSpace(c.0, c.1)
455    }
456}
457
458impl<'a> From<&'a [Color4f]> for GradientShaderColors<'a> {
459    fn from(c: &'a [Color4f]) -> Self {
460        GradientShaderColors::<'a>::ColorsInSpace(c, None)
461    }
462}