fix(layout): four axes that could always stale the cache, and the new roles
The height cache keys on a fingerprint of everything that can change a row's height. Four things that can were never in it: - ItalicFontV2.SizePt. ChunkRenderer pushes the italic face mid-row for emphasis, so there have been mixed sizes in a single line all along -- nobody called it that. Changing only the italic size moved every wrapped row and left the cache untouched. - ItalicEnabled, which swaps between ItalicFont at its own size and AxisItalic at the base size. - FontsEnabled and UseHellionFont, which swap the face outright. This pair is the quiet one: both size fields default to 12.75f, so the fingerprint did not move at all while the glyph widths underneath it did. On top of those, the two new role sizes. They follow the base arithmetically, but the resolved value is what belongs in the fingerprint -- a theme override moves the base without moving any factor. The three toggles go in the discrete half so they bypass the settle window, the same way density already does. The sizes are sliders and wait it out. Falsified rather than assumed: dropping FontsEnabled back out of Discrete turns the new test red, so it is measuring the axis and not just passing.
This commit is contained in:
@@ -59,7 +59,7 @@ public sealed class FontManager : IDisposable
|
||||
private Func<ThemeTypography?>? _typographySource;
|
||||
|
||||
// Lets RebuildDelegateFontsIfChanged skip rebuilds when the size is unchanged.
|
||||
private (float Global, float Symbols) _lastBuiltFingerprint;
|
||||
private (float Global, float Symbols, float Sender, float Meta, float Italic) _lastBuiltFingerprint;
|
||||
|
||||
// True once every required atlas-owned handle reports Available. Components
|
||||
// gate their first-frame draw on this — without it the layout math would
|
||||
@@ -216,8 +216,21 @@ public sealed class FontManager : IDisposable
|
||||
Plugin.Config.SymbolsFontSizeV2
|
||||
);
|
||||
|
||||
internal (float Global, float Symbols) EffectiveFontFingerprint() =>
|
||||
(ResolveGlobalFontPt(), ResolveSymbolsFontPt());
|
||||
// Every size that can land in one message row. Roles follow the base size
|
||||
// arithmetically, but the resolved value is what the height cache has to key
|
||||
// on -- a theme override moves the base without moving any factor.
|
||||
internal (float Global, float Symbols, float Sender, float Meta, float Italic)
|
||||
EffectiveFontFingerprint()
|
||||
{
|
||||
var basePt = ResolveGlobalFontPt();
|
||||
return (
|
||||
basePt,
|
||||
ResolveSymbolsFontPt(),
|
||||
TypeScale.SizePtOf(TypeRole.Sender, basePt),
|
||||
TypeScale.SizePtOf(TypeRole.Meta, basePt),
|
||||
Plugin.Config.ItalicFontV2.SizePt
|
||||
);
|
||||
}
|
||||
|
||||
// Rebuilds only when the effective size changed (live fingerprint, TOCTOU-free).
|
||||
// The atlas rebuild must run on the framework/draw thread — callers ensure that.
|
||||
|
||||
@@ -93,13 +93,25 @@ internal sealed class MessageList
|
||||
// Width is passed in (ContentRegionAvail is only valid inside the draw child);
|
||||
// enum modes widened to int so the record stays comparable. UiScale is in here
|
||||
// because it feeds CalcWordWrapPositionA -- a scale change rewraps every row.
|
||||
//
|
||||
// v1.13.0 added four axes that could always stale this cache and never did:
|
||||
// the italic size (pushed mid-row by ChunkRenderer), ItalicEnabled (which
|
||||
// swaps between two differently sized faces), FontsEnabled and UseHellionFont
|
||||
// (both swap the face outright, and their two size fields default to the same
|
||||
// 12.75f -- so the fingerprint did not move while the glyph widths did).
|
||||
private LayoutFingerprint BuildLayoutFingerprint(float contentWidth)
|
||||
{
|
||||
var (global, symbols) = _fonts.EffectiveFontFingerprint();
|
||||
var fonts = _fonts.EffectiveFontFingerprint();
|
||||
return new LayoutFingerprint(
|
||||
global,
|
||||
symbols,
|
||||
fonts.Global,
|
||||
fonts.Symbols,
|
||||
fonts.Sender,
|
||||
fonts.Meta,
|
||||
fonts.Italic,
|
||||
Plugin.Config.UseCompactDensity,
|
||||
Plugin.Config.FontsEnabled,
|
||||
Plugin.Config.UseHellionFont,
|
||||
Plugin.Config.ItalicEnabled,
|
||||
(int)Plugin.Config.NameFormMode,
|
||||
(int)Plugin.Config.WorldSuffixMode,
|
||||
contentWidth,
|
||||
|
||||
@@ -5,7 +5,13 @@ namespace HellionChat.Util;
|
||||
internal readonly record struct LayoutFingerprint(
|
||||
float FontGlobal,
|
||||
float FontSymbols,
|
||||
float FontSender,
|
||||
float FontMeta,
|
||||
float FontItalic,
|
||||
bool Compact,
|
||||
bool FontsEnabled,
|
||||
bool UseHellionFont,
|
||||
bool ItalicEnabled,
|
||||
int NameForm,
|
||||
int WorldSuffix,
|
||||
float Width,
|
||||
@@ -15,7 +21,8 @@ internal readonly record struct LayoutFingerprint(
|
||||
// Toggles: they land on a new value in one frame and stay there. Waiting on
|
||||
// them would leave the planner running against the previous density's
|
||||
// heights while the rows are already painted the new way.
|
||||
internal (bool, int, int) Discrete => (Compact, NameForm, WorldSuffix);
|
||||
internal (bool, bool, bool, bool, int, int) Discrete =>
|
||||
(Compact, FontsEnabled, UseHellionFont, ItalicEnabled, NameForm, WorldSuffix);
|
||||
}
|
||||
|
||||
// Dragging a window edge or the Dalamud UI-scale slider moves the continuous
|
||||
|
||||
Reference in New Issue
Block a user