Skip to main content

fonts/
lib.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 https://mozilla.org/MPL/2.0/. */
4
5#![deny(unsafe_code)]
6
7mod font;
8mod font_context;
9pub mod font_feature_values;
10mod font_store;
11mod glyph;
12#[expect(unsafe_code)]
13pub mod platform; // Public because integration tests need this
14mod shapers;
15mod system_font_service;
16
17pub(crate) use font::*;
18// These items are not meant to be part of the public API but are used for integration tests
19pub use font::{Font, FontFamilyDescriptor, FontSearchScope, PlatformFontMethods};
20pub use font::{
21    FontBaseline, FontGroup, FontMetrics, FontRef, LAST_RESORT_GLYPH_ADVANCE, ShapingFlags,
22    ShapingOptions,
23};
24pub use font_context::{
25    CspViolationHandler, FontContext, FontContextWebFontMethods, NetworkTimingHandler,
26    WebFontDocumentContext,
27};
28pub use font_store::FontTemplates;
29pub use fonts_traits::*;
30pub(crate) use glyph::*;
31pub use glyph::{GlyphInfo, ShapedText, ShapedTextSlice, ShapedTextSlicer};
32use icu_locid::subtags::Language;
33pub use platform::font_list::fallback_font_families;
34pub(crate) use shapers::*;
35pub use system_font_service::SystemFontService;
36use unicode_properties::{EmojiStatus, UnicodeEmoji, emoji};
37
38/// Whether or not font fallback selection prefers the emoji or text representation
39/// of a character. If `None` then either presentation is acceptable.
40#[derive(Clone, Copy, Debug, PartialEq)]
41pub(crate) enum EmojiPresentationPreference {
42    None,
43    Text,
44    Emoji,
45}
46
47#[derive(Clone, Debug)]
48pub struct FallbackFontSelectionOptions {
49    pub(crate) character: char,
50    pub(crate) presentation_preference: EmojiPresentationPreference,
51    pub(crate) language: Language,
52}
53
54impl Default for FallbackFontSelectionOptions {
55    fn default() -> Self {
56        Self {
57            character: ' ',
58            presentation_preference: EmojiPresentationPreference::None,
59            language: Language::UND,
60        }
61    }
62}
63
64impl FallbackFontSelectionOptions {
65    pub(crate) fn new(character: char, next_character: Option<char>, language: Language) -> Self {
66        let presentation_preference = match next_character {
67            Some(next_character) if emoji::is_emoji_presentation_selector(next_character) => {
68                EmojiPresentationPreference::Emoji
69            },
70            Some(next_character) if emoji::is_text_presentation_selector(next_character) => {
71                EmojiPresentationPreference::Text
72            },
73            // We don't want to select emoji prsentation for any possible character that might be an emoji, because
74            // that includes characters such as '0' that are also used outside of emoji clusters. Instead, only
75            // select the emoji font for characters that explicitly have an emoji presentation (in the absence
76            // of the emoji presentation selectors above).
77            _ if matches!(
78                character.emoji_status(),
79                EmojiStatus::EmojiPresentation |
80                    EmojiStatus::EmojiPresentationAndModifierBase |
81                    EmojiStatus::EmojiPresentationAndEmojiComponent |
82                    EmojiStatus::EmojiPresentationAndModifierAndEmojiComponent
83            ) =>
84            {
85                EmojiPresentationPreference::Emoji
86            },
87            _ if character.is_emoji_char() => EmojiPresentationPreference::Text,
88            _ => EmojiPresentationPreference::None,
89        };
90        Self {
91            character,
92            presentation_preference,
93            language,
94        }
95    }
96}
97
98pub(crate) fn float_to_fixed(before: usize, f: f64) -> i32 {
99    ((1i32 << before) as f64 * f) as i32
100}
101
102pub(crate) fn fixed_to_float(before: usize, f: i32) -> f64 {
103    f as f64 * 1.0f64 / ((1i32 << before) as f64)
104}