Leave a character the document font has in that font when substituting (#76) - #303
Merged
jakejackson1 merged 1 commit intoSep 22, 2026
Merged
Conversation
#76) A run moved to a backup font carried the spaces inside it along, so a space between two emoji was the emoji font's. Noto Color Emoji's space is as wide as an emoji. The Plane 2 branch's space clause never applied, since a space is never above U+1FFFF. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #76. Split out of #299, where it was the second commit. It fixes the CBDT, sbix and COLRv0 fonts already merged, so it doesn't need to wait for COLRv1.
Substitution no longer moves a character the document font has into a backup font.
What was wrong
A run moved to a backup font carried the spaces inside it along (
$flag == 1 && $char == 32inSubstituteCharsMB()). So a space between two emoji was the emoji font's own. Noto Color Emoji's space is as wide as an emoji, which left an emoji-sized blank after every space between emoji.What changes
SubstituteCharsNonCore(), carried spaces the same way and gets the same rule.fonttrans[$bsf]for a backup font that isn't a core font's name, which warned on every such font. The read is now guarded.What it costs
Every substituted run now ends at a space, so a run of words is one span per word, not one per paragraph.
Tfwhere it had 17.SubstituteCharsMB()finds emoji as its scan reaches them (Emoji::clusterAt(), now public), instead of finding every emoji in the rest of the text on every pass. The output is the same. On a 2000-word paragraph that is 1376 ms → 292 ms for emoji and 2262 ms → 573 ms for Korean.Tests
EmojiSubstitutionTestasserts the space splits the run, for a TrueType document font and for Helvetica.Merging with #299
#299's
color-emoji-colrv1snapshot and #300'scolor-emoji-svgwere made without this change. Whichever of #299 and this PR merges second needs a rebase andcomposer snapshot:update color-emoji-colrv1(andcolor-emoji-svgon #300).🤖 Generated with Claude Code