contours.
CONTEXT should be zeroed and put on the stack. RECURSION_COUNT
- should be initialized to 0. GET_GLYPH and FREE_GLYPH, along with
- DCONTEXT, mean the same as in sfnt_decompose_glyph.
+ should be initialized to 0. GET_GLYPH, FREE_GLYPH, and
+ GET_METRICS, along with DCONTEXT, mean the same as in
+ sfnt_decompose_glyph.
Value is 1 upon failure, else 0. */
struct sfnt_compound_glyph_context *context,
sfnt_get_glyph_proc get_glyph,
sfnt_free_glyph_proc free_glyph,
+ sfnt_get_metrics_proc get_metrics,
int recursion_count,
void *dcontext)
{
unsigned char *flags_base;
size_t base_index, contour_start;
bool defer_offsets;
+ struct sfnt_glyph_metrics sub_metrics;
+ sfnt_fixed f1, f2;
/* Set up the base index. This is the index from where on point
renumbering starts.
{
if (point2 >= subglyph->simple->number_of_points)
{
+ if (point2 < subglyph->simple->number_of_points + 2)
+ {
+ /* POINT2 is one of SUBGLYPH's phantom points.
+ Retrieve the glyph's metrics. */
+
+ if ((*get_metrics) (component->glyph_index, &sub_metrics,
+ dcontext))
+ {
+ if (need_free)
+ free_glyph (subglyph, dcontext);
+
+ return 1;
+ }
+
+ /* Derive the phantom points from those metrics. */
+ f1 = glyph->xmin - sub_metrics.lbearing;
+ f2 = f1 + sub_metrics.advance;
+
+ /* Apply the metrics distortion. */
+ f1 += glyph->origin_distortion;
+ f2 += glyph->advance_distortion;
+
+ /* Get the points and use them to compute the offsets. */
+
+ if (!(point2 - subglyph->simple->number_of_points))
+ x = f1 * 65536;
+ else
+ x = f2 * 65536;
+
+ x = context->x_coordinates[point] - x;
+ y = context->y_coordinates[point];
+
+ /* X and Y offsets have been ascertained. */
+ goto skip_computation;
+ }
+
if (need_free)
free_glyph (subglyph, dcontext);
ytemp = context->y_coordinates[point];
x = (xtemp - subglyph->simple->x_coordinates[point2] * 65536);
y = (ytemp - subglyph->simple->y_coordinates[point2] * 65536);
+
+ skip_computation:
+ ;
}
else
{
context,
get_glyph,
free_glyph,
+ get_metrics,
recursion_count + 1,
dcontext);
if (point2 >= context->num_points)
{
+ /* POINT2 might fall within the phantom points of
+ that glyph. */
+
+ if (point2 - context->num_points < 2)
+ {
+ if ((*get_metrics) (component->glyph_index, &sub_metrics,
+ dcontext))
+ goto error_in_defer_offsets;
+
+ /* Derive the phantom points from those metrics. */
+ f1 = glyph->xmin - sub_metrics.lbearing;
+ f2 = f1 + sub_metrics.advance;
+
+ /* Apply the metrics distortion. */
+ f1 += glyph->origin_distortion;
+ f2 += glyph->advance_distortion;
+
+ /* Get the points and use them to compute the offsets. */
+
+ if (!(point2 - context->num_points))
+ x = f1 * 65536;
+ else
+ x = f2 * 65536;
+
+ x = context->x_coordinates[point] - x;
+ y = context->y_coordinates[point];
+
+ /* X and Y offsets have been ascertained. */
+ goto skip_computation_from_defer_offsets;
+ }
+
+ error_in_defer_offsets:
if (need_free)
free_glyph (subglyph, dcontext);
ytemp = context->y_coordinates[point];
x = (xtemp - context->x_coordinates[point2]);
y = (ytemp - context->y_coordinates[point2]);
+
+ skip_computation_from_defer_offsets:
+ ;
}
sfnt_transform_coordinates (component,
context->x_coordinates + contour_start,
context->y_coordinates + contour_start,
- contour_start - context->num_points,
+ context->num_points - contour_start,
x, y);
}
If GLYPH is compound, use GET_GLYPH to obtain subglyphs. PROC must
return whether or not FREE_GLYPH will be called with the glyph
- after sfnt_decompose_glyph is done with it.
+ after sfnt_decompose_glyph is done with it. If GLYPH moreover
+ incorporates components whose anchor points are phantom points, use
+ GET_METRICS to obtain glyph metrics prerequisite for establishing
+ their coordinates.
All functions will be called with DCONTEXT as an argument.
sfnt_curve_to_proc curve_to,
sfnt_get_glyph_proc get_glyph,
sfnt_free_glyph_proc free_glyph,
+ sfnt_get_metrics_proc get_metrics,
void *dcontext)
{
size_t here, last, n;
if (sfnt_decompose_compound_glyph (glyph, &context,
get_glyph, free_glyph,
- 0, dcontext))
+ get_metrics, 0,
+ dcontext))
{
xfree (context.x_coordinates);
xfree (context.y_coordinates);
outline.
Call GET_GLYPH and FREE_GLYPH with the specified DCONTEXT to obtain
- glyphs for compound glyph subcomponents. */
+ glyphs for compound glyph subcomponents, and GET_METRICS with the
+ provided DCONTEXT for unscaled glyph metrics. */
TEST_STATIC struct sfnt_glyph_outline *
sfnt_build_glyph_outline (struct sfnt_glyph *glyph,
struct sfnt_glyph_metrics *metrics,
sfnt_get_glyph_proc get_glyph,
sfnt_free_glyph_proc free_glyph,
+ sfnt_get_metrics_proc get_metrics,
void *dcontext)
{
struct sfnt_glyph_outline *outline;
rc = sfnt_decompose_glyph (glyph, sfnt_move_to_and_build,
sfnt_line_to_and_build,
sfnt_curve_to_and_build,
- get_glyph, free_glyph, dcontext);
+ get_glyph, free_glyph, get_metrics,
+ dcontext);
/* Synchronize the outline object with what might have changed
inside sfnt_decompose_glyph. */
{
sfnt_f26dot6 x, y, original_x, original_y;
sfnt_f26dot6 magnitude;
- size_t start, end, n;
+ uint16_t reference_point;
+ size_t start, end, start1, end1, n;
if (!interpreter->glyph_zone)
TRAP ("SHC without glyph zone");
projection vector. */
if (opcode == 0x35)
- sfnt_address_zp0 (interpreter, interpreter->state.rp1,
+ sfnt_address_zp0 (interpreter,
+ (reference_point = interpreter->state.rp1),
&x, &y, &original_x, &original_y);
else
- sfnt_address_zp1 (interpreter, interpreter->state.rp2,
+ sfnt_address_zp1 (interpreter,
+ (reference_point = interpreter->state.rp2),
&x, &y, &original_x, &original_y);
magnitude = sfnt_project_vector (interpreter,
Verify that both are valid. */
if (contour)
- start = interpreter->glyph_zone->contour_end_points[contour - 1];
+ start = interpreter->glyph_zone->contour_end_points[contour - 1] + 1;
else
start = 0;
if (start > end || end >= interpreter->glyph_zone->num_points)
TRAP ("invalid contour data in glyph");
+ /* If the reference point falls between end and start, split the
+ range formed by end and start at the reference point and keep the
+ latter intact. */
+
+ if (start <= reference_point && reference_point <= end)
+ {
+ /* Do the points between start and rpN. */
+ start1 = start;
+ end1 = reference_point - 1;
+
+ if (start1 <= end1)
+ sfnt_move_glyph_zone (interpreter, start1,
+ end1 - start1 + 1, magnitude);
+
+ /* Now the points between rpN + 1 and end. */
+ start1 = reference_point + 1;
+ end1 = end;
+
+ if (start1 <= end1)
+ sfnt_move_glyph_zone (interpreter, start1,
+ end1 - start1 + 1, magnitude);
+
+ return;
+ }
+
/* Compute the number of points to move. */
n = end - start + 1;
}
else /* No scale, just apply x_off and y_off. */
{
- for (i = 0; i < num_coordinates; ++i)
- x[i] += x_off, y[i] += y_off;
+ if (x_off || y_off)
+ {
+ for (i = 0; i < num_coordinates; ++i)
+ x[i] += x_off, y[i] += y_off;
+ }
return;
}
CONTEXT contains the points and contours of this compound glyph,
numbered starting from BASE_INDEX and BASE_CONTOUR respectively.
+ In addition, CONTEXT also contains two additional ``phantom
+ points'' supplying the left and right side bearings of GLYPH.
Value is NULL upon success, or a description of the error upon
failure. */
size_t zone_size, temp;
struct sfnt_interpreter_zone *zone;
struct sfnt_interpreter_zone *volatile preserved_zone;
- sfnt_f26dot6 phantom_point_1_x;
- sfnt_f26dot6 phantom_point_1_y;
- sfnt_f26dot6 phantom_point_2_x;
- sfnt_f26dot6 phantom_point_2_y;
volatile bool zone_was_allocated;
int rc;
sfnt_f26dot6 *x_base, *y_base;
}
/* Now load the zone with data. */
- zone->num_points = num_points + 2;
+ zone->num_points = num_points;
zone->num_contours = num_contours;
zone->contour_end_points = (size_t *) (zone + 1);
zone->x_points = (sfnt_f26dot6 *) (zone->contour_end_points
zone->x_points[i] = context->x_coordinates[i + base_index];
}
- /* Compute phantom points. */
- sfnt_compute_phantom_points (glyph, metrics, interpreter->scale,
- &phantom_point_1_x, &phantom_point_1_y,
- &phantom_point_2_x, &phantom_point_2_y);
-
- /* Load phantom points. */
- zone->x_points[i] = phantom_point_1_x;
- zone->x_points[i + 1] = phantom_point_2_x;
- zone->x_current[i] = phantom_point_1_x;
- zone->x_current[i + 1] = phantom_point_2_x;
-
for (i = 0; i < num_points; ++i)
{
zone->y_current[i] = context->y_coordinates[i + base_index];
& ~SFNT_POINT_TOUCHED_BOTH);
}
- /* Load phantom points. */
- zone->y_points[i] = phantom_point_1_y;
- zone->y_points[i + 1] = phantom_point_2_y;
- zone->y_current[i] = phantom_point_1_x;
- zone->y_current[i + 1] = phantom_point_2_x;
-
- /* Load phantom point flags. */
- zone->flags[i] = SFNT_POINT_PHANTOM;
- zone->flags[i + 1] = SFNT_POINT_PHANTOM;
-
/* Load the compound glyph program. */
interpreter->IP = 0;
interpreter->SP = interpreter->stack;
bool defer_offsets;
struct sfnt_instructed_outline *value;
struct sfnt_glyph_metrics sub_metrics;
+ sfnt_f26dot6 phantom_point_1_x;
+ sfnt_f26dot6 phantom_point_1_y;
+ sfnt_f26dot6 phantom_point_2_x;
+ sfnt_f26dot6 phantom_point_2_y;
error = NULL;
if (!subglyph->compound)
{
- if (point2 >= subglyph->simple->number_of_points)
+ if (point2 >= subglyph->simple->number_of_points + 2)
{
+ /* If POINT2 is placed within a phantom point, use
+ that. */
+
if (need_free)
free_glyph (subglyph, dcontext);
return "Invalid component anchor point";
}
- /* Get the points and use them to compute the offsets. */
- xtemp = context->x_coordinates[point];
- ytemp = context->y_coordinates[point];
-
- /* Convert the unscaled coordinates within
- SIMPLE->x_coordinates to device space. */
- x = subglyph->simple->x_coordinates[point2];
- y = subglyph->simple->y_coordinates[point2];
- x = sfnt_mul_f26dot6_fixed (x * 64, interpreter->scale);
- y = sfnt_mul_f26dot6_fixed (y * 64, interpreter->scale);
-
- /* Derive the X and Y offsets from the difference
- between the reference point's position and the anchor
- point's. */
- x = xtemp - x;
- y = ytemp - y;
- }
- else
- {
/* First, set offsets to 0, because it is not yet
- possible to determine the position of the anchor
- point in the child. */
+ possible to ascertain the position of the anchor
+ point in the child. That position cannot be
+ established prior to the completion of
+ grid-fitting. */
x = 0;
y = 0;
}
/* Figure out how many more points and contours are
- needed. Here, last_point is not the end of the
- glyph's contours, as two phantom points are
- included. */
- last_point = value->num_points;
+ needed. While phantom points are not included within
+ the outline ultimately produced, they are temporarily
+ appended to the outline here, so as to enable
+ defer_offsets below to refer to them. */
+ assert (value->num_points >= 2);
+ last_point = value->num_points - 2;
number_of_contours = value->num_contours;
/* Grow various arrays. */
contour_base[i] = (contour_start
+ value->contour_end_points[i]);
+ /* Establish offsets for anchor points here. It is
+ possible for glyph anchors to be set to phantom
+ points, whose coordinates cannot be established until
+ grid fitting completes. */
+
+ if (defer_offsets)
+ {
+ x = 0;
+ y = 0;
+
+ /* Assert the child anchor is within the confines of
+ the zone. */
+ assert (point2 < value->num_points);
+
+ /* Get the points and use them to compute the
+ offsets. */
+
+ xtemp = context->x_coordinates[point];
+ ytemp = context->y_coordinates[point];
+ x = (xtemp - value->x_points[point2]);
+ y = (ytemp - value->y_points[point2]);
+ }
+
xfree (value);
- /* Apply the transform to the points. */
+ /* Apply the transform to the points, excluding phantom
+ points within. */
sfnt_transform_f26dot6 (component, x_base, y_base,
last_point, x, y);
}
return error;
}
- /* When an anchor point is being used to translate the
- glyph, and the subglyph in question is actually a
- compound glyph, it is impossible to know which offset to
- use until the compound subglyph has actually been
- loaded.
+ /* Anchor points for glyphs with instructions must be
+ computed after grid fitting completes.
- As a result, the offset is calculated here, using the
- points in the loaded child compound glyph. But first, X
- and Y must be reset to 0, as otherwise the translation
- might be applied twice if defer_offsets is not set. */
-
- x = 0;
- y = 0;
+ As such, the offset is calculated here, using the points
+ in the loaded child compound glyph. At present, CONTEXT
+ incorporates the two phantom points after the end of the
+ last component within SUBGLYPH. */
if (defer_offsets)
{
+ x = 0;
+ y = 0;
+
/* Renumber the non renumbered point2 to point into the
decomposed component. */
point2 += contour_start;
if (need_free)
free_glyph (subglyph, dcontext);
- return "Invalid point2";
+ return "Invalid anchor reference point";
}
/* Get the points and use them to compute the
y = (ytemp - context->y_coordinates[point2]);
}
+ /* Subtract the two phantom points from context->num_points.
+ This behavior is correct, as only the subglyph's phantom
+ points may be provided as anchor points. */
+ assert (context->num_points - contour_start >= 2);
+ context->num_points -= 2;
+
sfnt_transform_f26dot6 (component,
context->x_coordinates + contour_start,
context->y_coordinates + contour_start,
- contour_start - context->num_points,
+ /* Exclude phantom points from
+ transformations. */
+ context->num_points - contour_start,
x, y);
}
free_glyph (subglyph, dcontext);
}
- /* Run the program for the entire compound glyph, if any. */
+ /* Run the program for the entire compound glyph, if any. CONTEXT
+ should not contain phantom points by this point, so append its
+ own. */
+
+ /* Compute phantom points. */
+ sfnt_compute_phantom_points (glyph, metrics, interpreter->scale,
+ &phantom_point_1_x, &phantom_point_1_y,
+ &phantom_point_2_x, &phantom_point_2_y);
+
+ /* Grow various arrays to include those points. */
+ rc = sfnt_expand_compound_glyph_context (context,
+ /* Number of new contours
+ required. */
+ 0,
+ /* Number of new points
+ required. */
+ 2,
+ &x_base, &y_base,
+ &flags_base, &contour_base);
+
+ /* Store the phantom points within the compound glyph. */
+ x_base[0] = phantom_point_1_x;
+ x_base[1] = phantom_point_2_x;
+ y_base[0] = phantom_point_1_y;
+ y_base[1] = phantom_point_2_y;
+ flags_base[0] = SFNT_POINT_PHANTOM;
+ flags_base[1] = SFNT_POINT_PHANTOM;
if (glyph->compound->instruction_length)
{
struct sfnt_glyf_table *glyf;
struct sfnt_loca_table_short *loca_short;
struct sfnt_loca_table_long *loca_long;
+ struct sfnt_hmtx_table *hmtx;
+ struct sfnt_hhea_table *hhea;
+ struct sfnt_maxp_table *maxp;
struct sfnt_blend *blend;
};
sfnt_free_glyph (glyph);
}
+static int
+sfnt_test_get_metrics (sfnt_glyph glyph, struct sfnt_glyph_metrics *metrics,
+ void *dcontext)
+{
+ struct sfnt_test_dcontext *tables;
+
+ tables = dcontext;
+ return sfnt_lookup_glyph_metrics (glyph, -1, metrics,
+ tables->hmtx, tables->hhea,
+ NULL, tables->maxp);
+}
+
static void
sfnt_test_span (struct sfnt_edge *edge, sfnt_fixed y,
void *dcontext)
return 1;
}
-#define FANCY_PPEM 12
-#define EASY_PPEM 12
+#define FANCY_PPEM 18
+#define EASY_PPEM 18
interpreter = NULL;
head = sfnt_read_head_table (fd, font);
dcontext.glyf = glyf;
dcontext.loca_short = loca_short;
dcontext.loca_long = loca_long;
+ dcontext.hmtx = hmtx;
+ dcontext.hhea = hhea;
+ dcontext.maxp = maxp;
if (instance && gvar)
dcontext.blend = &blend;
sfnt_test_curve_to,
sfnt_test_get_glyph,
sfnt_test_free_glyph,
+ sfnt_test_get_metrics,
&dcontext))
printf ("decomposition failure\n");
&metrics,
sfnt_test_get_glyph,
sfnt_test_free_glyph,
+ sfnt_test_get_metrics,
&dcontext);
clock_gettime (CLOCK_THREAD_CPUTIME_ID, &end);