skia_safe/core/
paint.rs

1use crate::Blender;
2use crate::{
3    prelude::*, scalar, BlendMode, Color, Color4f, ColorFilter, ColorSpace, ImageFilter,
4    MaskFilter, PathEffect, Shader,
5};
6use core::fmt;
7
8use skia_bindings::{self as sb, SkPaint};
9
10pub use sb::SkPaint_Style as Style;
11variant_name!(Style::Fill);
12
13pub use sb::SkPaint_Cap as Cap;
14variant_name!(Cap::Butt);
15
16pub use sb::SkPaint_Join as Join;
17variant_name!(Join::Miter);
18
19pub type Paint = Handle<SkPaint>;
20unsafe_send_sync!(Paint);
21
22impl NativeDrop for SkPaint {
23    fn drop(&mut self) {
24        unsafe { sb::C_SkPaint_destruct(self) }
25    }
26}
27
28impl NativeClone for SkPaint {
29    fn clone(&self) -> Self {
30        unsafe { SkPaint::new2(self) }
31    }
32}
33
34impl NativePartialEq for SkPaint {
35    fn eq(&self, rhs: &Self) -> bool {
36        unsafe { sb::C_SkPaint_Equals(self, rhs) }
37    }
38}
39
40impl Default for Handle<SkPaint> {
41    fn default() -> Self {
42        Paint::from_native_c(unsafe { SkPaint::new() })
43    }
44}
45
46impl fmt::Debug for Paint {
47    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48        f.debug_struct("Paint")
49            .field("is_anti_alias", &self.is_anti_alias())
50            .field("is_dither", &self.is_dither())
51            .field("style", &self.style())
52            .field("color", &self.color4f())
53            .field("stroke_width", &self.stroke_width())
54            .field("stroke_miter", &self.stroke_miter())
55            .field("stroke_cap", &self.stroke_cap())
56            .field("stroke_join", &self.stroke_join())
57            .field("color_filter", &self.color_filter())
58            .field("blend_mode", &self.as_blend_mode())
59            .field("path_effect", &self.path_effect())
60            .field("mask_filter", &self.mask_filter())
61            .field("image_filter", &self.image_filter())
62            .finish()
63    }
64}
65
66impl Paint {
67    pub fn new<'a>(
68        color: impl AsRef<Color4f>,
69        color_space: impl Into<Option<&'a ColorSpace>>,
70    ) -> Paint {
71        let color_space = color_space.into();
72        Paint::from_native_c(unsafe {
73            SkPaint::new1(
74                color.as_ref().native(),
75                color_space.native_ptr_or_null_mut_force(),
76            )
77        })
78    }
79
80    pub fn reset(&mut self) -> &mut Self {
81        unsafe { self.native_mut().reset() }
82        self
83    }
84
85    pub fn is_anti_alias(&self) -> bool {
86        unsafe { self.native().__bindgen_anon_1.fBitfields.fAntiAlias() != 0 }
87    }
88
89    pub fn set_anti_alias(&mut self, anti_alias: bool) -> &mut Self {
90        unsafe {
91            self.native_mut()
92                .__bindgen_anon_1
93                .fBitfields
94                .set_fAntiAlias(anti_alias as _);
95        }
96        self
97    }
98
99    pub fn is_dither(&self) -> bool {
100        unsafe { self.native().__bindgen_anon_1.fBitfields.fDither() != 0 }
101    }
102
103    pub fn set_dither(&mut self, dither: bool) -> &mut Self {
104        unsafe {
105            self.native_mut()
106                .__bindgen_anon_1
107                .fBitfields
108                .set_fDither(dither as _);
109        }
110        self
111    }
112
113    pub fn style(&self) -> Style {
114        unsafe { sb::C_SkPaint_getStyle(self.native()) }
115    }
116
117    pub fn set_style(&mut self, style: Style) -> &mut Self {
118        unsafe { self.native_mut().setStyle(style) }
119        self
120    }
121
122    pub fn set_stroke(&mut self, stroke: bool) -> &mut Self {
123        unsafe { self.native_mut().setStroke(stroke) }
124        self
125    }
126
127    pub fn color(&self) -> Color {
128        self.color4f().to_color()
129    }
130
131    pub fn color4f(&self) -> Color4f {
132        Color4f::from_native_c(self.native().fColor4f)
133    }
134
135    pub fn set_color(&mut self, color: impl Into<Color>) -> &mut Self {
136        let color = color.into();
137        unsafe { self.native_mut().setColor(color.into_native()) }
138        self
139    }
140
141    pub fn set_color4f<'a>(
142        &mut self,
143        color: impl AsRef<Color4f>,
144        color_space: impl Into<Option<&'a ColorSpace>>,
145    ) -> &mut Self {
146        let color_space: Option<&'a ColorSpace> = color_space.into();
147        unsafe {
148            self.native_mut().setColor1(
149                color.as_ref().native(),
150                color_space.native_ptr_or_null_mut_force(),
151            )
152        }
153        self
154    }
155
156    pub fn alpha_f(&self) -> f32 {
157        self.color4f().a
158    }
159
160    pub fn alpha(&self) -> u8 {
161        unsafe { sb::C_SkPaint_getAlpha(self.native()) }
162    }
163
164    pub fn set_alpha_f(&mut self, alpha: f32) -> &mut Self {
165        unsafe { self.native_mut().setAlphaf(alpha) }
166        self
167    }
168
169    pub fn set_alpha(&mut self, alpha: u8) -> &mut Self {
170        self.set_alpha_f(f32::from(alpha) * (1.0 / 255.0))
171    }
172
173    pub fn set_argb(&mut self, a: u8, r: u8, g: u8, b: u8) -> &mut Self {
174        unsafe {
175            self.native_mut()
176                .setARGB(a.into(), r.into(), g.into(), b.into())
177        }
178        self
179    }
180
181    pub fn stroke_width(&self) -> scalar {
182        self.native().fWidth
183    }
184
185    pub fn set_stroke_width(&mut self, width: scalar) -> &mut Self {
186        unsafe { self.native_mut().setStrokeWidth(width) }
187        self
188    }
189
190    pub fn stroke_miter(&self) -> scalar {
191        self.native().fMiterLimit
192    }
193
194    pub fn set_stroke_miter(&mut self, miter_limit: scalar) -> &mut Self {
195        unsafe { self.native_mut().setStrokeMiter(miter_limit) }
196        self
197    }
198
199    pub fn stroke_cap(&self) -> Cap {
200        unsafe { sb::C_SkPaint_getStrokeCap(self.native()) }
201    }
202
203    pub fn set_stroke_cap(&mut self, cap: Cap) -> &mut Self {
204        unsafe { self.native_mut().setStrokeCap(cap) }
205        self
206    }
207
208    pub fn stroke_join(&self) -> Join {
209        unsafe { sb::C_SkPaint_getStrokeJoin(self.native()) }
210    }
211
212    pub fn set_stroke_join(&mut self, join: Join) -> &mut Self {
213        unsafe { self.native_mut().setStrokeJoin(join) }
214        self
215    }
216
217    pub fn shader(&self) -> Option<Shader> {
218        Shader::from_unshared_ptr(self.native().fShader.fPtr)
219    }
220
221    pub fn set_shader(&mut self, shader: impl Into<Option<Shader>>) -> &mut Self {
222        unsafe { sb::C_SkPaint_setShader(self.native_mut(), shader.into().into_ptr_or_null()) }
223        self
224    }
225
226    pub fn color_filter(&self) -> Option<ColorFilter> {
227        ColorFilter::from_unshared_ptr(self.native().fColorFilter.fPtr)
228    }
229
230    pub fn set_color_filter(&mut self, color_filter: impl Into<Option<ColorFilter>>) -> &mut Self {
231        unsafe {
232            sb::C_SkPaint_setColorFilter(self.native_mut(), color_filter.into().into_ptr_or_null())
233        }
234        self
235    }
236
237    pub fn as_blend_mode(&self) -> Option<BlendMode> {
238        let mut bm = BlendMode::default();
239        unsafe { sb::C_SkPaint_asBlendMode(self.native(), &mut bm) }.if_true_some(bm)
240    }
241
242    pub fn blend_mode_or(&self, default_mode: BlendMode) -> BlendMode {
243        unsafe { self.native().getBlendMode_or(default_mode) }
244    }
245
246    #[deprecated(
247        since = "0.42.0",
248        note = "Use as_blend_mode() or blend_mode_or() instead."
249    )]
250    pub fn blend_mode(&self) -> BlendMode {
251        self.blend_mode_or(BlendMode::SrcOver)
252    }
253
254    pub fn is_src_over(&self) -> bool {
255        unsafe { self.native().isSrcOver() }
256    }
257
258    pub fn set_blend_mode(&mut self, mode: BlendMode) -> &mut Self {
259        unsafe { self.native_mut().setBlendMode(mode) }
260        self
261    }
262
263    pub fn blender(&self) -> Option<Blender> {
264        Blender::from_unshared_ptr(self.native().fBlender.fPtr)
265    }
266
267    pub fn set_blender(&mut self, blender: impl Into<Option<Blender>>) -> &mut Self {
268        unsafe { sb::C_SkPaint_setBlender(self.native_mut(), blender.into().into_ptr_or_null()) }
269        self
270    }
271
272    pub fn path_effect(&self) -> Option<PathEffect> {
273        PathEffect::from_unshared_ptr(self.native().fPathEffect.fPtr)
274    }
275
276    pub fn set_path_effect(&mut self, path_effect: impl Into<Option<PathEffect>>) -> &mut Self {
277        unsafe {
278            sb::C_SkPaint_setPathEffect(self.native_mut(), path_effect.into().into_ptr_or_null())
279        }
280        self
281    }
282
283    pub fn mask_filter(&self) -> Option<MaskFilter> {
284        MaskFilter::from_unshared_ptr(self.native().fMaskFilter.fPtr)
285    }
286
287    pub fn set_mask_filter(&mut self, mask_filter: impl Into<Option<MaskFilter>>) -> &mut Self {
288        unsafe {
289            sb::C_SkPaint_setMaskFilter(self.native_mut(), mask_filter.into().into_ptr_or_null())
290        }
291        self
292    }
293
294    pub fn image_filter(&self) -> Option<ImageFilter> {
295        ImageFilter::from_unshared_ptr(self.native().fImageFilter.fPtr)
296    }
297
298    pub fn set_image_filter(&mut self, image_filter: impl Into<Option<ImageFilter>>) -> &mut Self {
299        unsafe {
300            sb::C_SkPaint_setImageFilter(self.native_mut(), image_filter.into().into_ptr_or_null())
301        }
302        self
303    }
304
305    pub fn nothing_to_draw(&self) -> bool {
306        unsafe { self.native().nothingToDraw() }
307    }
308}
309
310#[test]
311fn default_creation() {
312    let paint = Paint::default();
313    drop(paint)
314}
315
316#[test]
317fn method_chaining_compiles() {
318    let mut paint = Paint::default();
319    let _paint = paint.reset().reset();
320}
321
322#[test]
323fn union_flags() {
324    let mut paint = Paint::default();
325    assert!(!paint.is_anti_alias());
326    assert!(!paint.is_dither());
327    assert_eq!(paint.style(), Style::Fill);
328
329    {
330        paint.set_anti_alias(true);
331
332        assert!(paint.is_anti_alias());
333        assert!(!paint.is_dither());
334        assert_eq!(paint.style(), Style::Fill);
335
336        paint.set_anti_alias(false);
337    }
338
339    {
340        paint.set_style(Style::StrokeAndFill);
341
342        assert!(!paint.is_anti_alias());
343        assert!(!paint.is_dither());
344        assert_eq!(paint.style(), Style::StrokeAndFill);
345
346        paint.set_style(Style::Fill);
347    }
348}
349
350#[test]
351fn set_color4f_color_space() {
352    let mut paint = Paint::default();
353    let color = Color4f::from(Color::DARK_GRAY);
354    let color_space = ColorSpace::new_srgb();
355    paint.set_color4f(color, None);
356    paint.set_color4f(color, &color_space);
357    let color2 = Color4f::from(Color::DARK_GRAY);
358    paint.set_color4f(color2, Some(&color_space));
359}