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