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!(
35 sb::skia_textlayout_RectHeightStyle,
36 RectHeightStyle,
37 rect_height_style_layout
38);
39
40#[repr(i32)]
41#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Default)]
42pub enum RectWidthStyle {
43 /// Provide tight bounding boxes that fit widths to the runs of each line
44 /// independently.
45 #[default]
46 Tight,
47 /// Extends the width of the last rect of each line to match the position of
48 /// the widest rect over all the lines.
49 Max,
50}
51native_transmutable!(
52 sb::skia_textlayout_RectWidthStyle,
53 RectWidthStyle,
54 rect_width_style_layout
55);
56
57pub use sb::skia_textlayout_TextAlign as TextAlign;
58variant_name!(TextAlign::End);
59pub use sb::skia_textlayout_TextDirection as TextDirection;
60variant_name!(TextDirection::LTR);
61
62pub use sb::skia_textlayout_PositionWithAffinity as PositionWithAffinity;
63
64#[repr(C)]
65#[derive(Copy, Clone, PartialEq, Debug)]
66pub struct TextBox {
67 pub rect: Rect,
68 pub direct: TextDirection,
69}
70
71native_transmutable!(sb::skia_textlayout_TextBox, TextBox, text_box_layout);
72
73pub const EMPTY_INDEX: usize = std::usize::MAX;
74
75pub trait RangeExtensions {
76 fn width(&self) -> usize;
77 fn shift(&mut self, d: isize);
78 fn contains(&self, other: &Self) -> bool;
79 fn intersects(&self, other: &Self) -> bool;
80 #[must_use]
81 fn intersection(&self, other: &Self) -> Self;
82 fn empty(&self) -> bool;
83}
84
85impl RangeExtensions for Range<usize> {
86 fn width(&self) -> usize {
87 self.end - self.start
88 }
89
90 fn shift(&mut self, d: isize) {
91 if d >= 0 {
92 let u = d as usize;
93 self.start += u;
94 self.end += u;
95 } else {
96 let u = -d as usize;
97 self.start -= u;
98 self.end -= u;
99 }
100 }
101
102 fn contains(&self, other: &Self) -> bool {
103 self.start <= other.start && self.end >= other.end
104 }
105
106 fn intersects(&self, other: &Self) -> bool {
107 max(self.start, other.start) <= min(self.end, other.end)
108 }
109
110 fn intersection(&self, other: &Self) -> Self {
111 Self {
112 start: max(self.start, other.start),
113 end: min(self.end, other.end),
114 }
115 }
116
117 fn empty(&self) -> bool {
118 self.start == EMPTY_INDEX && self.end == EMPTY_INDEX
119 }
120}
121
122#[allow(clippy::reversed_empty_ranges)]
123pub const EMPTY_RANGE: Range<usize> = Range {
124 start: EMPTY_INDEX,
125 end: EMPTY_INDEX,
126};
127
128pub use sb::skia_textlayout_TextBaseline as TextBaseline;
129variant_name!(TextBaseline::Alphabetic);
130
131pub use sb::skia_textlayout_TextHeightBehavior as TextHeightBehavior;
132variant_name!(TextHeightBehavior::DisableFirstAscent);
133
134// m84: LineMetricStyle is declared but not used in the public API yet.
135