skia_safe/core/
stroke_rec.rs

1use crate::{paint, prelude::*, scalar, Paint, Path};
2use skia_bindings::{self as sb, SkStrokeRec};
3use std::fmt;
4
5pub use sb::SkStrokeRec_InitStyle as InitStyle;
6variant_name!(InitStyle::Hairline);
7
8pub use sb::SkStrokeRec_Style as Style;
9variant_name!(Style::Stroke);
10
11pub type StrokeRec = Handle<SkStrokeRec>;
12unsafe_send_sync!(StrokeRec);
13
14impl NativeDrop for SkStrokeRec {
15    fn drop(&mut self) {
16        unsafe { sb::C_SkStrokeRec_destruct(self) };
17    }
18}
19
20impl NativeClone for SkStrokeRec {
21    fn clone(&self) -> Self {
22        let mut copy = StrokeRec::new_hairline();
23        unsafe { sb::C_SkStrokeRec_copy(self, copy.native_mut()) }
24        *copy.native()
25    }
26}
27
28impl fmt::Debug for StrokeRec {
29    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30        f.debug_struct("StrokeRec")
31            .field("style", &self.style())
32            .field("width", &self.width())
33            .field("miter", &self.miter())
34            .field("cap", &self.cap())
35            .field("join", &self.join())
36            .field("res_scale", &self.res_scale())
37            .finish()
38    }
39}
40
41impl StrokeRec {
42    pub fn new(init_style: InitStyle) -> Self {
43        Self::from_native_c(unsafe { SkStrokeRec::new(init_style) })
44    }
45
46    // for convenience
47    pub fn new_hairline() -> Self {
48        Self::new(InitStyle::Hairline)
49    }
50
51    // for convenience
52    pub fn new_fill() -> Self {
53        Self::new(InitStyle::Fill)
54    }
55
56    pub fn from_paint(
57        paint: &Paint,
58        style: impl Into<Option<paint::Style>>,
59        res_scale: impl Into<Option<scalar>>,
60    ) -> Self {
61        let res_scale = res_scale.into().unwrap_or(1.0);
62        Self::from_native_c(unsafe {
63            match style.into() {
64                Some(style) => SkStrokeRec::new1(paint.native(), style, res_scale),
65                None => SkStrokeRec::new2(paint.native(), res_scale),
66            }
67        })
68    }
69
70    pub fn style(&self) -> Style {
71        unsafe { self.native().getStyle() }
72    }
73
74    pub fn width(&self) -> scalar {
75        self.native().fWidth
76    }
77
78    pub fn miter(&self) -> scalar {
79        self.native().fMiterLimit
80    }
81
82    pub fn cap(&self) -> paint::Cap {
83        unsafe { sb::C_SkStrokeRec_getCap(self.native()) }
84    }
85
86    pub fn join(&self) -> paint::Join {
87        unsafe { sb::C_SkStrokeRec_getJoin(self.native()) }
88    }
89
90    pub fn is_hairline_style(&self) -> bool {
91        self.style() == Style::Hairline
92    }
93
94    pub fn is_fill_style(&self) -> bool {
95        self.style() == Style::Fill
96    }
97
98    pub fn set_fill_style(&mut self) -> &mut Self {
99        unsafe { self.native_mut().setFillStyle() }
100        self
101    }
102
103    pub fn set_hairline_style(&mut self) -> &mut Self {
104        unsafe { self.native_mut().setHairlineStyle() }
105        self
106    }
107
108    pub fn set_stroke_style(
109        &mut self,
110        width: scalar,
111        stroke_and_fill: impl Into<Option<bool>>,
112    ) -> &mut Self {
113        let stroke_and_fill = stroke_and_fill.into().unwrap_or(false);
114        unsafe { self.native_mut().setStrokeStyle(width, stroke_and_fill) }
115        self
116    }
117
118    pub fn set_stroke_params(
119        &mut self,
120        cap: paint::Cap,
121        join: paint::Join,
122        miter_limit: scalar,
123    ) -> &mut Self {
124        let native = self.native_mut();
125        native.set_fCap(cap as _);
126        native.set_fJoin(join as _);
127        native.fMiterLimit = miter_limit;
128        self
129    }
130
131    pub fn res_scale(&self) -> scalar {
132        self.native().fResScale
133    }
134
135    pub fn set_res_scale(&mut self, rs: scalar) {
136        debug_assert!(rs > 0.0 && rs.is_finite());
137        self.native_mut().fResScale = rs;
138    }
139
140    pub fn need_to_apply(&self) -> bool {
141        let style = self.style();
142        style == Style::Stroke || style == Style::StrokeAndFill
143    }
144
145    pub fn apply_to_path(&self, dst: &mut Path, src: &Path) -> bool {
146        unsafe { self.native().applyToPath(dst.native_mut(), src.native()) }
147    }
148
149    pub fn apply_to_path_inplace(&self, path: &mut Path) -> bool {
150        unsafe { self.native().applyToPath(path.native_mut(), path.native()) }
151    }
152
153    pub fn apply_to_paint(&self, paint: &mut Paint) {
154        unsafe { self.native().applyToPaint(paint.native_mut()) }
155    }
156
157    pub fn inflation_radius(&self) -> scalar {
158        unsafe { self.native().getInflationRadius() }
159    }
160
161    pub fn inflation_radius_from_paint_and_style(paint: &Paint, style: paint::Style) -> scalar {
162        unsafe { SkStrokeRec::GetInflationRadius(paint.native(), style) }
163    }
164
165    pub fn inflation_radius_from_params(
166        join: paint::Join,
167        miter_limit: scalar,
168        cap: paint::Cap,
169        stroke_width: scalar,
170    ) -> scalar {
171        unsafe { SkStrokeRec::GetInflationRadius1(join, miter_limit, cap, stroke_width) }
172    }
173
174    pub fn has_equal_effect(&self, other: &StrokeRec) -> bool {
175        unsafe { sb::C_SkStrokeRec_hasEqualEffect(self.native(), other.native()) }
176    }
177}