Skip to content

text input: retry the font family resolve when the font asset lands - #25474

Open
Cyannide wants to merge 2 commits into
bevyengine:mainfrom
Cyannide:text_input_font_retry
Open

text input: retry the font family resolve when the font asset lands#25474
Cyannide wants to merge 2 commits into
bevyengine:mainfrom
Cyannide:text_input_font_retry

Conversation

@Cyannide

Copy link
Copy Markdown
Contributor

Objective

An EditableText field whose TextFont names a FontSource::Handle can end up
rendering in parley's default family for the rest of its life.

update_editable_text_styles pushes the resolved family only when
text_font.is_changed():

if text_font.is_changed()
    && let Ok(resolved_family) = text_font.font.resolve_font_family(fonts.as_ref())

On the frame a field spawns, its handle is usually still loading, so
resolve_font_family fails. TextFont is not is_changed() again after that
frame, so nothing ever retries: the font asset finishes loading, gets registered
into the FontContext, and the editor is never told to use it.

The field is left with whatever family parley defaults to, while an equivalent
non-editable Text node picks the font up correctly.

Solution

Also attempt the resolve when Assets<Font> changes, which is exactly when a
late handle becomes resolvable. One extra insert(FontFamily) per editable
field per font-asset change; it is skipped entirely once the resolve succeeds
and no further font assets arrive.

A narrower alternative would be to read AssetEvent<Font> and match the
Added/Modified ids against each field's handle. That is more code for a
system that already runs every frame and whose body is a handful of style
inserts, so this takes the simpler condition.

Testing

Found while chasing a related bug in a fork of 0.19, where the same skip also
swallowed LineHeight and TextLayout syncing (that code used continue
rather than a let-chain, so an unresolved font skipped the rest of the loop
body; main's let-chain refactor already fixed that half). With the retry, a
field whose font handle resolves a frame or two after spawn renders in the
requested family; without it, it never does.

update_editable_text_styles pushed the resolved family only on
`text_font.is_changed()`. On the frame an EditableText field spawns, a
FontSource::Handle is usually still loading, so resolve_font_family fails --
and TextFont is never `is_changed()` again, so nothing retries. The asset
finishes loading, gets registered into the FontContext, and the editor is
never told about it: the field renders in parley's default family for the rest
of its life, while an equivalent non-editable Text node picks the font up.

Attempt the resolve when Assets<Font> changes as well, which is when a late
handle actually becomes resolvable.
@alice-i-cecile alice-i-cecile added C-Bug An unexpected or incorrect behavior A-Assets Load files from disk to use for things like images, models, and sounds A-Text Rendering and layout for characters labels Aug 19, 2026
@github-project-automation github-project-automation Bot moved this to Needs SME Triage in Assets Aug 19, 2026
@alice-i-cecile alice-i-cecile added the S-Needs-Review Needs reviewer attention (from anyone!) to move forward label Aug 19, 2026

@alice-i-cecile alice-i-cecile left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you make this comment briefer? I have a hard time piecing together what it means in the current form. Logic seems fine though :)

@alice-i-cecile alice-i-cecile added S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Aug 20, 2026
I didn't really manage to make it shorter, but at least it reads better...
@Cyannide

Copy link
Copy Markdown
Contributor Author

Can you make this comment briefer? I have a hard time piecing together what it means in the current form. Logic seems fine though :)

I tried, but I think I just made it longer 🤣

@alice-i-cecile alice-i-cecile left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clearer still!

@alice-i-cecile alice-i-cecile added D-Straightforward Simple bug fixes and API improvements, docs, test and examples S-Needs-Review Needs reviewer attention (from anyone!) to move forward and removed S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged labels Aug 20, 2026
@alice-i-cecile alice-i-cecile added this to the 0.19.2 milestone Aug 20, 2026

@ickshonpe ickshonpe left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about adding this fonts changed check in #25450, but there is already a mechanism to set TextFonts changed when fonts are loaded, so it seemed like it would be okay without it. Maybe there is some weakness in the font loading detection logic, it is quite convoluted and confounded by system ordering etc.

It isn't ideal to update all EditableText's on any font asset changes, but it seems fine for now as a defensive measure. It's not like fonts assets are updated constantly, and apps don't tend to have more than a handful of active input fields at once anyway.

@ickshonpe ickshonpe added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Aug 20, 2026
@ickshonpe

Copy link
Copy Markdown
Contributor

This test passes on main:

    #[test]
    fn test_update_editable_text_styles_reresolves_family_once_font_loads() {
        let mut app = App::new();
        app.init_resource::<Assets<Font>>()
            .init_resource::<FontCx>()
            .init_resource::<RemSize>()
            .add_systems(
                Update,
                (
                    load_font_assets_into_font_collection,
                    update_editable_text_styles,
                )
                    .chain(),
            );

        let font_handle = app.world().resource::<Assets<Font>>().reserve_handle();
        let entity = app
            .world_mut()
            .spawn((
                EditableText::new("some text"),
                TextFont::from(font_handle.clone()),
                ComputedUiRenderTargetInfo::default(),
            ))
            .id();

        app.update();

        assert!(!app
            .world()
            .entity(entity)
            .get::<EditableText>()
            .unwrap()
            .editor
            .get_styles()
            .inner()
            .values()
            .any(|style| matches!(style, StyleProperty::FontFamily(_))));

        app.world_mut()
            .resource_mut::<Assets<Font>>()
            .insert(
                font_handle.id(),
                Font::from_bytes(
                    include_bytes!("../../../bevy_text/src/FiraMono-subset.ttf").to_vec(),
                ),
            )
            .unwrap();
        app.update();

        assert!(app
            .world()
            .entity(entity)
            .get::<EditableText>()
            .unwrap()
            .editor
            .get_styles()
            .inner()
            .values()
            .any(|style| matches!(
                    style,
                    StyleProperty::FontFamily(parley::FontFamily::Single(
                        parley::FontFamilyName::Named(name)
                    )) if name.as_ref() ==
            &app
                .world()
                .resource::<Assets<Font>>()
                .get(&font_handle)
                .unwrap()
                .alias
                )));
    }

So I'm not sure how it would fail to reresolve on loading, do you have a reproduction?

@Cyannide

Copy link
Copy Markdown
Contributor Author

This test passes on main:

So I'm not sure how it would fail to reresolve on loading, do you have a reproduction?

It may not even be an issue anymore because of the let-chain fix...it was reproducible before the let-chain with continue in place, but now the line height and alignment are properly handled at spawn even when the font hasn't resolved yet.

@ickshonpe ickshonpe removed the S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it label Aug 20, 2026
@alice-i-cecile
alice-i-cecile added this pull request to the merge queue Aug 20, 2026
@alice-i-cecile alice-i-cecile added the S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it label Aug 20, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Aug 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Assets Load files from disk to use for things like images, models, and sounds A-Text Rendering and layout for characters C-Bug An unexpected or incorrect behavior D-Straightforward Simple bug fixes and API improvements, docs, test and examples S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it

Projects

Status: Needs SME Triage

Development

Successfully merging this pull request may close these issues.

4 participants