Skip to content

[win32] Resolve tab stops entirely in points in TextLayout.computeRuns() - #3495

Draft
vogella wants to merge 2 commits into
eclipse-platform:masterfrom
vogella:textlayout-tab-stops-cleanup
Draft

[win32] Resolve tab stops entirely in points in TextLayout.computeRuns()#3495
vogella wants to merge 2 commits into
eclipse-platform:masterfrom
vogella:textlayout-tab-stops-cleanup

Conversation

@vogella

@vogella vogella commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Stacked on #3493, which contains the actual fix. Only the second commit belongs to this PR; it will show on its own once #3493 is merged.

The tab stop handling in TextLayout.computeRuns() mixes units: the stop is selected in points while the resulting position and the adjustment for merged consecutive tabs are accumulated from the pixel-converted stops. This keeps the whole computation in points and converts once, when the final position is known, so the pixel copy of the stops disappears and the merged-tab adjustment works on the same values as the lookup.

Besides being easier to follow, it removes a rounding drift: each step past the last tab stop currently rounds separately, so the positions can end up a pixel away from the stop the caller defined. No behavior change for well-formed tab stops.

TextLayout.setTabs() takes the tab stops in points, but computeRuns()
converted them to pixels and compared them against a pen position
accumulated from raw glyph advances. At zoom levels that are not a
multiple of 100 the point/pixel round trip can place a stop one pixel
past a pen position that actually sits exactly on that stop, so the
tab advanced by a single pixel instead of moving to the next stop.

StyledText hits this because it measures its tab width as the width of
N spaces in points and passes that back as the only tab stop, so a tab
following N spaces lands precisely on the stop. It became visible in
4.36 when monitor-specific scaling turned the effective auto-scale from
"integer" into "quarter", exposing zoom 125, 150 and 175.

Only the selection of the stop was ever wrong, so both comparisons that
ask whether a stop is still ahead of the pen now happen in points, the
unit the stops were defined in. Once a stop has been picked, its pixel
position is still used unchanged for the run width, and the block that
adjusts merged consecutive tabs is untouched.

Fixes eclipse-platform/eclipse.platform.ui#3052
The tab stop handling mixed units: the stop was selected in points while
the resulting position and the adjustment for merged consecutive tabs
were accumulated from the pixel-converted stops. That works, but every
step past the last stop rounds separately, so the positions can drift by
a pixel from the stop the caller defined, and reasoning about the block
requires tracking two units at once.

Keep the whole computation in points and convert once, when the final
position is known. This removes the pixel copy of the stops and makes
the merged-tab adjustment operate on the same values as the lookup.

The degenerate case of a non-increasing tabs array now leaves the run at
its measured glyph advance rather than adding a non-positive stop delta
to it, which was meaningless anyway.

No behavior change for well-formed tab stops.
@github-actions

Copy link
Copy Markdown
Contributor

Test Results (win32)

   35 files  ±0     35 suites  ±0   5m 19s ⏱️ -18s
4 873 tests +5  4 797 ✅ +5  76 💤 ±0  0 ❌ ±0 
1 400 runs  +5  1 376 ✅ +5  24 💤 ±0  0 ❌ ±0 

Results for commit 2cae3e0. ± Comparison against base commit 4755f49.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant