Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 68 additions & 23 deletions crates/bevy_text/src/font.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
use crate::ComputedTextBlock;
use crate::FontCx;
use crate::FontSource;
use crate::TextFont;
use bevy_asset::Asset;
use bevy_asset::AssetId;
use bevy_asset::Assets;
use bevy_ecs::change_detection::DetectChangesMut;
use bevy_ecs::system::Local;
use bevy_ecs::system::Query;
use bevy_ecs::system::Res;
use bevy_ecs::system::ResMut;
use bevy_platform::collections::HashSet;
use bevy_reflect::TypePath;
use parley::fontique::Blob;
use parley::fontique::FontInfoOverride;
use smol_str::SmolStr;

/// An [`Asset`] that contains the data for a loaded font, if loaded as an asset.
Expand All @@ -29,8 +29,9 @@ use smol_str::SmolStr;
pub struct Font {
/// Content of a font file as bytes
pub data: Blob<u8>,
/// Font family name.
/// If the font file is a collection with multiple families, the first family name from the last font is used.
/// Font family name used to resolve this asset when referenced by handle.
/// If the font file is a collection with multiple families, this is the family name from the
/// first font face in the collection.
pub family_name: SmolStr,
}

Expand All @@ -46,32 +47,76 @@ impl Font {

/// Add new font assets to the internal font collection.
pub fn load_font_assets_into_font_collection(
fonts: Res<Assets<Font>>,
mut fonts: ResMut<Assets<Font>>,
mut loaded_fonts: Local<HashSet<AssetId<Font>>>,
mut font_cx: ResMut<FontCx>,
mut text_block_query: Query<&mut ComputedTextBlock>,
mut text_font_query: Query<&mut TextFont>,
) {
let mut new_fonts_added = false;

loaded_fonts.retain(|id| fonts.contains(*id));

for (id, font) in fonts.iter() {
if loaded_fonts.insert(id) {
font_cx.0.collection.register_fonts(
font.data.clone(),
Some(FontInfoOverride {
family_name: Some(font.family_name.as_str()),
..Default::default()
}),
);
new_fonts_added = true;
let new_asset_ids: Vec<_> = fonts.ids().filter(|id| loaded_fonts.insert(*id)).collect();

if new_asset_ids.is_empty() {
return;
}

let mut new_family_ids = Vec::new();
for asset_id in new_asset_ids.iter() {
let font_data = fonts
.get(*asset_id)
.expect("AssetId should have a corresponding asset")
.data
.clone();

let new_fonts = font_cx.collection.register_fonts(font_data, None);

if let Some((_, family_id)) = new_fonts
.iter()
.flat_map(|(family_id, fonts)| {
fonts
.iter()
.map(move |font_info| (font_info.index(), *family_id))
})
.min_by_key(|(index, _)| *index)
&& let Some(family_name) = font_cx.0.collection.family_name(family_id)
&& let Some(font) = fonts.get_mut_untracked(*asset_id)
{
font.family_name = family_name.into();
new_family_ids.extend(new_fonts.iter().map(|(family_id, _)| *family_id));
}
}

// Whenever new fonts are added, update all text blocks so they use the new fonts.
if new_fonts_added {
for mut block in text_block_query.iter_mut() {
block.needs_rerender = true;
for mut text_font in text_font_query.iter_mut() {
if match &text_font.font {
FontSource::Handle(handle) => new_asset_ids.contains(&handle.id()),
FontSource::Family(name) => font_cx
.collection
.family_id(name)
.is_some_and(|id| new_family_ids.contains(&id)),
generic_source => {
let generic_family = match generic_source {
FontSource::Handle(_) | FontSource::Family(_) => unreachable!(),
FontSource::Serif => parley::GenericFamily::Serif,
FontSource::SansSerif => parley::GenericFamily::SansSerif,
FontSource::Cursive => parley::GenericFamily::Cursive,
FontSource::Fantasy => parley::GenericFamily::Fantasy,
FontSource::Monospace => parley::GenericFamily::Monospace,
FontSource::SystemUi => parley::GenericFamily::SystemUi,
FontSource::UiSerif => parley::GenericFamily::UiSerif,
FontSource::UiSansSerif => parley::GenericFamily::UiSansSerif,
FontSource::UiMonospace => parley::GenericFamily::UiMonospace,
FontSource::UiRounded => parley::GenericFamily::UiRounded,
FontSource::Emoji => parley::GenericFamily::Emoji,
FontSource::Math => parley::GenericFamily::Math,
FontSource::FangSong => parley::GenericFamily::FangSong,
};
font_cx
.collection
.generic_families(generic_family)
.any(|id| new_family_ids.contains(&id))
}
} {
text_font.set_changed();
}
}
}
16 changes: 8 additions & 8 deletions crates/bevy_ui/src/widget/text_input_layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ pub fn update_editable_text_content_size(
|| text_font.is_changed()
|| line_height.is_changed()
|| target.is_changed()
|| fonts.is_changed()
|| rem_size.is_changed())
{
continue;
Expand Down Expand Up @@ -170,10 +169,8 @@ pub fn update_editable_text_styles(
for (mut editable_text, text_font, line_height, target, text_layout) in
editable_text_query.iter_mut()
{
let editor = editable_text.editor_mut();

if f32::EPSILON < (target.scale_factor() - editor.get_scale()).abs() {
editor.set_scale(target.scale_factor());
if f32::EPSILON < (target.scale_factor() - editable_text.editor.get_scale()).abs() {
editable_text.editor.set_scale(target.scale_factor());
}

if text_font.is_changed()
Expand All @@ -183,9 +180,12 @@ pub fn update_editable_text_styles(
FontSize::Vw(_) | FontSize::Vh(_) | FontSize::VMin(_) | FontSize::VMax(_)
) && target.is_changed()
{
editor.edit_styles().insert(StyleProperty::FontSize(
text_font.font_size.eval(target.logical_size(), rem_size.0),
));
editable_text
.editor
.edit_styles()
.insert(StyleProperty::FontSize(
text_font.font_size.eval(target.logical_size(), rem_size.0),
));
}

if text_font.is_changed() {
Expand Down
Loading