From 18b34e9ca01deff8e0bde4b1e53293f27712a149 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Mon, 27 Mar 2023 11:24:05 +0800 Subject: [PATCH] Refactor sfntfont.c * src/sfnt.c (sfnt_build_glyph_outline): Take scale, not head and pixel size. (sfnt_scale_metrics_to_pixel_size): Delete function. (sfnt_get_scale): New function. (main): Update tests. * src/sfnt.h (PROTOTYPE): Update prototypes. * src/sfntfont.c (struct sfnt_outline_cache) (sfntfont_get_glyph_outline, struct sfnt_font_info) (sfntfont_open): Save scale in font information and use it. (sfntfont_measure_instructed_pcm): Delete function. (sfntfont_measure_pcm): Make this the only ``measure pcm'' function. (sfntfont_draw): Rely on sfntfont_get_glyph_outline for the scale. --- src/sfnt.c | 57 +++++++---------- src/sfnt.h | 6 +- src/sfntfont.c | 169 +++++++++++++++++-------------------------------- 3 files changed, 85 insertions(+), 147 deletions(-) diff --git a/src/sfnt.c b/src/sfnt.c index 8e7a30e3b05..9a1094a1ca9 100644 --- a/src/sfnt.c +++ b/src/sfnt.c @@ -3760,21 +3760,21 @@ sfnt_curve_to_and_build (struct sfnt_point control, } /* Non-reentrantly build the outline for the specified GLYPH at the - given pixel size. Return the outline data with a refcount of 0 + given scale factor. Return the outline data with a refcount of 0 upon success, or NULL upon failure. + SCALE is a scale factor that converts between em space and device + space. + Use the scaled glyph METRICS to determine the origin point of the outline. Call GET_GLYPH and FREE_GLYPH with the specified DCONTEXT to obtain - glyphs for compound glyph subcomponents. - - HEAD should be the `head' table of the font. */ + glyphs for compound glyph subcomponents. */ TEST_STATIC struct sfnt_glyph_outline * sfnt_build_glyph_outline (struct sfnt_glyph *glyph, - struct sfnt_head_table *head, - int pixel_size, + sfnt_fixed scale, struct sfnt_glyph_metrics *metrics, sfnt_get_glyph_proc get_glyph, sfnt_free_glyph_proc free_glyph, @@ -3805,19 +3805,8 @@ sfnt_build_glyph_outline (struct sfnt_glyph *glyph, outline->xmax = 0; outline->ymax = 0; - /* Figure out how to convert from font unit-space to pixel space. - To turn one unit to its corresponding pixel size given a ppem of - 1, the unit must be divided by head->units_per_em. Then, it must - be multipled by the ppem. So, - - PIXEL = UNIT / UPEM * PPEM - - which means: - - PIXEL = UNIT * PPEM / UPEM */ - - build_outline_context.factor - = sfnt_div_fixed (pixel_size, head->units_per_em); + /* Set the scale factor. */ + build_outline_context.factor = scale; /* Decompose the outline. */ rc = sfnt_decompose_glyph (glyph, sfnt_move_to_and_build, @@ -4536,21 +4525,24 @@ sfnt_scale_metrics (struct sfnt_glyph_metrics *metrics, = sfnt_mul_fixed (metrics->advance * 65536, factor); } -/* Like `sfnt_scale_metrics', except it scales the specified metrics - by a factor calculated using the given PPEM and HEAD table's UPEM - value. */ +/* Calculate the factor used to convert em space to device space for a + font with the specified HEAD table and PPEM value. */ -MAYBE_UNUSED TEST_STATIC void -sfnt_scale_metrics_to_pixel_size (struct sfnt_glyph_metrics *metrics, - int ppem, - struct sfnt_head_table *head) +MAYBE_UNUSED TEST_STATIC sfnt_fixed +sfnt_get_scale (struct sfnt_head_table *head, int ppem) { - sfnt_fixed factor; + /* Figure out how to convert from font unit-space to pixel space. + To turn one unit to its corresponding pixel size given a ppem of + 1, the unit must be divided by head->units_per_em. Then, it must + be multipled by the ppem. So, + + PIXEL = UNIT / UPEM * PPEM + + which means: + + PIXEL = UNIT * PPEM / UPEM */ - /* Now calculate the factor scale lbearing and advance up to the - given PPEM size. */ - factor = sfnt_div_fixed (ppem, head->units_per_em); - sfnt_scale_metrics (metrics, factor); + return sfnt_div_fixed (ppem, head->units_per_em); } @@ -19419,8 +19411,7 @@ main (int argc, char **argv) /* Time this important bit. */ clock_gettime (CLOCK_THREAD_CPUTIME_ID, &start); - outline = sfnt_build_glyph_outline (glyph, head, - EASY_PPEM, + outline = sfnt_build_glyph_outline (glyph, scale, &metrics, sfnt_test_get_glyph, sfnt_test_free_glyph, diff --git a/src/sfnt.h b/src/sfnt.h index 84e51ff6766..fb8cb80bae9 100644 --- a/src/sfnt.h +++ b/src/sfnt.h @@ -1370,8 +1370,7 @@ extern void sfnt_free_glyph (struct sfnt_glyph *); #define PROTOTYPE \ struct sfnt_glyph *, \ - struct sfnt_head_table *, \ - int, \ + sfnt_fixed, \ struct sfnt_glyph_metrics *, \ sfnt_get_glyph_proc, \ sfnt_free_glyph_proc, \ @@ -1403,8 +1402,7 @@ extern int sfnt_lookup_glyph_metrics (sfnt_glyph, int, extern void sfnt_scale_metrics (struct sfnt_glyph_metrics *, sfnt_fixed); -extern void sfnt_scale_metrics_to_pixel_size (struct sfnt_glyph_metrics *, - int, struct sfnt_head_table *); +extern sfnt_fixed sfnt_get_scale (struct sfnt_head_table *, int); #define PROTOTYPE int, struct sfnt_offset_subtable * extern struct sfnt_name_table *sfnt_read_name_table (PROTOTYPE); diff --git a/src/sfntfont.c b/src/sfntfont.c index 09aa89a9cdd..346e145082a 100644 --- a/src/sfntfont.c +++ b/src/sfntfont.c @@ -1648,7 +1648,10 @@ enum /* Caching subsystem. Generating outlines from glyphs is expensive, and so is rasterizing them, so two caches are maintained for both - glyph outlines and rasters. */ + glyph outlines and rasters. + + Computing metrics also requires some expensive processing if the + glyph has instructions or distortions. */ struct sfnt_outline_cache { @@ -1658,6 +1661,9 @@ struct sfnt_outline_cache /* Pointer to outline. */ struct sfnt_glyph_outline *outline; + /* Reference to glyph metrics. */ + struct sfnt_glyph_metrics metrics; + /* What glyph this caches. */ sfnt_glyph glyph; }; @@ -1724,20 +1730,21 @@ sfntfont_dereference_outline (struct sfnt_glyph_outline *outline) } /* Get the outline corresponding to the specified GLYPH_CODE in CACHE. - Use the pixel size PIXEL_SIZE, the glyf table GLYF, and the head - table HEAD. Keep *CACHE_SIZE updated with the number of elements - in the cache. + Use the scale factor SCALE, the glyf table GLYF, and the head table + HEAD. Keep *CACHE_SIZE updated with the number of elements in the + cache. Use the offset information in the long or short loca tables LOCA_LONG and LOCA_SHORT, whichever is set. - Use the specified HMTX, HHEA and MAXP tables when instructing + Use the specified HMTX, HEAD, HHEA and MAXP tables when instructing compound glyphs. - If INTERPRETER is non-NULL, then possibly use the unscaled glyph - metrics in METRICS and the interpreter STATE to instruct the glyph. - Otherwise, METRICS must contain scaled glyph metrics used to - compute the origin point of the outline. + If INTERPRETER is non-NULL, then possibly use it and the + interpreter graphics STATE to instruct the glyph. + + If METRICS is non-NULL, return the scaled glyph metrics after + variation and instructing. Return the outline with an incremented reference count and enter the generated outline into CACHE upon success, possibly discarding @@ -1746,7 +1753,7 @@ sfntfont_dereference_outline (struct sfnt_glyph_outline *outline) static struct sfnt_glyph_outline * sfntfont_get_glyph_outline (sfnt_glyph glyph_code, struct sfnt_outline_cache *cache, - int pixel_size, int *cache_size, + sfnt_fixed scale, int *cache_size, struct sfnt_glyf_table *glyf, struct sfnt_head_table *head, struct sfnt_hmtx_table *hmtx, @@ -1785,6 +1792,9 @@ sfntfont_get_glyph_outline (sfnt_glyph glyph_code, start->last->next = start; start->outline->refcount++; + if (metrics) + *metrics = start->metrics; + return start->outline; } } @@ -1804,6 +1814,12 @@ sfntfont_get_glyph_outline (sfnt_glyph glyph_code, dcontext.loca_short = loca_short; dcontext.glyf = glyf; + /* Now load the glyph's unscaled metrics into TEMP. */ + + if (sfnt_lookup_glyph_metrics (glyph_code, -1, &temp, hmtx, hhea, + head, maxp)) + goto fail; + if (interpreter) { if (glyph->simple) @@ -1813,7 +1829,7 @@ sfntfont_get_glyph_outline (sfnt_glyph glyph_code, interpreter->state = *state; error = sfnt_interpret_simple_glyph (glyph, interpreter, - metrics, &value); + &temp, &value); } else /* Restoring the interpreter state is done by @@ -1824,7 +1840,7 @@ sfntfont_get_glyph_outline (sfnt_glyph glyph_code, sfntfont_get_glyph, sfntfont_free_glyph, hmtx, hhea, maxp, - metrics, &dcontext, + &temp, &dcontext, &value); if (!error) @@ -1834,32 +1850,29 @@ sfntfont_get_glyph_outline (sfnt_glyph glyph_code, } } + /* At this point, the glyph metrics are unscaled. Scale them up. + If INTERPRETER is set, use the scale placed within. */ + + sfnt_scale_metrics (&temp, scale); + if (!outline) { - /* If INTERPRETER is NULL, METRICS contains scaled metrics. */ - if (!interpreter) - outline = sfnt_build_glyph_outline (glyph, head, pixel_size, - metrics, + outline = sfnt_build_glyph_outline (glyph, scale, + &temp, sfntfont_get_glyph, sfntfont_free_glyph, &dcontext); else - { - /* But otherwise, they are unscaled, and must be scaled - before being used. */ - - temp = *metrics; - sfnt_scale_metrics_to_pixel_size (&temp, pixel_size, - head); - outline = sfnt_build_glyph_outline (glyph, head, pixel_size, - &temp, - sfntfont_get_glyph, - sfntfont_free_glyph, - &dcontext); - } + outline = sfnt_build_glyph_outline (glyph, scale, + &temp, + sfntfont_get_glyph, + sfntfont_free_glyph, + &dcontext); } + fail: + xfree (glyph); if (!outline) @@ -1868,6 +1881,7 @@ sfntfont_get_glyph_outline (sfnt_glyph glyph_code, start = xmalloc (sizeof *start); start->glyph = glyph_code; start->outline = outline; + start->metrics = temp; /* One reference goes to the cache. The second reference goes to the caller. */ @@ -1898,7 +1912,11 @@ sfntfont_get_glyph_outline (sfnt_glyph glyph_code, (*cache_size)--; } - /* Return the cached outline. */ + /* Return the cached outline and metrics. */ + + if (metrics) + *metrics = temp; + return outline; } @@ -2104,6 +2122,9 @@ struct sfnt_font_info programs. */ struct sfnt_graphics_state state; + /* Factor used to convert from em space to pixel space. */ + sfnt_fixed scale; + #ifdef HAVE_MMAP /* Whether or not the glyph table has been mmapped. */ bool glyf_table_mapped; @@ -2647,6 +2668,7 @@ sfntfont_open (struct frame *f, Lisp_Object font_entity, font_info->raster_cache.last = &font_info->raster_cache; font_info->raster_cache_size = 0; font_info->interpreter = NULL; + font_info->scale = 0; #ifdef HAVE_MMAP font_info->glyf_table_mapped = false; #endif /* HAVE_MMAP */ @@ -2682,6 +2704,9 @@ sfntfont_open (struct frame *f, Lisp_Object font_entity, font_info->cmap_subtable = tables->cmap_subtable; font_info->uvs = tables->uvs; + /* Calculate the font's scaling factor. */ + font_info->scale = sfnt_get_scale (font_info->head, pixel_size); + /* Fill in font data. */ font = &font_info->font; font->pixel_size = pixel_size; @@ -2819,21 +2844,16 @@ sfntfont_encode_char (struct font *font, int c) Value is 0 upon success, 1 otherwise. */ static int -sfntfont_measure_instructed_pcm (struct sfnt_font_info *font, sfnt_glyph glyph, - struct font_metrics *pcm) +sfntfont_measure_pcm (struct sfnt_font_info *font, sfnt_glyph glyph, + struct font_metrics *pcm) { struct sfnt_glyph_metrics metrics; struct sfnt_glyph_outline *outline; - /* Ask for unscaled metrics. */ - if (sfnt_lookup_glyph_metrics (glyph, -1, &metrics, font->hmtx, - font->hhea, font->head, font->maxp)) - return 1; - /* Now get the glyph outline, which is required to obtain the rsb, ascent and descent. */ outline = sfntfont_get_glyph_outline (glyph, &font->outline_cache, - font->font.pixel_size, + font->scale, &font->outline_cache_size, font->glyf, font->head, font->hmtx, font->hhea, @@ -2846,57 +2866,6 @@ sfntfont_measure_instructed_pcm (struct sfnt_font_info *font, sfnt_glyph glyph, if (!outline) return 1; - /* Scale the metrics by the interpreter's scale. */ - sfnt_scale_metrics (&metrics, font->interpreter->scale); - - pcm->lbearing = metrics.lbearing >> 16; - pcm->rbearing = SFNT_CEIL_FIXED (outline->xmax) >> 16; - - /* Round the advance, ascent and descent upwards. */ - pcm->width = SFNT_CEIL_FIXED (metrics.advance) >> 16; - pcm->ascent = SFNT_CEIL_FIXED (outline->ymax) >> 16; - pcm->descent = SFNT_CEIL_FIXED (-outline->ymin) >> 16; - - sfntfont_dereference_outline (outline); - return 0; -} - -/* Measure the single glyph GLYPH in the font FONT and return its - metrics in *PCM. Value is 0 upon success, 1 otherwise. */ - -static int -sfntfont_measure_pcm (struct sfnt_font_info *font, sfnt_glyph glyph, - struct font_metrics *pcm) -{ - struct sfnt_glyph_metrics metrics; - struct sfnt_glyph_outline *outline; - - if (font->interpreter) - /* Use a function which instructs the glyph. */ - return sfntfont_measure_instructed_pcm (font, glyph, pcm); - - /* Get the glyph metrics first. */ - if (sfnt_lookup_glyph_metrics (glyph, font->font.pixel_size, - &metrics, font->hmtx, font->hhea, - font->head, font->maxp)) - return 1; - - /* Now get the glyph outline, which is required to obtain the rsb, - ascent and descent. */ - outline = sfntfont_get_glyph_outline (glyph, &font->outline_cache, - font->font.pixel_size, - &font->outline_cache_size, - font->glyf, font->head, - font->hmtx, font->hhea, - font->maxp, - font->loca_short, - font->loca_long, NULL, - &metrics, NULL); - - if (!outline) - return 1; - - /* How to round lbearing and rbearing? */ pcm->lbearing = metrics.lbearing >> 16; pcm->rbearing = SFNT_CEIL_FIXED (outline->xmax) >> 16; @@ -3049,15 +3018,10 @@ sfntfont_draw (struct glyph_string *s, int from, int to, struct font *font; struct sfnt_font_info *info; struct sfnt_glyph_metrics metrics; - int pixel_size; length = to - from; font = s->font; info = (struct sfnt_font_info *) font; - pixel_size = font->pixel_size; - - if (info->interpreter) - pixel_size = -1; rasters = alloca (length * sizeof *rasters); x_coords = alloca (length * sizeof *x_coords); @@ -3066,21 +3030,10 @@ sfntfont_draw (struct glyph_string *s, int from, int to, /* Get rasters and outlines for them. */ for (i = from; i < to; ++i) { - /* Look up the metrics for this glyph. The metrics are unscaled - if INFO->interpreter is set. */ - if (sfnt_lookup_glyph_metrics (s->char2b[i], pixel_size, - &metrics, info->hmtx, info->hhea, - info->head, info->maxp)) - { - rasters[i - from] = NULL; - x_coords[i - from] = 0; - continue; - } - /* Look up the outline. */ outline = sfntfont_get_glyph_outline (s->char2b[i], &info->outline_cache, - font->pixel_size, + info->scale, &info->outline_cache_size, info->glyf, info->head, info->hmtx, info->hhea, @@ -3098,10 +3051,6 @@ sfntfont_draw (struct glyph_string *s, int from, int to, continue; } - /* Scale the metrics if info->interpreter is set. */ - if (info->interpreter) - sfnt_scale_metrics (&metrics, info->interpreter->scale); - /* Rasterize the outline. */ rasters[i - from] = sfntfont_get_glyph_raster (s->char2b[i], &info->raster_cache, -- 2.39.2