1use std::fmt;
2
3use skia_bindings::{self as sb, SkFlattenable, SkRefCntBase, SkShader};
4
5use crate::{prelude::*, ColorFilter, ColorSpace, Image, Matrix, NativeFlattenable, TileMode};
6
7pub type Shader = RCHandle<SkShader>;
8unsafe_send_sync!(Shader);
9require_type_equality!(sb::SkShader_INHERITED, SkFlattenable);
10
11impl NativeBase<SkRefCntBase> for SkShader {}
12impl NativeBase<SkFlattenable> for SkShader {}
13
14impl NativeRefCountedBase for SkShader {
15 type Base = SkRefCntBase;
16 fn ref_counted_base(&self) -> &Self::Base {
17 self.base()
18 }
19}
20
21impl NativeFlattenable for SkShader {
22 fn native_flattenable(&self) -> &SkFlattenable {
23 self.base()
24 }
25
26 fn native_deserialize(data: &[u8]) -> *mut Self {
27 unsafe { sb::C_SkShader_Deserialize(data.as_ptr() as _, data.len()) }
28 }
29}
30
31impl Default for Shader {
32 fn default() -> Self {
33 shaders::empty()
34 }
35}
36
37impl fmt::Debug for Shader {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 f.debug_struct("Shader")
40 .field("is_opaque", &self.is_opaque())
41 .field("image", &self.image())
42 .finish()
43 }
44}
45
46impl Shader {
54 pub fn is_opaque(&self) -> bool {
59 unsafe { sb::C_SkShader_isOpaque(self.native()) }
60 }
61 pub fn image(&self) -> Option<(Image, Matrix, (TileMode, TileMode))> {
64 unsafe {
65 let mut matrix = Matrix::default();
66 let mut tile_mode = [TileMode::default(); 2];
67 let image = Image::from_unshared_ptr(
68 self.native()
69 .isAImage(matrix.native_mut(), tile_mode.as_mut_ptr()),
70 );
71 #[allow(clippy::tuple_array_conversions)]
72 image.map(|i| (i, matrix, (tile_mode[0], tile_mode[1])))
73 }
74 }
75
76 pub fn is_a_image(&self) -> bool {
77 unsafe { sb::C_SkShader_isAImage(self.native()) }
78 }
79
80 #[must_use]
83 pub fn with_local_matrix(&self, matrix: &Matrix) -> Self {
84 Self::from_ptr(unsafe {
85 sb::C_SkShader_makeWithLocalMatrix(self.native(), matrix.native())
86 })
87 .unwrap()
88 }
89
90 #[must_use]
93 pub fn with_color_filter(&self, color_filter: impl Into<ColorFilter>) -> Self {
94 Self::from_ptr(unsafe {
95 sb::C_SkShader_makeWithColorFilter(self.native(), color_filter.into().into_ptr())
96 })
97 .unwrap()
98 }
99
100 #[must_use]
118 pub fn with_working_color_space(
119 &self,
120 input_cs: impl Into<Option<ColorSpace>>,
121 output_cs: impl Into<Option<ColorSpace>>,
122 ) -> Self {
123 Self::from_ptr(unsafe {
124 sb::C_SkShader_makeWithWorkingColorSpace(
125 self.native(),
126 input_cs.into().into_ptr_or_null(),
127 output_cs.into().into_ptr_or_null(),
128 )
129 })
130 .unwrap()
131 }
132}
133
134pub mod shaders {
135 use skia_bindings as sb;
136
137 use crate::{
138 prelude::*, Blender, Color, Color4f, ColorSpace, Image, Matrix, Rect, SamplingOptions,
139 Shader, TileMode,
140 };
141
142 pub fn empty() -> Shader {
143 Shader::from_ptr(unsafe { sb::C_SkShaders_Empty() }).unwrap()
144 }
145
146 pub fn color(color: impl Into<Color>) -> Shader {
147 let color = color.into();
148 Shader::from_ptr(unsafe { sb::C_SkShaders_Color(color.into_native()) }).unwrap()
149 }
150
151 pub fn color_in_space(color: impl AsRef<Color4f>, space: impl Into<ColorSpace>) -> Shader {
152 Shader::from_ptr(unsafe {
153 sb::C_SkShaders_Color2(color.as_ref().native(), space.into().into_ptr())
154 })
155 .unwrap()
156 }
157
158 pub fn blend(
159 blender: impl Into<Blender>,
160 dst: impl Into<Shader>,
161 src: impl Into<Shader>,
162 ) -> Shader {
163 Shader::from_ptr(unsafe {
164 sb::C_SkShaders_Blend(
165 blender.into().into_ptr(),
166 dst.into().into_ptr(),
167 src.into().into_ptr(),
168 )
169 })
170 .unwrap()
171 }
172
173 pub fn coord_clamp(shader: impl Into<Shader>, rect: impl AsRef<Rect>) -> Option<Shader> {
174 Shader::from_ptr(unsafe {
175 sb::C_SkShaders_CoordClamp(shader.into().into_ptr(), rect.as_ref().native())
176 })
177 }
178
179 pub fn image<'a>(
181 image: impl Into<Image>,
182 tm: (TileMode, TileMode),
183 options: &SamplingOptions,
184 matrix: impl Into<Option<&'a Matrix>>,
185 ) -> Option<Shader> {
186 Shader::from_ptr(unsafe {
187 sb::C_SkShaders_Image(
188 image.into().into_ptr(),
189 tm.0,
190 tm.1,
191 options.native(),
192 matrix.into().native_ptr_or_null(),
193 )
194 })
195 }
196
197 pub fn raw_image<'a>(
200 image: impl Into<Image>,
201 tm: (TileMode, TileMode),
202 options: &SamplingOptions,
203 matrix: impl Into<Option<&'a Matrix>>,
204 ) -> Option<Shader> {
205 Shader::from_ptr(unsafe {
206 sb::C_SkShaders_RawImage(
207 image.into().into_ptr(),
208 tm.0,
209 tm.1,
210 options.native(),
211 matrix.into().native_ptr_or_null(),
212 )
213 })
214 }
215
216 pub use crate::effects::gradient::shaders::{
218 linear_gradient, radial_gradient, sweep_gradient, two_point_conical_gradient,
219 };
220}