From 103f36cced37eed1bb51cd704b0a64b42f7b8144 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Mon, 18 Dec 2023 11:10:40 +0800 Subject: [PATCH] Enable the new font scaler * src/sfnt.c (sfnt_curve_is_flat): Tighten threshold for flat curves. (sfnt_insert_raster_step): Rewrite loop for clarity. (sfnt_poly_set_steps): New function; fill small spans with a plain unexceptional loop rather than memset. (sfnt_poly_steps): Call that function. (sfnt_verbose, main): Adjust tests such that the scaler can be selected at runtime. * src/sfnt.h: Update prototypes. * src/sfntfont.c (sfntfont_get_glyph_raster) (syms_of_sfntfont) : New variable. --- src/sfnt.c | 96 +++++++++++++++++++++++++++++++++++--------------- src/sfnt.h | 1 + src/sfntfont.c | 13 ++++++- 3 files changed, 80 insertions(+), 30 deletions(-) diff --git a/src/sfnt.c b/src/sfnt.c index 208d0139022..7d43f06b748 100644 --- a/src/sfnt.c +++ b/src/sfnt.c @@ -3905,11 +3905,11 @@ sfnt_curve_is_flat (struct sfnt_point control0, h.x = endpoint.x - control0.x; h.y = endpoint.y - control0.y; - /* 2.0 is a constant describing the area covered at which point the - curve is considered "flat". */ + /* 1.0 is a constant representing the area covered at which point + the curve is considered "flat". */ return (abs (sfnt_mul_fixed (g.x, h.y) - sfnt_mul_fixed (g.y, h.x)) - <= 0400000); + <= 0200000); } /* Recursively split the splines in the bezier curve formed from @@ -4621,8 +4621,6 @@ sfnt_raster_glyph_outline (struct sfnt_glyph_outline *outline) -#ifdef SFNT_EXACT_SCALING - /* Exact coverage scaler. The foregoing routines calculate partial coverage for each pixel by @@ -4910,13 +4908,8 @@ sfnt_insert_raster_step (struct sfnt_step_raster *raster, p_next = &raster->steps[scanline]; - while (true) + while ((step = *p_next)) { - step = *p_next; - - if (!step) - break; - if (step->x > x) break; @@ -4926,7 +4919,8 @@ sfnt_insert_raster_step (struct sfnt_step_raster *raster, p_next = &step->next; } - if (!raster->chunks || raster->chunks->nused == SFNT_BLOCK_STEPS) + if (!raster->chunks + || raster->chunks->nused == SFNT_BLOCK_STEPS) { /* All chunks have been consumed, and consequently a new chunk must be allocated. */ @@ -4989,7 +4983,7 @@ sfnt_fedge_sort (struct sfnt_fedge *edges, size_t size) guarantee that no steps generated extend past WIDTH, steps starting after width might be omitted, and as such it must be accurate. */ -static void +TEST_STATIC void sfnt_poly_edges_exact (struct sfnt_fedge *edges, size_t nedges, size_t height, size_t width, sfnt_step_raster_proc proc, void *dcontext) @@ -5409,6 +5403,45 @@ sfnt_compute_fill (float value) return MIN (value * 255, 255); } +/* Set N pixels at DATA to the value VALUE. If N is large, call + memset; otherwise set this by hand. */ + +static void +sfnt_poly_set_steps (unsigned char *data, int value, int n) +{ + unsigned char *p; + + p = data; + switch (n) + { + case 7: + *p++ = value; + FALLTHROUGH; + case 6: + *p++ = value; + FALLTHROUGH; + case 5: + *p++ = value; + FALLTHROUGH; + case 4: + *p++ = value; + FALLTHROUGH; + case 3: + *p++ = value; + FALLTHROUGH; + case 2: + *p++ = value; + FALLTHROUGH; + case 1: + *p++ = value; + FALLTHROUGH; + case 0: + break; + default: + memset (data, value, n); + } +} + /* Transfer steps generated by sfnt_poly_edges_exact from STEPS to the provided raster RASTER. */ @@ -5438,7 +5471,7 @@ sfnt_poly_steps (struct sfnt_step_raster *steps, xend = MIN (step->x, raster->width); if (fill) - memset (data + x, fill, xend - x); + sfnt_poly_set_steps (data + x, fill, xend - x); total += step->coverage; fill = sfnt_compute_fill (total); @@ -5446,7 +5479,7 @@ sfnt_poly_steps (struct sfnt_step_raster *steps, } if (x < raster->width) - memset (data + x, fill, raster->width - x); + sfnt_poly_set_steps (data + x, fill, raster->width - x); } } @@ -5499,8 +5532,6 @@ sfnt_raster_glyph_outline_exact (struct sfnt_glyph_outline *outline) return data; } -#endif /* SFNT_EXACT_SCALING */ - /* Glyph metrics computation. */ @@ -16464,10 +16495,6 @@ sfnt_read_post_table (int fd, struct sfnt_offset_subtable *subtable) #ifdef TEST -#ifdef SFNT_EXACT_SCALING -#define sfnt_raster_glyph_outline sfnt_raster_glyph_outline_exact -#endif /* SFNT_EXACT_SCALING */ - struct sfnt_test_dcontext { /* Context for sfnt_test_get_glyph. */ @@ -20124,6 +20151,11 @@ sfnt_identify_instruction (struct sfnt_interpreter *interpreter) return buffer; } +/* Function called to rasterize a glyph outline. */ +#define TYPE struct sfnt_glyph_outline * +static struct sfnt_raster *(*test_raster_glyph_outline) (TYPE); +#undef TYPE + static void sfnt_verbose (struct sfnt_interpreter *interpreter) { @@ -20157,7 +20189,7 @@ sfnt_verbose (struct sfnt_interpreter *interpreter) sfnt_coerce_fixed (outline->xmax), sfnt_coerce_fixed (outline->ymax)); - raster = sfnt_raster_glyph_outline (outline); + raster = (*test_raster_glyph_outline) (outline); if (raster) sfnt_test_raster (raster, NULL, 0); @@ -20380,6 +20412,11 @@ main (int argc, char **argv) exit (0); } + if (getenv ("SFNT_EXACT_SCALING")) + test_raster_glyph_outline = sfnt_raster_glyph_outline_exact; + else + test_raster_glyph_outline = sfnt_raster_glyph_outline; + fd = open (argv[1], O_RDONLY); if (fd < 0) @@ -20471,8 +20508,8 @@ main (int argc, char **argv) return 1; } -#define FANCY_PPEM 12 -#define EASY_PPEM 12 +#define FANCY_PPEM 30 +#define EASY_PPEM 30 interpreter = NULL; head = sfnt_read_head_table (fd, font); @@ -20723,7 +20760,7 @@ main (int argc, char **argv) xfree (value); - raster = sfnt_raster_glyph_outline (outline); + raster = (*test_raster_glyph_outline) (outline); if (!raster) exit (7); @@ -21028,10 +21065,10 @@ main (int argc, char **argv) clock_gettime (CLOCK_THREAD_CPUTIME_ID, &start); - for (i = 0; i < 120; ++i) + for (i = 0; i < 800; ++i) { xfree (raster); - raster = sfnt_raster_glyph_outline (outline); + raster = (*test_raster_glyph_outline) (outline); } clock_gettime (CLOCK_THREAD_CPUTIME_ID, &end); @@ -21116,7 +21153,8 @@ main (int argc, char **argv) if (outline) { - raster = sfnt_raster_glyph_outline (outline); + raster + = (*test_raster_glyph_outline) (outline); if (raster) { @@ -21142,7 +21180,7 @@ main (int argc, char **argv) printf ("time spent building edges: %lld sec %ld nsec\n", (long long) sub1.tv_sec, sub1.tv_nsec); printf ("time spent rasterizing: %lld sec %ld nsec\n", - (long long) sub2.tv_sec / 120, sub2.tv_nsec / 120); + (long long) sub2.tv_sec / 800, sub2.tv_nsec / 800); xfree (outline); } diff --git a/src/sfnt.h b/src/sfnt.h index a875c1a722d..2ae47ad30ce 100644 --- a/src/sfnt.h +++ b/src/sfnt.h @@ -1512,6 +1512,7 @@ extern void sfnt_prepare_raster (struct sfnt_raster *, #define PROTOTYPE struct sfnt_glyph_outline * extern struct sfnt_raster *sfnt_raster_glyph_outline (PROTOTYPE); +extern struct sfnt_raster *sfnt_raster_glyph_outline_exact (PROTOTYPE); #undef PROTOTYPE #define PROTOTYPE \ diff --git a/src/sfntfont.c b/src/sfntfont.c index f002712dc10..0a8797bfb3b 100644 --- a/src/sfntfont.c +++ b/src/sfntfont.c @@ -2444,7 +2444,11 @@ sfntfont_get_glyph_raster (sfnt_glyph glyph_code, } /* Not already cached. Raster the outline. */ - raster = sfnt_raster_glyph_outline (outline); + + if (!sfnt_raster_glyphs_exactly) + raster = sfnt_raster_glyph_outline (outline); + else + raster = sfnt_raster_glyph_outline_exact (outline); if (!raster) return NULL; @@ -4116,6 +4120,13 @@ eliminating artifacts and chance effects consequent upon the direct upscaling of glyph outline data. Instruction code is occasionally incompatible with Emacs and must be disregarded. */); Vsfnt_uninstructable_family_regexp = Qnil; + + DEFVAR_BOOL ("sfnt-raster-glyphs-exactly", sfnt_raster_glyphs_exactly, + doc: /* How font glyph outlines should be converted to graphics. +If non-nil, glyphs will be displayed in a more precise manner, at the +cost of performance on devices where floating-point math operations +are slow. */); + sfnt_raster_glyphs_exactly = true; } void -- 2.39.2