text_system.rs

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