1 | use std::fmt; |
2 | |
3 | use skia_bindings::{self as sb, SkFlattenable, SkRefCntBase, SkShader}; |
4 | |
5 | use crate::{ |
6 | gradient_shader, prelude::*, scalar, Color, ColorFilter, ColorSpace, Image, Matrix, |
7 | NativeFlattenable, TileMode, |
8 | }; |
9 | |
10 | #[derive (Clone, PartialEq, Debug)] |
11 | pub struct GradientInfo<'a> { |
12 | pub colors: &'a [Color], |
13 | pub color_offsets: &'a [scalar], |
14 | pub tile_mode: TileMode, |
15 | pub gradient_flags: gradient_shader::Flags, |
16 | } |
17 | |
18 | impl<'a> GradientInfo<'a> { |
19 | pub fn color_count(&self) -> usize { |
20 | self.colors.len() |
21 | } |
22 | } |
23 | |
24 | pub type Shader = RCHandle<SkShader>; |
25 | unsafe_send_sync!(Shader); |
26 | require_type_equality!(sb::SkShader_INHERITED, SkFlattenable); |
27 | |
28 | impl NativeBase<SkRefCntBase> for SkShader {} |
29 | impl NativeBase<SkFlattenable> for SkShader {} |
30 | |
31 | impl NativeRefCountedBase for SkShader { |
32 | type Base = SkRefCntBase; |
33 | fn ref_counted_base(&self) -> &Self::Base { |
34 | self.base() |
35 | } |
36 | } |
37 | |
38 | impl NativeFlattenable for SkShader { |
39 | fn native_flattenable(&self) -> &SkFlattenable { |
40 | self.base() |
41 | } |
42 | |
43 | fn native_deserialize(data: &[u8]) -> *mut Self { |
44 | unsafe { sb::C_SkShader_Deserialize(data:data.as_ptr() as _, length:data.len()) } |
45 | } |
46 | } |
47 | |
48 | impl Default for Shader { |
49 | fn default() -> Self { |
50 | shaders::empty() |
51 | } |
52 | } |
53 | |
54 | impl fmt::Debug for Shader { |
55 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
56 | f&mut DebugStruct<'_, '_>.debug_struct("Shader" ) |
57 | .field("is_opaque" , &self.is_opaque()) |
58 | .field(name:"image" , &self.image()) |
59 | .finish() |
60 | } |
61 | } |
62 | |
63 | /// Shaders specify the source color(s) for what is being drawn. If a paint |
64 | /// has no shader, then the paint's color is used. If the paint has a |
65 | /// shader, then the shader's color(s) are use instead, but they are |
66 | /// modulated by the paint's alpha. This makes it easy to create a shader |
67 | /// once (e.g. bitmap tiling or gradient) and then change its transparency |
68 | /// w/o having to modify the original shader... only the paint's alpha needs |
69 | /// to be modified. |
70 | impl Shader { |
71 | /// Returns `true` if the shader is guaranteed to produce only opaque |
72 | /// colors, subject to the [`crate::Paint`] using the shader to apply an opaque |
73 | /// alpha value. Subclasses should override this to allow some |
74 | /// optimizations. |
75 | pub fn is_opaque(&self) -> bool { |
76 | unsafe { sb::C_SkShader_isOpaque(self.native()) } |
77 | } |
78 | /// Returns iff this shader is backed by a single [`Image`]. |
79 | /// If not, returns `None`. |
80 | pub fn image(&self) -> Option<(Image, Matrix, (TileMode, TileMode))> { |
81 | unsafe { |
82 | let mut matrix = Matrix::default(); |
83 | let mut tile_mode = [TileMode::default(); 2]; |
84 | let image = Image::from_unshared_ptr( |
85 | self.native() |
86 | .isAImage(matrix.native_mut(), tile_mode.as_mut_ptr()), |
87 | ); |
88 | #[allow (clippy::tuple_array_conversions)] |
89 | image.map(|i| (i, matrix, (tile_mode[0], tile_mode[1]))) |
90 | } |
91 | } |
92 | |
93 | pub fn is_a_image(&self) -> bool { |
94 | unsafe { sb::C_SkShader_isAImage(self.native()) } |
95 | } |
96 | |
97 | /// Return a shader that will apply the specified `local_matrix` to this shader. |
98 | /// The specified matrix will be applied before any matrix associated with this shader. |
99 | #[must_use ] |
100 | pub fn with_local_matrix(&self, matrix: &Matrix) -> Self { |
101 | Self::from_ptr(unsafe { |
102 | sb::C_SkShader_makeWithLocalMatrix(self.native(), matrix.native()) |
103 | }) |
104 | .unwrap() |
105 | } |
106 | |
107 | /// Create a new shader that produces the same colors as invoking this shader and then applying |
108 | /// the color filter. |
109 | #[must_use ] |
110 | pub fn with_color_filter(&self, color_filter: impl Into<ColorFilter>) -> Self { |
111 | Self::from_ptr(unsafe { |
112 | sb::C_SkShader_makeWithColorFilter(self.native(), color_filter.into().into_ptr()) |
113 | }) |
114 | .unwrap() |
115 | } |
116 | |
117 | /// Return a shader that will compute this shader in a specific color space. |
118 | /// By default, all shaders operate in the destination (surface) color space. |
119 | /// The results of a shader are still always converted to the destination - this |
120 | /// API has no impact on simple shaders or images. Primarily, it impacts shaders |
121 | /// that perform mathematical operations, like Blend shaders, or runtime shaders. |
122 | #[must_use ] |
123 | pub fn with_working_color_space(&self, color_space: impl Into<ColorSpace>) -> Self { |
124 | Self::from_ptr(unsafe { |
125 | sb::C_SkShader_makeWithWorkingColorSpace(self.native(), color_space.into().into_ptr()) |
126 | }) |
127 | .unwrap() |
128 | } |
129 | } |
130 | |
131 | pub mod shaders { |
132 | use crate::{prelude::*, Blender, Color, Color4f, ColorSpace, Rect, Shader}; |
133 | use skia_bindings as sb; |
134 | |
135 | pub fn empty() -> Shader { |
136 | Shader::from_ptr(unsafe { sb::C_SkShaders_Empty() }).unwrap() |
137 | } |
138 | |
139 | pub fn color(color: impl Into<Color>) -> Shader { |
140 | let color = color.into(); |
141 | Shader::from_ptr(unsafe { sb::C_SkShaders_Color(color.into_native()) }).unwrap() |
142 | } |
143 | |
144 | pub fn color_in_space(color: impl AsRef<Color4f>, space: impl Into<ColorSpace>) -> Shader { |
145 | Shader::from_ptr(unsafe { |
146 | sb::C_SkShaders_Color2(color.as_ref().native(), space.into().into_ptr()) |
147 | }) |
148 | .unwrap() |
149 | } |
150 | |
151 | pub fn blend( |
152 | blender: impl Into<Blender>, |
153 | dst: impl Into<Shader>, |
154 | src: impl Into<Shader>, |
155 | ) -> Shader { |
156 | Shader::from_ptr(unsafe { |
157 | sb::C_SkShaders_Blend( |
158 | blender.into().into_ptr(), |
159 | dst.into().into_ptr(), |
160 | src.into().into_ptr(), |
161 | ) |
162 | }) |
163 | .unwrap() |
164 | } |
165 | |
166 | pub fn coord_clamp(shader: impl Into<Shader>, rect: impl AsRef<Rect>) -> Option<Shader> { |
167 | Shader::from_ptr(unsafe { |
168 | sb::C_SkShaders_CoordClamp(shader.into().into_ptr(), rect.as_ref().native()) |
169 | }) |
170 | } |
171 | } |
172 | |