webrender_api/
font.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5use peek_poke::PeekPoke;
6use std::cmp::Ordering;
7use std::hash::{Hash, Hasher};
8#[cfg(not(any(target_os = "macos", target_os = "ios")))]
9use std::path::PathBuf;
10use std::sync::Arc;
11// local imports
12use crate::IdNamespace;
13use crate::channel::Sender;
14use crate::units::LayoutPoint;
15
16/// Hashable floating-point storage for font size.
17#[repr(C)]
18#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd, Deserialize, Serialize)]
19pub struct FontSize(pub f32);
20
21impl Ord for FontSize {
22    fn cmp(&self, other: &FontSize) -> Ordering {
23        self.partial_cmp(other).unwrap_or(Ordering::Equal)
24    }
25}
26
27impl Eq for FontSize {}
28
29impl Hash for FontSize {
30    fn hash<H: Hasher>(&self, state: &mut H) {
31        self.0.to_bits().hash(state);
32    }
33}
34
35impl From<f32> for FontSize {
36    fn from(size: f32) -> Self { FontSize(size) }
37}
38
39impl From<FontSize> for f32 {
40    fn from(size: FontSize) -> Self { size.0 }
41}
42
43impl FontSize {
44    pub fn zero() -> Self { FontSize(0.0) }
45
46    pub fn from_f32_px(size: f32) -> Self { FontSize(size) }
47
48    pub fn to_f32_px(&self) -> f32 { self.0 }
49
50    pub fn from_f64_px(size: f64) -> Self { FontSize(size as f32) }
51
52    pub fn to_f64_px(&self) -> f64 { self.0 as f64 }
53}
54
55#[cfg(not(any(target_os = "macos", target_os = "ios")))]
56#[derive(Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
57pub struct NativeFontHandle {
58    pub path: PathBuf,
59    pub index: u32,
60}
61
62#[cfg(any(target_os = "macos", target_os = "ios"))]
63#[derive(Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
64pub struct NativeFontHandle {
65    pub name: String,
66    pub path: String,
67}
68
69#[repr(C)]
70#[derive(Copy, Clone, Deserialize, Serialize, Debug)]
71pub struct GlyphDimensions {
72    pub left: i32,
73    pub top: i32,
74    pub width: i32,
75    pub height: i32,
76    pub advance: f32,
77}
78
79pub struct GlyphDimensionRequest {
80    pub key: FontInstanceKey,
81    pub glyph_indices: Vec<GlyphIndex>,
82    pub sender: Sender<Vec<Option<GlyphDimensions>>>,
83}
84
85pub struct GlyphIndexRequest {
86    pub key: FontKey,
87    pub text: String,
88    pub sender: Sender<Vec<Option<u32>>>,
89}
90
91#[repr(C)]
92#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, Ord, PartialOrd)]
93pub struct FontKey(pub IdNamespace, pub u32);
94
95impl FontKey {
96    pub fn new(namespace: IdNamespace, key: u32) -> FontKey {
97        FontKey(namespace, key)
98    }
99}
100
101/// Container for the raw data describing a font. This might be a stream of
102/// bytes corresponding to a downloaded font, or a handle to a native font from
103/// the operating system.
104///
105/// Note that fonts need to be instantiated before being used, which involves
106/// assigning size and various other options. The word 'template' here is
107/// intended to distinguish this data from instance-specific data.
108#[derive(Debug, Clone, Hash, Eq, PartialEq)]
109pub enum FontTemplate {
110    Raw(Arc<Vec<u8>>, u32),
111    Native(NativeFontHandle),
112}
113
114#[repr(u8)]
115#[derive(Debug, Copy, Clone, Hash, Eq, MallocSizeOf, PartialEq, Serialize, Deserialize, Ord, PartialOrd, PeekPoke)]
116pub enum FontRenderMode {
117    Mono = 0,
118    Alpha,
119    Subpixel,
120}
121
122impl Default for FontRenderMode {
123    fn default() -> Self {
124        FontRenderMode::Mono
125    }
126}
127
128impl FontRenderMode {
129    // Combine two font render modes such that the lesser amount of AA limits the AA of the result.
130    pub fn limit_by(self, other: FontRenderMode) -> FontRenderMode {
131        match (self, other) {
132            (FontRenderMode::Subpixel, _) | (_, FontRenderMode::Mono) => other,
133            _ => self,
134        }
135    }
136}
137
138#[repr(C)]
139#[derive(Clone, Copy, Debug, MallocSizeOf, PartialOrd, Deserialize, Serialize)]
140pub struct FontVariation {
141    pub tag: u32,
142    pub value: f32,
143}
144
145impl Ord for FontVariation {
146    fn cmp(&self, other: &FontVariation) -> Ordering {
147        self.tag.cmp(&other.tag)
148            .then(self.value.to_bits().cmp(&other.value.to_bits()))
149    }
150}
151
152impl PartialEq for FontVariation {
153    fn eq(&self, other: &FontVariation) -> bool {
154        self.tag == other.tag &&
155        self.value.to_bits() == other.value.to_bits()
156    }
157}
158
159impl Eq for FontVariation {}
160
161impl Hash for FontVariation {
162    fn hash<H: Hasher>(&self, state: &mut H) {
163        self.tag.hash(state);
164        self.value.to_bits().hash(state);
165    }
166}
167
168#[repr(C)]
169#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize, PeekPoke)]
170pub struct GlyphOptions {
171    pub render_mode: FontRenderMode,
172    pub flags: FontInstanceFlags,
173}
174
175impl Default for GlyphOptions {
176    fn default() -> Self {
177        GlyphOptions {
178            render_mode: FontRenderMode::Subpixel,
179            flags: FontInstanceFlags::empty(),
180        }
181    }
182}
183
184#[repr(C)]
185#[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash, Deserialize, MallocSizeOf, Serialize, PeekPoke)]
186pub struct FontInstanceFlags(u32);
187
188bitflags! {
189    impl FontInstanceFlags: u32 {
190        // Common flags
191        // Use native synthetic bold, if supported.
192        const SYNTHETIC_BOLD    = 1 << 1;
193        const EMBEDDED_BITMAPS  = 1 << 2;
194        const SUBPIXEL_BGR      = 1 << 3;
195        const TRANSPOSE         = 1 << 4;
196        const FLIP_X            = 1 << 5;
197        const FLIP_Y            = 1 << 6;
198        const SUBPIXEL_POSITION = 1 << 7;
199        const VERTICAL          = 1 << 8;
200        // Explicitly use multi-strike bold emulation.
201        const MULTISTRIKE_BOLD  = 1 << 9;
202
203        // Internal flags
204        const TRANSFORM_GLYPHS  = 1 << 12;
205        const TEXTURE_PADDING   = 1 << 13;
206
207        // Windows flags
208        const FORCE_GDI         = 1 << 16;
209        const FORCE_SYMMETRIC   = 1 << 17;
210        const NO_SYMMETRIC      = 1 << 18;
211
212        // Mac flags
213        const FONT_SMOOTHING    = 1 << 16;
214
215        // FreeType flags
216        const FORCE_AUTOHINT    = 1 << 16;
217        const NO_AUTOHINT       = 1 << 17;
218        const VERTICAL_LAYOUT   = 1 << 18;
219        const LCD_VERTICAL      = 1 << 19;
220    }
221}
222
223impl core::fmt::Debug for FontInstanceFlags {
224    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
225        if self.is_empty() {
226            write!(f, "{:#x}", Self::empty().bits())
227        } else {
228            bitflags::parser::to_writer(self, f)
229        }
230    }
231}
232
233impl Default for FontInstanceFlags {
234    #[cfg(target_os = "windows")]
235    fn default() -> FontInstanceFlags {
236        FontInstanceFlags::SUBPIXEL_POSITION
237    }
238
239    #[cfg(any(target_os = "macos", target_os = "ios"))]
240    fn default() -> FontInstanceFlags {
241        FontInstanceFlags::SUBPIXEL_POSITION |
242        FontInstanceFlags::FONT_SMOOTHING
243    }
244
245    #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows")))]
246    fn default() -> FontInstanceFlags {
247        FontInstanceFlags::SUBPIXEL_POSITION
248    }
249}
250
251
252#[repr(C)]
253#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, MallocSizeOf, PartialEq, PartialOrd, Ord, Serialize)]
254pub struct SyntheticItalics {
255    // Angle in degrees (-90..90) for synthetic italics in 8.8 fixed-point.
256    pub angle: i16,
257}
258
259impl SyntheticItalics {
260    pub const ANGLE_SCALE: f32 = 256.0;
261
262    pub fn from_degrees(degrees: f32) -> Self {
263        SyntheticItalics { angle: (degrees.clamp(-89.0, 89.0) * Self::ANGLE_SCALE) as i16 }
264    }
265
266    pub fn to_degrees(self) -> f32 {
267        self.angle as f32 / Self::ANGLE_SCALE
268    }
269
270    pub fn to_radians(self) -> f32 {
271        self.to_degrees().to_radians()
272    }
273
274    pub fn to_skew(self) -> f32 {
275        self.to_radians().tan()
276    }
277
278    pub fn enabled() -> Self {
279        Self::from_degrees(14.0)
280    }
281
282    pub fn disabled() -> Self {
283        SyntheticItalics { angle: 0 }
284    }
285
286    pub fn is_enabled(self) -> bool {
287        self.angle != 0
288    }
289}
290
291impl Default for SyntheticItalics {
292    fn default() -> Self {
293        SyntheticItalics::disabled()
294    }
295}
296
297#[repr(C)]
298#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, MallocSizeOf, PartialEq, PartialOrd, Ord, Serialize)]
299pub struct FontInstanceOptions {
300    pub flags: FontInstanceFlags,
301    pub synthetic_italics: SyntheticItalics,
302    pub render_mode: FontRenderMode,
303    // We need to pad this struct out so that all bytes are part of fields, in
304    // order to satisfy the robustness requirements (and static_asserts) of
305    // ParamTraits_TiedFields.
306    // The sizeof(T) must be equal to the sum of the sizeof each field in T.
307    pub _padding: u8,
308}
309
310impl Default for FontInstanceOptions {
311    fn default() -> FontInstanceOptions {
312        FontInstanceOptions {
313            render_mode: FontRenderMode::Subpixel,
314            flags: Default::default(),
315            synthetic_italics: SyntheticItalics::disabled(),
316            _padding: 0,
317        }
318    }
319}
320
321#[cfg(target_os = "windows")]
322#[repr(C)]
323#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, MallocSizeOf, PartialEq, PartialOrd, Ord, Serialize)]
324pub struct FontInstancePlatformOptions {
325    pub gamma: u16, // percent
326    pub contrast: u8, // percent
327    pub cleartype_level: u8, // percent
328}
329
330#[cfg(target_os = "windows")]
331impl Default for FontInstancePlatformOptions {
332    fn default() -> FontInstancePlatformOptions {
333        FontInstancePlatformOptions {
334            gamma: 180, // Default DWrite gamma
335            contrast: 100,
336            cleartype_level: 100,
337        }
338    }
339}
340
341#[cfg(any(target_os = "macos", target_os = "ios"))]
342#[repr(C)]
343#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, MallocSizeOf, PartialEq, PartialOrd, Ord, Serialize)]
344pub struct FontInstancePlatformOptions {
345    pub unused: u32,
346}
347
348#[cfg(any(target_os = "macos", target_os = "ios"))]
349impl Default for FontInstancePlatformOptions {
350    fn default() -> FontInstancePlatformOptions {
351        FontInstancePlatformOptions {
352            unused: 0,
353        }
354    }
355}
356
357#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows")))]
358#[repr(u8)]
359#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, PartialOrd, Ord, Serialize)]
360pub enum FontLCDFilter {
361    None,
362    Default,
363    Light,
364    Legacy,
365}
366
367#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows")))]
368#[repr(u8)]
369#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, PartialOrd, Ord, Serialize)]
370pub enum FontHinting {
371    None,
372    Mono,
373    Light,
374    Normal,
375    LCD,
376}
377
378#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows")))]
379#[repr(C)]
380#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, MallocSizeOf, PartialEq, PartialOrd, Ord, Serialize)]
381pub struct FontInstancePlatformOptions {
382    pub lcd_filter: FontLCDFilter,
383    pub hinting: FontHinting,
384}
385
386#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows")))]
387impl Default for FontInstancePlatformOptions {
388    fn default() -> FontInstancePlatformOptions {
389        FontInstancePlatformOptions {
390            lcd_filter: FontLCDFilter::Default,
391            hinting: FontHinting::LCD,
392        }
393    }
394}
395
396#[repr(C)]
397#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq, Ord, PartialOrd, MallocSizeOf, PeekPoke)]
398#[derive(Deserialize, Serialize)]
399pub struct FontInstanceKey(pub IdNamespace, pub u32);
400
401impl FontInstanceKey {
402    pub fn new(namespace: IdNamespace, key: u32) -> FontInstanceKey {
403        FontInstanceKey(namespace, key)
404    }
405}
406
407/// Data corresponding to an instantiation of a font, with size and
408/// other options specified.
409///
410/// Note that the actual font is stored out-of-band in `FontTemplate`.
411#[derive(Clone)]
412pub struct FontInstanceData {
413    pub font_key: FontKey,
414    pub size: f32,
415    pub options: Option<FontInstanceOptions>,
416    pub platform_options: Option<FontInstancePlatformOptions>,
417    pub variations: Vec<FontVariation>,
418}
419
420pub type GlyphIndex = u32;
421
422#[repr(C)]
423#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)]
424pub struct GlyphInstance {
425    pub index: GlyphIndex,
426    pub point: LayoutPoint,
427}
428
429impl Default for GlyphInstance {
430    fn default() -> Self {
431        GlyphInstance {
432            index: 0,
433            point: LayoutPoint::zero(),
434        }
435    }
436}
437
438impl Eq for GlyphInstance {}
439
440#[allow(clippy::derived_hash_with_manual_eq)]
441impl Hash for GlyphInstance {
442    fn hash<H: Hasher>(&self, state: &mut H) {
443        // Note: this is inconsistent with the Eq impl for -0.0 (don't care).
444        self.index.hash(state);
445        self.point.x.to_bits().hash(state);
446        self.point.y.to_bits().hash(state);
447    }
448}