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    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}