Metal: draw the real zigzag wave underline (F2)

The wave fell back to a straight line, and the fallback branch was dead
anyway: FACE_UNDERLINE_WAVE is above FACE_UNDERLINE_SINGLE in the enum,
so the >= SINGLE branch swallowed it. Check wave first (like NS) and
draw the ns_draw_underwave zigzag: wave height 3, period 4, triangle
pattern 0,1,2,1 at ybase..ybase+2, one 1px cell per column, phase
anchored to the absolute column so the wave continues seamlessly across
adjacent glyph strings. Verified visually against NS (red and default).
This commit is contained in:
Andros Fenollosa 2026-06-03 17:07:45 +02:00
parent 84354c2696
commit e139b04f16

View file

@ -2148,10 +2148,23 @@ mtl_draw_glyph_string_impl (struct glyph_string *s)
pen_x += adv;
}
/* Underline. Single/double lines (the common case for buttons and links)
use font-derived position/thickness; wave falls back to a straight line at
the same position for now. */
if (face && face->underline >= FACE_UNDERLINE_SINGLE)
/* Underline. Wave FIRST: FACE_UNDERLINE_WAVE is above FACE_UNDERLINE_SINGLE
in the enum, so the >= SINGLE branch would otherwise swallow it (NS checks
wave first too). */
if (face && face->underline == FACE_UNDERLINE_WAVE)
{
/* Zigzag wave matching ns_draw_underwave: wave_height 3, wave_length 2,
drawn at ybase..ybase+2 (y = ybase - wave_height + 3). One 1px cell
per column following the triangle pattern 0,1,2,1; indexing by the
absolute column keeps the wave continuous across adjacent strings,
like NS's a.x = x - (x % dx) phase anchoring. */
unsigned long uc = face->underline_defaulted_p ? fg : face->underline_color;
static const int wave[4] = {0, 1, 2, 1};
int wy = s->ybase;
for (int cx = s->x; cx < s->x + s->width; cx++)
[fd fillRect:NSMakeRect (cx, wy + wave[cx & 3], 1, 1) color:uc];
}
else if (face && face->underline >= FACE_UNDERLINE_SINGLE)
{
int position, thickness;
mtl_underline_metrics (s, &position, &thickness);
@ -2168,14 +2181,6 @@ mtl_draw_glyph_string_impl (struct glyph_string *s)
color:uc];
}
}
else if (face && face->underline == FACE_UNDERLINE_WAVE)
{
int position, thickness;
mtl_underline_metrics (s, &position, &thickness);
unsigned long uc = face->underline_defaulted_p ? fg : face->underline_color;
[fd fillRect:NSMakeRect (s->x, s->ybase + position, s->width, thickness)
color:uc];
}
/* Overline: 1px at the top of the string (NS ignores overline_margin too). */
if (face && face->overline_p)