Skip to content

Commit 0ce9d15

Browse files
committed
fix(text): wrap-shrink axis error; substring measure; trailing-icon trim
Three inline-|T measure fixes, the first one load-bearing for chat. 1) Wrap shrink was overscaled by the render aspect. The wrap stepper's inputs are gxu-normalized PER AXIS -- fontH normalized-Y (x rasterY = pen px), wrapWidth/outWidth normalized-X (x rasterX = pen px); both caller flavors land there (the draw builder passes node+0x1C/+0x3C, pre-normalized at block creation via FUN_0041ae50/ae40, and the fs-level callers x-normalize inside FUN_0044d670 before gxu, verified by decompile). The hook converted the pen-x icon sum with fontH/fontHPx -- a Y-AXIS factor -- overshrinking the wrap budget by rasterX/rasterY: x1.33 at the 4:3 setups it was calibrated on (subtle, and the glyph-relative tolerances were inflated by the same factor, masking it), x2.37 at 2560x1080 -- icon-bearing chat lines wrapped a word or two early per icon. The correct pen-x -> width-units factor is 1/rasterX; the auto-width bail, feasibility band, escalation step and bisect threshold now derive from fontHPx/rasterX so a "half glyph" tolerance is an actual glyph width. 2) The substring measure (FUN_00772AE0, new Offsets entry) is now icon-aware. An earlier note claimed nothing consumed it; its xrefs refute that: the GameTooltip auto-size measures each WRAPPED SEGMENT of a wrap-enabled line through it (breaks from FUN_00772B60, already icon-aware via the stepper hook) and takes the max as the tooltip width -- so icon-bearing wrapped tooltip lines undersized their tooltip. Same pen-exact adjustment as the width hook; the editbox caret/selection callers (10 of its 11 xrefs) keep measuring raw via the established editable-bit / focused-buffer gates. 3) A string-final icon now reports its INK edge instead of its full advance (TrailingIconTrimPen: subtract the trail half-pad + half the outline ink when the text ends in a well-formed span), matching the engine's own last-glyph convention -- the measure loop ends on ink, not advance. Render/justify/wrap keep the full advance (the pen genuinely moves); only the reported width changes. The visible beneficiary is the money-string shape ("...|TCoin:0|t"): a right-anchored auto-width money fs sizes to the coin's drawn edge instead of ~2px past it. Remaining width residual is sub-pixel (region placement rounding + the base loop's ~0 payload-0 token contribution).
1 parent 23b622a commit 0ce9d15

3 files changed

Lines changed: 188 additions & 57 deletions

File tree

docs/InlineTextureEscapes.md

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,15 @@ The DLL hooks the engine's own text pipeline — no companion addon:
7979
TGA.
8080
- **Anti-spoof** — chat strips player-injected `|T` icons.
8181

82-
The one measure path still icon-blind is the substring width (`FUN_00772AE0`),
83-
which nothing consumes yet. The Lua control surface is one kill switch,
84-
`_classicapi_InlineTexEnable` (the SEH latch trips it on a flush fault); the
85-
bring-up tune / stat / probe functions were removed (`5e5677b`, `6800a9a`).
82+
Every fs-level measure path now counts icons: width (`FUN_00772890`), height
83+
(`FUN_007729B0`), wrap (`FUN_005C7260`), and the substring measure
84+
(`FUN_00772AE0` — an earlier note claimed nothing consumed it; its xrefs
85+
refute that: the GameTooltip auto-size measures each WRAPPED SEGMENT of a
86+
wrap-enabled line through it, so icon-bearing wrapped tooltip lines
87+
undersized their tooltip until it was hooked too). The Lua control surface is
88+
one kill switch, `_classicapi_InlineTexEnable` (the SEH latch trips it on a
89+
flush fault); the bring-up tune / stat / probe functions were removed
90+
(`5e5677b`, `6800a9a`).
8691

8792
## REMOVED (bring-up record) — the raw-GxU-quad rendering primitive
8893

@@ -364,17 +369,19 @@ together. (A `_classicapi_InlineTexWrap(n)` ring dumped the last 8
364369
icon-bearing calls during bring-up; removed with the other diagnostics in
365370
`5e5677b`.)
366371

367-
Unit trap #2 (hit on first flight, like the width hook's): each caller passes
368-
fontH/wrapWidth in its OWN space — the draw builder passes node text units
369-
(node+0x1C / node+0x3C), and the fs-level callers (the path chat wraps
370-
through) pass the much smaller anchor-converted space. Subtracting a raw
371-
pixel advance annihilated the small widths to the floor and shredded
372-
icon-bearing chat lines into 2-glyph fragments. The space-agnostic conversion
373-
uses the engine's own convention: the measure loops realize their fontH param
374-
as pixels via `FUN_TEXT_FONT_HEIGHT(flag, fontH)` (see `FUN_005c6940`'s final
375-
scale), so px → caller units is exactly `fontH / fontHPx`. The hook computes
376-
the icon sum in true pixels (the same value the emitter reserves) and scales
377-
by that ratio.
372+
Unit trap #2 (hit TWICE): the stepper's inputs are gxu-normalized, PER AXIS —
373+
fontH is normalized-Y (× rasterY = pen px) and wrapWidth/outWidth are
374+
normalized-X (× rasterX = pen px). Both caller flavors land there: the draw
375+
builder passes node+0x1C/+0x3C (normalized at block creation), and the
376+
fs-level callers (the path chat wraps through) x-normalize their widths
377+
inside `FUN_0044d670` before gxu. First flight subtracted raw pixels and
378+
annihilated the small normalized widths (2-glyph chat fragments). The second
379+
converted with `fontH / fontHPx` — a Y-AXIS factor applied to an X-axis
380+
width — overshrinking the budget by the render aspect (×1.33 at 4:3, ×2.37
381+
at 2560×1080): icon-bearing chat lines wrapped a word or two early, worse per
382+
icon and per aspect. The correct pen-x → width-units factor is `1/rasterX`,
383+
and the glyph-relative tolerances use `fontHPx/rasterX` so "half a glyph"
384+
means an actual glyph width.
378385

379386
**Chat hyperlink hover over inline icons works (verified).** An emote wrapped in a
380387
hyperlink — `|Htel:name|h|T…|t|h`, the TwitchEmotes pattern — pops its tooltip when
@@ -393,14 +400,13 @@ formula.)
393400

394401
**Still icon-blind (accepted residuals):**
395402

396-
- The substring measure (`FUN_00772AE0`) still sees icons as ~0. It is a
397-
*separate* function from the hyperlink hover rect above (which works) — nothing
398-
consumes it yet; revisit it (also cold) if a consumer needs icon-aware substring
399-
widths.
400-
- A ~≤1px artifact when an icon is the last token: the gxu width loop ends on
401-
the last *glyph's* ink width rather than its advance (`FUN_005c6b70` gets the
402-
remaining-text pointer), and a trailing icon shifts the previous glyph's
403-
treatment — the source of the old −0.8px measurement.
403+
- Sub-pixel only for a string-final icon: the width hooks report its INK edge
404+
(advance minus the trail half-pad/ink — `TrailingIconTrimPen`), matching the
405+
engine's own last-glyph convention (the gxu width loop ends on ink, not
406+
advance — the source of the old −0.8px measurement, whose previous-glyph
407+
advance treatment is semantically CORRECT once an icon renders after it).
408+
What remains is the icon region's ±0.5px placement rounding and the base
409+
loop's ~0 contribution for the payload-0 icon token.
404410
- An fs whose `fs+0xFC` cache was filled while the feature was toggled
405411
differently (`_classicapi_InlineTexEnable`) keeps its old base width until
406412
the next `SetText`/font change re-dirties it. Debug-toggle-only.
@@ -518,10 +524,12 @@ backend note.)
518524
decode in 1.12 (uncompressed only) — convert with
519525
`magick in.tga -compress none in.tga` (no `-orient`/`-flip`: the region
520526
renderer's texcoord order shows the frame right-side-up).
521-
- **Still icon-blind** (accepted): the substring measure `FUN_00772AE0`; the
522-
hyperlink hit-test past a tall icon OUTSIDE the link on the same line; and a
523-
≤1px trailing-icon residual in `GetStringWidth` (the measure loop ends on the
524-
last glyph's ink width, not its advance).
527+
- **Still icon-blind** (accepted): the hyperlink hit-test past a tall icon
528+
OUTSIDE the link on the same line. The substring measure `FUN_00772AE0` was
529+
hooked once its real consumer surfaced (the tooltip auto-size measures
530+
wrapped SEGMENTS with it), and the trailing-icon width residual is trimmed
531+
to sub-pixel (`TrailingIconTrimPen` — a string-final icon reports its ink
532+
edge, not its advance, per the engine's own last-glyph convention).
525533

526534
## Goal & spec
527535

src/Offsets.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,18 @@ enum Offsets {
375375
// 2 pen px).
376376
FLOAT_OUTLINE_EXTRA_THICK = 0x0080306C,
377377
FLOAT_OUTLINE_EXTRA_THIN = 0x00801628,
378+
// Substring width measure: `__thiscall(fs, const char *text, int len)` →
379+
// ST0 (len 0 = strlen). Same measure-core call + `out / fs+0x7C` shape as
380+
// GetStringWidthInternal, but for an ARBITRARY string in the fs's font —
381+
// no cache. Callers (xrefs): the GameTooltip auto-size FUN_00530640, which
382+
// measures each WRAPPED SEGMENT of a wrap-enabled line between the
383+
// FUN_00772B60 break positions and takes the max as the tooltip width —
384+
// the icon-relevant consumer (an earlier note claimed nothing consumed
385+
// this function; the xref list refutes it) — plus the editbox
386+
// caret/selection cluster (FUN_0077DA80, FUN_0077DE70, FUN_0077D0D0),
387+
// which must stay raw and is excluded by the editable/focused-buffer
388+
// gates in the co-hook.
389+
FUN_FONTSTRING_MEASURE_SUBSTRING = 0x00772AE0,
378390
// FontString → gxu face resolution, for fs-level (measure-hook) callers
379391
// that need the face the RENDER will use. The rebuild (FUN_007724a0)
380392
// passes [fs+0xE0] (the font HANDLE) to the block creator FUN_0044d420,

0 commit comments

Comments
 (0)