skia_safe/modules/paragraph/
dart_types.rs

1use crate::Rect;
2use skia_bindings as sb;
3use std::{
4    cmp::{max, min},
5    ops::Range,
6};
7
8pub use sb::skia_textlayout_Affinity as Affinity;
9variant_name!(Affinity::Downstream);
10
11#[repr(i32)]
12#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Default)]
13pub enum RectHeightStyle {
14    /// Provide tight bounding boxes that fit heights per run.
15    #[default]
16    Tight,
17    // The height of the boxes will be the maximum height of all runs in the
18    // line. All rects in the same line will be the same height.
19    Max,
20    // Extends the top and/or bottom edge of the bounds to fully cover any line
21    // spacing. The top edge of each line should be the same as the bottom edge
22    // of the line above. There should be no gaps in vertical coverage given any
23    // ParagraphStyle line_height.
24    //
25    // The top and bottom of each rect will cover half of the
26    // space above and half of the space below the line.
27    IncludeLineSpacingMiddle,
28    // The line spacing will be added to the top of the rect.
29    IncludeLineSpacingTop,
30    // The line spacing will be added to the bottom of the rect.
31    IncludeLineSpacingBottom,
32    Strut,
33}
34native_transmutable!(sb::skia_textlayout_RectHeightStyle, RectHeightStyle);
35
36#[repr(i32)]
37#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Default)]
38pub enum RectWidthStyle {
39    /// Provide tight bounding boxes that fit widths to the runs of each line
40    /// independently.
41    #[default]
42    Tight,
43    /// Extends the width of the last rect of each line to match the position of
44    /// the widest rect over all the lines.
45    Max,
46}
47native_transmutable!(sb::skia_textlayout_RectWidthStyle, RectWidthStyle);
48
49pub use sb::skia_textlayout_TextAlign as TextAlign;
50variant_name!(TextAlign::End);
51pub use sb::skia_textlayout_TextDirection as TextDirection;
52variant_name!(TextDirection::LTR);
53
54pub use sb::skia_textlayout_PositionWithAffinity as PositionWithAffinity;
55
56#[repr(C)]
57#[derive(Copy, Clone, PartialEq, Debug)]
58pub struct TextBox {
59    pub rect: Rect,
60    pub direct: TextDirection,
61}
62
63native_transmutable!(sb::skia_textlayout_TextBox, TextBox);
64
65pub const EMPTY_INDEX: usize = usize::MAX;
66
67pub trait RangeExtensions {
68    fn width(&self) -> usize;
69    fn shift(&mut self, d: isize);
70    fn contains(&self, other: &Self) -> bool;
71    fn intersects(&self, other: &Self) -> bool;
72    #[must_use]
73    fn intersection(&self, other: &Self) -> Self;
74    fn empty(&self) -> bool;
75}
76
77impl RangeExtensions for Range<usize> {
78    fn width(&self) -> usize {
79        self.end - self.start
80    }
81
82    fn shift(&mut self, d: isize) {
83        if d >= 0 {
84            let u = d as usize;
85            self.start += u;
86            self.end += u;
87        } else {
88            let u = -d as usize;
89            self.start -= u;
90            self.end -= u;
91        }
92    }
93
94    fn contains(&self, other: &Self) -> bool {
95        self.start <= other.start && self.end >= other.end
96    }
97
98    fn intersects(&self, other: &Self) -> bool {
99        max(self.start, other.start) <= min(self.end, other.end)
100    }
101
102    fn intersection(&self, other: &Self) -> Self {
103        Self {
104            start: max(self.start, other.start),
105            end: min(self.end, other.end),
106        }
107    }
108
109    fn empty(&self) -> bool {
110        self.start == EMPTY_INDEX && self.end == EMPTY_INDEX
111    }
112}
113
114#[allow(clippy::reversed_empty_ranges)]
115pub const EMPTY_RANGE: Range<usize> = Range {
116    start: EMPTY_INDEX,
117    end: EMPTY_INDEX,
118};
119
120pub use sb::skia_textlayout_TextBaseline as TextBaseline;
121variant_name!(TextBaseline::Alphabetic);
122
123pub use sb::skia_textlayout_TextHeightBehavior as TextHeightBehavior;
124variant_name!(TextHeightBehavior::DisableFirstAscent);
125
126// m84: LineMetricStyle is declared but not used in the public API yet.