skia_safe/core/
stroke_rec.rs

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