bd85159b36db7ff8c02b32eb18d96ed6066feb8f
braney
  Wed Aug 5 13:59:46 2026 -0700
hgTracks: measure text with the same font engine that will draw it, refs #38027

Pack mode works out how many rows a track needs by measuring its item labels,
and mgFontStringWidth answers from whichever text engine is loaded at the time.
FreeType was only loaded when an image was created, so the measuring could
happen on the bitmap engine while the drawing happened on FreeType -- and which
one you got depended on whether the ideogram image had been built first.

Load the engine in initTl(), alongside the rest of the font setup, before
anything measures a string.  maybeNewFonts() and the new initFontEngine() share
chosenFreeTypeFont(), and mgLoadFontEngine() loads an engine without attaching
it to an image.  ftInitialize() now keeps the face it already has when asked for
the same font file, so the glyph cache hanging off that face survives the extra
call.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

diff --git src/hg/hgTracks/simpleTracks.c src/hg/hgTracks/simpleTracks.c
index 34fb8f9101f..fca35355391 100644
--- src/hg/hgTracks/simpleTracks.c
+++ src/hg/hgTracks/simpleTracks.c
@@ -287,30 +287,34 @@
 struct rgbColor lightSeaColor = {200, 220, 255, 255};
 
 struct hash *hgFindMatches; /* The matches found by hgFind that should be highlighted. */
 boolean hgFindMatchesShowHighlight; /* For use with pdf mode which suppresses label highlight */
 
 struct hash *itemColorHash; /* Per-item background highlight colors keyed by "track\titemName". */
 
 struct trackLayout tl;
 
 void initTl()
 /* Initialize layout around small font and a picture about 600 pixels
  * wide. */
 {
 trackLayoutInit(&tl, cart);
 
+// Settle the text engine here, with the rest of the font setup, so that every
+// string measured from now on -- including the item labels that decide how pack
+// mode lays out its rows -- is measured with the engine that will draw it.
+initFontEngine();
 }
 
 static boolean isTooLightForTextOnWhite(struct hvGfx *hvg, Color color)
 /* Return TRUE if text in this color would probably be invisible on a white background. */
 {
 struct rgbColor rgbColor =  hvGfxColorIxToRgb(hvg, color);
 int colorTotal = rgbColor.r + 2*rgbColor.g + rgbColor.b;
 return colorTotal >= 512;
 }
 
 Color darkerColor(struct hvGfx *hvg, Color color)
 /* Get darker shade of a color - half way between this color and black */
 {
 struct rgbColor rgbColor =  hvGfxColorIxToRgb(hvg, color);
 rgbColor.r = ((int)rgbColor.r)/2;