text_system.rs

  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}