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/lib/memgfx.c src/lib/memgfx.c
index b5d159f649d..857ce69a1f1 100644
--- src/lib/memgfx.c
+++ src/lib/memgfx.c
@@ -845,37 +845,46 @@
 #endif
 }
 
 int mgFontStringWidth(MgFont *font, char *string)
 /* How wide is a string? */
 {
 return mgFontWidth(font, string, strlen(string));
 }
 
 int mgGetFontStringWidth(struct memGfx *mg, MgFont *font, char *string)
 /* How wide is a string? */
 {
 return mgFontStringWidth(font, string);
 }
 
+void mgLoadFontEngine(unsigned int method, char *fontFile)
+/* Load a text engine without attaching it to an image.  Text measurement
+ * (mgFontStringWidth) answers from whichever engine is loaded, so a caller that
+ * measures text before it has an image to draw on needs to load the engine
+ * first, or it will measure with one engine and draw with another. */
+{
+if (method == FONT_METHOD_FREETYPE)
+    ftInitialize(fontFile);
+}
+
 void mgSetFontMethod(struct memGfx *mg, unsigned int method, char *fontName, char *fontFile)
 /* Which font drawing method shoud we use. */
 {
 mg->fontMethod = method;
 
-if (method == FONT_METHOD_FREETYPE)
-    ftInitialize(fontFile);
+mgLoadFontEngine(method, fontFile);
 }
 
 int mgFontCharWidth(MgFont *font, char c)
 /* How wide is a character? */
 {
 return mgFontWidth(font, &c, 1);
 }
 
 char *mgFontSizeBackwardsCompatible(char *size)
 /* Given "size" argument that may be in old tiny/small/medium/big/huge format,
  * return it in new numerical string format. Do NOT free the return string*/
 {
 if (isdigit(size[0]))
     return size;
 else if (sameWord(size, "tiny"))