Repository navigation
fix(text-editor): keep huge text from corrupting the glyph atlas - #908
Merged
Merged
Conversation
Impeller rasterizes every glyph into one atlas shared by all text, also the glyphs it then draws as paths, and a text layer's scale is applied as its font size, so a layer scaled up very large needed glyphs thousands of pixels big. Once growing the atlas failed, every glyph added later was drawn from the wrong place, garbling text across the whole app until it restarted. Text above 64 pixels now keeps its layout at its real size and draws only its glyphs from copies set in a 5.25 pixel font, scaled up onto the place each run has in the real layout. Emoji runs are copied at 32 pixels, where color emoji keep their proportions.
Each copied run was painted at the negative of its anchor while its gradient was spread in the run's own coordinates. A shader does not move with the offset a paragraph is painted at, so the gradient of large text slid by the copy's baseline: a vertical gradient came out almost inverted, a diagonal one shifted. The run is now painted at its origin with the anchor folded into the canvas transform, and the gradient test also runs down and across the lines. Also shortens the changelog entry.
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.
Description
Problem. Scaling a text layer up very large, or zooming the canvas onto big text, could leave text across the whole app garbled until the app restarted: letters missing or replaced by pieces of other letters, editor icons turning into blocks. Impeller rasterizes every glyph into one atlas shared by all text, including glyphs it then draws as paths (above 250 device pixels). The editor applies a text layer's scale as its font size, and Impeller only caps the canvas scale at 48×, not the font size, so the glyphs of a big layer reached thousands of pixels. When growing the atlas failed, Impeller did not roll back its bookkeeping, and every glyph added after that was drawn from the wrong place. With 14.19.0 a long text layer broke the atlas from about 7.5× and a short one between 14× and 20×. Zooming the canvas 5× onto a 192 pt outlined text broke it as well.
Approach. Text above 64 pixels keeps its layout at its real size and only draws its glyphs from copies set in a 5.25 pixel font, scaled up onto the place each run has in that layout.
TextPainterstill decides everything else. Size, line breaks, background, hit testing and captures are unchanged. A smaller layout would not match: SkParagraph rounds every line height to a whole unit, so a small layout cannot reproduce the real line positions.top + floor(ascent + 0.5). The reportedLineMetrics.baselineuses the rounded line height instead, and anchoring there shifted large text by up to 4 px.Not covered.
Testing.
ProImageEditor. Each case was run with 14.19.0 and with this branch.scaled_text_lines_testcompares the ink of the copies with the realTextPainteracross alignments, wrapping, line breaks, mixed sizes, strokes and gradients. It catches the reported-baseline mistake. It also covers emoji segmentation andcanDraw.rounded_background_text_large_text_testcovers the wiring: the threshold, box shrinking, silhouette shadows and the justified fallback.flutter analyzeis clean, and all 1265 tests pass.Related Issue: Closes #none
Type of Change