1mod font_features;
2mod line_wrapper;
3mod text_layout_cache;
4
5pub use font_features::*;
6use line_wrapper::*;
7pub use text_layout_cache::*;
8
9use crate::{
10 Bounds, Hsla, Pixels, PlatformTextSystem, Point, Result, SharedString, Size, UnderlineStyle,
11};
12use collections::HashMap;
13use core::fmt;
14use parking_lot::Mutex;
15use std::{
16 fmt::{Debug, Display, Formatter},
17 hash::{Hash, Hasher},
18 ops::{Deref, DerefMut},
19 sync::Arc,
20};
21
22#[derive(Hash, PartialEq, Eq, Clone, Copy, Debug)]
23pub struct FontId(pub usize);
24
25#[derive(Hash, PartialEq, Eq, Clone, Copy, Debug)]
26pub struct FontFamilyId(pub usize);
27
28pub struct TextSystem {
29 text_layout_cache: Arc<TextLayoutCache>,
30 platform_text_system: Arc<dyn PlatformTextSystem>,
31 wrapper_pool: Mutex<HashMap<(Font, Pixels), Vec<LineWrapper>>>,
32}
33
34impl TextSystem {
35 pub fn new(platform_text_system: Arc<dyn PlatformTextSystem>) -> Self {
36 TextSystem {
37 text_layout_cache: Arc::new(TextLayoutCache::new(platform_text_system.clone())),
38 wrapper_pool: Mutex::new(HashMap::default()),
39 platform_text_system,
40 }
41 }
42
43 pub fn select_font(&self, descriptor: impl Into<Font>) -> Result<FontId> {
44 self.platform_text_system.select_font(descriptor.into())
45 }
46
47 pub fn bounding_box(&self, font_id: FontId, font_size: Pixels) -> Size<Pixels> {
48 let metrics = self.platform_text_system.font_metrics(font_id);
49
50 todo!()
51 // self.font_cache.bounding_box(font_id, font_size)
52 }
53
54 pub fn em_width(&self, font_id: FontId, font_size: Pixels) -> Pixels {
55 todo!()
56 // self.font_cache.em_width(font_id, font_size)
57 }
58
59 pub fn em_advance(&self, font_id: FontId, font_size: Pixels) -> Pixels {
60 todo!()
61 // self.font_cache.em_advance(font_id, font_size)
62 }
63
64 pub fn line_height(&self, font_size: Pixels) -> Pixels {
65 todo!()
66 // self.font_cache.line_height(font_size)
67 }
68
69 pub fn cap_height(&self, font_id: FontId, font_size: Pixels) -> Pixels {
70 todo!()
71 // self.font_cache.cap_height(font_id, font_size)
72 }
73
74 pub fn x_height(&self, font_id: FontId, font_size: Pixels) -> Pixels {
75 todo!()
76 // self.font_cache.x_height(font_id, font_size)
77 }
78
79 pub fn ascent(&self, font_id: FontId, font_size: Pixels) -> Pixels {
80 todo!()
81 // self.font_cache.ascent(font_id, font_size)
82 }
83
84 pub fn descent(&self, font_id: FontId, font_size: Pixels) -> Pixels {
85 todo!()
86 // self.font_cache.descent(font_id, font_size)
87 }
88
89 pub fn em_size(&self, font_id: FontId, font_size: Pixels) -> Pixels {
90 todo!()
91 // self.font_cache.em_size(font_id, font_size)
92 }
93
94 pub fn baseline_offset(&self, font_id: FontId, font_size: Pixels) -> Pixels {
95 todo!()
96 // self.font_cache.baseline_offset(font_id, font_size)
97 }
98
99 pub fn layout_str<'a>(
100 &'a self,
101 text: &'a str,
102 font_size: Pixels,
103 runs: &'a [(usize, RunStyle)],
104 ) -> Line {
105 self.text_layout_cache.layout_str(text, font_size, runs)
106 }
107
108 pub fn finish_frame(&self) {
109 self.text_layout_cache.finish_frame()
110 }
111
112 pub fn line_wrapper(self: &Arc<Self>, font: Font, font_size: Pixels) -> LineWrapperHandle {
113 let lock = &mut self.wrapper_pool.lock();
114 let wrappers = lock.entry((font.clone(), font_size)).or_default();
115 let wrapper = wrappers.pop().unwrap_or_else(|| {
116 LineWrapper::new(font, font_size, self.platform_text_system.clone())
117 });
118
119 LineWrapperHandle {
120 wrapper: Some(wrapper),
121 text_system: self.clone(),
122 }
123 }
124}
125
126pub struct LineWrapperHandle {
127 wrapper: Option<LineWrapper>,
128 text_system: Arc<TextSystem>,
129}
130
131impl Drop for LineWrapperHandle {
132 fn drop(&mut self) {
133 let mut state = self.text_system.wrapper_pool.lock();
134 let wrapper = self.wrapper.take().unwrap();
135 state
136 .get_mut(&(wrapper.font.clone(), wrapper.font_size))
137 .unwrap()
138 .push(wrapper);
139 }
140}
141
142impl Deref for LineWrapperHandle {
143 type Target = LineWrapper;
144
145 fn deref(&self) -> &Self::Target {
146 self.wrapper.as_ref().unwrap()
147 }
148}
149
150impl DerefMut for LineWrapperHandle {
151 fn deref_mut(&mut self) -> &mut Self::Target {
152 self.wrapper.as_mut().unwrap()
153 }
154}
155
156/// The degree of blackness or stroke thickness of a font. This value ranges from 100.0 to 900.0,
157/// with 400.0 as normal.
158#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
159pub struct FontWeight(pub f32);
160
161impl Default for FontWeight {
162 #[inline]
163 fn default() -> FontWeight {
164 FontWeight::NORMAL
165 }
166}
167
168impl Hash for FontWeight {
169 fn hash<H: Hasher>(&self, state: &mut H) {
170 state.write_u32(u32::from_be_bytes(self.0.to_be_bytes()));
171 }
172}
173
174impl Eq for FontWeight {}
175
176impl FontWeight {
177 /// Thin weight (100), the thinnest value.
178 pub const THIN: FontWeight = FontWeight(100.0);
179 /// Extra light weight (200).
180 pub const EXTRA_LIGHT: FontWeight = FontWeight(200.0);
181 /// Light weight (300).
182 pub const LIGHT: FontWeight = FontWeight(300.0);
183 /// Normal (400).
184 pub const NORMAL: FontWeight = FontWeight(400.0);
185 /// Medium weight (500, higher than normal).
186 pub const MEDIUM: FontWeight = FontWeight(500.0);
187 /// Semibold weight (600).
188 pub const SEMIBOLD: FontWeight = FontWeight(600.0);
189 /// Bold weight (700).
190 pub const BOLD: FontWeight = FontWeight(700.0);
191 /// Extra-bold weight (800).
192 pub const EXTRA_BOLD: FontWeight = FontWeight(800.0);
193 /// Black weight (900), the thickest value.
194 pub const BLACK: FontWeight = FontWeight(900.0);
195}
196
197/// Allows italic or oblique faces to be selected.
198#[derive(Clone, Copy, Eq, PartialEq, Debug, Hash)]
199pub enum FontStyle {
200 /// A face that is neither italic not obliqued.
201 Normal,
202 /// A form that is generally cursive in nature.
203 Italic,
204 /// A typically-sloped version of the regular face.
205 Oblique,
206}
207
208impl Default for FontStyle {
209 fn default() -> FontStyle {
210 FontStyle::Normal
211 }
212}
213
214impl Display for FontStyle {
215 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
216 Debug::fmt(self, f)
217 }
218}
219
220#[derive(Clone, Debug, PartialEq, Eq)]
221pub struct RunStyle {
222 pub font: Font,
223 pub color: Hsla,
224 pub underline: Option<UnderlineStyle>,
225}
226
227#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
228pub struct GlyphId(u32);
229
230impl From<GlyphId> for u32 {
231 fn from(value: GlyphId) -> Self {
232 value.0
233 }
234}
235
236impl From<u16> for GlyphId {
237 fn from(num: u16) -> Self {
238 GlyphId(num as u32)
239 }
240}
241
242impl From<u32> for GlyphId {
243 fn from(num: u32) -> Self {
244 GlyphId(num)
245 }
246}
247
248#[derive(Clone, Debug)]
249pub struct Glyph {
250 pub id: GlyphId,
251 pub position: Point<Pixels>,
252 pub index: usize,
253 pub is_emoji: bool,
254}
255
256#[derive(Default, Debug)]
257pub struct LineLayout {
258 pub font_size: Pixels,
259 pub width: Pixels,
260 pub ascent: Pixels,
261 pub descent: Pixels,
262 pub runs: Vec<Run>,
263 pub len: usize,
264}
265
266#[derive(Debug)]
267pub struct Run {
268 pub font_id: FontId,
269 pub glyphs: Vec<Glyph>,
270}
271
272#[derive(Clone, Debug, Eq, PartialEq, Hash)]
273pub struct Font {
274 pub family: SharedString,
275 pub features: FontFeatures,
276 pub weight: FontWeight,
277 pub style: FontStyle,
278}
279
280pub fn font(family: impl Into<SharedString>) -> Font {
281 Font {
282 family: family.into(),
283 features: FontFeatures::default(),
284 weight: FontWeight::default(),
285 style: FontStyle::default(),
286 }
287}
288
289impl Font {
290 pub fn bold(mut self) -> Self {
291 self.weight = FontWeight::BOLD;
292 self
293 }
294}
295
296#[derive(Clone, Copy, Debug)]
297pub struct FontMetrics {
298 pub units_per_em: u32,
299 pub ascent: f32,
300 pub descent: f32,
301 pub line_gap: f32,
302 pub underline_position: f32,
303 pub underline_thickness: f32,
304 pub cap_height: f32,
305 pub x_height: f32,
306 pub bounding_box: Bounds<f32>,
307}