43f042236ce180b8e0712d43c8baabc4ad8df1cd
max
  Sat Jul 25 18:21:54 2026 -0700
hgTracks: add compactPack mode and codon strand-direction arrows

When zoomed to codon-coloring level, draw strand-direction chevrons across the
exons (white over coding codons when too small to label, contrasting color over
UTRs), and a per-codon arrow between amino-acid letters via drawScaledBoxWithText.
Add a compactPack trackDb setting for shorter pack/squish rows and a small
squish-mode codon font. Adds mgFontForCellHeight() to memgfx and enables
compactPack on the JASPAR track.

diff --git src/lib/memgfx.c src/lib/memgfx.c
index 5adcec2b894..b5d159f649d 100644
--- src/lib/memgfx.c
+++ src/lib/memgfx.c
@@ -965,30 +965,46 @@
 	 font = mgHelvetica34Font();
     else
 	 errAbort("unknown textSize %s", textSize);
     }
 return font;
 }
 
 MgFont *mgFontForSize(char *textSize)
 /* Get a font of given size and style.  Abort with error message if not found.
  * The textSize should be 6,8,10,12,14,18,24 or 34.  For backwards compatibility
  * textSizes of "tiny" "small", "medium", "large" and "huge" are also ok. */
 {
 return mgFontForSizeAndStyle(textSize, "medium");
 }
 
+MgFont *mgFontForCellHeight(int cellHeight)
+/* Return a font whose reported cell height is cellHeight, cloned from the small
+ * font.  Built-in fonts only come in fixed sizes, but the FreeType engine
+ * derives its render size from the font's cell height (see getFontCorrection in
+ * freeType.c), so this yields an in-between size that no fixed font offers (e.g.
+ * cellHeight 10 renders ~9px).  VALID ONLY UNDER FREETYPE: the GEM bitmap engine
+ * indexes fixed bitmap rows by this height, so the glyphs would be misread.
+ * Callers must fall back to a real fixed-size font when FreeType is off.  Not
+ * thread-safe; it hands back one static header re-stamped on each call. */
+{
+static struct font_hdr clone;
+clone = *mgSmallFont();        // copy the header; FreeType ignores the glyph data
+clone.frm_hgt = cellHeight;    // this is what mgFontPixelHeight() returns
+return &clone;
+}
+
 
 void mgSlowDot(struct memGfx *mg, int x, int y, int colorIx)
 /* Draw a dot when a macro won't do. */
 {
 mixDot(mg, x, y, COLOR_32_ALPHA(colorIx)/255.0, colorIx);
 }
 
 int mgSlowGetDot(struct memGfx *mg, int x, int y)
 /* Fetch a dot when a macro won't do. */
 {
 return mgGetDot(mg, x, y);
 }
 
 struct memGfx *mgRotate90(struct memGfx *in)
 /* Create a copy of input that is rotated 90 degrees clockwise. */