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.
This commit is contained in:
Po Lu 2023-03-27 11:24:05 +08:00
parent 67a325243c
commit 18b34e9ca0
3 changed files with 85 additions and 147 deletions

View file

@ -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,
/* 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);
PIXEL = UNIT / UPEM * PPEM
which means:
PIXEL = UNIT * PPEM / UPEM */
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,

View file

@ -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);

View file

@ -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,