fix(ui): round-5 review polish — S1 block outline pass, S2 non-UiText outline paths, S3 citation fix

Collects the post-gate polish left uncommitted by the killed round-5 agent
(S1/S3 + review fixes N1/N3/N4) and completes the missing S2 half:

- S1: UiText multi-line transcript + colored-run label now submit EVERY
  line/run's outline pass before ANY fill pass, matching retail's
  UIElement_Text::DrawSelf @0x00467aa0 whole-block walk. DrawStringDatPass
  is exposed for block-level batching; single lines keep DrawStringDat.
- S2 (completed this commit): authored outline 0x21/0x22 now reaches every
  text-bearing widget — UiButton, UiDatElement, UiField, UiMeter, UiMenu,
  UiCatalogSlot — seeded from the element's effective-default state exactly
  like UiText (BuildButton lifts the label-bearing Text child's authored
  value first, same chain as the label color). Per-STATE outline switching
  (dialog/character/combat buttons author 0x21 in state 0x3 only) is NOT
  ported — filed as register row AP-192 in this commit.
- S3: ChatWindowController reconciliation comment corrects the misread
  indicator action ids 0x10000514-17 -> 0x10000114-17 and re-attributes the
  id-coincidence to the pagination widget's m_prevButton/m_nextButton, not
  gmFriendsUI; register + window-shell research doc corrected to match.
- N1: LayoutImporter's duplicate per-state any-state-first-wins 0x21 read is
  deleted — ElementReader.ApplyCanonicalLegacyProjection's DirectState-then-
  effective-default resolution is the single source (the duplicate would have
  lit state-0x3-only outlines permanently once S2 widened consumption).
- N3: the outline pass tints with the outline color's OWN alpha, not the
  fill's (retail tints m_curOutlineColor and m_curTextColor independently).
- N4: the outline-inflated glyph SOURCE rect is clamped to the atlas bounds
  with matching dest shrink, porting CreateCharRectPair @0x00441480's edge
  behavior — edge glyphs crop instead of sampling a neighbour's texels.

Full Release suite: 12,610 passed / 4 skipped / 0 failed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-10 22:15:20 +02:00
parent ed0dbff90a
commit aa6635aebf
14 changed files with 258 additions and 66 deletions

View file

@ -557,8 +557,9 @@ public sealed class ChatWindowController : IRetainedWindowStateController, IReta
/// buttons genuinely author property <c>0x12</c> as an Enum (not merely
/// a stray/mistyped property): <c>chat_2100006f.json</c>'s four
/// indicator elements each carry it, with values
/// <c>0x10000514</c>-<c>0x10000517</c> in id order. But the OTHER half
/// of the wiring is where retail's own data falls short: the floating
/// <c>0x10000114</c>-<c>0x10000117</c> in id order (an earlier pass here
/// misread these as <c>0x10000514</c>-<c>0x10000517</c>). But the OTHER
/// half of the wiring is where retail's own data falls short: the floating
/// chat window fixture (<c>chat_floaty_2100005b.json</c>) authors NO
/// Enum-kind property <c>0x24</c> anywhere (its one hit on property
/// number 36 is Integer-kind, an unrelated attribute) and NO property
@ -567,14 +568,19 @@ public sealed class ChatWindowController : IRetainedWindowStateController, IReta
/// ids, and <c>RegisterElementForInputAction</c> has exactly one call
/// site in the whole binary (the property-driven one above; no class
/// anywhere calls it directly in code). <c>DoVisibilityToggleAction</c>
/// would find zero listeners and silently no-op. (The four action-id
/// VALUES themselves are not chat-specific either — the SAME four
/// numbers are <c>gmFriendsUI::PostInit</c>'s own Add/Remove/Tell
/// button and friends-listbox child ids, a coincidence of Turbine's
/// global asset-id allocator, not a cross-reference.) So even with the
/// generic mechanism confirmed real and armed on the button side, the
/// authored DATA available to us does not wire a target — which is
/// consistent with, not a refutation of, the original CH6b grep.
/// would find zero listeners and silently no-op. (Two of the four action-id
/// VALUES are not chat-specific either — <c>0x10000114</c>/<c>0x10000115</c>
/// are <c>m_prevButton</c>/<c>m_nextButton</c> child ids for an unrelated
/// pagination widget elsewhere in the decomp
/// (<c>acclient_2013_pseudo_c.txt:194343-194344</c>), a coincidence of
/// Turbine's global asset-id allocator, not a cross-reference — an
/// earlier pass here misattributed this coincidence to
/// <c>gmFriendsUI::PostInit</c>'s Add/Remove/Tell child ids, which match
/// only the wrong, misread values above and are not actually involved.)
/// So even with the generic mechanism confirmed real and armed on the
/// button side, the authored DATA available to us does not wire a
/// target — which is consistent with, not a refutation of, the original
/// CH6b grep.
/// </para>
///
/// <para>