1use super::{FontArguments, FontFamilies, TextBaseline, TextShadow};
2use crate::{
3 Color, FontHinting, FontMetrics, FontStyle, Paint, Typeface, font,
4 interop::{self, AsStr, FromStrs, SetStr},
5 prelude::*,
6 scalar,
7 textlayout::{EMPTY_INDEX, EMPTY_RANGE, RangeExtensions},
8};
9use skia_bindings as sb;
10use std::{fmt, ops::Range};
11
12bitflags! {
13 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
16 pub struct TextDecoration: u32 {
17 const NO_DECORATION = sb::skia_textlayout_TextDecoration::kNoDecoration as _;
18 const UNDERLINE = sb::skia_textlayout_TextDecoration::kUnderline as _;
19 const OVERLINE = sb::skia_textlayout_TextDecoration::kOverline as _;
20 const LINE_THROUGH = sb::skia_textlayout_TextDecoration::kLineThrough as _;
21 }
22}
23
24pub const ALL_TEXT_DECORATIONS: TextDecoration = TextDecoration::ALL;
25
26impl Default for TextDecoration {
27 fn default() -> Self {
28 TextDecoration::NO_DECORATION
29 }
30}
31
32impl TextDecoration {
33 pub const ALL: TextDecoration = TextDecoration::all();
34}
35
36pub use sb::skia_textlayout_TextDecorationStyle as TextDecorationStyle;
37#[test]
38fn text_decoration_style_naming() {
39 let _ = TextDecorationStyle::Solid;
40}
41
42pub use sb::skia_textlayout_TextDecorationMode as TextDecorationMode;
43#[test]
44fn text_decoration_mode_naming() {
45 let _ = TextDecorationMode::Gaps;
46}
47
48pub use sb::skia_textlayout_StyleType as StyleType;
49#[test]
50fn style_type_member_naming() {
51 let _ = StyleType::Foreground;
52 let _ = StyleType::LetterSpacing;
53}
54
55#[repr(C)]
56#[derive(Copy, Clone, PartialEq, Debug)]
57pub struct Decoration {
58 pub ty: TextDecoration,
59 pub mode: TextDecorationMode,
60 pub color: Color,
61 pub style: TextDecorationStyle,
62 pub thickness_multiplier: scalar,
63}
64
65impl Default for Decoration {
66 fn default() -> Self {
67 Self {
68 ty: TextDecoration::default(),
69 mode: TextDecorationMode::default(),
70 color: Color::TRANSPARENT,
71 style: TextDecorationStyle::default(),
72 thickness_multiplier: 1.0,
73 }
74 }
75}
76
77native_transmutable!(sb::skia_textlayout_Decoration, Decoration);
78
79#[repr(i32)]
81#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Default)]
82pub enum PlaceholderAlignment {
83 #[default]
85 Baseline,
86
87 AboveBaseline,
90
91 BelowBaseline,
94
95 Top,
99
100 Bottom,
104
105 Middle,
109}
110native_transmutable!(
111 sb::skia_textlayout_PlaceholderAlignment,
112 PlaceholderAlignment
113);
114
115pub type FontFeature = Handle<sb::skia_textlayout_FontFeature>;
116unsafe_send_sync!(FontFeature);
117
118impl NativeDrop for sb::skia_textlayout_FontFeature {
119 fn drop(&mut self) {
120 unsafe { sb::C_FontFeature_destruct(self) }
121 }
122}
123
124impl NativeClone for sb::skia_textlayout_FontFeature {
125 fn clone(&self) -> Self {
126 construct(|ts| unsafe { sb::C_FontFeature_CopyConstruct(ts, self) })
127 }
128}
129
130impl PartialEq for FontFeature {
131 fn eq(&self, other: &Self) -> bool {
132 self.name() == other.name() && self.value() == other.value()
133 }
134}
135
136impl fmt::Debug for FontFeature {
137 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138 f.debug_tuple("FontFeature")
139 .field(&self.name())
140 .field(&self.value())
141 .finish()
142 }
143}
144
145impl FontFeature {
146 pub fn name(&self) -> &str {
147 self.native().fName.as_str()
148 }
149
150 pub fn value(&self) -> i32 {
151 self.native().fValue
152 }
153}
154
155#[repr(C)]
156#[derive(Clone, Default, Debug)]
157pub struct PlaceholderStyle {
158 pub width: scalar,
159 pub height: scalar,
160 pub alignment: PlaceholderAlignment,
161 pub baseline: TextBaseline,
162 pub baseline_offset: scalar,
171}
172
173native_transmutable!(sb::skia_textlayout_PlaceholderStyle, PlaceholderStyle);
174
175impl PartialEq for PlaceholderStyle {
176 fn eq(&self, other: &Self) -> bool {
177 unsafe { self.native().equals(other.native()) }
178 }
179}
180
181impl PlaceholderStyle {
182 pub fn new(
183 width: scalar,
184 height: scalar,
185 alignment: PlaceholderAlignment,
186 baseline: TextBaseline,
187 offset: scalar,
188 ) -> Self {
189 Self {
190 width,
191 height,
192 alignment,
193 baseline,
194 baseline_offset: offset,
195 }
196 }
197}
198
199pub type TextStyle = Handle<sb::skia_textlayout_TextStyle>;
200unsafe_send_sync!(TextStyle);
201
202impl NativeDrop for sb::skia_textlayout_TextStyle {
203 fn drop(&mut self) {
204 unsafe { sb::C_TextStyle_destruct(self) }
205 }
206}
207
208impl NativeClone for sb::skia_textlayout_TextStyle {
209 fn clone(&self) -> Self {
210 construct(|ts| unsafe { sb::C_TextStyle_CopyConstruct(ts, self) })
211 }
212}
213
214impl NativePartialEq for sb::skia_textlayout_TextStyle {
215 fn eq(&self, rhs: &Self) -> bool {
216 unsafe { self.equals(rhs) }
217 }
218}
219
220impl Default for TextStyle {
221 fn default() -> Self {
222 Self::new()
223 }
224}
225
226impl fmt::Debug for TextStyle {
227 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
228 f.debug_struct("TextStyle")
229 .field("color", &self.color())
230 .field("has_foreground", &self.has_foreground())
231 .field("foreground", &self.foreground())
232 .field("has_background", &self.has_background())
233 .field("background", &self.background())
234 .field("decoration", &self.decoration())
235 .field("font_style", &self.font_style())
236 .field("shadows", &self.shadows())
237 .field("font_features", &self.font_features())
238 .field("font_size", &self.font_size())
239 .field("font_families", &self.font_families())
240 .field("baseline_shift", &self.baseline_shift())
241 .field("height", &self.height())
242 .field("height_override", &self.height_override())
243 .field("half_leading", &self.half_leading())
244 .field("letter_spacing", &self.letter_spacing())
245 .field("word_spacing", &self.word_spacing())
246 .field("typeface", &self.typeface())
247 .field("locale", &self.locale())
248 .field("text_baseline", &self.text_baseline())
249 .field("is_placeholder", &self.is_placeholder())
250 .field("font_edging", &self.font_edging())
251 .field("subpixel", &self.subpixel())
252 .field("font_hinting", &self.font_hinting())
253 .finish()
254 }
255}
256
257impl TextStyle {
258 pub fn new() -> Self {
259 TextStyle::construct(|ts| unsafe { sb::C_TextStyle_Construct(ts) })
260 }
261
262 #[deprecated(since = "0.51.0", note = "Use clone_for_placeholder")]
263 #[must_use]
264 pub fn to_placeholder(&self) -> Self {
265 self.clone_for_placeholder()
266 }
267
268 #[must_use]
269 pub fn clone_for_placeholder(&self) -> Self {
270 Self::construct(|ts| unsafe { sb::C_TextStyle_cloneForPlaceholder(self.native(), ts) })
271 }
272
273 pub fn equals(&self, other: &TextStyle) -> bool {
274 *self == *other
275 }
276
277 pub fn equals_by_fonts(&self, that: &TextStyle) -> bool {
278 unsafe { self.native().equalsByFonts(that.native()) }
279 }
280
281 pub fn match_one_attribute(&self, style_type: StyleType, other: &TextStyle) -> bool {
282 unsafe { self.native().matchOneAttribute(style_type, other.native()) }
283 }
284
285 pub fn color(&self) -> Color {
286 Color::from_native_c(self.native().fColor)
287 }
288
289 pub fn set_color(&mut self, color: impl Into<Color>) -> &mut Self {
290 self.native_mut().fColor = color.into().into_native();
291 self
292 }
293
294 pub fn has_foreground(&self) -> bool {
295 self.native().fHasForeground
296 }
297
298 pub fn foreground(&self) -> Paint {
299 Paint::construct(|p| unsafe { sb::C_TextStyle_getForeground(self.native(), p) })
300 }
301
302 pub fn set_foreground_paint(&mut self, paint: &Paint) -> &mut Self {
303 unsafe { sb::C_TextStyle_setForegroundPaint(self.native_mut(), paint.native()) };
304 self
305 }
306
307 #[deprecated(since = "0.64.0", note = "use set_foreground_paint()")]
308 pub fn set_foreground_color(&mut self, paint: &Paint) -> &mut Self {
309 self.set_foreground_paint(paint)
310 }
311
312 pub fn clear_foreground_color(&mut self) -> &mut Self {
313 self.native_mut().fHasForeground = false;
314 self
315 }
316
317 pub fn has_background(&self) -> bool {
318 self.native().fHasBackground
319 }
320
321 pub fn background(&self) -> Paint {
322 Paint::construct(|p| unsafe { sb::C_TextStyle_getBackground(self.native(), p) })
323 }
324
325 pub fn set_background_paint(&mut self, paint: &Paint) -> &mut Self {
326 unsafe { sb::C_TextStyle_setBackgroundPaint(self.native_mut(), paint.native()) };
327 self
328 }
329
330 #[deprecated(since = "0.64.0", note = "use set_background_paint()")]
331 pub fn set_background_color(&mut self, paint: &Paint) -> &mut Self {
332 self.set_background_paint(paint)
333 }
334
335 pub fn clear_background_color(&mut self) -> &mut Self {
336 self.native_mut().fHasBackground = false;
337 self
338 }
339
340 pub fn decoration(&self) -> &Decoration {
341 Decoration::from_native_ref(&self.native().fDecoration)
342 }
343
344 pub fn decoration_type(&self) -> TextDecoration {
345 self.decoration().ty
346 }
347
348 pub fn decoration_mode(&self) -> TextDecorationMode {
349 self.decoration().mode
350 }
351
352 pub fn decoration_color(&self) -> Color {
353 self.decoration().color
354 }
355
356 pub fn decoration_style(&self) -> TextDecorationStyle {
357 self.decoration().style
358 }
359
360 pub fn decoration_thickness_multiplier(&self) -> scalar {
361 self.decoration().thickness_multiplier
362 }
363
364 pub fn set_decoration(&mut self, decoration: &Decoration) {
365 *self.decoration_mut_internal() = *decoration;
366 }
367
368 pub fn set_decoration_type(&mut self, decoration: TextDecoration) {
369 self.decoration_mut_internal().ty = decoration;
370 }
371
372 pub fn set_decoration_mode(&mut self, mode: TextDecorationMode) {
373 self.decoration_mut_internal().mode = mode;
374 }
375
376 pub fn set_decoration_style(&mut self, style: TextDecorationStyle) {
377 self.decoration_mut_internal().style = style;
378 }
379
380 pub fn set_decoration_color(&mut self, color: impl Into<Color>) {
381 self.decoration_mut_internal().color = color.into();
382 }
383
384 pub fn set_decoration_thickness_multiplier(&mut self, multiplier: scalar) {
385 self.decoration_mut_internal().thickness_multiplier = multiplier;
386 }
387
388 #[deprecated(since = "0.63.1", note = "use set_decoration()")]
389 pub fn decoration_mut(&mut self) -> &mut Decoration {
390 self.decoration_mut_internal()
391 }
392
393 fn decoration_mut_internal(&mut self) -> &mut Decoration {
394 Decoration::from_native_ref_mut(&mut self.native_mut().fDecoration)
395 }
396
397 pub fn font_style(&self) -> FontStyle {
398 FontStyle::from_native_c(self.native().fFontStyle)
399 }
400
401 pub fn set_font_style(&mut self, font_style: FontStyle) -> &mut Self {
402 self.native_mut().fFontStyle = font_style.into_native();
403 self
404 }
405
406 pub fn shadows(&self) -> &[TextShadow] {
407 unsafe {
408 let mut count = 0;
409 let ptr = sb::C_TextStyle_getShadows(&self.native().fTextShadows, &mut count);
410 safer::from_raw_parts(TextShadow::from_native_ptr(ptr), count)
411 }
412 }
413
414 pub fn add_shadow(&mut self, shadow: TextShadow) -> &mut Self {
415 unsafe { sb::C_TextStyle_addShadow(self.native_mut(), shadow.native()) }
416 self
417 }
418
419 pub fn reset_shadows(&mut self) -> &mut Self {
420 unsafe { sb::C_TextStyle_resetShadows(self.native_mut()) }
421 self
422 }
423
424 pub fn font_features(&self) -> &[FontFeature] {
425 unsafe {
426 let mut count = 0;
427 let ptr = sb::C_TextStyle_getFontFeatures(&self.native().fFontFeatures, &mut count);
428 safer::from_raw_parts(FontFeature::from_native_ptr(ptr), count)
429 }
430 }
431
432 pub fn add_font_feature(&mut self, font_feature: impl AsRef<str>, value: i32) {
433 let font_feature = interop::String::from_str(font_feature);
434 unsafe { sb::C_TextStyle_addFontFeature(self.native_mut(), font_feature.native(), value) }
435 }
436
437 pub fn reset_font_features(&mut self) {
438 unsafe { sb::C_TextStyle_resetFontFeatures(self.native_mut()) }
439 }
440
441 pub fn font_arguments(&self) -> Option<&FontArguments> {
442 unsafe { sb::C_TextStyle_getFontArguments(self.native()) }
443 .into_non_null()
444 .map(|ptr| FontArguments::from_native_ref(unsafe { ptr.as_ref() }))
445 }
446
447 pub fn set_font_arguments<'fa>(
449 &mut self,
450 arguments: impl Into<Option<&'fa crate::FontArguments<'fa, 'fa>>>,
451 ) {
452 unsafe {
453 sb::C_TextStyle_setFontArguments(
454 self.native_mut(),
455 arguments.into().native_ptr_or_null(),
456 )
457 }
458 }
459
460 pub fn font_size(&self) -> scalar {
461 self.native().fFontSize
462 }
463
464 pub fn set_font_size(&mut self, size: scalar) -> &mut Self {
465 self.native_mut().fFontSize = size;
466 self
467 }
468
469 pub fn font_families(&self) -> FontFamilies {
470 unsafe {
471 let mut count = 0;
472 let ptr = sb::C_TextStyle_getFontFamilies(self.native(), &mut count);
473 FontFamilies(safer::from_raw_parts(ptr, count))
474 }
475 }
476
477 pub fn set_font_families(&mut self, families: &[impl AsRef<str>]) -> &mut Self {
478 let families: Vec<interop::String> = FromStrs::from_strs(families);
479 let families = families.native();
480 unsafe {
481 sb::C_TextStyle_setFontFamilies(self.native_mut(), families.as_ptr(), families.len())
482 }
483 self
484 }
485
486 pub fn baseline_shift(&self) -> scalar {
487 self.native().fBaselineShift
488 }
489
490 pub fn set_baseline_shift(&mut self, baseline_shift: scalar) -> &mut Self {
491 self.native_mut().fBaselineShift = baseline_shift;
492 self
493 }
494
495 pub fn set_height(&mut self, height: scalar) -> &mut Self {
496 self.native_mut().fHeight = height;
497 self
498 }
499
500 pub fn height(&self) -> scalar {
501 let n = self.native();
502 if n.fHeightOverride { n.fHeight } else { 0.0 }
503 }
504
505 pub fn set_height_override(&mut self, height_override: bool) -> &mut Self {
506 self.native_mut().fHeightOverride = height_override;
507 self
508 }
509
510 pub fn height_override(&self) -> bool {
511 self.native().fHeightOverride
512 }
513
514 pub fn set_half_leading(&mut self, half_leading: bool) -> &mut Self {
515 self.native_mut().fHalfLeading = half_leading;
516 self
517 }
518
519 pub fn half_leading(&self) -> bool {
520 self.native().fHalfLeading
521 }
522
523 pub fn set_letter_spacing(&mut self, letter_spacing: scalar) -> &mut Self {
524 self.native_mut().fLetterSpacing = letter_spacing;
525 self
526 }
527
528 pub fn letter_spacing(&self) -> scalar {
529 self.native().fLetterSpacing
530 }
531
532 pub fn set_word_spacing(&mut self, word_spacing: scalar) -> &mut Self {
533 self.native_mut().fWordSpacing = word_spacing;
534 self
535 }
536
537 pub fn word_spacing(&self) -> scalar {
538 self.native().fWordSpacing
539 }
540
541 pub fn typeface(&self) -> Option<Typeface> {
542 Typeface::from_unshared_ptr(self.native().fTypeface.fPtr)
543 }
544
545 pub fn set_typeface(&mut self, typeface: impl Into<Option<Typeface>>) -> &mut Self {
546 unsafe {
547 sb::C_TextStyle_setTypeface(self.native_mut(), typeface.into().into_ptr_or_null())
548 }
549 self
550 }
551
552 pub fn locale(&self) -> &str {
553 self.native().fLocale.as_str()
554 }
555
556 pub fn set_locale(&mut self, locale: impl AsRef<str>) -> &mut Self {
557 self.native_mut().fLocale.set_str(locale);
558 self
559 }
560
561 pub fn text_baseline(&self) -> TextBaseline {
562 self.native().fTextBaseline
563 }
564
565 pub fn set_text_baseline(&mut self, baseline: TextBaseline) -> &mut Self {
566 self.native_mut().fTextBaseline = baseline;
567 self
568 }
569
570 pub fn font_metrics(&self) -> FontMetrics {
571 FontMetrics::construct(|fm| unsafe { self.native().getFontMetrics(fm) })
572 }
573
574 pub fn is_placeholder(&self) -> bool {
575 self.native().fIsPlaceholder
576 }
577
578 pub fn set_placeholder(&mut self) -> &mut Self {
579 self.native_mut().fIsPlaceholder = true;
580 self
581 }
582
583 pub fn set_font_edging(&mut self, edging: font::Edging) -> &mut Self {
584 self.native_mut().fEdging = edging;
585 self
586 }
587
588 pub fn font_edging(&self) -> font::Edging {
589 self.native().fEdging
590 }
591
592 pub fn set_subpixel(&mut self, subpixel: bool) -> &mut Self {
593 self.native_mut().fSubpixel = subpixel;
594 self
595 }
596
597 pub fn subpixel(&self) -> bool {
598 self.native().fSubpixel
599 }
600
601 pub fn set_font_hinting(&mut self, hinting: FontHinting) -> &mut Self {
602 self.native_mut().fHinting = hinting;
603 self
604 }
605
606 pub fn font_hinting(&self) -> FontHinting {
607 self.native().fHinting
608 }
609}
610
611pub type TextIndex = usize;
612pub type TextRange = Range<usize>;
613pub const EMPTY_TEXT: TextRange = EMPTY_RANGE;
614
615#[repr(C)]
616#[derive(Clone, PartialEq, Debug)]
617pub struct Block {
618 pub range: TextRange,
619 pub style: TextStyle,
620}
621
622native_transmutable!(sb::skia_textlayout_Block, Block);
623
624impl Default for Block {
625 fn default() -> Self {
626 Self {
627 range: EMPTY_RANGE,
628 style: Default::default(),
629 }
630 }
631}
632
633impl Block {
634 pub fn new(text_range: TextRange, style: TextStyle) -> Self {
635 Self {
636 range: text_range,
637 style,
638 }
639 }
640
641 pub fn add(&mut self, tail: TextRange) -> &mut Self {
642 debug_assert!(self.range.end == tail.start);
643 self.range = self.range.start..self.range.start + self.range.width() + tail.width();
644 self
645 }
646}
647
648pub type BlockIndex = usize;
649pub type BlockRange = Range<usize>;
650
651pub const EMPTY_BLOCK: usize = EMPTY_INDEX;
652pub const EMPTY_BLOCKS: Range<usize> = EMPTY_RANGE;
653
654#[repr(C)]
655#[derive(Clone, PartialEq, Debug)]
656pub struct Placeholder {
657 pub range: TextRange,
658 pub style: PlaceholderStyle,
659 pub text_style: TextStyle,
660 pub blocks_before: BlockRange,
661 pub text_before: TextRange,
662}
663
664native_transmutable!(sb::skia_textlayout_Placeholder, Placeholder);
665
666impl Default for Placeholder {
667 fn default() -> Self {
668 #[allow(clippy::reversed_empty_ranges)]
669 Self {
670 range: EMPTY_RANGE,
671 style: Default::default(),
672 text_style: Default::default(),
673 blocks_before: 0..0,
674 text_before: 0..0,
675 }
676 }
677}
678
679impl Placeholder {
680 pub fn new(
681 range: Range<usize>,
682 style: PlaceholderStyle,
683 text_style: TextStyle,
684 blocks_before: BlockRange,
685 text_before: TextRange,
686 ) -> Self {
687 Self {
688 range,
689 style,
690 text_style,
691 blocks_before,
692 text_before,
693 }
694 }
695}
696
697#[cfg(test)]
698mod tests {
699 use super::*;
700
701 #[test]
702 fn getting_setting_comparing_font_arguments() {
703 let mut ts = TextStyle::new();
704 let mut fa = crate::FontArguments::default();
705 fa.set_collection_index(100);
706 ts.set_font_arguments(&fa);
707 let tl_fa: FontArguments = fa.into();
708 let fa = ts.font_arguments().unwrap();
709 assert_eq!(tl_fa, *fa);
710 let default_fa: FontArguments = crate::FontArguments::default().into();
711 assert_ne!(default_fa, *fa);
712 }
713}