1use std::{
2 ffi::{CStr, CString},
3 fmt,
4 marker::PhantomData,
5 os::raw,
6};
7
8use skia_bindings::{
9 self as sb, RustRunHandler, SkShaper, SkShaper_BiDiRunIterator, SkShaper_FontRunIterator,
10 SkShaper_LanguageRunIterator, SkShaper_RunHandler, SkShaper_RunIterator,
11 SkShaper_ScriptRunIterator, SkTextBlobBuilderRunHandler,
12};
13
14use crate::{prelude::*, scalar, Font, FontMgr, FourByteTag, Point, TextBlob};
15
16pub(crate) mod core_text;
18pub(crate) mod harfbuzz;
19pub(crate) mod unicode;
20
21pub use run_handler::RunHandler;
22
23pub type Shaper = RefHandle<SkShaper>;
24unsafe_send_sync!(Shaper);
25
26impl NativeDrop for SkShaper {
27 fn drop(&mut self) {
28 unsafe { sb::C_SkShaper_delete(self) }
29 }
30}
31
32impl Default for Shaper {
33 fn default() -> Self {
34 Self::new(None)
35 }
36}
37
38impl fmt::Debug for Shaper {
39 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40 f.debug_struct("Shaper").finish()
41 }
42}
43
44impl Shaper {
45 #[deprecated(since = "0.74.0", note = "use shapers::primitive::primitive_text()")]
46 pub fn new_primitive() -> Self {
47 crate::shapers::primitive::primitive_text()
48 }
49
50 pub fn new_shaper_driven_wrapper(
51 fallback_font_mgr: impl Into<Option<FontMgr>>,
52 ) -> Option<Self> {
53 crate::shapers::hb::shaper_driven_wrapper(fallback_font_mgr)
54 }
55
56 pub fn new_shape_then_wrap(fallback_font_mgr: impl Into<Option<FontMgr>>) -> Option<Self> {
57 crate::shapers::hb::shape_then_wrap(fallback_font_mgr)
58 }
59
60 #[deprecated(
61 since = "0.74.0",
62 note = "use shapers::hb::shape_dont_wrap_or_reorder()"
63 )]
64 pub fn new_shape_dont_wrap_or_reorder(
65 fallback_font_mgr: impl Into<Option<FontMgr>>,
66 ) -> Option<Self> {
67 crate::shapers::hb::shape_dont_wrap_or_reorder(fallback_font_mgr)
68 }
69
70 pub fn purge_harf_buzz_cache() {
71 unsafe { sb::SkShaper_PurgeHarfBuzzCache() }
72 }
73
74 pub fn new_core_text() -> Option<Self> {
75 #[cfg(feature = "embed-icudtl")]
76 crate::icu::init();
77
78 Self::from_ptr(unsafe { sb::C_SkShaper_MakeCoreText() })
79 }
80
81 pub fn new(font_mgr: impl Into<Option<FontMgr>>) -> Self {
82 #[cfg(feature = "embed-icudtl")]
83 crate::icu::init();
84
85 Self::from_ptr(unsafe { sb::C_SkShaper_Make(font_mgr.into().into_ptr_or_null()) }).unwrap()
86 }
87
88 pub fn purge_caches() {
89 unsafe { sb::SkShaper_PurgeCaches() }
90 }
91}
92
93pub use skia_bindings::SkShaper_Feature as Feature;
94
95pub trait RunIterator {
96 fn consume(&mut self);
97 fn end_of_current_run(&self) -> usize;
98 fn at_end(&self) -> bool;
99}
100
101impl<T> RunIterator for RefHandle<T>
102where
103 T: NativeDrop,
104 T: NativeBase<SkShaper_RunIterator>,
105{
106 fn consume(&mut self) {
107 unsafe { sb::C_SkShaper_RunIterator_consume(self.native_mut().base_mut()) }
108 }
109
110 fn end_of_current_run(&self) -> usize {
111 unsafe { sb::C_SkShaper_RunIterator_endOfCurrentRun(self.native().base()) }
112 }
113
114 fn at_end(&self) -> bool {
115 unsafe { sb::C_SkShaper_RunIterator_atEnd(self.native().base()) }
116 }
117}
118
119pub type FontRunIterator = RefHandle<SkShaper_FontRunIterator>;
120
121impl NativeBase<SkShaper_RunIterator> for SkShaper_FontRunIterator {}
122
123impl NativeDrop for SkShaper_FontRunIterator {
124 fn drop(&mut self) {
125 unsafe { sb::C_SkShaper_RunIterator_delete(self.base_mut()) }
126 }
127}
128
129impl fmt::Debug for FontRunIterator {
130 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
131 f.debug_struct("FontRunIterator")
132 .field("current_font", &self.current_font())
133 .finish()
134 }
135}
136
137impl FontRunIterator {
138 pub fn current_font(&self) -> &Font {
139 Font::from_native_ref(unsafe {
140 &*sb::C_SkShaper_FontRunIterator_currentFont(self.native())
141 })
142 }
143}
144
145impl Shaper {
146 pub fn new_font_mgr_run_iterator<'a>(
147 utf8: &'a str,
148 font: &Font,
149 fallback: impl Into<Option<FontMgr>>,
150 ) -> Borrows<'a, FontRunIterator> {
151 let bytes = utf8.as_bytes();
152 FontRunIterator::from_ptr(unsafe {
153 sb::C_SkShaper_MakeFontMgrRunIterator(
154 bytes.as_ptr() as _,
155 bytes.len(),
156 font.native(),
157 fallback.into().into_ptr_or_null(),
158 )
159 })
160 .unwrap()
161 .borrows(utf8)
162 }
163
164 pub fn new_trivial_font_run_iterator(font: &Font, utf8_bytes: usize) -> FontRunIterator {
168 FontRunIterator::from_ptr(unsafe {
169 sb::C_SkShaper_TrivialFontRunIterator_new(font.native(), utf8_bytes)
170 })
171 .unwrap()
172 }
173}
174
175pub type BiDiRunIterator = RefHandle<SkShaper_BiDiRunIterator>;
176
177impl NativeBase<SkShaper_RunIterator> for SkShaper_BiDiRunIterator {}
178
179impl NativeDrop for SkShaper_BiDiRunIterator {
180 fn drop(&mut self) {
181 unsafe { sb::C_SkShaper_RunIterator_delete(self.base_mut()) }
182 }
183}
184
185impl fmt::Debug for BiDiRunIterator {
186 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
187 f.debug_struct("BiDiRunIterator")
188 .field("current_level", &self.current_level())
189 .finish()
190 }
191}
192
193impl BiDiRunIterator {
194 pub fn current_level(&self) -> u8 {
195 unsafe { sb::C_SkShaper_BiDiRunIterator_currentLevel(self.native()) }
196 }
197}
198
199impl Shaper {
200 pub fn new_bidi_run_iterator(utf8: &str, bidi_level: u8) -> Option<Borrows<BiDiRunIterator>> {
201 let bytes = utf8.as_bytes();
202 BiDiRunIterator::from_ptr(unsafe {
203 sb::C_SkShaper_MakeBidiRunIterator(bytes.as_ptr() as _, bytes.len(), bidi_level)
204 })
205 .map(|i| i.borrows(utf8))
206 }
207
208 pub fn new_icu_bidi_run_iterator(utf8: &str, level: u8) -> Option<Borrows<BiDiRunIterator>> {
209 let bytes = utf8.as_bytes();
210 BiDiRunIterator::from_ptr(unsafe {
211 sb::C_SkShaper_MakeIcuBidiRunIterator(bytes.as_ptr() as _, bytes.len(), level)
212 })
213 .map(|i| i.borrows(utf8))
214 }
215
216 #[deprecated(
217 since = "0.74.0",
218 note = "use shapers::primitive::trivial_bidi_run_iterator()"
219 )]
220 pub fn new_trivial_bidi_run_iterator(bidi_level: u8, utf8_bytes: usize) -> BiDiRunIterator {
221 shapers::primitive::trivial_bidi_run_iterator(bidi_level, utf8_bytes)
222 }
223}
224
225pub type ScriptRunIterator = RefHandle<SkShaper_ScriptRunIterator>;
226
227impl NativeBase<SkShaper_RunIterator> for SkShaper_ScriptRunIterator {}
228
229impl NativeDrop for SkShaper_ScriptRunIterator {
230 fn drop(&mut self) {
231 unsafe { sb::C_SkShaper_RunIterator_delete(self.base_mut()) }
232 }
233}
234
235impl fmt::Debug for ScriptRunIterator {
236 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
237 f.debug_struct("ScriptRunIterator")
238 .field("current_script", &self.current_script())
239 .finish()
240 }
241}
242
243impl ScriptRunIterator {
244 pub fn current_script(&self) -> FourByteTag {
245 FourByteTag::from_native_c(unsafe {
246 sb::C_SkShaper_ScriptRunIterator_currentScript(self.native())
247 })
248 }
249}
250
251impl Shaper {
252 pub fn new_script_run_iterator(utf8: &str, script: FourByteTag) -> Borrows<ScriptRunIterator> {
253 let bytes = utf8.as_bytes();
254 ScriptRunIterator::from_ptr(unsafe {
255 sb::C_SkShaper_MakeScriptRunIterator(
256 bytes.as_ptr() as _,
257 bytes.len(),
258 script.into_native(),
259 )
260 })
261 .unwrap()
262 .borrows(utf8)
263 }
264
265 pub fn new_hb_icu_script_run_iterator(utf8: &str) -> Borrows<ScriptRunIterator> {
268 let bytes = utf8.as_bytes();
269 ScriptRunIterator::from_ptr(unsafe {
270 sb::C_SkShaper_MakeHbIcuScriptRunIterator(bytes.as_ptr() as _, bytes.len())
271 })
272 .unwrap()
273 .borrows(utf8)
274 }
275
276 #[deprecated(
277 since = "0.74.0",
278 note = "use shapers::primitive::trivial_script_run_iterator"
279 )]
280 pub fn new_trivial_script_run_iterator(bidi_level: u8, utf8_bytes: usize) -> ScriptRunIterator {
281 shapers::primitive::trivial_script_run_iterator(bidi_level, utf8_bytes)
282 }
283}
284
285pub type LanguageRunIterator = RefHandle<SkShaper_LanguageRunIterator>;
286
287impl NativeBase<SkShaper_RunIterator> for SkShaper_LanguageRunIterator {}
288
289impl NativeDrop for SkShaper_LanguageRunIterator {
290 fn drop(&mut self) {
291 unsafe { sb::C_SkShaper_RunIterator_delete(self.base_mut()) }
292 }
293}
294
295impl fmt::Debug for LanguageRunIterator {
296 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
297 f.debug_struct("LanguageRunIterator")
298 .field("current_language", &self.current_language())
299 .finish()
300 }
301}
302
303impl LanguageRunIterator {
304 pub fn current_language(&self) -> &CStr {
305 unsafe {
306 CStr::from_ptr(sb::C_SkShaper_LanguageRunIterator_currentLanguage(
307 self.native(),
308 ))
309 }
310 }
311}
312
313impl Shaper {
314 pub fn new_std_language_run_iterator(utf8: &str) -> Option<LanguageRunIterator> {
315 let bytes = utf8.as_bytes();
318 LanguageRunIterator::from_ptr(unsafe {
319 sb::C_SkShaper_MakeStdLanguageRunIterator(bytes.as_ptr() as _, bytes.len())
320 })
321 }
322
323 pub fn new_trivial_language_run_iterator(
324 language: impl AsRef<str>,
325 utf8_bytes: usize,
326 ) -> LanguageRunIterator {
327 let language = CString::new(language.as_ref()).unwrap();
328 LanguageRunIterator::from_ptr(unsafe {
329 sb::C_SkShaper_TrivialLanguageRunIterator_new(language.as_ptr(), utf8_bytes)
330 })
331 .unwrap()
332 }
333}
334
335pub mod run_handler {
336 use std::{ffi::CStr, ops::Range, slice};
337
338 use skia_bindings::{SkShaper_RunHandler_Buffer, SkShaper_RunHandler_RunInfo};
339
340 use crate::{prelude::*, Font, FourByteTag, GlyphId, Point, Vector};
341
342 pub trait RunHandler {
343 fn begin_line(&mut self);
344 fn run_info(&mut self, info: &RunInfo);
345 fn commit_run_info(&mut self);
346 fn run_buffer(&mut self, info: &RunInfo) -> Buffer;
347 fn commit_run_buffer(&mut self, info: &RunInfo);
348 fn commit_line(&mut self);
349 }
350
351 #[derive(Debug)]
352 pub struct RunInfo<'a> {
353 pub font: &'a Font,
354 pub bidi_level: u8,
355 pub script: FourByteTag,
356 pub language: Option<&'a str>,
357 pub advance: Vector,
358 pub glyph_count: usize,
359 pub utf8_range: Range<usize>,
360 }
361
362 impl RunInfo<'_> {
363 pub(crate) fn from_native(ri: &SkShaper_RunHandler_RunInfo) -> Self {
364 let utf8_range = ri.utf8Range;
365 RunInfo {
366 font: Font::from_native_ref(unsafe { &*ri.fFont }),
367 bidi_level: ri.fBidiLevel,
368 script: ri.fScript.into(),
369 language: unsafe {
370 if ri.fLanguage.is_null() {
371 None
372 } else {
373 CStr::from_ptr(ri.fLanguage).to_str().ok()
374 }
375 },
376 advance: Vector::from_native_c(ri.fAdvance),
377 glyph_count: ri.glyphCount,
378 utf8_range: utf8_range.fBegin..utf8_range.fBegin + utf8_range.fSize,
379 }
380 }
381 }
382
383 #[derive(Debug)]
384 pub struct Buffer<'a> {
385 pub glyphs: &'a mut [GlyphId],
386 pub positions: &'a mut [Point],
387 pub offsets: Option<&'a mut [Point]>,
388 pub clusters: Option<&'a mut [u32]>,
389 pub point: Point,
390 }
391
392 impl<'a> Buffer<'a> {
393 pub fn new(
394 glyphs: &'a mut [GlyphId],
395 positions: &'a mut [Point],
396 point: impl Into<Option<Point>>,
397 ) -> Self {
398 Buffer {
399 glyphs,
400 positions,
401 offsets: None,
402 clusters: None,
403 point: point.into().unwrap_or_default(),
404 }
405 }
406
407 #[allow(unused)]
408 pub(crate) unsafe fn from_native(
409 buffer: &SkShaper_RunHandler_Buffer,
410 glyph_count: usize,
411 ) -> Buffer {
412 let offsets = buffer.offsets.into_non_null().map(|mut offsets| {
413 slice::from_raw_parts_mut(Point::from_native_ref_mut(offsets.as_mut()), glyph_count)
414 });
415
416 let clusters = buffer
417 .clusters
418 .into_non_null()
419 .map(|clusters| slice::from_raw_parts_mut(clusters.as_ptr(), glyph_count));
420
421 Buffer {
422 glyphs: safer::from_raw_parts_mut(buffer.glyphs, glyph_count),
423 positions: safer::from_raw_parts_mut(
424 Point::from_native_ptr_mut(buffer.positions),
425 glyph_count,
426 ),
427 offsets,
428 clusters,
429 point: Point::from_native_c(buffer.point),
430 }
431 }
432
433 pub(crate) fn native_buffer_mut(
434 &mut self,
435 glyph_count: usize,
436 ) -> SkShaper_RunHandler_Buffer {
437 assert_eq!(self.glyphs.len(), glyph_count);
438 assert_eq!(self.positions.len(), glyph_count);
439 if let Some(offsets) = &self.offsets {
440 assert_eq!(offsets.len(), glyph_count)
441 }
442 if let Some(clusters) = &self.clusters {
443 assert_eq!(clusters.len(), glyph_count)
444 }
445 SkShaper_RunHandler_Buffer {
446 glyphs: self.glyphs.as_mut_ptr(),
447 positions: self.positions.native_mut().as_mut_ptr(),
448 offsets: self.offsets.native_mut().as_ptr_or_null_mut(),
449 clusters: self.clusters.as_ptr_or_null_mut(),
450 point: self.point.into_native(),
451 }
452 }
453 }
454}
455
456pub trait AsRunHandler<'a> {
457 type RunHandler: AsNativeRunHandler + 'a;
458 fn as_run_handler<'b>(&'b mut self) -> Self::RunHandler
459 where
460 'b: 'a;
461}
462
463pub trait AsNativeRunHandler {
465 fn as_native_run_handler(&mut self) -> &mut SkShaper_RunHandler;
466}
467
468impl<'a, T: RunHandler> AsRunHandler<'a> for T {
469 type RunHandler = RustRunHandler;
470
471 fn as_run_handler<'b>(&'b mut self) -> Self::RunHandler
472 where
473 'b: 'a,
474 {
475 let param = unsafe { rust_run_handler::new_param(self) };
476 rust_run_handler::from_param(¶m)
477 }
478}
479
480impl Shaper {
481 pub fn shape<'a, 'b: 'a>(
482 &self,
483 utf8: &str,
484 font: &Font,
485 left_to_right: bool,
486 width: scalar,
487 run_handler: &'b mut impl AsRunHandler<'a>,
488 ) {
489 let bytes = utf8.as_bytes();
490 let mut run_handler = run_handler.as_run_handler();
491
492 unsafe {
493 sb::C_SkShaper_shape(
494 self.native(),
495 bytes.as_ptr() as _,
496 bytes.len(),
497 font.native(),
498 left_to_right,
499 width,
500 run_handler.as_native_run_handler(),
501 )
502 }
503 }
504
505 #[allow(clippy::too_many_arguments)]
506 pub fn shape_with_iterators<'a, 'b: 'a>(
507 &self,
508 utf8: &str,
509 font_run_iterator: &mut FontRunIterator,
510 bidi_run_iterator: &mut BiDiRunIterator,
511 script_run_iterator: &mut ScriptRunIterator,
512 language_run_iterator: &mut LanguageRunIterator,
513 width: scalar,
514 run_handler: &'b mut impl AsRunHandler<'a>,
515 ) {
516 let mut run_handler = run_handler.as_run_handler();
517
518 let bytes = utf8.as_bytes();
519 unsafe {
520 sb::C_SkShaper_shape2(
521 self.native(),
522 bytes.as_ptr() as _,
523 bytes.len(),
524 font_run_iterator.native_mut(),
525 bidi_run_iterator.native_mut(),
526 script_run_iterator.native_mut(),
527 language_run_iterator.native_mut(),
528 width,
529 run_handler.as_native_run_handler(),
530 )
531 }
532 }
533
534 #[allow(clippy::too_many_arguments)]
535 pub fn shape_with_iterators_and_features<'a, 'b: 'a>(
536 &self,
537 utf8: &str,
538 font_run_iterator: &mut FontRunIterator,
539 bidi_run_iterator: &mut BiDiRunIterator,
540 script_run_iterator: &mut ScriptRunIterator,
541 language_run_iterator: &mut LanguageRunIterator,
542 features: &[Feature],
543 width: scalar,
544 run_handler: &'b mut impl AsRunHandler<'a>,
545 ) {
546 let mut run_handler = run_handler.as_run_handler();
547
548 let bytes = utf8.as_bytes();
549 unsafe {
550 sb::C_SkShaper_shape3(
551 self.native(),
552 bytes.as_ptr() as _,
553 bytes.len(),
554 font_run_iterator.native_mut(),
555 bidi_run_iterator.native_mut(),
556 script_run_iterator.native_mut(),
557 language_run_iterator.native_mut(),
558 features.as_ptr(),
559 features.len(),
560 width,
561 run_handler.as_native_run_handler(),
562 )
563 }
564 }
565}
566
567mod rust_run_handler {
568 use std::mem;
569
570 use skia_bindings as sb;
571 use skia_bindings::{
572 RustRunHandler, RustRunHandler_Param, SkShaper_RunHandler, SkShaper_RunHandler_Buffer,
573 SkShaper_RunHandler_RunInfo, TraitObject,
574 };
575
576 use crate::{
577 prelude::*,
578 shaper::{run_handler::RunInfo, AsNativeRunHandler, RunHandler},
579 };
580
581 impl NativeBase<SkShaper_RunHandler> for RustRunHandler {}
582
583 impl AsNativeRunHandler for RustRunHandler {
584 fn as_native_run_handler(&mut self) -> &mut SkShaper_RunHandler {
585 self.base_mut()
586 }
587 }
588
589 pub unsafe fn new_param(run_handler: &mut dyn RunHandler) -> RustRunHandler_Param {
590 RustRunHandler_Param {
591 trait_: mem::transmute::<&mut dyn RunHandler, TraitObject>(run_handler),
592 beginLine: Some(begin_line),
593 runInfo: Some(run_info),
594 commitRunInfo: Some(commit_run_info),
595 runBuffer: Some(run_buffer),
596 commitRunBuffer: Some(commit_run_buffer),
597 commitLine: Some(commit_line),
598 }
599 }
600
601 pub fn from_param(param: &RustRunHandler_Param) -> RustRunHandler {
602 construct(|rh| unsafe { sb::C_RustRunHandler_construct(rh, param) })
603 }
604
605 extern "C" fn begin_line(to: TraitObject) {
606 to_run_handler(to).begin_line()
607 }
608
609 extern "C" fn run_info(to: TraitObject, ri: *const SkShaper_RunHandler_RunInfo) {
610 to_run_handler(to).run_info(&RunInfo::from_native(unsafe { &*ri }));
611 }
612
613 extern "C" fn commit_run_info(to: TraitObject) {
614 to_run_handler(to).commit_run_info()
615 }
616
617 extern "C" fn run_buffer(
618 to: TraitObject,
619 ri: *const SkShaper_RunHandler_RunInfo,
620 ) -> SkShaper_RunHandler_Buffer {
621 let ri = unsafe { &*ri };
622 to_run_handler(to)
623 .run_buffer(&RunInfo::from_native(ri))
624 .native_buffer_mut(ri.glyphCount)
625 }
626
627 extern "C" fn commit_run_buffer(to: TraitObject, ri: *const SkShaper_RunHandler_RunInfo) {
628 to_run_handler(to).commit_run_buffer(&RunInfo::from_native(unsafe { &*ri }))
629 }
630
631 extern "C" fn commit_line(to: TraitObject) {
632 to_run_handler(to).commit_line()
633 }
634
635 fn to_run_handler<'a>(to: TraitObject) -> &'a mut dyn RunHandler {
636 unsafe { mem::transmute(to) }
637 }
638}
639
640#[repr(transparent)]
641#[derive(Debug)]
642pub struct TextBlobBuilderRunHandler<'text>(SkTextBlobBuilderRunHandler, PhantomData<&'text str>);
643
644impl NativeAccess for TextBlobBuilderRunHandler<'_> {
645 type Native = SkTextBlobBuilderRunHandler;
646
647 fn native(&self) -> &SkTextBlobBuilderRunHandler {
648 &self.0
649 }
650 fn native_mut(&mut self) -> &mut SkTextBlobBuilderRunHandler {
651 &mut self.0
652 }
653}
654
655impl NativeBase<SkShaper_RunHandler> for SkTextBlobBuilderRunHandler {}
656
657impl TextBlobBuilderRunHandler<'_> {
658 pub fn new(text: &str, offset: impl Into<Point>) -> TextBlobBuilderRunHandler {
659 let ptr = text.as_ptr();
660 let run_handler = construct(|rh| unsafe {
665 sb::C_SkTextBlobBuilderRunHandler_construct(
666 rh,
667 ptr as *const raw::c_char,
668 offset.into().native(),
669 )
670 });
671 TextBlobBuilderRunHandler(run_handler, PhantomData)
672 }
673
674 pub fn make_blob(&mut self) -> Option<TextBlob> {
675 TextBlob::from_ptr(unsafe { sb::C_SkTextBlobBuilderRunHandler_makeBlob(self.native_mut()) })
676 }
677
678 pub fn end_point(&mut self) -> Point {
679 Point::from_native_c(unsafe {
680 sb::C_SkTextBlobBuilderRunHandler_endPoint(self.native_mut())
681 })
682 }
683}
684
685impl<'a> AsRunHandler<'a> for TextBlobBuilderRunHandler<'_> {
686 type RunHandler = &'a mut SkShaper_RunHandler;
687
688 fn as_run_handler<'b>(&'b mut self) -> Self::RunHandler
689 where
690 'b: 'a,
691 {
692 (*self).as_native_run_handler()
693 }
694}
695
696impl AsNativeRunHandler for &mut SkShaper_RunHandler {
697 fn as_native_run_handler(&mut self) -> &mut SkShaper_RunHandler {
698 self
699 }
700}
701
702impl AsNativeRunHandler for TextBlobBuilderRunHandler<'_> {
703 fn as_native_run_handler(&mut self) -> &mut SkShaper_RunHandler {
704 self.0.base_mut()
705 }
706}
707
708impl Shaper {
709 pub fn shape_text_blob(
710 &self,
711 text: &str,
712 font: &Font,
713 left_to_right: bool,
714 width: scalar,
715 offset: impl Into<Point>,
716 ) -> Option<(TextBlob, Point)> {
717 let bytes = text.as_bytes();
718 let mut builder = TextBlobBuilderRunHandler::new(text, offset);
719 unsafe {
720 sb::C_SkShaper_shape(
721 self.native(),
722 bytes.as_ptr() as _,
723 bytes.len(),
724 font.native(),
725 left_to_right,
726 width,
727 builder.native_mut().base_mut(),
728 )
729 };
730 builder.make_blob().map(|tb| (tb, builder.end_point()))
731 }
732}
733
734pub(crate) mod shapers {
735 use super::{BiDiRunIterator, ScriptRunIterator, Shaper};
736
737 #[deprecated(since = "0.74.0", note = "use shapers::primitive::primitive_text()")]
738 pub fn primitive() -> Shaper {
739 primitive::primitive_text()
740 }
741
742 #[deprecated(
743 since = "0.74.0",
744 note = "use shapers::primitive::trivial_bidi_run_iterator()"
745 )]
746 pub fn trivial_bidi_run_iterator(bidi_level: u8, utf8_bytes: usize) -> BiDiRunIterator {
747 primitive::trivial_bidi_run_iterator(bidi_level, utf8_bytes)
748 }
749
750 #[deprecated(
751 since = "0.74.0",
752 note = "use shapers::primitive::trivial_script_run_iterator()"
753 )]
754 pub fn trivial_script_run_iterator(bidi_level: u8, utf8_bytes: usize) -> ScriptRunIterator {
755 primitive::trivial_script_run_iterator(bidi_level, utf8_bytes)
756 }
757
758 pub mod primitive {
759 use skia_bindings as sb;
760
761 use crate::shaper::{BiDiRunIterator, ScriptRunIterator, Shaper};
762
763 pub fn primitive_text() -> Shaper {
764 Shaper::from_ptr(unsafe { sb::C_SkShapers_Primitive_PrimitiveText() }).unwrap()
765 }
766
767 pub fn trivial_bidi_run_iterator(bidi_level: u8, utf8_bytes: usize) -> BiDiRunIterator {
768 BiDiRunIterator::from_ptr(unsafe {
769 sb::C_SkShapers_Primitive_TrivialBidiRunIterator_new(bidi_level, utf8_bytes)
770 })
771 .unwrap()
772 }
773
774 pub fn trivial_script_run_iterator(bidi_level: u8, utf8_bytes: usize) -> ScriptRunIterator {
775 ScriptRunIterator::from_ptr(unsafe {
776 sb::C_SkShapers_Primitive_TrivialScriptRunIterator_new(bidi_level, utf8_bytes)
777 })
778 .unwrap()
779 }
780 }
781}
782
783pub mod icu {
784 pub fn init() {
796 skia_bindings::icu::init();
797 }
798
799 #[test]
800 #[serial_test::serial]
801 fn test_text_blob_builder_run_handler() {
802 use crate::{Font, FontMgr, FontStyle};
803 init();
804 let str = "العربية";
805 let mut text_blob_builder_run_handler =
806 crate::shaper::TextBlobBuilderRunHandler::new(str, crate::Point::default());
807
808 let font_mgr = FontMgr::new();
809 let default_typeface = font_mgr
810 .legacy_make_typeface(None, FontStyle::default())
811 .unwrap();
812 let default_font = Font::new(default_typeface, 10.0);
813 let shaper = crate::Shaper::new(font_mgr);
814 shaper.shape(
815 str,
816 &default_font,
817 false,
818 10000.0,
819 &mut text_blob_builder_run_handler,
820 );
821
822 let blob = text_blob_builder_run_handler.make_blob().unwrap();
823 let bounds = blob.bounds();
824 assert!(bounds.width() > 0.0 && bounds.height() > 0.0);
825 }
826
827 #[test]
828 #[serial_test::serial]
829 fn icu_init_is_idempotent() {
830 init();
831 init();
832 }
833}