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 crate::prelude::*;
337 use crate::{Font, GlyphId, Point, Vector};
338 use skia_bindings::{
339 SkShaper_RunHandler_Buffer, SkShaper_RunHandler_Range, SkShaper_RunHandler_RunInfo,
340 };
341 use std::ops::Range;
342 use std::slice;
343
344 pub trait RunHandler {
345 fn begin_line(&mut self);
346 fn run_info(&mut self, info: &RunInfo);
347 fn commit_run_info(&mut self);
348 fn run_buffer(&mut self, info: &RunInfo) -> Buffer;
349 fn commit_run_buffer(&mut self, info: &RunInfo);
350 fn commit_line(&mut self);
351 }
352
353 #[derive(Debug)]
354 pub struct RunInfo<'a> {
355 pub font: &'a Font,
356 pub bidi_level: u8,
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;
366 RunInfo {
367 font: Font::from_native_ref(unsafe { &*ri.fFont }),
368 bidi_level: ri.fBidiLevel,
369 advance: Vector::from_native_c(ri.fAdvance),
370 glyph_count: ri.glyphCount,
371 utf8_range: utf8_range.fBegin..utf8_range.fBegin + utf8_range.fSize,
372 }
373 }
374
375 #[allow(unused)]
376 pub(crate) fn to_native(&self) -> SkShaper_RunHandler_RunInfo {
377 SkShaper_RunHandler_RunInfo {
378 fFont: self.font.native(),
379 fBidiLevel: self.bidi_level,
380 fAdvance: self.advance.into_native(),
381 glyphCount: self.glyph_count,
382 utf8Range: SkShaper_RunHandler_Range {
383 fBegin: self.utf8_range.start,
384 fSize: self.utf8_range.end - self.utf8_range.start,
385 },
386 }
387 }
388 }
389
390 #[derive(Debug)]
391 pub struct Buffer<'a> {
392 pub glyphs: &'a mut [GlyphId],
393 pub positions: &'a mut [Point],
394 pub offsets: Option<&'a mut [Point]>,
395 pub clusters: Option<&'a mut [u32]>,
396 pub point: Point,
397 }
398
399 impl<'a> Buffer<'a> {
400 pub fn new(
401 glyphs: &'a mut [GlyphId],
402 positions: &'a mut [Point],
403 point: impl Into<Option<Point>>,
404 ) -> Self {
405 Buffer {
406 glyphs,
407 positions,
408 offsets: None,
409 clusters: None,
410 point: point.into().unwrap_or_default(),
411 }
412 }
413
414 #[allow(unused)]
415 pub(crate) unsafe fn from_native(
416 buffer: &SkShaper_RunHandler_Buffer,
417 glyph_count: usize,
418 ) -> Buffer {
419 let offsets = buffer.offsets.into_option().map(|mut offsets| {
420 slice::from_raw_parts_mut(Point::from_native_ref_mut(offsets.as_mut()), glyph_count)
421 });
422
423 let clusters = buffer
424 .clusters
425 .into_option()
426 .map(|clusters| slice::from_raw_parts_mut(clusters.as_ptr(), glyph_count));
427
428 Buffer {
429 glyphs: safer::from_raw_parts_mut(buffer.glyphs, glyph_count),
430 positions: safer::from_raw_parts_mut(
431 Point::from_native_ptr_mut(buffer.positions),
432 glyph_count,
433 ),
434 offsets,
435 clusters,
436 point: Point::from_native_c(buffer.point),
437 }
438 }
439
440 pub(crate) fn native_buffer_mut(
441 &mut self,
442 glyph_count: usize,
443 ) -> SkShaper_RunHandler_Buffer {
444 assert_eq!(self.glyphs.len(), glyph_count);
445 assert_eq!(self.positions.len(), glyph_count);
446 if let Some(offsets) = &self.offsets {
447 assert_eq!(offsets.len(), glyph_count)
448 }
449 if let Some(clusters) = &self.clusters {
450 assert_eq!(clusters.len(), glyph_count)
451 }
452 SkShaper_RunHandler_Buffer {
453 glyphs: self.glyphs.as_mut_ptr(),
454 positions: self.positions.native_mut().as_mut_ptr(),
455 offsets: self.offsets.native_mut().as_ptr_or_null_mut(),
456 clusters: self.clusters.as_ptr_or_null_mut(),
457 point: self.point.into_native(),
458 }
459 }
460 }
461}
462
463pub trait AsRunHandler<'a> {
464 type RunHandler: AsNativeRunHandler + 'a;
465 fn as_run_handler<'b>(&'b mut self) -> Self::RunHandler
466 where
467 'b: 'a;
468}
469
470pub trait AsNativeRunHandler {
472 fn as_native_run_handler(&mut self) -> &mut SkShaper_RunHandler;
473}
474
475impl<'a, T: RunHandler> AsRunHandler<'a> for T {
476 type RunHandler = RustRunHandler;
477
478 fn as_run_handler<'b>(&'b mut self) -> Self::RunHandler
479 where
480 'b: 'a,
481 {
482 let param = unsafe { rust_run_handler::new_param(self) };
483 rust_run_handler::from_param(¶m)
484 }
485}
486
487impl Shaper {
488 pub fn shape<'a, 'b: 'a>(
489 &self,
490 utf8: &str,
491 font: &Font,
492 left_to_right: bool,
493 width: scalar,
494 run_handler: &'b mut impl AsRunHandler<'a>,
495 ) {
496 let bytes = utf8.as_bytes();
497 let mut run_handler = run_handler.as_run_handler();
498
499 unsafe {
500 sb::C_SkShaper_shape(
501 self.native(),
502 bytes.as_ptr() as _,
503 bytes.len(),
504 font.native(),
505 left_to_right,
506 width,
507 run_handler.as_native_run_handler(),
508 )
509 }
510 }
511
512 #[allow(clippy::too_many_arguments)]
513 pub fn shape_with_iterators<'a, 'b: 'a>(
514 &self,
515 utf8: &str,
516 font_run_iterator: &mut FontRunIterator,
517 bidi_run_iterator: &mut BiDiRunIterator,
518 script_run_iterator: &mut ScriptRunIterator,
519 language_run_iterator: &mut LanguageRunIterator,
520 width: scalar,
521 run_handler: &'b mut impl AsRunHandler<'a>,
522 ) {
523 let mut run_handler = run_handler.as_run_handler();
524
525 let bytes = utf8.as_bytes();
526 unsafe {
527 sb::C_SkShaper_shape2(
528 self.native(),
529 bytes.as_ptr() as _,
530 bytes.len(),
531 font_run_iterator.native_mut(),
532 bidi_run_iterator.native_mut(),
533 script_run_iterator.native_mut(),
534 language_run_iterator.native_mut(),
535 width,
536 run_handler.as_native_run_handler(),
537 )
538 }
539 }
540
541 #[allow(clippy::too_many_arguments)]
542 pub fn shape_with_iterators_and_features<'a, 'b: 'a>(
543 &self,
544 utf8: &str,
545 font_run_iterator: &mut FontRunIterator,
546 bidi_run_iterator: &mut BiDiRunIterator,
547 script_run_iterator: &mut ScriptRunIterator,
548 language_run_iterator: &mut LanguageRunIterator,
549 features: &[Feature],
550 width: scalar,
551 run_handler: &'b mut impl AsRunHandler<'a>,
552 ) {
553 let mut run_handler = run_handler.as_run_handler();
554
555 let bytes = utf8.as_bytes();
556 unsafe {
557 sb::C_SkShaper_shape3(
558 self.native(),
559 bytes.as_ptr() as _,
560 bytes.len(),
561 font_run_iterator.native_mut(),
562 bidi_run_iterator.native_mut(),
563 script_run_iterator.native_mut(),
564 language_run_iterator.native_mut(),
565 features.as_ptr(),
566 features.len(),
567 width,
568 run_handler.as_native_run_handler(),
569 )
570 }
571 }
572}
573
574mod rust_run_handler {
575 use std::mem;
576
577 use skia_bindings as sb;
578 use skia_bindings::{
579 RustRunHandler, RustRunHandler_Param, SkShaper_RunHandler, SkShaper_RunHandler_Buffer,
580 SkShaper_RunHandler_RunInfo, TraitObject,
581 };
582
583 use crate::{
584 prelude::*,
585 shaper::{run_handler::RunInfo, AsNativeRunHandler, RunHandler},
586 };
587
588 impl NativeBase<SkShaper_RunHandler> for RustRunHandler {}
589
590 impl AsNativeRunHandler for RustRunHandler {
591 fn as_native_run_handler(&mut self) -> &mut SkShaper_RunHandler {
592 self.base_mut()
593 }
594 }
595
596 pub unsafe fn new_param(run_handler: &mut dyn RunHandler) -> RustRunHandler_Param {
597 RustRunHandler_Param {
598 trait_: mem::transmute::<&mut dyn RunHandler, TraitObject>(run_handler),
599 beginLine: Some(begin_line),
600 runInfo: Some(run_info),
601 commitRunInfo: Some(commit_run_info),
602 runBuffer: Some(run_buffer),
603 commitRunBuffer: Some(commit_run_buffer),
604 commitLine: Some(commit_line),
605 }
606 }
607
608 pub fn from_param(param: &RustRunHandler_Param) -> RustRunHandler {
609 construct(|rh| unsafe { sb::C_RustRunHandler_construct(rh, param) })
610 }
611
612 extern "C" fn begin_line(to: TraitObject) {
613 to_run_handler(to).begin_line()
614 }
615
616 extern "C" fn run_info(to: TraitObject, ri: *const SkShaper_RunHandler_RunInfo) {
617 to_run_handler(to).run_info(&RunInfo::from_native(unsafe { &*ri }));
618 }
619
620 extern "C" fn commit_run_info(to: TraitObject) {
621 to_run_handler(to).commit_run_info()
622 }
623
624 extern "C" fn run_buffer(
625 to: TraitObject,
626 ri: *const SkShaper_RunHandler_RunInfo,
627 ) -> SkShaper_RunHandler_Buffer {
628 let ri = unsafe { &*ri };
629 to_run_handler(to)
630 .run_buffer(&RunInfo::from_native(ri))
631 .native_buffer_mut(ri.glyphCount)
632 }
633
634 extern "C" fn commit_run_buffer(to: TraitObject, ri: *const SkShaper_RunHandler_RunInfo) {
635 to_run_handler(to).commit_run_buffer(&RunInfo::from_native(unsafe { &*ri }))
636 }
637
638 extern "C" fn commit_line(to: TraitObject) {
639 to_run_handler(to).commit_line()
640 }
641
642 fn to_run_handler<'a>(to: TraitObject) -> &'a mut dyn RunHandler {
643 unsafe { mem::transmute(to) }
644 }
645}
646
647#[repr(transparent)]
648#[derive(Debug)]
649pub struct TextBlobBuilderRunHandler<'text>(SkTextBlobBuilderRunHandler, PhantomData<&'text str>);
650
651impl NativeAccess for TextBlobBuilderRunHandler<'_> {
652 type Native = SkTextBlobBuilderRunHandler;
653
654 fn native(&self) -> &SkTextBlobBuilderRunHandler {
655 &self.0
656 }
657 fn native_mut(&mut self) -> &mut SkTextBlobBuilderRunHandler {
658 &mut self.0
659 }
660}
661
662impl NativeBase<SkShaper_RunHandler> for SkTextBlobBuilderRunHandler {}
663
664impl TextBlobBuilderRunHandler<'_> {
665 pub fn new(text: &str, offset: impl Into<Point>) -> TextBlobBuilderRunHandler {
666 let ptr = text.as_ptr();
667 let run_handler = construct(|rh| unsafe {
672 sb::C_SkTextBlobBuilderRunHandler_construct(
673 rh,
674 ptr as *const raw::c_char,
675 offset.into().native(),
676 )
677 });
678 TextBlobBuilderRunHandler(run_handler, PhantomData)
679 }
680
681 pub fn make_blob(&mut self) -> Option<TextBlob> {
682 TextBlob::from_ptr(unsafe { sb::C_SkTextBlobBuilderRunHandler_makeBlob(self.native_mut()) })
683 }
684
685 pub fn end_point(&mut self) -> Point {
686 Point::from_native_c(unsafe {
687 sb::C_SkTextBlobBuilderRunHandler_endPoint(self.native_mut())
688 })
689 }
690}
691
692impl<'a> AsRunHandler<'a> for TextBlobBuilderRunHandler<'_> {
693 type RunHandler = &'a mut SkShaper_RunHandler;
694
695 fn as_run_handler<'b>(&'b mut self) -> Self::RunHandler
696 where
697 'b: 'a,
698 {
699 (*self).as_native_run_handler()
700 }
701}
702
703impl AsNativeRunHandler for &mut SkShaper_RunHandler {
704 fn as_native_run_handler(&mut self) -> &mut SkShaper_RunHandler {
705 self
706 }
707}
708
709impl AsNativeRunHandler for TextBlobBuilderRunHandler<'_> {
710 fn as_native_run_handler(&mut self) -> &mut SkShaper_RunHandler {
711 self.0.base_mut()
712 }
713}
714
715impl Shaper {
716 pub fn shape_text_blob(
717 &self,
718 text: &str,
719 font: &Font,
720 left_to_right: bool,
721 width: scalar,
722 offset: impl Into<Point>,
723 ) -> Option<(TextBlob, Point)> {
724 let bytes = text.as_bytes();
725 let mut builder = TextBlobBuilderRunHandler::new(text, offset);
726 unsafe {
727 sb::C_SkShaper_shape(
728 self.native(),
729 bytes.as_ptr() as _,
730 bytes.len(),
731 font.native(),
732 left_to_right,
733 width,
734 builder.native_mut().base_mut(),
735 )
736 };
737 builder.make_blob().map(|tb| (tb, builder.end_point()))
738 }
739}
740
741pub(crate) mod shapers {
742 use super::{BiDiRunIterator, ScriptRunIterator, Shaper};
743
744 #[deprecated(since = "0.74.0", note = "use shapers::primitive::primitive_text()")]
745 pub fn primitive() -> Shaper {
746 primitive::primitive_text()
747 }
748
749 #[deprecated(
750 since = "0.74.0",
751 note = "use shapers::primitive::trivial_bidi_run_iterator()"
752 )]
753 pub fn trivial_bidi_run_iterator(bidi_level: u8, utf8_bytes: usize) -> BiDiRunIterator {
754 primitive::trivial_bidi_run_iterator(bidi_level, utf8_bytes)
755 }
756
757 #[deprecated(
758 since = "0.74.0",
759 note = "use shapers::primitive::trivial_script_run_iterator()"
760 )]
761 pub fn trivial_script_run_iterator(bidi_level: u8, utf8_bytes: usize) -> ScriptRunIterator {
762 primitive::trivial_script_run_iterator(bidi_level, utf8_bytes)
763 }
764
765 pub mod primitive {
766 use skia_bindings as sb;
767
768 use crate::shaper::{BiDiRunIterator, ScriptRunIterator, Shaper};
769
770 pub fn primitive_text() -> Shaper {
771 Shaper::from_ptr(unsafe { sb::C_SkShapers_Primitive_PrimitiveText() }).unwrap()
772 }
773
774 pub fn trivial_bidi_run_iterator(bidi_level: u8, utf8_bytes: usize) -> BiDiRunIterator {
775 BiDiRunIterator::from_ptr(unsafe {
776 sb::C_SkShapers_Primitive_TrivialBidiRunIterator_new(bidi_level, utf8_bytes)
777 })
778 .unwrap()
779 }
780
781 pub fn trivial_script_run_iterator(bidi_level: u8, utf8_bytes: usize) -> ScriptRunIterator {
782 ScriptRunIterator::from_ptr(unsafe {
783 sb::C_SkShapers_Primitive_TrivialScriptRunIterator_new(bidi_level, utf8_bytes)
784 })
785 .unwrap()
786 }
787 }
788}
789
790pub mod icu {
791 pub fn init() {
803 skia_bindings::icu::init();
804 }
805
806 #[test]
807 #[serial_test::serial]
808 fn test_text_blob_builder_run_handler() {
809 use crate::{Font, FontMgr, FontStyle};
810 init();
811 let str = "العربية";
812 let mut text_blob_builder_run_handler =
813 crate::shaper::TextBlobBuilderRunHandler::new(str, crate::Point::default());
814
815 let font_mgr = FontMgr::new();
816 let default_typeface = font_mgr
817 .legacy_make_typeface(None, FontStyle::default())
818 .unwrap();
819 let default_font = Font::new(default_typeface, 10.0);
820 let shaper = crate::Shaper::new(font_mgr);
821 shaper.shape(
822 str,
823 &default_font,
824 false,
825 10000.0,
826 &mut text_blob_builder_run_handler,
827 );
828
829 let blob = text_blob_builder_run_handler.make_blob().unwrap();
830 let bounds = blob.bounds();
831 assert!(bounds.width() > 0.0 && bounds.height() > 0.0);
832 }
833
834 #[test]
835 #[serial_test::serial]
836 fn icu_init_is_idempotent() {
837 init();
838 init();
839 }
840}