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