piet_cosmic_text/
lines.rs1use crate::metadata::Metadata;
24
25use core::mem;
26use cosmic_text::LayoutGlyph;
27use line_straddler::{Glyph, GlyphStyle, Line as LsLine, LineGenerator, LineType};
28
29use piet::kurbo::{Line, Point, Rect};
30use piet::{Color, FontWeight};
31
32#[derive(Debug, Clone, Copy, PartialEq)]
34pub struct StyledLine {
35 pub line: Line,
37
38 pub color: Color,
40
41 pub bold: FontWeight,
43
44 pub font_size: f32,
46}
47
48impl StyledLine {
49 pub fn into_rect(self) -> Rect {
51 const FONT_WEIGHT_MULTIPLIER: f32 = 0.05;
52 const OFFSET_MULTIPLIER: f32 = -0.83;
53
54 let offset = self.font_size * OFFSET_MULTIPLIER;
55 let width = self.font_size
56 * (self.bold.to_raw() as f32 / FontWeight::NORMAL.to_raw() as f32)
57 * FONT_WEIGHT_MULTIPLIER;
58
59 let mut p0 = self.line.p0;
60 let mut p1 = self.line.p1;
61 p0.y += f64::from(offset);
62 p1.y = p0.y - f64::from(width);
63 Rect::from_points(p0, p1)
64 }
65}
66
67#[derive(Debug)]
71pub struct LineProcessor {
72 underline: LineGenerator,
74
75 strikethrough: LineGenerator,
77
78 lines: Vec<StyledLine>,
80
81 last_glyph_size: f32,
83}
84
85impl Default for LineProcessor {
86 fn default() -> Self {
87 Self::new()
88 }
89}
90
91impl LineProcessor {
92 pub fn new() -> Self {
94 Self {
95 underline: LineGenerator::new(LineType::Underline),
96 strikethrough: LineGenerator::new(LineType::StrikeThrough),
97 lines: Vec::new(),
98 last_glyph_size: 0.0,
99 }
100 }
101
102 pub fn handle_glyph(&mut self, glyph: &LayoutGlyph, line_y: f32, color: cosmic_text::Color) {
104 let metadata = Metadata::from_raw(glyph.metadata);
106 let font_size = glyph.font_size;
107 let glyph = Glyph {
108 line_y,
109 font_size,
110 width: glyph.w,
111 x: glyph.x,
112 style: GlyphStyle {
113 boldness: metadata.boldness().to_raw(),
114 color: match glyph.color_opt {
115 Some(color) => {
116 let [r, g, b, a] = [color.r(), color.g(), color.b(), color.a()];
117 line_straddler::Color::rgba(r, g, b, a)
118 }
119
120 None => {
121 let [r, g, b, a] = [color.r(), color.g(), color.b(), color.a()];
122 line_straddler::Color::rgba(r, g, b, a)
123 }
124 },
125 },
126 };
127
128 let Self {
129 underline,
130 strikethrough,
131 lines,
132 last_glyph_size,
133 } = self;
134
135 let handle_meta = |generator: &mut LineGenerator, has_it| {
136 let line = if has_it {
137 generator.add_glyph(glyph)
138 } else {
139 generator.pop_line()
140 };
141
142 line.map(|line| cvt_line(line, font_size))
143 };
144
145 let underline = handle_meta(underline, metadata.underline());
146 let strikethrough = handle_meta(strikethrough, metadata.strikethrough());
147
148 lines.extend(underline);
149 lines.extend(strikethrough);
150 *last_glyph_size = font_size;
151 }
152
153 pub fn lines(&mut self) -> Vec<StyledLine> {
155 let underline = self.underline.pop_line();
157 let strikethrough = self.strikethrough.pop_line();
158 let font_size = self.last_glyph_size;
159 self.lines
160 .extend(underline.map(|line| cvt_line(line, font_size)));
161 self.lines
162 .extend(strikethrough.map(|line| cvt_line(line, font_size)));
163
164 mem::take(&mut self.lines)
165 }
166}
167
168fn cvt_line(ls_line: LsLine, font_size: f32) -> StyledLine {
169 let line = Line {
170 p0: Point::new(ls_line.start_x.into(), ls_line.y.into()),
171 p1: Point::new(ls_line.end_x.into(), ls_line.y.into()),
172 };
173
174 StyledLine {
175 line,
176 color: cvt_color(ls_line.style.color),
177 bold: FontWeight::new(ls_line.style.boldness),
178 font_size,
179 }
180}
181
182fn cvt_color(color: line_straddler::Color) -> Color {
183 let [r, g, b, a] = color.components();
184 Color::rgba8(r, g, b, a)
185}