1use std::fmt;
2
3use skia_bindings::{self as sb, SkFlattenable, SkRefCntBase, SkShader};
4
5use crate::{
6 gradient_shader, prelude::*, scalar, Color, ColorFilter, ColorSpace, Image, Matrix,
7 NativeFlattenable, TileMode,
8};
9
10#[derive(Clone, PartialEq, Debug)]
11pub 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
18impl GradientInfo<'_> {
19 pub fn color_count(&self) -> usize {
20 self.colors.len()
21 }
22}
23
24pub type Shader = RCHandle<SkShader>;
25unsafe_send_sync!(Shader);
26require_type_equality!(sb::SkShader_INHERITED, SkFlattenable);
27
28impl NativeBase<SkRefCntBase> for SkShader {}
29impl NativeBase<SkFlattenable> for SkShader {}
30
31impl NativeRefCountedBase for SkShader {
32 type Base = SkRefCntBase;
33 fn ref_counted_base(&self) -> &Self::Base {
34 self.base()
35 }
36}
37
38impl 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.as_ptr() as _, data.len()) }
45 }
46}
47
48impl Default for Shader {
49 fn default() -> Self {
50 shaders::empty()
51 }
52}
53
54impl fmt::Debug for Shader {
55 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56 f.debug_struct("Shader")
57 .field("is_opaque", &self.is_opaque())
58 .field("image", &self.image())
59 .finish()
60 }
61}
62
63impl Shader {
71 pub fn is_opaque(&self) -> bool {
76 unsafe { sb::C_SkShader_isOpaque(self.native()) }
77 }
78 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 #[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 #[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 #[must_use]
135 pub fn with_working_color_space(
136 &self,
137 input_cs: impl Into<Option<ColorSpace>>,
138 output_cs: impl Into<Option<ColorSpace>>,
139 ) -> Self {
140 Self::from_ptr(unsafe {
141 sb::C_SkShader_makeWithWorkingColorSpace(
142 self.native(),
143 input_cs.into().into_ptr_or_null(),
144 output_cs.into().into_ptr_or_null(),
145 )
146 })
147 .unwrap()
148 }
149}
150
151pub mod shaders {
152 use skia_bindings as sb;
153
154 use crate::{
155 prelude::*, Blender, Color, Color4f, ColorSpace, Image, Matrix, Rect, SamplingOptions,
156 Shader, TileMode,
157 };
158
159 pub fn empty() -> Shader {
160 Shader::from_ptr(unsafe { sb::C_SkShaders_Empty() }).unwrap()
161 }
162
163 pub fn color(color: impl Into<Color>) -> Shader {
164 let color = color.into();
165 Shader::from_ptr(unsafe { sb::C_SkShaders_Color(color.into_native()) }).unwrap()
166 }
167
168 pub fn color_in_space(color: impl AsRef<Color4f>, space: impl Into<ColorSpace>) -> Shader {
169 Shader::from_ptr(unsafe {
170 sb::C_SkShaders_Color2(color.as_ref().native(), space.into().into_ptr())
171 })
172 .unwrap()
173 }
174
175 pub fn blend(
176 blender: impl Into<Blender>,
177 dst: impl Into<Shader>,
178 src: impl Into<Shader>,
179 ) -> Shader {
180 Shader::from_ptr(unsafe {
181 sb::C_SkShaders_Blend(
182 blender.into().into_ptr(),
183 dst.into().into_ptr(),
184 src.into().into_ptr(),
185 )
186 })
187 .unwrap()
188 }
189
190 pub fn coord_clamp(shader: impl Into<Shader>, rect: impl AsRef<Rect>) -> Option<Shader> {
191 Shader::from_ptr(unsafe {
192 sb::C_SkShaders_CoordClamp(shader.into().into_ptr(), rect.as_ref().native())
193 })
194 }
195
196 pub fn image<'a>(
198 image: impl Into<Image>,
199 tm: (TileMode, TileMode),
200 options: &SamplingOptions,
201 matrix: impl Into<Option<&'a Matrix>>,
202 ) -> Option<Shader> {
203 Shader::from_ptr(unsafe {
204 sb::C_SkShaders_Image(
205 image.into().into_ptr(),
206 tm.0,
207 tm.1,
208 options.native(),
209 matrix.into().native_ptr_or_null(),
210 )
211 })
212 }
213
214 pub fn raw_image<'a>(
217 image: impl Into<Image>,
218 tm: (TileMode, TileMode),
219 options: &SamplingOptions,
220 matrix: impl Into<Option<&'a Matrix>>,
221 ) -> Option<Shader> {
222 Shader::from_ptr(unsafe {
223 sb::C_SkShaders_RawImage(
224 image.into().into_ptr(),
225 tm.0,
226 tm.1,
227 options.native(),
228 matrix.into().native_ptr_or_null(),
229 )
230 })
231 }
232}