1 | use std::{fmt, os::raw, ptr, str}; |
2 | |
3 | use skia_bindings as sb; |
4 | |
5 | use super::{FontCollection, Paragraph, ParagraphStyle, PlaceholderStyle, TextStyle}; |
6 | use crate::prelude::*; |
7 | |
8 | pub type ParagraphBuilder = RefHandle<sb::skia_textlayout_ParagraphBuilder>; |
9 | unsafe_send_sync!(ParagraphBuilder); |
10 | |
11 | impl NativeDrop for sb::skia_textlayout_ParagraphBuilder { |
12 | fn drop(&mut self) { |
13 | unsafe { sb::C_ParagraphBuilder_delete(self) } |
14 | } |
15 | } |
16 | |
17 | impl fmt::Debug for ParagraphBuilder { |
18 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
19 | f.debug_struct(name:"ParagraphBuilder" ).finish() |
20 | } |
21 | } |
22 | |
23 | impl ParagraphBuilder { |
24 | pub fn push_style(&mut self, style: &TextStyle) -> &mut Self { |
25 | unsafe { sb::C_ParagraphBuilder_pushStyle(self.native_mut(), style.native()) } |
26 | self |
27 | } |
28 | |
29 | pub fn pop(&mut self) -> &mut Self { |
30 | unsafe { sb::C_ParagraphBuilder_pop(self.native_mut()) } |
31 | self |
32 | } |
33 | |
34 | pub fn peek_style(&mut self) -> TextStyle { |
35 | let mut ts = TextStyle::default(); |
36 | unsafe { sb::C_ParagraphBuilder_peekStyle(self.native_mut(), ts.native_mut()) } |
37 | ts |
38 | } |
39 | |
40 | pub fn add_text(&mut self, str: impl AsRef<str>) -> &mut Self { |
41 | let str = str.as_ref(); |
42 | unsafe { |
43 | sb::C_ParagraphBuilder_addText( |
44 | self.native_mut(), |
45 | str.as_ptr() as *const raw::c_char, |
46 | str.len(), |
47 | ) |
48 | } |
49 | self |
50 | } |
51 | |
52 | pub fn add_placeholder(&mut self, placeholder_style: &PlaceholderStyle) -> &mut Self { |
53 | unsafe { |
54 | sb::C_ParagraphBuilder_addPlaceholder(self.native_mut(), placeholder_style.native()) |
55 | } |
56 | self |
57 | } |
58 | |
59 | pub fn build(&mut self) -> Paragraph { |
60 | Paragraph::from_ptr(unsafe { sb::C_ParagraphBuilder_Build(self.native_mut()) }).unwrap() |
61 | } |
62 | |
63 | pub fn get_text(&mut self) -> &str { |
64 | unsafe { |
65 | let mut ptr = ptr::null_mut(); |
66 | let mut len = 0; |
67 | sb::C_ParagraphBuilder_getText(self.native_mut(), &mut ptr, &mut len); |
68 | // ptr may indeed be `null` if there is no text. |
69 | str::from_utf8_unchecked(safer::from_raw_parts(ptr as *const u8, len)) |
70 | } |
71 | } |
72 | |
73 | pub fn get_paragraph_style(&self) -> ParagraphStyle { |
74 | ParagraphStyle::from_ptr(unsafe { sb::C_ParagraphBuilder_getParagraphStyle(self.native()) }) |
75 | .unwrap() |
76 | } |
77 | |
78 | // TODO: Wrap SetWords*, SetGraphemeBreaks*, setLineBreaks*, setUnicode. |
79 | |
80 | pub fn reset(&mut self) { |
81 | unsafe { sb::C_ParagraphBuilder_Reset(self.native_mut()) } |
82 | } |
83 | |
84 | pub fn new(style: &ParagraphStyle, font_collection: impl Into<FontCollection>) -> Self { |
85 | #[cfg (feature = "embed-icudtl" )] |
86 | crate::icu::init(); |
87 | |
88 | Self::from_ptr(unsafe { |
89 | sb::C_ParagraphBuilder_make(style.native(), font_collection.into().into_ptr()) |
90 | }) |
91 | .expect("Unicode initialization error" ) |
92 | } |
93 | } |
94 | |