simple->instructions comes one word past number_of_contours,
because end_pts_of_contours also contains the instruction
length. */
- simple->instructions = (uint8_t *) (simple->end_pts_of_contours
- + glyph->number_of_contours + 1);
+
+ simple->x_coordinates = (int16_t *) (simple->end_pts_of_contours
+ + glyph->number_of_contours + 1);
+ simple->y_coordinates = simple->x_coordinates + number_of_points;
+ simple->instructions = (uint8_t *) (simple->y_coordinates + number_of_points);
simple->flags = simple->instructions + simple->instruction_length;
/* Read instructions into the glyph. */
/* Now that the flags have been decoded, start decoding the
vectors. */
- simple->x_coordinates = (int16_t *) (simple->flags + number_of_points);
vec_start = flags_start;
i = 0;
x = 0;
pointer to the flags for the current vector. */
flags_start = simple->flags;
y = 0;
- simple->y_coordinates = simple->x_coordinates + i;
i = 0;
while (i < number_of_points)
{ \
int16_t word; \
\
- word = (((int8_t) high) << 8 | low); \
+ word = (((uint8_t) high) << 8 | low); \
PUSH_UNCHECKED (word); \
} \
#define SLOOP() \
{ \
- uint32_t loop; \
+ int32_t loop; \
\
loop = POP (); \
\
- if (!loop) \
- TRAP ("loop set to 0"); \
+ if (loop < 0) \
+ TRAP ("loop set to invalid value"); \
\
- interpreter->state.loop = loop; \
+ /* N.B. loop might be greater than 65535, \
+ but no reasonable font should define \
+ such values. */ \
+ interpreter->state.loop \
+ = MIN (65535, loop); \
}
#define SMD() \
if (number >= interpreter->glyph_zone->num_points)
TRAP ("address to ZP2 (glyph zone) out of bounds");
- *x = interpreter->glyph_zone->x_current[number];
- *y = interpreter->glyph_zone->y_current[number];
+ if (x && y)
+ {
+ *x = interpreter->glyph_zone->x_current[number];
+ *y = interpreter->glyph_zone->y_current[number];
+ }
if (x_org && y_org)
{
if (number >= interpreter->glyph_zone->num_points)
TRAP ("address to ZP1 (glyph zone) out of bounds");
- *x = interpreter->glyph_zone->x_current[number];
- *y = interpreter->glyph_zone->y_current[number];
+ if (x && y)
+ {
+ *x = interpreter->glyph_zone->x_current[number];
+ *y = interpreter->glyph_zone->y_current[number];
+ }
if (x_org && y_org)
{
if (number >= interpreter->glyph_zone->num_points)
TRAP ("address to ZP0 (glyph zone) out of bounds");
- *x = interpreter->glyph_zone->x_current[number];
- *y = interpreter->glyph_zone->y_current[number];
+ if (x && y)
+ {
+ *x = interpreter->glyph_zone->x_current[number];
+ *y = interpreter->glyph_zone->y_current[number];
+ }
if (x_org && y_org)
{
return (int32_t) (((uint32_t) hi << 18) | (l >> 14));
#else
int64_t xx, yy;
+ int64_t temp;
xx = (int64_t) ax * bx;
yy = (int64_t) ay * by;
yy = xx >> 63;
xx += 0x2000 + yy;
- return (int32_t) (xx / (1 << 14));
+ /* TrueType fonts rely on "division" here truncating towards
+ negative infinity, so compute the arithmetic right shift in place
+ of division. */
+ temp = -(xx < 0);
+ temp = (temp ^ xx) >> 14 ^ temp;
+ return (int32_t) (temp);
#endif
}
interpreter->state.rp0 = p;
}
+/* Return the projection of the two points P1 and P2's original values
+ along the dual projection vector, with P1 inside ZP0 and P2 inside
+ ZP1. If this zone is the glyph zone and the outline positions of
+ those points are directly accessible, project their original
+ positions and scale the result with rounding, so as to prevent
+ rounding-introduced inaccuracies.
+
+ The scenario where such inaccuracies are significant is generally
+ where an Italic glyph is being instructed at small PPEM sizes,
+ during which a point moved by MDAP[rN] is within 1/64th of a
+ pixel's distance from a point on the grid, yet the measurements
+ taken between such a point and the reference point against which
+ the distance to move is computed is such that the position of the
+ point after applying their rounded values differs by one grid
+ coordinate from the font designer's intentions, either exaggerating
+ or neutralizing the slant of the stem to which it belongs.
+
+ This behavior applies only to MDRP, which see. */
+
+static sfnt_f26dot6
+sfnt_project_zp1_zp0_org (struct sfnt_interpreter *interpreter,
+ uint32_t p1, uint32_t p2)
+{
+ sfnt_fword x1, y1, x2, y2, projection;
+ struct sfnt_simple_glyph *simple;
+ sfnt_f26dot6 org_x1, org_y1, org_x2, org_y2;
+
+ /* Addressing the twilight zone, perhaps only partially. */
+ if (!interpreter->state.zp0
+ || !interpreter->state.zp1
+ /* Not interpreting a glyph. */
+ || !interpreter->glyph_zone
+ /* Not interpreting a simple glyph. */
+ || !interpreter->glyph_zone->simple
+ /* P1 or P2 are phantom points. */
+ || p1 >= interpreter->glyph_zone->simple->number_of_points
+ || p2 >= interpreter->glyph_zone->simple->number_of_points)
+ goto project_normally;
+
+ simple = interpreter->glyph_zone->simple;
+ x1 = simple->x_coordinates[p1];
+ y1 = simple->y_coordinates[p1];
+ x2 = simple->x_coordinates[p2];
+ y2 = simple->y_coordinates[p2];
+
+ /* Compute the projection. */
+ projection = DUAL_PROJECT (x1 - x2, y1 - y2);
+
+ /* Return the projection, scaled with rounding. */
+ return sfnt_mul_fixed_round (projection, interpreter->scale);
+
+ project_normally:
+ sfnt_address_zp1 (interpreter, p1, NULL, NULL, &org_x1, &org_y1);
+ sfnt_address_zp0 (interpreter, p2, NULL, NULL, &org_x2, &org_y2);
+ return DUAL_PROJECT (org_x1 - org_x2, org_y1 - org_y2);
+}
+
/* Interpret an MDRP instruction with the specified OPCODE in
INTERPRETER. Pop a point in ZP1, and move the point until its
distance from RP0 in ZP0 is the same as in the original outline.
uint32_t p;
sfnt_f26dot6 distance, applied;
sfnt_f26dot6 current_projection;
- sfnt_f26dot6 x, y, org_x, org_y;
- sfnt_f26dot6 rx, ry, org_rx, org_ry;
+ sfnt_f26dot6 x, y, rx, ry;
/* Point number. */
p = POP ();
/* Load the points. */
- sfnt_address_zp1 (interpreter, p, &x, &y, &org_x, &org_y);
+ sfnt_address_zp1 (interpreter, p, &x, &y, NULL, NULL);
sfnt_address_zp0 (interpreter, interpreter->state.rp0,
- &rx, &ry, &org_rx, &org_ry);
+ &rx, &ry, NULL, NULL);
/* Calculate the distance between P and rp0 prior to hinting. */
- distance = DUAL_PROJECT (org_x - org_rx,
- org_y - org_ry);
+ distance = sfnt_project_zp1_zp0_org (interpreter, p,
+ interpreter->state.rp0);
/* Calculate the distance between P and rp0 as of now in the hinting
process. */
zone->y_current = zone->y_points + zone->num_points;
zone->flags = (unsigned char *) (zone->y_current
+ zone->num_points);
+ zone->simple = glyph->simple;
/* Load x_points and x_current. */
for (i = 0; i < glyph->simple->number_of_points; ++i)
zone->y_current = zone->y_points + zone->num_points;
zone->flags = (unsigned char *) (zone->y_current
+ zone->num_points);
+ zone->simple = NULL;
/* Copy and renumber all contour end points to start from
base_index. */
"SLOOP",
/* PUSHB[0] 2
SLOOP[]
- PUSHB[0] 0
+ PUSHW[0] 255 255 (-1)
SLOOP[] */
(unsigned char []) { 0xb0, 2,
0x17,
- 0xb0, 0,
+ 0xb8, 255, 255,
0x17, },
- 6,
+ 7,
NULL,
sfnt_check_sloop,
},
return buffer;
}
- if (exec_fpgm->instructions
+ if (exec_fpgm
+ && exec_fpgm->instructions
&& where >= exec_fpgm->instructions
&& where < (exec_fpgm->instructions
+ exec_fpgm->num_instructions))
if (!interpreter)
abort ();
+ if (getenv ("SFNT_VERBOSE"))
+ {
+ interpreter->run_hook = sfnt_verbose;
+ interpreter->push_hook = sfnt_push_hook;
+ interpreter->pop_hook = sfnt_pop_hook;
+ }
+
for (i = 0; i < ARRAYELTS (all_tests); ++i)
sfnt_run_interpreter_test (&all_tests[i], interpreter);
return 1;
}
-#define FANCY_PPEM 14
-#define EASY_PPEM 14
+#define FANCY_PPEM 16
+#define EASY_PPEM 16
interpreter = NULL;
head = sfnt_read_head_table (fd, font);
interpreter = sfnt_make_interpreter (maxp, cvt, head,
fvar, FANCY_PPEM,
FANCY_PPEM);
+
+ if (getenv ("SFNT_DEBUG"))
+ interpreter->run_hook = sfnt_run_hook;
+ else if (getenv ("SFNT_VERBOSE"))
+ {
+ interpreter->run_hook = sfnt_verbose;
+ interpreter->push_hook = sfnt_push_hook;
+ interpreter->pop_hook = sfnt_pop_hook;
+ }
+
state = interpreter->state;
if (instance && gvar)
if (interpreter)
{
- if (getenv ("SFNT_DEBUG"))
- interpreter->run_hook = sfnt_run_hook;
- else if (getenv ("SFNT_VERBOSE"))
- {
- interpreter->run_hook = sfnt_verbose;
- interpreter->push_hook = sfnt_push_hook;
- interpreter->pop_hook = sfnt_pop_hook;
- }
-
if (!sfnt_lookup_glyph_metrics (code, &metrics,
hmtx, hhea, maxp))
{