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