-/* sfnt format font support for GNU Emacs.
+/* TrueType format font support for GNU Emacs.
Copyright (C) 2023 Free Software Foundation, Inc.
Try not to keep this file too dependent on Emacs. Everything Lisp
related goes in sfntfont.c. The author wants to keep using it for
- some other (free) software. */
+ some other (free) software.
+
+ The source of reference is the TrueType Reference Manual, published
+ by Apple Computer, which is currently found at:
+
+ https://developer.apple.com/fonts/TrueType-Reference-Manual/
+
+ Apple's TrueType implementation is notably missing features
+ provided by Microsoft's extended OpenType scaler, such as the two
+ additional phantom points on the Y axis, and also behaves
+ differently, especially when it comes to considering phantom points
+ as anchors in compound glyphs.
+
+ As a result, do not expect this scaler to work well with Microsoft
+ fonts such as Arial. */
\f
sfnt_f26dot6 (*project) (sfnt_f26dot6, sfnt_f26dot6,
struct sfnt_interpreter *);
+ /* Pointer to the function used to project euclidean vectors onto
+ the dual projection vector. Value is the magnitude of the
+ projected vector. */
+ sfnt_f26dot6 (*dual_project) (sfnt_f26dot6, sfnt_f26dot6,
+ struct sfnt_interpreter *);
+
/* Pointer to the function used to move specified points
along the freedom vector by a distance specified in terms
of the projection vector. */
\
id = POP (); \
n = POP (); \
+ def = NULL; /* Pacify -fanalyzer. */ \
\
if (n > 65535) \
TRAP ("invalid LOOPCALL count"); \
\f
-/* CVT delta exception instructions.
+/* CVT and point delta exception instructions.
``Exceptions'' can be placed directly inside the control value
table, as it is reloaded every time the point size changes. */
goto deltac3_start; \
}
+#define DELTAP1() \
+ { \
+ uint32_t n, argn, pn; \
+ \
+ n = POP (); \
+ \
+ deltap1_start: \
+ if (!n) \
+ break; \
+ \
+ argn = POP (); \
+ pn = POP (); \
+ sfnt_deltap (1, interpreter, argn, pn); \
+ goto deltap1_start; \
+ }
+
+#define DELTAP2() \
+ { \
+ uint32_t n, argn, pn; \
+ \
+ n = POP (); \
+ \
+ deltap2_start: \
+ if (!n) \
+ break; \
+ \
+ argn = POP (); \
+ pn = POP (); \
+ sfnt_deltap (2, interpreter, argn, pn); \
+ goto deltap2_start; \
+ }
+
+#define DELTAP3() \
+ { \
+ uint32_t n, argn, pn; \
+ \
+ n = POP (); \
+ \
+ deltap3_start: \
+ if (!n) \
+ break; \
+ \
+ argn = POP (); \
+ pn = POP (); \
+ sfnt_deltap (3, interpreter, argn, pn); \
+ goto deltap3_start; \
+ }
+
\f
/* Anachronistic angle instructions. */
/* Projection and freedom vector operations. */
+#define PROJECT(x, y) \
+ sfnt_project_vector (interpreter, x, y)
+
+#define DUAL_PROJECT(x, y) \
+ sfnt_dual_project_vector (interpreter, x, y)
+
#define SVTCAy() \
{ \
sfnt_set_freedom_vector (interpreter, \
interpreter->state.loop = 1; \
}
+#define IP() \
+ { \
+ sfnt_interpret_ip (interpreter); \
+ }
+
+#define MSIRP() \
+ { \
+ sfnt_f26dot6 d; \
+ uint32_t p; \
+ \
+ d = POP (); \
+ p = POP (); \
+ \
+ sfnt_interpret_msirp (interpreter, d, p, \
+ opcode); \
+ }
+
+#define ALIGNRP() \
+ { \
+ sfnt_interpret_alignrp (interpreter); \
+ }
+
+#define MIAP() \
+ { \
+ uint32_t cvt; \
+ uint32_t p; \
+ \
+ cvt = POP (); \
+ p = POP (); \
+ \
+ sfnt_interpret_miap (interpreter, cvt, p, \
+ opcode); \
+ }
+
+#define GC() \
+ { \
+ uint32_t p; \
+ sfnt_f26dot6 x, y, value; \
+ sfnt_f26dot6 org_x, org_y; \
+ \
+ p = POP (); \
+ \
+ sfnt_address_zp2 (interpreter, p, &x, &y, \
+ &org_x, &org_y); \
+ \
+ if (opcode == 0x47) \
+ value = DUAL_PROJECT (org_x, org_y); \
+ else \
+ value = PROJECT (x, y); \
+ \
+ PUSH (value); \
+ }
+
+#define SCFS() \
+ { \
+ uint32_t p; \
+ sfnt_f26dot6 c; \
+ \
+ c = POP (); \
+ p = POP (); \
+ \
+ sfnt_interpret_scfs (interpreter, c, p); \
+ }
+
+#define MD() \
+ { \
+ uint32_t p1, p2; \
+ sfnt_f26dot6 distance; \
+ \
+ p1 = POP (); \
+ p2 = POP (); \
+ \
+ distance \
+ = sfnt_measure_distance (interpreter, \
+ p1, p2, \
+ opcode); \
+ PUSH (distance); \
+ }
+
\f
#define NOT_IMPLEMENTED() \
interpreter->glyph_zone->flags[p] &= ~SFNT_POINT_TOUCHED_X;
}
-/* Save the specified unit VECTOR into INTERPRETER's graphics
- state. */
+/* Save the specified unit VECTOR into INTERPRETER's graphics state as
+ both the projection and the dual projection vectors. */
static void
sfnt_save_projection_vector (struct sfnt_interpreter *interpreter,
struct sfnt_unit_vector *vector)
{
interpreter->state.projection_vector = *vector;
+ interpreter->state.dual_projection_vector = *vector;
sfnt_validate_gs (&interpreter->state);
}
TRAP ("point lies outside glyph zone (ZP2)");
}
+/* Check that the specified POINT lies within the zone addressed by
+ INTERPRETER's ZP0 register. Trap if it does not. */
+
+static void
+sfnt_check_zp0 (struct sfnt_interpreter *interpreter, uint32_t point)
+{
+ if (!interpreter->state.zp0)
+ {
+ if (point >= interpreter->twilight_zone_size)
+ TRAP ("point lies outside twilight zone (ZP0)");
+ }
+ else if (!interpreter->glyph_zone
+ || point >= interpreter->glyph_zone->num_points)
+ TRAP ("point lies outside glyph zone (ZP0)");
+}
+
/* Move N points starting from the specified POINT in the zone
addressed by INTERPRETER's ZP0 register by the given DISTANCE along
the freedom vector.
return interpreter->state.project (vx, vy, interpreter);
}
+/* Project the vector VX, VY onto INTERPRETER's dual projection
+ vector. Return the magnitude of the projection. */
+
+static sfnt_f26dot6
+sfnt_dual_project_vector (struct sfnt_interpreter *interpreter,
+ sfnt_f26dot6 vx, sfnt_f26dot6 vy)
+{
+ return interpreter->state.dual_project (vx, vy, interpreter);
+}
+
+/* Interpret an SCFS instruction.
+ Move P in ZP2 along the freedom vector until its projection is
+ equal to C. */
+
+static void
+sfnt_interpret_scfs (struct sfnt_interpreter *interpreter,
+ uint32_t p, sfnt_f26dot6 c)
+{
+ sfnt_f26dot6 x, y, distance;
+
+ sfnt_address_zp2 (interpreter, p, &x, &y, NULL, NULL);
+ distance = PROJECT (x, y);
+ sfnt_move_zp2 (interpreter, p, 1, sfnt_sub (c, distance));
+}
+
+/* Symmetrically round the 26.6 fixed point value X using the rounding
+ mode in INTERPRETER. Return the result. */
+
+static sfnt_f26dot6
+sfnt_round_symmetric (struct sfnt_interpreter *interpreter, sfnt_f26dot6 x)
+{
+ int sign;
+
+ sign = 1;
+
+ if (x < 0)
+ {
+ sign = -1;
+ x = -x;
+ }
+
+ return interpreter->state.round (x, interpreter) * sign;
+}
+
+/* Interpret an MIAP (``Move Indirect Absolute Point'') instruction
+ using INTERPRETER.
+
+ Move P in ZP0 along the freedom vector until its projection on the
+ projection vector is equal to CVT units in the projection vector.
+
+ Finally, set RP0 and RP1 to P.
+
+ If OPCODE is 0x3f, then in addition check the CVT value against the
+ control value cut-in, and round the magnitudes of the movement. */
+
+static void
+sfnt_interpret_miap (struct sfnt_interpreter *interpreter,
+ uint32_t cvt, uint32_t p, unsigned char opcode)
+{
+ sfnt_f26dot6 x, y, distance, value, delta;
+
+ sfnt_address_zp0 (interpreter, p, &x, &y, NULL, NULL);
+
+ /* Read the cvt value. */
+
+ if (cvt >= interpreter->cvt_size)
+ TRAP ("out of bounds read to cvt");
+
+ value = interpreter->cvt[cvt];
+
+ /* Obtain the original distance. */
+ distance = sfnt_project_vector (interpreter, x, y);
+
+ /* Round the distance and apply the cvt cut in if necessary. */
+
+ if (opcode == 0x3f)
+ {
+ delta = sfnt_sub (value, distance);
+
+ if (delta < 0)
+ delta = -delta;
+
+ /* If delta is more than the cvt cut in (more aptly named ``cut
+ out''), use the original distance. */
+
+ if (delta > interpreter->state.cvt_cut_in)
+ value = distance;
+
+ /* Round value. */
+ value = sfnt_round_symmetric (interpreter, value);
+ }
+
+ /* Move the point by the distance. */
+ sfnt_move_zp0 (interpreter, p, 1, sfnt_sub (value, distance));
+
+ /* Set reference points. */
+ interpreter->state.rp0 = p;
+ interpreter->state.rp1 = p;
+}
+
+/* Perform a single iteration of sfnt_interpret_alignrp. RP0X and
+ RP0Y should be the position of the reference point RP0 in ZP0. */
+
+static void
+sfnt_interpret_alignrp_1 (struct sfnt_interpreter *interpreter,
+ sfnt_f26dot6 rp0x, sfnt_f26dot6 rp0y)
+{
+ sfnt_f26dot6 distance, x, y;
+ uint32_t point;
+
+ point = POP ();
+
+ /* Load this point. */
+ sfnt_address_zp1 (interpreter, point, &x, &y, NULL, NULL);
+
+ /* Measure the distance from here to rp0. */
+ distance = sfnt_project_vector (interpreter, sfnt_sub (x, rp0x),
+ sfnt_sub (y, rp0y));
+
+ /* Move by the opposite. */
+ sfnt_move_zp1 (interpreter, point, 1, -distance);
+}
+
+/* For loop times, pop a point in ZP1 and align it to RP0 in ZP0 by
+ moving it along the freedom vector until its projected distance
+ from RP0 becomes 0. */
+
+static void
+sfnt_interpret_alignrp (struct sfnt_interpreter *interpreter)
+{
+ sfnt_f26dot6 rp0x, rp0y;
+
+ sfnt_address_zp0 (interpreter, interpreter->state.rp0,
+ &rp0x, &rp0y, NULL, NULL);
+
+ while (interpreter->state.loop--)
+ sfnt_interpret_alignrp_1 (interpreter, rp0x, rp0y);
+
+ interpreter->state.loop = 1;
+}
+
/* Align the two points P1 and P2 relative to the projection vector.
P1 is addressed relative to ZP0, and P2 is addressed relative to
ZP1.
sfnt_normalize_vector (a, b, vector);
}
+/* Measure the distance between P1 in ZP0 and P2 in ZP1,
+ relative to the projection or dual projection vector.
+
+ Return the distance of P1 and P2 relative to their original
+ un-instructed positions should OPCODE be 0x49, and to their
+ instructed positions should OPCODE be 0x4A. */
+
+static sfnt_f26dot6
+sfnt_measure_distance (struct sfnt_interpreter *interpreter,
+ uint32_t p1, uint32_t p2,
+ unsigned char opcode)
+{
+ sfnt_f26dot6 p1x, p1y, p1_original_x, p1_original_y;
+ sfnt_f26dot6 p2x, p2y, p2_original_x, p2_original_y;
+
+ /* P1 is relative to ZP0 and P2 is relative to ZP1.
+ Apple's manual says this, Microsoft's does not. */
+
+ sfnt_address_zp0 (interpreter, p1, &p1x, &p1y,
+ &p1_original_x, &p1_original_y);
+ sfnt_address_zp1 (interpreter, p2, &p2x, &p2y,
+ &p2_original_x, &p2_original_y);
+
+ if (opcode == 0x49)
+ {
+ /* When measuring in the glyph zone, measure the distance using
+ the dual projection vector, relative to the ``original
+ original outlines''.
+
+ This is not written down anywhere, leading you to believe
+ that the distance is measured using the scaled outline prior
+ to instructing. */
+
+ if (interpreter->state.zp0 == 1
+ && interpreter->state.zp1 == 1)
+ return sfnt_div_fixed (DUAL_PROJECT (sfnt_sub (p1x, p2x),
+ sfnt_sub (p1y, p2y)),
+ interpreter->scale);
+
+ return DUAL_PROJECT (sfnt_sub (p1x, p2x),
+ sfnt_sub (p1y, p2y));
+ }
+
+ return PROJECT (sfnt_sub (p1x, p2x),
+ sfnt_sub (p1y, p2y));
+}
+
+/* Interpret an MSIRP instruction in INTERPRETER.
+ Take a point P, and make the distance between P in ZP1 and the
+ current position of RP0 in ZP0 equal to D.
+
+ Then, if OPCODE is equal to 0x3b, make P RP0. */
+
+static void
+sfnt_interpret_msirp (struct sfnt_interpreter *interpreter,
+ uint32_t p, sfnt_f26dot6 d, unsigned char opcode)
+{
+ sfnt_f26dot6 rp0x, rp0y;
+ sfnt_f26dot6 x, y;
+ sfnt_f26dot6 old_distance;
+
+ sfnt_address_zp0 (interpreter, interpreter->state.rp0,
+ &rp0x, &rp0y, NULL, NULL);
+ sfnt_address_zp1 (interpreter, p, &x, &y, NULL, NULL);
+
+ /* Compute the original distance. */
+ old_distance = sfnt_project_vector (interpreter,
+ sfnt_sub (x, rp0x),
+ sfnt_sub (y, rp0y));
+
+ /* Move the point. */
+ sfnt_move_zp1 (interpreter, p, 1, sfnt_sub (d, old_distance));
+
+ /* Nothing in the TrueType reference manual says directly that this
+ instruction should change rp1 and rp2. However, it says this
+ instruction is ``very similar to the MIRP[] instruction
+ except...'', and FreeType seems to do this, so do it as well. */
+
+ interpreter->state.rp1 = interpreter->state.rp0;
+ interpreter->state.rp2 = p;
+
+ if (opcode == 0x3b)
+ interpreter->state.rp0 = p;
+}
+
+/* Interpret an IP instruction in INTERPRETER. For loop times, pop a
+ single point in ZP2, and interpolate it so that its original
+ relationship to the points RP1 in ZP0 and RP2 in ZP1 as measured
+ along the dual projection vector continues to hold true. */
+
+static void
+sfnt_interpret_ip (struct sfnt_interpreter *interpreter)
+{
+ sfnt_f26dot6 rp1x, rp1y, rp1_original_x, rp1_original_y;
+ sfnt_f26dot6 rp2x, rp2y, rp2_original_x, rp2_original_y;
+ sfnt_f26dot6 range, new_range, org_distance, cur_distance;
+ sfnt_f26dot6 new_distance;
+ uint32_t p;
+ sfnt_f26dot6 x, y, original_x, original_y;
+
+ /* First load both reference points. */
+ sfnt_address_zp0 (interpreter, interpreter->state.rp1,
+ &rp1x, &rp1y, &rp1_original_x,
+ &rp1_original_y);
+ sfnt_address_zp1 (interpreter, interpreter->state.rp2,
+ &rp2x, &rp2y, &rp2_original_x,
+ &rp2_original_y);
+
+ /* Get the original distance between of RP1 and RP2 measured
+ relative to the dual projection vector. */
+ range = sfnt_dual_project_vector (interpreter,
+ sfnt_sub (rp2_original_x,
+ rp2_original_y),
+ sfnt_sub (rp1_original_x,
+ rp1_original_y));
+
+ /* Get the new distance. */
+ new_range = sfnt_dual_project_vector (interpreter,
+ sfnt_sub (rp2x, rp2y),
+ sfnt_sub (rp1x, rp1y));
+
+ while (interpreter->state.loop--)
+ {
+ p = POP ();
+
+ /* Load this point relative to zp2. */
+ sfnt_address_zp2 (interpreter, p, &x, &y, &original_x,
+ &original_y);
+
+ /* Now compute the old distance from this point to rp1. */
+ org_distance
+ = sfnt_dual_project_vector (interpreter,
+ sfnt_sub (original_x,
+ rp1_original_x),
+ sfnt_sub (original_y,
+ rp1_original_y));
+
+ /* And the current distance from this point to rp1, so
+ how much to move can be determined. */
+ cur_distance
+ = sfnt_dual_project_vector (interpreter,
+ sfnt_sub (x, rp1x),
+ sfnt_sub (y, rp1y));
+
+ /* Finally, apply the ratio of the new distance between RP1 and
+ RP2 to that of the old distance between the two reference
+ points to org_distance, making new_distance.
+
+ If both reference points occupy the same position on the dual
+ projection vector, then simply use the old distance. */
+
+ if (org_distance)
+ {
+ if (range)
+ new_distance = sfnt_multiply_divide (org_distance, new_range,
+ range);
+ else
+ new_distance = org_distance;
+ }
+ else
+ new_distance = 0;
+
+ /* And move the point along the freedom vector to reflect the
+ change in distance. */
+ sfnt_move_zp2 (interpreter, p, 1,
+ sfnt_sub (new_distance, cur_distance));
+ }
+
+ interpreter->state.loop = 1;
+}
+
/* Apply the delta specified by OPERAND to the control value table
entry at INDEX currently loaded inside INTERPRETER.
Trap if INDEX is out of bounds.
- NUMBER is the number of the specific DELTAC instruction this
- instruction is being applied on behalf of. It must be between 1
- and 3. */
+ NUMBER is the number of the specific DELTAC instruction this delta
+ is being applied on behalf of. It must be between 1 and 3. */
static void
sfnt_deltac (int number, struct sfnt_interpreter *interpreter,
sfnt_interpret_mdap (struct sfnt_interpreter *interpreter,
uint32_t p, uint32_t opcode)
{
- sfnt_f26dot6 distance, px, py;
+ sfnt_f26dot6 here, distance, px, py;
sfnt_address_zp0 (interpreter, p, &px, &py, NULL, NULL);
+ /* Measure the current distance. */
+ here = sfnt_project_vector (interpreter, px, py);
+
if (opcode == 0x7f)
{
- /* Measure distance, round, then move by distance. */
+ /* Measure distance, round, then move to the distance. */
distance = sfnt_project_vector (interpreter, px, py);
- distance = sfnt_sub (interpreter->state.round (distance,
- interpreter),
- distance);
+ distance = sfnt_round_symmetric (interpreter, distance);
+ distance = sfnt_sub (distance, here);
}
else
/* Don't move. Just touch the point. */
interpreter->state.rp1 = p;
}
+/* Apply the delta specified by OPERAND to the point P in ZP0
+ currently loaded inside INTERPRETER.
+
+ Trap if P is out of bounds.
+
+ NUMBER is the number of the specific DELTAP instruction this delta
+ is being applied on behalf of. It must be between 1 and 3. */
+
+static void
+sfnt_deltap (int number, struct sfnt_interpreter *interpreter,
+ unsigned char operand, unsigned int index)
+{
+ int ppem, delta;
+
+ /* Extract the ppem from OPERAND. The format is the same as in
+ sfnt_deltac. */
+
+ ppem = (operand >> 4) + interpreter->state.delta_base;
+
+ switch (number)
+ {
+ case 1:
+ break;
+
+ case 2:
+ ppem += 16;
+ break;
+
+ case 3:
+ ppem += 32;
+ break;
+ }
+
+ /* Don't apply the delta if the ppem size doesn't match. */
+
+ if (interpreter->ppem != ppem)
+ return;
+
+ /* Now, determine the magnitude of the movement and find the
+ delta. */
+
+ switch (operand & 0xf)
+ {
+ case 0:
+ delta = -8;
+ break;
+
+ case 1:
+ delta = -7;
+ break;
+
+ case 2:
+ delta = -6;
+ break;
+
+ case 3:
+ delta = -5;
+ break;
+
+ case 4:
+ delta = -4;
+ break;
+
+ case 5:
+ delta = -3;
+ break;
+
+ case 6:
+ delta = -2;
+ break;
+
+ case 7:
+ delta = -1;
+ break;
+
+ case 8:
+ delta = 1;
+ break;
+
+ case 9:
+ delta = 2;
+ break;
+
+ case 10:
+ delta = 3;
+ break;
+
+ case 11:
+ delta = 4;
+ break;
+
+ case 12:
+ delta = 5;
+ break;
+
+ case 13:
+ delta = 6;
+ break;
+
+ case 14:
+ delta = 7;
+ break;
+
+ case 15:
+ delta = 8;
+ break;
+
+ /* To pacify -fanalyzer. */
+ default:
+ abort ();
+ }
+
+ /* Now, scale up the delta by the step size, which is determined by
+ the delta shift. */
+ delta *= 1l << (6 - interpreter->state.delta_shift);
+
+ /* Move the point. */
+ sfnt_check_zp0 (interpreter, index);
+ sfnt_move_zp0 (interpreter, index, 1, delta);
+}
+
/* Needed by sfnt_interpret_call. */
static void sfnt_interpret_run (struct sfnt_interpreter *,
enum sfnt_interpreter_run_context);
interpreter->state.projection_vector.y);
}
+/* Project the specified vector VX and VY onto the unit vector that is
+ INTERPRETER's dual projection vector, making only the assumption
+ that the dual projection vector is a valid unit vector.
+
+ The dual projection vector is a vector that is normally the
+ projection vector, but can be set using the original unscaled
+ coordinates of two points as well.
+
+ Value is the magnitude of the projected vector. */
+
+static sfnt_f26dot6
+sfnt_dual_project_onto_any_vector (sfnt_f26dot6 vx, sfnt_f26dot6 vy,
+ struct sfnt_interpreter *interpreter)
+{
+ return sfnt_dot_fix_14 (vx, vy,
+ interpreter->state.dual_projection_vector.x,
+ interpreter->state.dual_projection_vector.y);
+}
+
/* Move N points at *X, *Y by DISTANCE along INTERPRETER's freedom
vector. Set *FLAGS where appropriate and when non-NULL.
else
gs->project = sfnt_project_onto_any_vector;
+ /* Do the same for the dual projection vector. */
+
+ if (gs->dual_projection_vector.x == 040000)
+ gs->dual_project = sfnt_project_onto_x_axis_vector;
+ else if (gs->dual_projection_vector.y == 040000)
+ gs->dual_project = sfnt_project_onto_y_axis_vector;
+ else
+ gs->dual_project = sfnt_dual_project_onto_any_vector;
+
/* Compute dot product of the freedom and projection vectors.
Handle the common case where the freedom vector is aligned
to an axis. */
{
interpreter->state.projection_vector.x = x;
interpreter->state.projection_vector.y = y;
+ interpreter->state.dual_projection_vector.x = x;
+ interpreter->state.dual_projection_vector.y = y;
sfnt_validate_gs (&interpreter->state);
}
{
point = POP ();
- sfnt_move_zp2 (interpreter, point, 1, magnitude);
sfnt_check_zp2 (interpreter, point);
+ sfnt_move_zp2 (interpreter, point, 1, magnitude);
}
/* Restore interpreter->state.loop to 1. */
break;
case 0x39: /* IP */
- NOT_IMPLEMENTED ();
+ IP ();
break;
case 0x3A: /* MSIRP */
case 0x3B: /* MSIRP */
- NOT_IMPLEMENTED ();
+ MSIRP ();
break;
- case 0x3C: /* AlignRP */
- NOT_IMPLEMENTED ();
+ case 0x3C: /* ALIGNRP */
+ ALIGNRP ();
break;
case 0x3D: /* RTDG */
case 0x3E: /* MIAP */
case 0x3F: /* MIAP */
- NOT_IMPLEMENTED ();
+ MIAP ();
break;
case 0x40: /* NPUSHB */
case 0x46: /* GC */
case 0x47: /* GC */
- NOT_IMPLEMENTED ();
+ GC ();
break;
case 0x48: /* SCFS */
- NOT_IMPLEMENTED ();
+ SCFS ();
break;
case 0x49: /* MD */
case 0x4A: /* MD */
- NOT_IMPLEMENTED ();
+ MD ();
break;
case 0x4B: /* MPPEM */
break;
case 0x5D: /* DELTAP1 */
- NOT_IMPLEMENTED ();
+ DELTAP1 ();
break;
case 0x5E: /* SDB */
break;
case 0x71: /* DELTAP2 */
+ DELTAP2 ();
+ break;
+
case 0x72: /* DELTAP3 */
- NOT_IMPLEMENTED ();
+ DELTAP3 ();
break;
case 0x73: /* DELTAC1 */
sfnt_check_sloop (struct sfnt_interpreter *interpreter,
void *arg, bool trap)
{
- if (interpreter->state.loop != 2)
+ if (interpreter->state.loop != 1)
{
- fprintf (stderr, "failed, GS->loop should be 2, not %d\n",
+ /* The trap should've restored GS->loop to 1. */
+ fprintf (stderr, "failed, GS->loop should be 1, not %d\n",
interpreter->state.loop);
return;
}
for (i = 0; i < table->num_subtables; ++i)
{
fprintf (stderr, "Found cmap table %"PRIu32": %p\n",
- subtables[i].offset, data[i]);
+ subtables[i].offset, (void *) data[i]);
if (data[i])
fprintf (stderr, " format: %"PRIu16"\n",