[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
feature/android 87cdbbeb8a 1/3: Update Android port
From: |
Po Lu |
Subject: |
feature/android 87cdbbeb8a 1/3: Update Android port |
Date: |
Sun, 5 Feb 2023 08:15:58 -0500 (EST) |
branch: feature/android
commit 87cdbbeb8a229926277578a9f5f958438e8679b6
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>
Update Android port
* src/sfnt.c (struct sfnt_graphics_state):
(LOOPCALL):
(DELTAC3):
(PROJECT):
(SHPIX):
(sfnt_save_projection_vector):
(sfnt_check_zp0):
(sfnt_dual_project_vector):
(sfnt_interpret_scfs):
(sfnt_round_symmetric):
(sfnt_interpret_miap):
(sfnt_interpret_alignrp_1):
(sfnt_interpret_alignrp):
(sfnt_measure_distance):
(sfnt_interpret_msirp):
(sfnt_interpret_ip):
(sfnt_interpret_mdap):
(sfnt_deltap):
(sfnt_dual_project_onto_any_vector):
(sfnt_validate_gs):
(sfnt_set_projection_vector):
(sfnt_interpret_shp):
(sfnt_interpret_run):
(sfnt_check_sloop):
(main): Check in more WIP font code.
---
src/sfnt.c | 693 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 666 insertions(+), 27 deletions(-)
diff --git a/src/sfnt.c b/src/sfnt.c
index 0d87ed36da..6d060fde7d 100644
--- a/src/sfnt.c
+++ b/src/sfnt.c
@@ -1,4 +1,4 @@
-/* sfnt format font support for GNU Emacs.
+/* TrueType format font support for GNU Emacs.
Copyright (C) 2023 Free Software Foundation, Inc.
@@ -106,7 +106,21 @@ xfree (void *ptr)
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. */
@@ -4915,6 +4929,12 @@ struct sfnt_graphics_state
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. */
@@ -5776,6 +5796,7 @@ sfnt_interpret_trap (struct sfnt_interpreter *interpreter,
\
id = POP (); \
n = POP (); \
+ def = NULL; /* Pacify -fanalyzer. */ \
\
if (n > 65535) \
TRAP ("invalid LOOPCALL count"); \
@@ -6444,7 +6465,7 @@ sfnt_interpret_trap (struct sfnt_interpreter *interpreter,
-/* 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. */
@@ -6503,6 +6524,54 @@ sfnt_interpret_trap (struct sfnt_interpreter
*interpreter,
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; \
+ }
+
/* Anachronistic angle instructions. */
@@ -6521,6 +6590,12 @@ sfnt_interpret_trap (struct sfnt_interpreter
*interpreter,
/* 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, \
@@ -6738,6 +6813,85 @@ sfnt_interpret_trap (struct sfnt_interpreter
*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); \
+ }
+
#define NOT_IMPLEMENTED() \
@@ -6787,14 +6941,15 @@ sfnt_interpret_utp (struct sfnt_interpreter
*interpreter,
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);
}
@@ -7034,6 +7189,22 @@ sfnt_check_zp2 (struct sfnt_interpreter *interpreter,
uint32_t point)
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.
@@ -7175,6 +7346,147 @@ sfnt_project_vector (struct sfnt_interpreter
*interpreter,
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.
@@ -7468,14 +7780,184 @@ sfnt_line_to_vector (struct sfnt_interpreter
*interpreter,
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,
@@ -7612,17 +8094,19 @@ static void
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. */
@@ -7634,6 +8118,127 @@ sfnt_interpret_mdap (struct sfnt_interpreter
*interpreter,
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);
@@ -8242,6 +8847,25 @@ sfnt_project_onto_any_vector (sfnt_f26dot6 vx,
sfnt_f26dot6 vy,
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.
@@ -8390,6 +9014,15 @@ sfnt_validate_gs (struct sfnt_graphics_state *gs)
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. */
@@ -8444,6 +9077,8 @@ sfnt_set_projection_vector (struct sfnt_interpreter
*interpreter,
{
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);
}
@@ -8574,8 +9209,8 @@ sfnt_interpret_shp (struct sfnt_interpreter *interpreter,
{
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. */
@@ -9041,16 +9676,16 @@ sfnt_interpret_run (struct sfnt_interpreter
*interpreter,
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 */
@@ -9059,7 +9694,7 @@ sfnt_interpret_run (struct sfnt_interpreter *interpreter,
case 0x3E: /* MIAP */
case 0x3F: /* MIAP */
- NOT_IMPLEMENTED ();
+ MIAP ();
break;
case 0x40: /* NPUSHB */
@@ -9088,16 +9723,16 @@ sfnt_interpret_run (struct sfnt_interpreter
*interpreter,
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 */
@@ -9173,7 +9808,7 @@ sfnt_interpret_run (struct sfnt_interpreter *interpreter,
break;
case 0x5D: /* DELTAP1 */
- NOT_IMPLEMENTED ();
+ DELTAP1 ();
break;
case 0x5E: /* SDB */
@@ -9235,8 +9870,11 @@ sfnt_interpret_run (struct sfnt_interpreter *interpreter,
break;
case 0x71: /* DELTAP2 */
+ DELTAP2 ();
+ break;
+
case 0x72: /* DELTAP3 */
- NOT_IMPLEMENTED ();
+ DELTAP3 ();
break;
case 0x73: /* DELTAC1 */
@@ -10108,9 +10746,10 @@ static void
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;
}
@@ -12764,7 +13403,7 @@ main (int argc, char **argv)
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",