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}