Repository navigation
Conversation
Fonts are often loaded asynchronously: text is shaped with the fonts available now, missing glyphs are reported through the fallback callback, the application fetches the fonts and adds them to the collection. Until now there was no way to make existing layouts pick up the newly added fonts: - skb_layout_params_hash_append() identified the font collection only by its id, which is assigned once at creation. A layout shaped against an older state of the collection therefore hashed identically to an up-to-date one, so both the layout cache and the rich layout's incremental rebuild kept serving stale layouts. - The editor relayouts only as a side effect of content mutations (set text, insert, remove, attribute changes, undo); there was no public entry point to refresh the layout without touching the text. The only workaround was to reset the content wholesale, e.g. calling skb_editor_set_rich_text() with a copy of the current text, which churns the selection, composition, and undo state. This commit makes font collection changes observable, and gives the editor a way to act on them: - skb_font_collection_t keeps a revision counter, bumped on every successful font add or remove, exposed via skb_font_collection_get_revision(). - skb_layout_params_hash_append() includes the revision next to the collection id, so the layout cache and skb_rich_layout's params hash naturally treat layouts shaped against an older revision as stale. - New skb_editor_update_layout() re-runs the editor's layout update without modifying any editor state. Through the params hash it rebuilds everything when the font collection has changed, and is effectively a no-op otherwise, so it is safe to call liberally (e.g. whenever an async font fetch completes). Tests: font_collection_tests covers the revision bumps on add/remove (including no bump on failed add/remove) and the resulting params hash change; editor_tests covers the end-to-end case of shaping Latin and Arabic text with a Latin-only collection, adding an Arabic font, and verifying that skb_editor_update_layout() reshapes the Arabic run with the new font while the text and selection stay untouched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Sorry this slipped through my radar on summer vacation. The approach feels a bit rough, as adding a (non-missing) font can also cause full refresh. Thinking out loud: In skb__itemize() around line 440, we detect if we have a missing font. We could use that opportunity flag that the layout has missing fonts (e.g. add SKB_LAYOUT_HAS_MISSING_FONT to skb_layout_flags_t). I think this on it's own could be useful. In skb_rich_layout_set_from_rich_text(), we could add font_collection_version (looks like I use version instead of revision in some places) in skb_layout_paragraph_t, rebuild a paragraph is the font collection version changes, and we have missing fonts. It should be possible to do similar treatment to layout cache by storing font_collection_version to skb__cached_layout_t too, and rebuild the layout if missing fonts. |
In some applications, fonts are loaded asynchronously: text is shaped with the fonts available now, missing glyphs are reported through the fallback callback, the application fetches the fonts and adds them to the collection. Until now there was no way to make existing layouts pick up the newly added fonts:
This commit makes font collection changes observable, and gives the editor a way to act on them:
Tests: font_collection_tests covers the revision bumps on add/remove (including no bump on failed add/remove) and the resulting params hash change; editor_tests covers the end-to-end case of shaping Latin and Arabic text with a Latin-only collection, adding an Arabic font, and verifying that skb_editor_update_layout() reshapes the Arabic run with the new font while the text and selection stay untouched.
As with my recent commits, I've used Claude to help me with this change. I've thoroughly reviewed it. I believe the use-case is real, and it solves a problem in my project. As always I defer to your judgement on all matters. Happy to iterate as much as you need.