1use std::{convert::TryInto, fmt, ptr, slice};
2
3use skia_bindings::{
4 self as sb, SkTextBlob, SkTextBlobBuilder, SkTextBlob_Iter, SkTextBlob_Iter_Run, SkTypeface,
5};
6
7use crate::{
8 prelude::*, scalar, EncodedText, Font, GlyphId, Paint, Point, RSXform, Rect, Typeface,
9};
10
11pub type TextBlob = RCHandle<SkTextBlob>;
12unsafe_send_sync!(TextBlob);
13require_base_type!(SkTextBlob, sb::SkNVRefCnt);
14
15impl NativeRefCounted for SkTextBlob {
16 fn _ref(&self) {
17 unsafe { sb::C_SkTextBlob_ref(self) };
18 }
19
20 fn _unref(&self) {
21 unsafe { sb::C_SkTextBlob_unref(self) }
22 }
23
24 fn unique(&self) -> bool {
25 unsafe { sb::C_SkTextBlob_unique(self) }
26 }
27}
28
29impl fmt::Debug for TextBlob {
30 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31 f&mut DebugStruct<'_, '_>.debug_struct("TextBlob")
32 .field("bounds", &self.bounds())
33 .field(name:"unique_id", &self.unique_id())
34 .finish()
35 }
36}
37
38impl TextBlob {
39 pub fn new(str: impl AsRef<str>, font: &Font) -> Option<Self> {
40 Self::from_str(str, font)
41 }
42
43 pub fn bounds(&self) -> &Rect {
44 Rect::from_native_ref(&self.native().fBounds)
45 }
46
47 pub fn unique_id(&self) -> u32 {
48 self.native().fUniqueID
49 }
50
51 // TODO: consider to provide an inplace variant.
52 pub fn get_intercepts(&self, bounds: [scalar; 2], paint: Option<&Paint>) -> Vec<scalar> {
53 unsafe {
54 let count = self.native().getIntercepts(
55 bounds.as_ptr(),
56 ptr::null_mut(),
57 paint.native_ptr_or_null(),
58 );
59 let mut intervals = vec![Default::default(); count.try_into().unwrap()];
60 let count_2 = self.native().getIntercepts(
61 bounds.as_ptr(),
62 intervals.as_mut_ptr(),
63 paint.native_ptr_or_null(),
64 );
65 assert_eq!(count, count_2);
66 intervals
67 }
68 }
69
70 pub fn from_str(str: impl AsRef<str>, font: &Font) -> Option<TextBlob> {
71 Self::from_text(str.as_ref(), font)
72 }
73
74 pub fn from_text(text: impl EncodedText, font: &Font) -> Option<TextBlob> {
75 let (ptr, size, encoding) = text.as_raw();
76 TextBlob::from_ptr(unsafe {
77 sb::C_SkTextBlob_MakeFromText(ptr, size, font.native(), encoding.into_native())
78 })
79 }
80
81 pub fn from_pos_text_h(
82 text: impl EncodedText,
83 x_pos: &[scalar],
84 const_y: scalar,
85 font: &Font,
86 ) -> Option<TextBlob> {
87 // TODO: avoid that somehow.
88 assert_eq!(x_pos.len(), font.count_text(&text));
89 let (ptr, size, encoding) = text.as_raw();
90 TextBlob::from_ptr(unsafe {
91 sb::C_SkTextBlob_MakeFromPosTextH(
92 ptr,
93 size,
94 x_pos.as_ptr(),
95 const_y,
96 font.native(),
97 encoding.into_native(),
98 )
99 })
100 }
101
102 pub fn from_pos_text(text: impl EncodedText, pos: &[Point], font: &Font) -> Option<TextBlob> {
103 // TODO: avoid that somehow.
104 let (ptr, size, encoding) = text.as_raw();
105 assert_eq!(pos.len(), font.count_text(text));
106 TextBlob::from_ptr(unsafe {
107 sb::C_SkTextBlob_MakeFromPosText(
108 ptr,
109 size,
110 pos.native().as_ptr(),
111 font.native(),
112 encoding.into_native(),
113 )
114 })
115 }
116
117 pub fn from_rsxform(
118 text: impl EncodedText,
119 xform: &[RSXform],
120 font: &Font,
121 ) -> Option<TextBlob> {
122 // TODO: avoid that somehow.
123 let (ptr, size, encoding) = text.as_raw();
124 assert_eq!(xform.len(), font.count_text(text));
125 TextBlob::from_ptr(unsafe {
126 sb::C_SkTextBlob_MakeFromRSXform(
127 ptr,
128 size,
129 xform.native().as_ptr(),
130 font.native(),
131 encoding.into_native(),
132 )
133 })
134 }
135}
136
137pub type TextBlobBuilder = Handle<SkTextBlobBuilder>;
138unsafe_send_sync!(TextBlobBuilder);
139
140impl NativeDrop for SkTextBlobBuilder {
141 fn drop(&mut self) {
142 unsafe { sb::C_SkTextBlobBuilder_destruct(self) }
143 }
144}
145
146impl fmt::Debug for TextBlobBuilder {
147 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
148 f.debug_struct(name:"TextBlobBuilder").finish()
149 }
150}
151
152impl TextBlobBuilder {
153 pub fn new() -> Self {
154 Self::from_native_c(unsafe { SkTextBlobBuilder::new() })
155 }
156
157 pub fn make(&mut self) -> Option<TextBlob> {
158 TextBlob::from_ptr(unsafe { sb::C_SkTextBlobBuilder_make(self.native_mut()) })
159 }
160
161 pub fn alloc_run(
162 &mut self,
163 font: &Font,
164 count: usize,
165 offset: impl Into<Point>,
166 bounds: Option<&Rect>,
167 ) -> &mut [GlyphId] {
168 let offset = offset.into();
169 unsafe {
170 let buffer = &*self.native_mut().allocRun(
171 font.native(),
172 count.try_into().unwrap(),
173 offset.x,
174 offset.y,
175 bounds.native_ptr_or_null(),
176 );
177 safer::from_raw_parts_mut(buffer.glyphs, count)
178 }
179 }
180
181 pub fn alloc_run_pos_h(
182 &mut self,
183 font: &Font,
184 count: usize,
185 y: scalar,
186 bounds: Option<&Rect>,
187 ) -> (&mut [GlyphId], &mut [scalar]) {
188 unsafe {
189 let buffer = &*self.native_mut().allocRunPosH(
190 font.native(),
191 count.try_into().unwrap(),
192 y,
193 bounds.native_ptr_or_null(),
194 );
195 (
196 safer::from_raw_parts_mut(buffer.glyphs, count),
197 safer::from_raw_parts_mut(buffer.pos, count),
198 )
199 }
200 }
201
202 pub fn alloc_run_pos(
203 &mut self,
204 font: &Font,
205 count: usize,
206 bounds: Option<&Rect>,
207 ) -> (&mut [GlyphId], &mut [Point]) {
208 unsafe {
209 let buffer = &*self.native_mut().allocRunPos(
210 font.native(),
211 count.try_into().unwrap(),
212 bounds.native_ptr_or_null(),
213 );
214 (
215 safer::from_raw_parts_mut(buffer.glyphs, count),
216 safer::from_raw_parts_mut(buffer.pos as *mut Point, count),
217 )
218 }
219 }
220
221 pub fn alloc_run_rsxform(
222 &mut self,
223 font: &Font,
224 count: usize,
225 ) -> (&mut [GlyphId], &mut [RSXform]) {
226 unsafe {
227 let buffer = &*self
228 .native_mut()
229 .allocRunRSXform(font.native(), count.try_into().unwrap());
230 (
231 safer::from_raw_parts_mut(buffer.glyphs, count),
232 safer::from_raw_parts_mut(buffer.pos as *mut RSXform, count),
233 )
234 }
235 }
236
237 pub fn alloc_run_text(
238 &mut self,
239 font: &Font,
240 count: usize,
241 offset: impl Into<Point>,
242 text_byte_count: usize,
243 bounds: Option<&Rect>,
244 ) -> (&mut [GlyphId], &mut [u8], &mut [u32]) {
245 let offset = offset.into();
246 unsafe {
247 let buffer = &*self.native_mut().allocRunText(
248 font.native(),
249 count.try_into().unwrap(),
250 offset.x,
251 offset.y,
252 text_byte_count.try_into().unwrap(),
253 bounds.native_ptr_or_null(),
254 );
255 (
256 safer::from_raw_parts_mut(buffer.glyphs, count),
257 safer::from_raw_parts_mut(buffer.utf8text as *mut u8, text_byte_count),
258 safer::from_raw_parts_mut(buffer.clusters, count),
259 )
260 }
261 }
262
263 pub fn alloc_run_text_pos_h(
264 &mut self,
265 font: &Font,
266 count: usize,
267 y: scalar,
268 text_byte_count: usize,
269 bounds: Option<&Rect>,
270 ) -> (&mut [GlyphId], &mut [scalar], &mut [u8], &mut [u32]) {
271 unsafe {
272 let buffer = &*self.native_mut().allocRunTextPosH(
273 font.native(),
274 count.try_into().unwrap(),
275 y,
276 text_byte_count.try_into().unwrap(),
277 bounds.native_ptr_or_null(),
278 );
279 (
280 safer::from_raw_parts_mut(buffer.glyphs, count),
281 safer::from_raw_parts_mut(buffer.pos, count),
282 safer::from_raw_parts_mut(buffer.utf8text as *mut u8, text_byte_count),
283 safer::from_raw_parts_mut(buffer.clusters, count),
284 )
285 }
286 }
287
288 pub fn alloc_run_text_pos(
289 &mut self,
290 font: &Font,
291 count: usize,
292 text_byte_count: usize,
293 bounds: Option<&Rect>,
294 ) -> (&mut [GlyphId], &mut [Point], &mut [u8], &mut [u32]) {
295 unsafe {
296 let buffer = &*self.native_mut().allocRunTextPos(
297 font.native(),
298 count.try_into().unwrap(),
299 text_byte_count.try_into().unwrap(),
300 bounds.native_ptr_or_null(),
301 );
302 (
303 safer::from_raw_parts_mut(buffer.glyphs, count),
304 safer::from_raw_parts_mut(buffer.pos as *mut Point, count),
305 safer::from_raw_parts_mut(buffer.utf8text as *mut u8, text_byte_count),
306 safer::from_raw_parts_mut(buffer.clusters, count),
307 )
308 }
309 }
310
311 pub fn alloc_run_text_rsxform(
312 &mut self,
313 font: &Font,
314 count: usize,
315 text_byte_count: usize,
316 bounds: Option<&Rect>,
317 ) -> (&mut [GlyphId], &mut [RSXform], &mut [u8], &mut [u32]) {
318 unsafe {
319 let buffer = &*self.native_mut().allocRunTextPos(
320 font.native(),
321 count.try_into().unwrap(),
322 text_byte_count.try_into().unwrap(),
323 bounds.native_ptr_or_null(),
324 );
325 (
326 safer::from_raw_parts_mut(buffer.glyphs, count),
327 safer::from_raw_parts_mut(buffer.pos as *mut RSXform, count),
328 safer::from_raw_parts_mut(buffer.utf8text as *mut u8, text_byte_count),
329 safer::from_raw_parts_mut(buffer.clusters, count),
330 )
331 }
332 }
333}
334
335pub type TextBlobIter<'a> = Borrows<'a, Handle<SkTextBlob_Iter>>;
336
337pub struct TextBlobRun<'a> {
338 typeface: *mut SkTypeface,
339 pub glyph_indices: &'a [u16],
340}
341
342impl fmt::Debug for TextBlobRun<'_> {
343 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
344 f&mut DebugStruct<'_, '_>.debug_struct("TextBlobRun")
345 .field("typeface", self.typeface())
346 .field(name:"glyph_indices", &self.glyph_indices)
347 .finish()
348 }
349}
350
351impl TextBlobRun<'_> {
352 pub fn typeface(&self) -> &Option<Typeface> {
353 Typeface::from_unshared_ptr_ref(&self.typeface)
354 }
355}
356
357impl<'a> Borrows<'a, Handle<SkTextBlob_Iter>> {
358 pub fn new(text_blob: &'a TextBlob) -> Self {
359 Handle::from_native_c(unsafe { SkTextBlob_Iter::new(text_blob.native()) })
360 .borrows(_dep:text_blob)
361 }
362}
363
364impl NativeDrop for SkTextBlob_Iter {
365 fn drop(&mut self) {
366 unsafe { sb::C_SkTextBlob_Iter_destruct(self) }
367 }
368}
369
370impl<'a> Iterator for Borrows<'a, Handle<SkTextBlob_Iter>> {
371 type Item = TextBlobRun<'a>;
372 fn next(&mut self) -> Option<Self::Item> {
373 let mut run = SkTextBlob_Iter_Run {
374 fTypeface: ptr::null_mut(),
375 fGlyphCount: 0,
376 fGlyphIndices: ptr::null_mut(),
377 };
378 unsafe {
379 if self.native_mut().next(&mut run) {
380 let indices = if !run.fGlyphIndices.is_null() && run.fGlyphCount != 0 {
381 slice::from_raw_parts(run.fGlyphIndices, run.fGlyphCount.try_into().unwrap())
382 } else {
383 &[]
384 };
385
386 Some(TextBlobRun {
387 typeface: run.fTypeface,
388 glyph_indices: indices,
389 })
390 } else {
391 None
392 }
393 }
394 }
395}
396
397#[test]
398fn test_point_size_equals_size_of_two_scalars_used_in_alloc_run_pos() {
399 use std::mem;
400 assert_eq!(mem::size_of::<Point>(), mem::size_of::<[scalar; 2]>())
401}
402