Ensure GlyphRunImpl has consistent bounds #12765
Merged
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.
What does the pull request do?
This PR makes sure that the bounds of a
GlyphRunImpl
are always computed with the same edging.What is the current behavior?
Currently, the font's edging might be changed between two
GlyphRunImpl
creations, resulting in different bounds with the same parameters with some specific fonts and sizes.What is the updated/expected behavior with this PR?
The same parameters result in the same
GlyphRun
bounds. A test has been added.How was the solution implemented (if it's not obvious)?
Avoiding
SKFont
sharingThe
SKFont
property has been removed fromGlyphTypefaceImpl
to avoid mutating the same font instance depending on usages. TheSKFont
was initially created with default parameters, but those parameters were changed by various methods (GlyphRunImpl.GetTextBlob()
,PlatformRenderInterface.BuildGlyphRunGeometry()
).Fixing those methods to restore the old font property values isn't sufficient: the
SKFont
is currently implicitly used (through theGlyphRun
) by both the UI and the render thread, and it's theoretically possible to have some text being rendered with a given size, while the font is mutated by the UI thread to another size: it's not thread safe.Since the
SkFont
itself is pretty lightweight (it's basically a typeface pointer + some primitive fields), it's created when needed instead. Performance wise, It's two very short-lived (Gen0) allocations perGlyphRun
, which is basically noise in text processing.Using a default edging
GlyphRunImpl
now always use a default font edging ofSubpixelAntialias
while computing the bounds. Ideally the requested edging should be passed to the glyph run, but we can't since the actual edging is computed dynamically by the drawing context from theRenderOptions
. The bounds are needed earlier, in the UI thread, for measuring purposes.This can result in a 1px difference between the computed bounds and the rendered text in some cases. While the solution isn't perfect, it's still better than using the latest globally used edging: at least it's now consistent.
Fixed issues
Future
In the long term, I think the UI layer should be responsible for computing the actual render options so they can be used in the layout pass, and passed directly to the drawing context implementation. A possible implementation would be an inherited property (as a bonus, it would allow render options to be settable in styles).
It would also avoid repeating the same render options logic in every graphics platform (not that we have that many).
Pinging @Gillibald the text master :)