Skip to main content

bevy_text/
parley_context.rs

1use crate::TextError;
2use crate::{FontSmoothing, FontSource};
3use bevy_derive::Deref;
4use bevy_derive::DerefMut;
5use bevy_ecs::resource::Resource;
6use bevy_platform::collections::HashMap;
7use parley::LayoutContext;
8use parley::{FontContext, GenericFamily};
9use swash::scale::ScaleContext;
10
11#[derive(#[automatically_derived]
impl ::core::marker::Copy for TextBrush { }Copy, #[automatically_derived]
impl ::core::clone::Clone for TextBrush {
    #[inline]
    fn clone(&self) -> TextBrush {
        let _: ::core::clone::AssertParamIsClone<u32>;
        let _: ::core::clone::AssertParamIsClone<FontSmoothing>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for TextBrush {
    #[inline]
    fn eq(&self, other: &TextBrush) -> bool {
        self.section_index == other.section_index &&
            self.font_smoothing == other.font_smoothing
    }
}PartialEq, #[automatically_derived]
impl ::core::default::Default for TextBrush {
    #[inline]
    fn default() -> TextBrush {
        TextBrush {
            section_index: ::core::default::Default::default(),
            font_smoothing: ::core::default::Default::default(),
        }
    }
}Default, #[automatically_derived]
impl ::core::fmt::Debug for TextBrush {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f, "TextBrush",
            "section_index", &self.section_index, "font_smoothing",
            &&self.font_smoothing)
    }
}Debug)]
12/// Per-section metadata attached to shaped text runs.
13///
14/// This brush is stored in Parley's [`Layout`](`parley::Layout`) so Bevy can identify which text section
15/// a glyph run belongs to, and the antialiasing method that should be used during rendering.
16pub struct TextBrush {
17    /// Index of the text section within its `ComputedTextBlock`.
18    pub section_index: u32,
19    /// Antialiasing method to use when rendering the text.
20    pub font_smoothing: FontSmoothing,
21}
22
23impl TextBrush {
24    /// Creates a new brush for glyphs from the given text section.
25    pub fn new(section_index: u32, font_smoothing: FontSmoothing) -> Self {
26        TextBrush {
27            section_index,
28            font_smoothing,
29        }
30    }
31}
32
33/// A font database and cache, used for font family resolution and text layout.
34///
35/// This resource is a wrapper around [`parley::FontContext`].
36#[derive(impl bevy_ecs::resource::Resource for FontCx where
    Self: ::core::marker::Send + ::core::marker::Sync + 'static {}Resource, #[automatically_derived]
impl ::core::default::Default for FontCx {
    #[inline]
    fn default() -> FontCx {
        FontCx {
            context: ::core::default::Default::default(),
            generic_families: ::core::default::Default::default(),
        }
    }
}Default, impl ::core::ops::Deref for FontCx {
    type Target = FontContext;
    fn deref(&self) -> &Self::Target { &self.context }
}Deref, impl ::core::ops::DerefMut for FontCx {
    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.context }
}DerefMut)]
37pub struct FontCx {
38    /// A font database/cache (wrapper around a Fontique [`Collection`](parley::fontique::Collection) and [`SourceCache`](parley::fontique::SourceCache)).
39    #[deref]
40    pub context: FontContext,
41    /// Backup, used to restore the generic family mappings after the font [`Collection`](parley::fontique::Collection) is cleared.
42    generic_families: HashMap<GenericFamily, String>,
43}
44
45impl FontCx {
46    /// Get the family name associated with a [`FontSource`].
47    ///
48    /// If the `FontSource` is a `Handle`, returns `None`. The family name can be found by using the handle to look
49    /// up the `Font` asset instead.
50    pub fn get_family<'a>(&'a mut self, source: &'a FontSource) -> Option<&'a str> {
51        let generic_family = match source {
52            FontSource::Handle(_) => return None,
53            FontSource::Family(family) => return Some(family.as_str()),
54            FontSource::Serif => GenericFamily::Serif,
55            FontSource::SansSerif => GenericFamily::SansSerif,
56            FontSource::Cursive => GenericFamily::Cursive,
57            FontSource::Fantasy => GenericFamily::Fantasy,
58            FontSource::Monospace => GenericFamily::Monospace,
59            FontSource::SystemUi => GenericFamily::SystemUi,
60            FontSource::UiSerif => GenericFamily::UiSerif,
61            FontSource::UiSansSerif => GenericFamily::UiSansSerif,
62            FontSource::UiMonospace => GenericFamily::UiMonospace,
63            FontSource::UiRounded => GenericFamily::UiRounded,
64            FontSource::Emoji => GenericFamily::Emoji,
65            FontSource::Math => GenericFamily::Math,
66            FontSource::FangSong => GenericFamily::FangSong,
67        };
68
69        let family_id = self.collection.generic_families(generic_family).next();
70        family_id.and_then(|id| self.collection.family_name(id))
71    }
72
73    /// Sets the fallback font for a given generic family.
74    ///
75    /// In most cases, these methods do not need to called manually,
76    /// as [`parley::fontique`] will automatically select appropriate default fonts based on available system fonts.
77    ///
78    /// Note that the `parley/system` feature must be enabled to allow automatic system font discovery.
79    ///
80    /// These methods will return an error if the provided family name does not already exist in the font collection.
81    pub fn set_generic_family(
82        &mut self,
83        generic: GenericFamily,
84        family_name: &str,
85    ) -> Result<(), TextError> {
86        self.collection
87            .family_id(family_name)
88            .ok_or(TextError::NoSuchFontFamily(family_name.to_string()))
89            .map(|id| {
90                self.collection
91                    .set_generic_families(generic, core::iter::once(id));
92                self.generic_families
93                    .insert(generic, family_name.to_string());
94            })
95    }
96
97    /// Sets the serif generic family mapping.
98    pub fn set_serif_family(&mut self, family_name: &str) -> Result<(), TextError> {
99        self.set_generic_family(GenericFamily::Serif, family_name)
100    }
101
102    /// Sets the sans-serif generic family mapping.
103    pub fn set_sans_serif_family(&mut self, family_name: &str) -> Result<(), TextError> {
104        self.set_generic_family(GenericFamily::SansSerif, family_name)
105    }
106
107    /// Sets the cursive generic family mapping.
108    pub fn set_cursive_family(&mut self, family_name: &str) -> Result<(), TextError> {
109        self.set_generic_family(GenericFamily::Cursive, family_name)
110    }
111
112    /// Sets the fantasy generic family mapping.
113    pub fn set_fantasy_family(&mut self, family_name: &str) -> Result<(), TextError> {
114        self.set_generic_family(GenericFamily::Fantasy, family_name)
115    }
116
117    /// Sets the monospace generic family mapping.
118    pub fn set_monospace_family(&mut self, family_name: &str) -> Result<(), TextError> {
119        self.set_generic_family(GenericFamily::Monospace, family_name)
120    }
121
122    /// Sets the system-ui generic family mapping.
123    pub fn set_system_ui_family(&mut self, family_name: &str) -> Result<(), TextError> {
124        self.set_generic_family(GenericFamily::SystemUi, family_name)
125    }
126
127    /// Sets the ui-serif generic family mapping.
128    pub fn set_ui_serif_family(&mut self, family_name: &str) -> Result<(), TextError> {
129        self.set_generic_family(GenericFamily::UiSerif, family_name)
130    }
131
132    /// Sets the ui-sans-serif generic family mapping.
133    pub fn set_ui_sans_serif_family(&mut self, family_name: &str) -> Result<(), TextError> {
134        self.set_generic_family(GenericFamily::UiSansSerif, family_name)
135    }
136
137    /// Sets the ui-monospace generic family mapping.
138    pub fn set_ui_monospace_family(&mut self, family_name: &str) -> Result<(), TextError> {
139        self.set_generic_family(GenericFamily::UiMonospace, family_name)
140    }
141
142    /// Sets the ui-rounded generic family mapping.
143    pub fn set_ui_rounded_family(&mut self, family_name: &str) -> Result<(), TextError> {
144        self.set_generic_family(GenericFamily::UiRounded, family_name)
145    }
146
147    /// Sets the emoji generic family mapping.
148    pub fn set_emoji_family(&mut self, family_name: &str) -> Result<(), TextError> {
149        self.set_generic_family(GenericFamily::Emoji, family_name)
150    }
151
152    /// Sets the math generic family mapping.
153    pub fn set_math_family(&mut self, family_name: &str) -> Result<(), TextError> {
154        self.set_generic_family(GenericFamily::Math, family_name)
155    }
156
157    /// Sets the fangsong generic family mapping.
158    pub fn set_fang_song_family(&mut self, family_name: &str) -> Result<(), TextError> {
159        self.set_generic_family(GenericFamily::FangSong, family_name)
160    }
161
162    /// Call after clearing the font `Collection` to restore the generic family mappings.
163    pub fn restore_generic_families(&mut self) {
164        for (generic_family, family_name) in core::mem::take(&mut self.generic_families).iter() {
165            if let Err(err) = self.set_generic_family(*generic_family, family_name) {
166                {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event src/parley_context.rs:166",
                        "bevy_text::parley_context", ::tracing::Level::WARN,
                        ::tracing_core::__macro_support::Option::Some("src/parley_context.rs"),
                        ::tracing_core::__macro_support::Option::Some(166u32),
                        ::tracing_core::__macro_support::Option::Some("bevy_text::parley_context"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::WARN <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::WARN <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("Failed to restore generic font family mapping: {0:?} -> {1}, {2}",
                                                    generic_family, family_name, err) as
                                            &dyn ::tracing::field::Value))])
            });
    } else { ; }
};bevy_log::warn!(
167                    "Failed to restore generic font family mapping: {generic_family:?} -> {family_name}, {err}"
168                );
169            }
170        }
171    }
172}
173
174/// Text layout context
175#[derive(impl bevy_ecs::resource::Resource for LayoutCx where
    Self: ::core::marker::Send + ::core::marker::Sync + 'static {}Resource, #[automatically_derived]
impl ::core::default::Default for LayoutCx {
    #[inline]
    fn default() -> LayoutCx { LayoutCx(::core::default::Default::default()) }
}Default, impl ::core::ops::Deref for LayoutCx {
    type Target = LayoutContext<TextBrush>;
    fn deref(&self) -> &Self::Target { &self.0 }
}Deref, impl ::core::ops::DerefMut for LayoutCx {
    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
}DerefMut)]
176pub struct LayoutCx(pub LayoutContext<TextBrush>);
177
178/// Text scaler context
179#[derive(impl bevy_ecs::resource::Resource for ScaleCx where
    Self: ::core::marker::Send + ::core::marker::Sync + 'static {}Resource, #[automatically_derived]
impl ::core::default::Default for ScaleCx {
    #[inline]
    fn default() -> ScaleCx { ScaleCx(::core::default::Default::default()) }
}Default, impl ::core::ops::Deref for ScaleCx {
    type Target = ScaleContext;
    fn deref(&self) -> &Self::Target { &self.0 }
}Deref, impl ::core::ops::DerefMut for ScaleCx {
    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
}DerefMut)]
180pub struct ScaleCx(pub ScaleContext);