Generate stem hints

These are generated from the glyph bitmap by a similar
pattern-matching arrangement that generates the outline.  Then, like
emit_path(), there's an emit_hints() that turns them into valid
charstrings.  The handling of overlapping hints could be cleverer: at
the moment we emit the leftmost-possible set of hints, but we collect
a histogram of where hints are needed so could instead emit the most
useful.  Or even try to do hint substitution.

This makes the Bedstead Web page at 90% zoom much prettier than
before, but it's not as good as the FontForge auto-hinter managed.
Edge hints and counter hints will probably help.
This commit is contained in:
Ben Harris 2024-11-09 23:51:36 +00:00
parent e572e11b12
commit 4254bff53a

View File

@ -3746,6 +3746,43 @@ emit_path(void)
printf(" endchar");
}
static void
emit_hints(int vstems[XSIZE], int hstems[YSIZE])
{
int i, start, size, cur;
bool printed;
cur = 0; printed = false;
size = XPIX_S + weight->weight;
for (i = 0; i < XSIZE; i++) {
if (vstems[i] > 0) {
start = i * XPIX_S - weight->weight;
printf(" %g %g",
(double)((start - cur) / XSCALE),
(double)(size / XSCALE));
cur = start + size;
i++; /* Avoid overlapping stems. */
printed = true;
}
}
if (printed) printf(" vstem");
cur = DESCENT * YPIX; printed = false;
size = YPIX_S;
for (i = YSIZE - 1; i >= 0; i--) {
if (hstems[i] > 0) {
start = (YSIZE - i - 1) * YPIX_S;
printf(" %g %g",
(double)((start - cur) / YSCALE),
(double)(size / YSCALE));
cur = start + size;
i--; /* Avoid overlapping stems. */
printed = true;
}
}
if (printed) printf(" hstem");
}
/*
* To vary the weight of Bedstead, we just vary the thickness of
* vertical strokes. More precisely, we pretend that the weight
@ -3883,6 +3920,7 @@ static void
dochar(struct glyph *g)
{
int x, y;
int vstems[XSIZE], hstems[YSIZE];
#define GETPIX(x,y) (getpix(g->data, (x), (y), g->flags))
#define L GETPIX(x-1, y)
@ -3894,6 +3932,8 @@ dochar(struct glyph *g)
#define DL GETPIX(x-1, y+1)
#define DR GETPIX(x+1, y+1)
for (x = 0; x < XSIZE; x++) vstems[x] = 0;
for (y = 0; y < YSIZE; y++) hstems[y] = 0;
clearpath();
for (x = 0; x < XSIZE; x++) {
for (y = 0; y < YSIZE; y++) {
@ -3913,6 +3953,14 @@ dochar(struct glyph *g)
if (L || DL || D) bl = true;
if (R || DR || D) br = true;
blackpixel(x, YSIZE - y - 1, bl, br, tr, tl);
if (!L && !R && (U || D))
vstems[x]++;
if (!U && !D && (L || R))
hstems[y]++;
if (UL + U + UR + L + R + DL + D + DR == 0) {
vstems[x]++;
hstems[y]++;
}
} else {
bool tl, tr, bl, br;
@ -3930,6 +3978,7 @@ dochar(struct glyph *g)
clean_path();
adjust_weight();
record_lsb(g);
emit_hints(vstems, hstems);
emit_path();
}