ttf.c: rasterization -- Bezier flattening + even-odd scanline fill
Punch list §25 item 4.3.7c complete. ttf_rasterize_glyph() flattens quadratic-Bezier contours (fixed 8-segment subdivision, matching CIRCLE/ELLIPSE's fixed-segment precedent) and fills them into a caller-supplied bitmap via even-odd scanline fill, no AA. A local signed Q48.16 multiply (q48_smul) handles negative outline coordinates, since the shared q48_mul/q48_div are unsigned-only. Verified two ways: tools/ttftest.c's ASCII-art dump + structural checks for 'A'/'.'/'a', all recognizable and passing; and a live amd64 screendump via a throwaway TTF-PROBE word (loaded the font capsule, rasterized 'A', blit via fb_put_pixel), showing a clearly legible 'A' on the CANVAS -- probe reverted immediately after capture, only the permanent ttf.c/ttf.h rasterizer remains. Compile-checked clean on all three architectures (hal/*.c wildcard); this item's own acceptance is the amd64 screendump, not a three-arch boot (that's 4.3.7f). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
2ef8d26c6f
commit
095860251a
@@ -149,6 +149,78 @@ static void test_outlines(const ttf_font_t *font) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Rasterization (4.3.7c) sanity check: rasterize a glyph at a modest
|
||||
* pixel size, print an ASCII-art dump for visual "is this recognizable"
|
||||
* inspection (this item's own acceptance criterion), plus loose
|
||||
* structural checks -- fill coverage in a plausible range, background
|
||||
* untouched in the far corner -- since there's no independent reference
|
||||
* rasterizer to diff against pixel-for-pixel (unlike 4.3.7/4.3.7a, which
|
||||
* had a from-scratch Python decoder to check against). */
|
||||
static void test_rasterize(const ttf_font_t *font, uint32_t codepoint, const char *label) {
|
||||
enum { SIZE_PX = 28, MARGIN = 6 };
|
||||
uint32_t w = SIZE_PX + MARGIN * 2;
|
||||
uint32_t h = SIZE_PX + MARGIN * 2;
|
||||
uint8_t *pixels = calloc((size_t) w * h, 1);
|
||||
ttf_bitmap_t bmp;
|
||||
q48_16_t scale;
|
||||
uint32_t gid;
|
||||
int rc;
|
||||
uint32_t x, y, filled = 0;
|
||||
|
||||
if (!pixels) {
|
||||
printf("test_rasterize U+%04X: calloc failed\n", codepoint);
|
||||
failures++;
|
||||
return;
|
||||
}
|
||||
|
||||
bmp.pixels = pixels;
|
||||
bmp.width = w;
|
||||
bmp.height = h;
|
||||
|
||||
scale = q48_div(q48_from_u64(SIZE_PX), q48_from_u64(font->units_per_em));
|
||||
gid = ttf_codepoint_to_glyph(font, codepoint);
|
||||
|
||||
rc = ttf_rasterize_glyph(font, gid, scale,
|
||||
q48_from_u64(MARGIN),
|
||||
q48_from_u64(SIZE_PX + MARGIN),
|
||||
255, &bmp);
|
||||
if (rc != TTF_OK) {
|
||||
printf("test_rasterize U+%04X (%s): ttf_glyph_outline/rasterize rc=%d\n",
|
||||
codepoint, label, rc);
|
||||
failures++;
|
||||
free(pixels);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("U+%04X (%s) rasterized %ux%u:\n", codepoint, label, w, h);
|
||||
for (y = 0; y < h; y++) {
|
||||
putchar('|');
|
||||
for (x = 0; x < w; x++) {
|
||||
int on = pixels[y * w + x] != 0;
|
||||
putchar(on ? '#' : '.');
|
||||
if (on) filled++;
|
||||
}
|
||||
putchar('|');
|
||||
putchar('\n');
|
||||
}
|
||||
printf(" filled=%u / %u px (%.1f%%)\n", filled, w * h, 100.0 * filled / (w * h));
|
||||
|
||||
if (filled == 0) {
|
||||
printf(" FAIL U+%04X (%s): rasterized to nothing\n", codepoint, label);
|
||||
failures++;
|
||||
} else if (filled > (w * h * 3) / 4) {
|
||||
printf(" FAIL U+%04X (%s): implausibly full (%u/%u px) -- looks like a fill-rule bug\n",
|
||||
codepoint, label, filled, w * h);
|
||||
failures++;
|
||||
}
|
||||
if (pixels[0] != 0) {
|
||||
printf(" FAIL U+%04X (%s): top-left corner (background) is filled\n", codepoint, label);
|
||||
failures++;
|
||||
}
|
||||
|
||||
free(pixels);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
FILE *fp;
|
||||
long size;
|
||||
@@ -211,6 +283,10 @@ int main(int argc, char **argv) {
|
||||
|
||||
test_outlines(&font);
|
||||
|
||||
test_rasterize(&font, 0x0041, "'A'");
|
||||
test_rasterize(&font, 0x002E, "'.'");
|
||||
test_rasterize(&font, 0x0061, "'a'");
|
||||
|
||||
free(buf);
|
||||
|
||||
if (failures) {
|
||||
|
||||
Reference in New Issue
Block a user