* Add failing tests for whitespace absorbed into a fallback run
A fallback run is extended for as long as the fallback font has glyphs
instead of ending where the primary font regains coverage. Practically
every font maps U+0020, so the space that follows fallback text is
pulled into the fallback run and shaped with its space glyph.
- itemization: a Hebrew letter followed by " b" must produce a 1-char
fallback run, not a 2-char one that swallows the space
- measurement: the space after an emoji must have the same advance as
the same space elsewhere in the line
* Merge abutting text bounds within the usual float tolerance
The two edges being compared are reached by summing glyph advances along
different paths, so abutting bounds can land an ULP apart and a single
directional span gets reported as two rectangles. Compare them the way
the rest of layout compares coordinates.
* End a fallback run where the default typeface regains coverage
Whitespace was exempt from the return-to-primary check so that a space
wouldn't split a fallback run. Practically every font maps U+0020, so
the exemption let a fallback run reach past the text the default
typeface couldn't render and shape the following space with the
fallback's own advance - a full em in most emoji fonts, which is the
long space reported after an emoji.
- the check now applies to spacing whitespace (Zs), so a fallback run
ends at the first cluster the default typeface can render; control
and format codepoints stay exempt - many fonts map the
default-ignorable bidi controls, and a default typeface whose cmap
merely has such a mark must not pull it out of the fallback run: the
mark renders nothing either way, and the split cuts the run for no
reason
- a default typeface that cannot shape the run's script is still not a
return target for text, but it does reclaim the spacing whitespace
between the words, which carries no shaping
- a run of pure whitespace no longer becomes the anti-thrashing bias for
the next run, so the words on either side of a space keep resolving to
the same fallback font
Test expectations that encoded the old run structure move with it: a
line of emoji separated by spaces is no longer a single run, glyph
clusters are relative to each run's own text (the affected helpers now
add the run's start), and the spaces of a right-to-left line measure
with the primary font, which widens those lines.
* Add failing test for a word gap at a run boundary
Justification collects break opportunities run by run. The line breaker
always reports a break at the end of the text it is given, and that
artificial run-final break is filtered out - so a real word gap that
happens to fall on a run boundary produces no opportunity at all and is
never widened. A line whose word gap borders a fallback run is left
partly or entirely unjustified.
* Search break opportunities in the line text, not per run
A run boundary is not a text boundary - a font fallback or a style
change splits a run mid-sentence - but the line breaker reports a break
at the end of whatever text it is given. Searching run by run invented a
break at every run boundary, and dropping those artefacts also dropped
every real word gap that fell on one.
- collect the opportunities from each stretch of consecutive text runs,
copied into a pooled buffer, and exclude only the stretch-final break
- runs that carry no text (embedded objects, end of line) end a stretch,
as do runs whose length doesn't match their text, since neither can be
mapped back to text source positions by offset
* Fix TextBlock ellipsis not showing with TextWrapping and MaxLines
When TextWrapping and MaxLines are set, the collapsing width was using the
layout's maximum width instead of the current line's width. This caused the
ellipsis to not appear when the last line was shorter than other lines.
Also added HasCollapsed check to prevent double-collapsing when text has
already been collapsed due to overflow.
* Remove HasCollapsed check
* Add unit test for MaxLines trailing ellipsis on short wrapped lines
* Remove redundant comment
* fix: simplify TextLayout test
* Fix inter-word justification distribution and safety
TextAlignment.Justify was incorrect or a no-op in several common cases.
This corrects glyph targeting, buffer safety, run partitioning, the fill
target, and which lines get justified.
- Target the glyph ending each break boundary; step zero-width breaks
(CJK/Korean ideograph boundaries, hyphens) back one so the widened gap
sits on the break and the last visible glyph is never stretched.
- Copy-on-write the shaped buffer before adjusting advances and swap in a
fresh run, so justification never mutates glyph storage shared with a
TextRunCache entry, a Split sibling or a WithBidiLevel alias. Adds
ShapedBuffer.CloneWritable and TextLineImpl.ReplaceTextRun, which also
repoints the bidi-reordered runs used by draw and hit-test.
- Consume break opportunities per run instead of draining the whole queue
against the first run.
- Fill the visible Width to the paragraph width rather than the width
including trailing whitespace, so wrapped lines with trailing whitespace
justify instead of being left un-justified.
- Target MaxWidth for wrapped text rather than the widest produced line.
- Skip the last line, newline-terminated lines and hard-break lines.
Adds justification test coverage: CJK, mixed Latin+CJK, Arabic buffer
integrity, Latin wrapping, trailing whitespace and multi-run lines.
* Add failing test for trailing-whitespace overcount across runs
- TextLineImpl.CreateLineMetrics walks a line's runs backward to
compute trailing whitespace, stopping only when a run has none of
its own - not when a run is only partly whitespace.
- On a multi-run line where an interior run also ends in a space
(common at a script boundary, since each script run tends to end at
the following space), that space gets wrongly counted as trailing
too, even though visible content follows it later in the line.
- This shrinks Width, which InterWordJustification uses to decide how
much space a line still needs to reach the target width.
* Fix trailing-whitespace overcount across runs
- Only continue accumulating trailing whitespace from an earlier run
when the current run is entirely whitespace; otherwise the current
run's own visible content is the line's true end, and an earlier
run's trailing space is interior, not trailing.
- Width now correctly includes interior, non-trailing whitespace, so
wrapped multi-run lines (e.g. mixed-script text) no longer get
stretched past the target width when justified.
* Ignore CLAUDE.md
* Introduce a universal IGlyphTypeface implementation that does not rely on any platform implementation
* Revert changes
* Fix Android
* Make the test happy
* Fix build
* Update baseline
* Fix naming
* Fix headless
* Move interfaces to dedicated files
Make GlyphTypeface.GlyphCount an integer
* Fix GlyphCount
* Make IGlyphTypeface NotClientImplementable
* Make sure we cache platform typefaces by their desired name, style, weight and stretch
* Update baseline
* Only use IGlyphTypeface
* Fix Android
* Try to clear the buffer before we encode somethimg
* Add needed test font
* Add more unit tests
* Reduce allocations
* Remove Direct2D1 test files
* More tests
* More complete table implementations
* More adjustments
* Use batch APIs
* Handle invalid timestamps
* Update baseline
* Introduce a CharacterToGlyphMap struct for faster access
* Remove AggressiveInlining
* Remove AggressiveInlining
* Make the head table optional for legacy fonts
* Remove Load method. Fix TextBlockTests
* Fix nullables
* Remove redundant folder
* Update Api baseline
* revert diff helper changes
* revert changes
* Use bare minimum font for Headless platform and introduce a test font manager that uses the Inter font for testing.
* Add missing font file for Headless platform
---------
Co-authored-by: Gillibald <stebner@avaloniaui.net>
Co-authored-by: Julien Lebosquain <julien@lebosquain.net>
* Enable nullability in RenderTests
* Enable nullability in LeakTests
* Enable nullability in Skia.UnitTests
* Enable nullability in Generators.Tests
* Enable nullability in DesignerSupport.Tests
* Enable nullability in Build.Tasks.UnitTests
* xml documentatation for paragraph properties
* TextTestApp
* text test files renamed parameter
* glyph ink bounds
* shaped buffer make selected row visible
* text test app force light theme
* text test app distinguish start and end distance marks
---------
Co-authored-by: Jan Kučera <miloush@users.noreply.github.com>
Co-authored-by: Benedikt Stebner <Gillibald@users.noreply.github.com>
Co-authored-by: Julien Lebosquain <julien@lebosquain.net>
* Fix issue with MinTextWidth (Fixes#18372)
* Make sure that MeasureOverride for TextPresenter and TextBlock are using same textWidth
* Revert #16601 that is introducing an invalid calculation for the OverhangLeading
Add tests for OverhangLeading and OverhangTrailing
* Revert MinTextWidth
* Fix tests to not rely on fixed values
* Fix remaining issues
* Fix comment in Direct2D1 GlyphRunImpl.cs
* Fix Direct2D1 rendering
* Fix gold images
* Restore TextLineImpl
* Update gold image
* Restore Math.Max on OverhangLeading and Trailing
* Adopt similar behavior to WPF: don't use OverhangLeading/Trailing for measuring and remove clip by default.
But it requires further support with NeedsClipBounds
* Remove MinTextWidth
Keep ClipToBounds=true default for TextBlock
* Revert change
---------
Co-authored-by: Benedikt Stebner <Gillibald@users.noreply.github.com>