skia_safe/modules/paragraph/
paragraph_style.rs

1use std::fmt;
2
3use skia_bindings as sb;
4
5use super::{FontFamilies, TextAlign, TextDirection, TextStyle};
6use crate::{
7    interop::{self, AsStr, FromStrs, SetStr},
8    modules::paragraph::TextHeightBehavior,
9    prelude::*,
10    scalar, FontStyle,
11};
12
13pub type StrutStyle = Handle<sb::skia_textlayout_StrutStyle>;
14unsafe_send_sync!(StrutStyle);
15
16impl NativeDrop for sb::skia_textlayout_StrutStyle {
17    fn drop(&mut self) {
18        unsafe { sb::C_StrutStyle_destruct(self) }
19    }
20}
21
22impl NativeClone for sb::skia_textlayout_StrutStyle {
23    fn clone(&self) -> Self {
24        construct(|ss| unsafe { sb::C_StrutStyle_CopyConstruct(ss, self) })
25    }
26}
27
28impl NativePartialEq for sb::skia_textlayout_StrutStyle {
29    fn eq(&self, rhs: &Self) -> bool {
30        unsafe { sb::C_StrutStyle_equals(self, rhs) }
31    }
32}
33
34impl Default for StrutStyle {
35    fn default() -> Self {
36        Self::new()
37    }
38}
39
40impl fmt::Debug for StrutStyle {
41    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42        f.debug_struct("StrutStyle")
43            .field("font_families", &self.font_families())
44            .field("font_style", &self.font_style())
45            .field("font_size", &self.font_size())
46            .field("height", &self.height())
47            .field("leading", &self.leading())
48            .field("strut_enabled", &self.strut_enabled())
49            .field("force_strut_height", &self.force_strut_height())
50            .field("height_override", &self.height_override())
51            .field("half_leading", &self.half_leading())
52            .finish()
53    }
54}
55
56impl StrutStyle {
57    pub fn new() -> Self {
58        StrutStyle::construct(|ss| unsafe { sb::C_StrutStyle_Construct(ss) })
59    }
60
61    pub fn font_families(&self) -> FontFamilies {
62        unsafe {
63            let mut count = 0;
64            let ptr = sb::C_StrutStyle_getFontFamilies(self.native(), &mut count);
65            FontFamilies(safer::from_raw_parts(ptr, count))
66        }
67    }
68
69    pub fn set_font_families(&mut self, families: &[impl AsRef<str>]) -> &mut Self {
70        let families: Vec<interop::String> = FromStrs::from_strs(families);
71        let families = families.native();
72        unsafe {
73            sb::C_StrutStyle_setFontFamilies(self.native_mut(), families.as_ptr(), families.len());
74        }
75        self
76    }
77
78    pub fn font_style(&self) -> FontStyle {
79        FontStyle::from_native_c(self.native().fFontStyle)
80    }
81
82    pub fn set_font_style(&mut self, font_style: FontStyle) -> &mut Self {
83        self.native_mut().fFontStyle = font_style.into_native();
84        self
85    }
86
87    pub fn font_size(&self) -> scalar {
88        self.native().fFontSize
89    }
90
91    pub fn set_font_size(&mut self, font_size: scalar) -> &mut Self {
92        self.native_mut().fFontSize = font_size;
93        self
94    }
95
96    pub fn set_height(&mut self, height: scalar) -> &mut Self {
97        self.native_mut().fHeight = height;
98        self
99    }
100
101    pub fn height(&self) -> scalar {
102        self.native().fHeight
103    }
104
105    pub fn set_leading(&mut self, leading: scalar) -> &mut Self {
106        self.native_mut().fLeading = leading;
107        self
108    }
109
110    pub fn leading(&self) -> scalar {
111        self.native().fLeading
112    }
113
114    pub fn strut_enabled(&self) -> bool {
115        self.native().fEnabled
116    }
117
118    pub fn set_strut_enabled(&mut self, enabled: bool) -> &mut Self {
119        self.native_mut().fEnabled = enabled;
120        self
121    }
122
123    pub fn force_strut_height(&self) -> bool {
124        self.native().fForceHeight
125    }
126
127    pub fn set_force_strut_height(&mut self, force_height: bool) -> &mut Self {
128        self.native_mut().fForceHeight = force_height;
129        self
130    }
131
132    pub fn height_override(&self) -> bool {
133        self.native().fHeightOverride
134    }
135
136    pub fn set_height_override(&mut self, height_override: bool) -> &mut Self {
137        self.native_mut().fHeightOverride = height_override;
138        self
139    }
140
141    pub fn half_leading(&self) -> bool {
142        self.native().fHalfLeading
143    }
144
145    pub fn set_half_leading(&mut self, half_leading: bool) -> &mut Self {
146        self.native_mut().fHalfLeading = half_leading;
147        self
148    }
149}
150
151// Can't use `Handle<>` here, `std::u16string` maintains an interior pointer.
152pub type ParagraphStyle = RefHandle<sb::skia_textlayout_ParagraphStyle>;
153unsafe_send_sync!(ParagraphStyle);
154
155impl NativeDrop for sb::skia_textlayout_ParagraphStyle {
156    fn drop(&mut self) {
157        unsafe { sb::C_ParagraphStyle_delete(self) }
158    }
159}
160
161impl Clone for ParagraphStyle {
162    fn clone(&self) -> Self {
163        Self::from_ptr(unsafe { sb::C_ParagraphStyle_newCopy(self.native()) }).unwrap()
164    }
165}
166
167impl NativePartialEq for sb::skia_textlayout_ParagraphStyle {
168    fn eq(&self, rhs: &Self) -> bool {
169        unsafe { sb::C_ParagraphStyle_Equals(self, rhs) }
170    }
171}
172
173impl Default for ParagraphStyle {
174    fn default() -> Self {
175        Self::new()
176    }
177}
178
179impl fmt::Debug for ParagraphStyle {
180    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
181        f.debug_struct("ParagraphStyle")
182            .field("strut_style", &self.strut_style())
183            .field("text_style", &self.text_style())
184            .field("text_direction", &self.text_direction())
185            .field("text_align", &self.text_align())
186            .field("max_lines", &self.max_lines())
187            .field("ellipsis", &self.ellipsis())
188            .field("height", &self.height())
189            .field("text_height_behavior", &self.text_height_behavior())
190            .field("unlimited_lines", &self.unlimited_lines())
191            .field("ellipsized", &self.ellipsized())
192            .field("effective_align", &self.effective_align())
193            .field("hinting_is_on", &self.hinting_is_on())
194            .field("replace_tab_characters", &self.replace_tab_characters())
195            .finish()
196    }
197}
198
199impl ParagraphStyle {
200    pub fn new() -> Self {
201        Self::from_ptr(unsafe { sb::C_ParagraphStyle_new() }).unwrap()
202    }
203
204    pub fn strut_style(&self) -> &StrutStyle {
205        StrutStyle::from_native_ref(&self.native().fStrutStyle)
206    }
207
208    pub fn set_strut_style(&mut self, strut_style: StrutStyle) -> &mut Self {
209        self.native_mut().fStrutStyle.replace_with(strut_style);
210        self
211    }
212
213    pub fn text_style(&self) -> &TextStyle {
214        TextStyle::from_native_ref(&self.native().fDefaultTextStyle)
215    }
216
217    pub fn set_text_style(&mut self, text_style: &TextStyle) -> &mut Self {
218        // TODO: implement the assignment operator in C.
219        self.native_mut()
220            .fDefaultTextStyle
221            .replace_with(text_style.clone());
222        self
223    }
224
225    pub fn text_direction(&self) -> TextDirection {
226        self.native().fTextDirection
227    }
228
229    pub fn set_text_direction(&mut self, direction: TextDirection) -> &mut Self {
230        self.native_mut().fTextDirection = direction;
231        self
232    }
233
234    pub fn text_align(&self) -> TextAlign {
235        self.native().fTextAlign
236    }
237
238    pub fn set_text_align(&mut self, align: TextAlign) -> &mut Self {
239        self.native_mut().fTextAlign = align;
240        self
241    }
242
243    pub fn max_lines(&self) -> Option<usize> {
244        match self.native().fLinesLimit {
245            std::usize::MAX => None,
246            lines => Some(lines),
247        }
248    }
249
250    pub fn set_max_lines(&mut self, lines: impl Into<Option<usize>>) -> &mut Self {
251        self.native_mut().fLinesLimit = lines.into().unwrap_or(usize::MAX);
252        self
253    }
254
255    // TODO: Support u16 ellipsis, but why? Doesn't SkString support UTF-8?
256
257    pub fn ellipsis(&self) -> &str {
258        self.native().fEllipsis.as_str()
259    }
260
261    pub fn set_ellipsis(&mut self, ellipsis: impl AsRef<str>) -> &mut Self {
262        self.native_mut().fEllipsis.set_str(ellipsis);
263        self
264    }
265
266    pub fn height(&self) -> scalar {
267        self.native().fHeight
268    }
269
270    pub fn set_height(&mut self, height: scalar) -> &mut Self {
271        self.native_mut().fHeight = height;
272        self
273    }
274
275    pub fn text_height_behavior(&self) -> TextHeightBehavior {
276        self.native().fTextHeightBehavior
277    }
278
279    pub fn set_text_height_behavior(&mut self, v: TextHeightBehavior) -> &mut Self {
280        self.native_mut().fTextHeightBehavior = v;
281        self
282    }
283
284    pub fn unlimited_lines(&self) -> bool {
285        self.max_lines().is_none()
286    }
287
288    pub fn ellipsized(&self) -> bool {
289        unsafe { sb::C_ParagraphStyle_ellipsized(self.native()) }
290    }
291
292    pub fn effective_align(&self) -> TextAlign {
293        unsafe { self.native().effective_align() }
294    }
295
296    pub fn hinting_is_on(&self) -> bool {
297        self.native().fHintingIsOn
298    }
299
300    pub fn turn_hinting_off(&mut self) -> &mut Self {
301        self.native_mut().fHintingIsOn = false;
302        self
303    }
304
305    pub fn replace_tab_characters(&self) -> bool {
306        self.native().fReplaceTabCharacters
307    }
308
309    pub fn set_replace_tab_characters(&mut self, value: bool) -> &mut Self {
310        self.native_mut().fReplaceTabCharacters = value;
311        self
312    }
313
314    pub fn apply_rounding_hack(&self) -> bool {
315        self.native().fApplyRoundingHack
316    }
317
318    pub fn set_apply_rounding_hack(&mut self, value: bool) -> &mut Self {
319        self.native_mut().fApplyRoundingHack = value;
320        self
321    }
322}
323
324#[cfg(test)]
325mod tests {
326    use super::ParagraphStyle;
327
328    // Regression test for https://github.com/rust-skia/rust-skia/issues/607
329    #[test]
330    fn paragraph_style_supports_equality() {
331        let a = ParagraphStyle::default();
332        let b = ParagraphStyle::default();
333        assert_eq!(a, b)
334    }
335}