emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

feature/android 85dd157c38 1/2: Implement instructing compound glyphs


From: Po Lu
Subject: feature/android 85dd157c38 1/2: Implement instructing compound glyphs
Date: Thu, 9 Feb 2023 07:37:36 -0500 (EST)

branch: feature/android
commit 85dd157c38dc8e52367a3a6e574c512d2b7f7c9b
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Implement instructing compound glyphs
    
    * src/sfnt.c (sfnt_read_simple_glyph, sfnt_read_compound_glyph)
    (sfnt_read_glyph): Take size_t offsets.
    (struct sfnt_compound_glyph_context)
    (sfnt_expand_compound_glyph_context)
    (sfnt_decompose_compound_glyph): Take size_t contour offsets.
    (sfnt_decompose_glyph): Always close contour even if the first
    point isn't on-curve.
    (sfnt_build_outline_edges): Fix coding style.
    (sfnt_interpret_iup): Skip phantom points during IUP.
    (sfnt_decompose_instructed_outline): Clarify documentation.
    Always close contour even if the first point isn't on-curve.
    (struct sfnt_test_dcontext, sfnt_test_move_to, sfnt_test_line_to)
    (sfnt_test_curve_to, sfnt_transform_f26dot6, sfnt_test_get_glyph)
    (sfnt_test_free_glyph, sfnt_test_span, sfnt_test_edge_ignore)
    (sfnt_interpret_compound_glyph_2, sfnt_test_edges, main): Update
    tests.
    
    * src/sfnt.h: Export new function.
    
    * src/sfntfont.c (sfntfont_get_glyph_outline): Handle compound
    glyphs.
    (sfntfont_measure_instructed_pcm, sfntfont_measure_pcm)
    (sfntfont_draw): Update accordingly.
---
 src/sfnt.c     | 1193 +++++++++++++++++++++++++++++++++++++++++++++++---------
 src/sfnt.h     |   22 ++
 src/sfntfont.c |   46 ++-
 3 files changed, 1059 insertions(+), 202 deletions(-)

diff --git a/src/sfnt.c b/src/sfnt.c
index 1a5bac2258..a800f0ef7a 100644
--- a/src/sfnt.c
+++ b/src/sfnt.c
@@ -1590,7 +1590,7 @@ sfnt_read_glyf_table (int fd, struct sfnt_offset_subtable 
*subtable)
 static void
 sfnt_read_simple_glyph (struct sfnt_glyph *glyph,
                        struct sfnt_glyf_table *glyf,
-                       ptrdiff_t offset)
+                       size_t offset)
 {
   struct sfnt_simple_glyph *simple;
   ssize_t min_size, min_size_2;
@@ -1862,7 +1862,7 @@ sfnt_read_simple_glyph (struct sfnt_glyph *glyph,
 static void
 sfnt_read_compound_glyph (struct sfnt_glyph *glyph,
                          struct sfnt_glyf_table *glyf,
-                         ptrdiff_t offset)
+                         size_t offset)
 {
   uint16_t flags, instruction_length, words[2], words4[4];
   size_t required_bytes, num_components, i;
@@ -2105,7 +2105,7 @@ sfnt_read_glyph (sfnt_glyph glyph_code,
                 struct sfnt_loca_table_long *loca_long)
 {
   struct sfnt_glyph glyph, *memory;
-  ptrdiff_t offset, next_offset;
+  size_t offset, next_offset;
 
   /* Check the glyph code is within bounds.  */
   if (glyph_code > 65535)
@@ -2301,7 +2301,8 @@ sfnt_transform_coordinates (struct 
sfnt_compound_glyph_component *component,
 
 struct sfnt_compound_glyph_context
 {
-  /* Array of points.  */
+  /* Arrays of points.  The underlying type is actually sfnt_f26dot6
+     when instructing a compound glyph.  */
   sfnt_fixed *x_coordinates, *y_coordinates;
 
   /* Array of flags for the points.  */
@@ -2311,7 +2312,7 @@ struct sfnt_compound_glyph_context
   size_t num_points, points_size;
 
   /* Array of contour end points.  */
-  ptrdiff_t *contour_end_points;
+  size_t *contour_end_points;
 
   /* Number of elements in and the size of that array.  */
   size_t num_end_points, end_points_size;
@@ -2331,7 +2332,7 @@ sfnt_expand_compound_glyph_context (struct 
sfnt_compound_glyph_context *context,
                                    size_t number_of_points,
                                    sfnt_fixed **x_base, sfnt_fixed **y_base,
                                    unsigned char **flags_base,
-                                   ptrdiff_t **contour_base)
+                                   size_t **contour_base)
 {
   size_t size_bytes;
 
@@ -2433,12 +2434,12 @@ sfnt_decompose_compound_glyph (struct sfnt_glyph *glyph,
   bool need_free;
   struct sfnt_compound_glyph_component *component;
   sfnt_fixed x, y, xtemp, ytemp;
-  ptrdiff_t point, point2, index;
+  size_t point, point2, index;
   uint16_t last_point, number_of_contours;
   sfnt_fixed *x_base, *y_base;
-  ptrdiff_t *contour_base;
+  size_t *contour_base;
   unsigned char *flags_base;
-  ptrdiff_t base_index, contour_start;
+  size_t base_index, contour_start;
   bool defer_offsets;
 
   /* Set up the base index.  This is the index from where on point
@@ -2546,8 +2547,8 @@ sfnt_decompose_compound_glyph (struct sfnt_glyph *glyph,
              /* Get the points and use them to compute the offsets.  */
              xtemp = context->x_coordinates[point];
              ytemp = context->y_coordinates[point];
-             x = (xtemp - subglyph->simple->x_coordinates[point2]) * 65536;
-             y = (ytemp - subglyph->simple->y_coordinates[point2]) * 65536;
+             x = (xtemp - subglyph->simple->x_coordinates[point2] * 65536);
+             y = (ytemp - subglyph->simple->y_coordinates[point2] * 65536);
            }
          else
            {
@@ -2713,8 +2714,8 @@ sfnt_lerp_half (struct sfnt_point *control1, struct 
sfnt_point *control2,
    spline.
 
    If GLYPH is compound, use GET_GLYPH to obtain subglyphs.  PROC must
-   return whether or not FREE_PROC will be called with the glyph after
-   sfnt_decompose_glyph is done with it.
+   return whether or not FREE_GLYPH will be called with the glyph
+   after sfnt_decompose_glyph is done with it.
 
    All functions will be called with DCONTEXT as an argument.
 
@@ -2832,27 +2833,31 @@ sfnt_decompose_glyph (struct sfnt_glyph *glyph,
              /* Restore here after the for loop increased it.  */
              here --;
 
-             if (glyph->simple->flags[start] & 01) /* On Curve */
-               {
-                 pen.x = glyph->simple->x_coordinates[start] * 65536;
-                 pen.y = glyph->simple->y_coordinates[start] * 65536;
+             /* Previously, this would check whether or not start is
+                an ``on curve'' point, but that is not necessary.
 
-                 /* See if the last point (in this case, `here') was
-                    on the curve.  If it wasn't, then curve from
-                    there to here.  */
-                 if (!(glyph->simple->flags[here] & 01))
-                   {
-                     control1.x
-                       = glyph->simple->x_coordinates[here] * 65536;
-                     control1.y
-                       = glyph->simple->y_coordinates[here] * 65536;
-                     curve_to (control1, pen, dcontext);
-                   }
-                 else
-                   /* Otherwise, this is an ordinary line from there
-                      to here.  */
-                   line_to (pen, dcontext);
+                If a contour is not closed and the edge building
+                process skips the second to last vertex, then the
+                outline can end up with missing edges.  */
+
+             pen.x = glyph->simple->x_coordinates[start] * 65536;
+             pen.y = glyph->simple->y_coordinates[start] * 65536;
+
+             /* See if the last point (in this case, `here') was
+                on the curve.  If it wasn't, then curve from
+                there to here.  */
+             if (!(glyph->simple->flags[here] & 01))
+               {
+                 control1.x
+                   = glyph->simple->x_coordinates[here] * 65536;
+                 control1.y
+                   = glyph->simple->y_coordinates[here] * 65536;
+                 curve_to (control1, pen, dcontext);
                }
+             else
+               /* Otherwise, this is an ordinary line from there
+                  to here.  */
+               line_to (pen, dcontext);
 
              /* Restore here to where it was earlier.  */
              here++;
@@ -2968,25 +2973,28 @@ sfnt_decompose_glyph (struct sfnt_glyph *glyph,
          /* Restore here after the for loop increased it.  */
          here --;
 
-         if (context.flags[start] & 01) /* On Curve */
-           {
-             pen.x = context.x_coordinates[start];
-             pen.y = context.y_coordinates[start];
+         /* Previously, this would check whether or not start is an
+            ``on curve'' point, but that is not necessary.
 
-             /* See if the last point (in this case, `here') was
-                on the curve.  If it wasn't, then curve from
-                there to here.  */
-             if (!(context.flags[here] & 01))
-               {
-                 control1.x = context.x_coordinates[here];
-                 control1.y = context.y_coordinates[here];
-                 curve_to (control1, pen, dcontext);
-               }
-             else
-               /* Otherwise, this is an ordinary line from there
-                  to here.  */
-               line_to (pen, dcontext);
+            If a contour is not closed and the edge building process
+            skips the second to last vertex, then the outline can end
+            up with missing edges.  */
+
+         pen.x = context.x_coordinates[start];
+         pen.y = context.y_coordinates[start];
+
+         /* See if the last point (in this case, `here') was on the
+            curve.  If it wasn't, then curve from there to here.  */
+         if (!(context.flags[here] & 01))
+           {
+             control1.x = context.x_coordinates[here];
+             control1.y = context.y_coordinates[here];
+             curve_to (control1, pen, dcontext);
            }
+         else
+           /* Otherwise, this is an ordinary line from there
+              to here.  */
+           line_to (pen, dcontext);
 
          /* Restore here to where it was earlier.  */
          here++;
@@ -3672,7 +3680,8 @@ sfnt_build_outline_edges (struct sfnt_glyph_outline 
*outline,
       y = sfnt_poly_grid_ceil (bot);
 
       /* If rounding would make the edge not cover any area, skip this
-        edge.  */
+        edge. */
+
       if (y >= edges[edge].top)
        continue;
 
@@ -4125,7 +4134,7 @@ sfnt_read_hmtx_table (int fd, struct sfnt_offset_subtable 
*subtable,
    metrics could be found, else 1.
 
    If PIXEL_SIZE is -1, do not perform any scaling on the glyph
-   metrics.
+   metrics; HEAD need not be specified in that case.
 
    HMTX, HHEA, HEAD and MAXP should be the hmtx, hhea, head, and maxp
    tables of the font respectively.  */
@@ -9554,6 +9563,13 @@ sfnt_interpret_iup (struct sfnt_interpreter *interpreter,
       sfnt_interpret_iup_1 (interpreter, first_point, end,
                            opcode, mask);
       point = end + 1;
+
+      /* Skip the subsequent phantom points, which may end up
+        intermixed with contours inside a compound glyph.  */
+
+      while (point < interpreter->glyph_zone->num_points
+            && interpreter->glyph_zone->flags[point] & SFNT_POINT_PHANTOM)
+       point++;
     }
 }
 
@@ -10470,7 +10486,7 @@ sfnt_interpret_control_value_program (struct 
sfnt_interpreter *interpreter,
    comprising the spline.  Call each of those functions with 16.16
    fixed point coordinates.
 
-   All functions will be called with DCONTEXT as an argument.
+   Call all functions with DCONTEXT as an argument.
 
    The winding rule used to fill the resulting lines is described in
    chapter 2 of the TrueType reference manual, under the heading
@@ -10578,29 +10594,42 @@ sfnt_decompose_instructed_outline (struct 
sfnt_instructed_outline *outline,
          /* Restore here after the for loop increased it.  */
          here --;
 
-         if (outline->flags[start] & 01) /* On Curve */
-           {
-             pen.x = outline->x_points[start] * 1024;
-             pen.y = outline->y_points[start] * 1024;
+         /* Previously, this would check whether or not start is an
+            ``on curve'' point, but that is not necessary.
 
-             /* See if the last point (in this case, `here') was
-                on the curve.  If it wasn't, then curve from
-                there to here.  */
-             if (!(outline->flags[here] & 01))
-               {
-                 control1.x = outline->x_points[here] * 1024;
-                 control1.y = outline->y_points[here] * 1024;
-                 curve_to (control1, pen, dcontext);
-               }
-             else
-               /* Otherwise, this is an ordinary line from there
-                  to here.  */
-               line_to (pen, dcontext);
+            If a contour is not closed and the edge building process
+            skips the second to last vertex, then the outline can end
+            up with missing edges.  */
+
+         pen.x = outline->x_points[start] * 1024;
+         pen.y = outline->y_points[start] * 1024;
+
+         /* See if the last point (in this case, `here') was
+            on the curve.  If it wasn't, then curve from
+            there to here.  */
+         if (!(outline->flags[here] & 01))
+           {
+             control1.x = outline->x_points[here] * 1024;
+             control1.y = outline->y_points[here] * 1024;
+             curve_to (control1, pen, dcontext);
            }
+         else
+           /* Otherwise, this is an ordinary line from there
+              to here.  */
+           line_to (pen, dcontext);
 
          /* Restore here to where it was earlier.  */
          here++;
        }
+
+      /* here may be a phantom point when outlining a compound glyph,
+        as they can have phantom points mixed in with contours.
+
+        When that happens, skip past all the phantom points.  */
+
+      while (here < outline->num_points
+            && outline->flags[here] & SFNT_POINT_PHANTOM)
+       here++;
     }
 
   return 0;
@@ -10713,7 +10742,8 @@ sfnt_interpret_simple_glyph (struct sfnt_glyph *glyph,
                             struct sfnt_instructed_outline **value)
 {
   size_t zone_size, temp, outline_size, i;
-  struct sfnt_interpreter_zone *volatile zone;
+  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;
@@ -10806,6 +10836,9 @@ sfnt_interpret_simple_glyph (struct sfnt_glyph *glyph,
       /* Set flags.  */
       zone->flags[i] = (glyph->simple->flags[i]
                        & ~SFNT_POINT_TOUCHED_BOTH);
+
+      /* Make sure to clear the phantom points flag.  */
+      zone->flags[i] &= ~SFNT_POINT_PHANTOM;
     }
 
   /* Load phantom points.  */
@@ -10815,8 +10848,8 @@ sfnt_interpret_simple_glyph (struct sfnt_glyph *glyph,
   zone->y_current[i + 1] = phantom_point_2_x;
 
   /* Load phantom point flags.  */
-  zone->flags[i] = 0;
-  zone->flags[i + 1] = 0;
+  zone->flags[i] = SFNT_POINT_PHANTOM;
+  zone->flags[i + 1] = SFNT_POINT_PHANTOM;
 
   /* Load contour end points.  */
   for (i = 0; i < zone->num_contours; ++i)
@@ -10830,16 +10863,23 @@ sfnt_interpret_simple_glyph (struct sfnt_glyph *glyph,
   interpreter->num_instructions = glyph->simple->instruction_length;
   interpreter->glyph_zone = zone;
 
+  /* Copy zone over to this volatile variable.  */
+  preserved_zone = zone;
+
   if (setjmp (interpreter->trap))
     {
       if (zone_was_allocated)
-       xfree (zone);
+       xfree (preserved_zone);
 
       interpreter->glyph_zone = NULL;
       return interpreter->trap_reason;
     }
 
   sfnt_interpret_run (interpreter, SFNT_RUN_CONTEXT_GLYPH_PROGRAM);
+  interpreter->glyph_zone = NULL;
+
+  /* Move preserved_zone back to zone.  */
+  zone = preserved_zone;
 
   /* Now that the program has been run, build the scaled outline.  */
 
@@ -10879,142 +10919,892 @@ sfnt_interpret_simple_glyph (struct sfnt_glyph 
*glyph,
   return NULL;
 }
 
-#endif /* SFNT_ENABLE_HINTING */
-
-
-
-#ifdef TEST
+/* Apply the transform in the compound glyph component COMPONENT to
+   the array of points of length NUM_COORDINATES given as X and Y.
 
-struct sfnt_test_dcontext
-{
-  /* Context for sfnt_test_get_glyph.  */
-  struct sfnt_glyf_table *glyf;
-  struct sfnt_loca_table_short *loca_short;
-  struct sfnt_loca_table_long *loca_long;
-};
+   Treat X and Y as arrays of 26.6 fixed point values.
 
-/* Global context for test functions.  Height of glyph.  */
-static sfnt_fixed sfnt_test_max;
+   Also, apply the 26.6 fixed point offsets X_OFF and Y_OFF to each X
+   and Y coordinate.
 
-static void
-sfnt_test_move_to (struct sfnt_point point, void *dcontext)
-{
-  printf ("move_to: %g, %g\n", sfnt_coerce_fixed (point.x),
-         sfnt_coerce_fixed (point.y));
-}
+   See sfnt_decompose_compound_glyph for an explanation of why offsets
+   might be applied here, and not while reading the subglyph
+   itself.  */
 
 static void
-sfnt_test_line_to (struct sfnt_point point, void *dcontext)
+sfnt_transform_f26dot6 (struct sfnt_compound_glyph_component *component,
+                       sfnt_f26dot6 *restrict x, sfnt_f26dot6 *restrict y,
+                       size_t num_coordinates,
+                       sfnt_f26dot6 x_off, sfnt_f26dot6 y_off)
 {
-  printf ("line_to: %g, %g\n", sfnt_coerce_fixed (point.x),
-         sfnt_coerce_fixed (point.y));
-}
+  double m1, m2, m3;
+  double m4, m5, m6;
+  size_t i;
 
-static void
-sfnt_test_curve_to (struct sfnt_point control,
-                   struct sfnt_point endpoint,
-                   void *dcontext)
-{
-  printf ("curve_to: %g, %g - %g, %g\n",
-         sfnt_coerce_fixed (control.x),
-         sfnt_coerce_fixed (control.y),
-         sfnt_coerce_fixed (endpoint.x),
-         sfnt_coerce_fixed (endpoint.y));
-}
+  if (component->flags & 010) /* WE_HAVE_A_SCALE */
+    {
+      for (i = 0; i < num_coordinates; ++i)
+       {
+         x[i] *= component->u.scale / 16384.0;
+         y[i] *= component->u.scale / 16384.0;
+         x[i] += x_off;
+         y[i] += y_off;
+       }
+    }
+  else if (component->flags & 0100) /* WE_HAVE_AN_X_AND_Y_SCALE */
+    {
+      for (i = 0; i < num_coordinates; ++i)
+       {
+         x[i] *= component->u.a.xscale / 16384.0;
+         y[i] *= component->u.a.yscale / 16384.0;
+         x[i] += x_off;
+         y[i] += y_off;
+       }
+    }
+  else if (component->flags & 0200) /* WE_HAVE_A_TWO_BY_TWO */
+    {
+      /* Apply the specified affine transformation.
+        A transform looks like:
 
-static struct sfnt_glyph *
-sfnt_test_get_glyph (sfnt_glyph glyph, void *dcontext,
-                    bool *need_free)
-{
-  struct sfnt_test_dcontext *tables;
+          M1 M2 M3     X
+          M4 M5 M6   * Y
 
-  tables = dcontext;
-  *need_free = true;
+          =
 
-  return sfnt_read_glyph (glyph, tables->glyf,
-                         tables->loca_short,
-                         tables->loca_long);
-}
+          M1*X + M2*Y + M3*1 = X1
+          M4*X + M5*Y + M6*1 = Y1
 
-static void
-sfnt_test_free_glyph (struct sfnt_glyph *glyph, void *dcontext)
-{
-  sfnt_free_glyph (glyph);
-}
+        (In most transforms, there is another row at the bottom for
+         mathematical reasons.  Since Z1 is always 1.0, the row is
+         simply implied to be 0 0 1, because 0 * x + 0 * y + 1 * 1 =
+         1.0.  See the definition of matrix3x3 in image.c for some
+         more explanations about this.) */
+      m1 = component->u.b.xscale / 16384.0;
+      m2 = component->u.b.scale01 / 16384.0;
+      m3 = 0;
+      m4 = component->u.b.scale10 / 16384.0;
+      m5 = component->u.b.yscale / 16384.0;
+      m6 = 0;
 
-static void
-sfnt_test_span (struct sfnt_edge *edge, sfnt_fixed y,
-               void *dcontext)
-{
-#if 1
-  printf ("/* span at %g */\n", sfnt_coerce_fixed (y));
-  for (; edge; edge = edge->next)
-    {
-      if (y >= edge->bottom && y < edge->top)
-       printf ("ctx.fillRect (%g, %g, 1, 1); "
-               "/* %g top: %g bot: %g stepx: %g winding: %d */\n",
-               sfnt_coerce_fixed (edge->x),
-               sfnt_coerce_fixed (sfnt_test_max - y),
-               sfnt_coerce_fixed (y),
-               sfnt_coerce_fixed (edge->bottom),
-               sfnt_coerce_fixed (edge->top),
-               sfnt_coerce_fixed (edge->step_x),
-               edge->winding);
+      for (i = 0; i < num_coordinates; ++i)
+       {
+         x[i] = m1 * x[i] + m2 * y[i] + m3 * 1;
+         y[i] = m4 * x[i] + m5 * y[i] + m6 * 1;
+         x[i] += x_off;
+         y[i] += y_off;
+       }
     }
-#elif 0
-  int winding;
-  short x, dx;
+}
 
-  winding = 0;
-  x = 0;
+/* Internal helper for sfnt_interpret_compound_glyph_3.
 
-  for (; edge; edge = edge->next)
-    {
-      dx = (edge->x >> 16) - x;
-      x = edge->x >> 16;
+   Instruct the compound glyph GLYPH using INTERPRETER after all of
+   its components have been instructed.
 
-      for (; dx > 0; --dx)
-       putc (winding ? '.' : ' ', stdout);
+   Use the unscaled METRICS to compute the phantom points of this
+   glyph.
 
-      winding = !winding;
-    }
+   CONTEXT contains the points and contours of this compound glyph,
+   numbered starting from BASE_INDEX and BASE_CONTOUR respectively.
 
-  putc ('\n', stdout);
-#elif 0
-  for (; edge; edge = edge->next)
-    printf ("%g-", sfnt_coerce_fixed (edge->x));
-  puts ("");
-#endif
-}
+   Value is NULL upon success, or a description of the error upon
+   failure.  */
 
-static void
-sfnt_test_edge_ignore (struct sfnt_edge *edges, size_t num_edges,
-                      void *dcontext)
-{
+static const char *
+sfnt_interpret_compound_glyph_2 (struct sfnt_glyph *glyph,
+                                struct sfnt_interpreter *interpreter,
+                                struct sfnt_compound_glyph_context *context,
+                                size_t base_index, size_t base_contour,
+                                struct sfnt_glyph_metrics *metrics)
+{
+  size_t num_points, num_contours, i;
+  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;
+  size_t *contour_base;
+  unsigned char *flags_base;
 
-}
+  /* Figure out how many points and contours there are to
+     instruct.  */
+  num_points = context->num_points - base_index;
+  num_contours = context->num_end_points - base_contour;
 
-/* The same debugger stuff is used here.  */
-static void sfnt_setup_debugger (void);
+  /* Nothing to instruct! */
+  if (!num_points && !num_contours)
+    return NULL;
 
-/* The debugger's X display.  */
-static Display *display;
+  /* Build the zone.  First, calculate the size of the zone
+     structure.  */
 
-/* The debugger window.  */
-static Window window;
+  zone_size = 0;
+  zone_was_allocated = false;
 
-/* The GC.  */
-static GC point_gc, background_gc;
+  if (INT_MULTIPLY_WRAPV (num_points + 2,
+                         sizeof *zone->x_points * 4,
+                         &temp)
+      || INT_ADD_WRAPV (temp, zone_size, &zone_size)
+      || INT_MULTIPLY_WRAPV (num_contours,
+                            sizeof *zone->contour_end_points,
+                            &temp)
+      || INT_ADD_WRAPV (temp, zone_size, &zone_size)
+      || INT_MULTIPLY_WRAPV (num_points + 2,
+                            sizeof *zone->flags,
+                            &temp)
+      || INT_ADD_WRAPV (temp, zone_size, &zone_size)
+      || INT_ADD_WRAPV (sizeof *zone, zone_size, &zone_size))
+    return "Glyph exceeded maximum permissible size";
 
-static void
-sfnt_test_edges (struct sfnt_edge *edges, size_t num_edges)
-{
-  static sfnt_fixed y;
-  size_t i;
+  /* Don't use malloc if possible.  */
 
-  for (i = 0; i < num_edges; ++i)
+  if (zone_size <= 1024 * 16)
+    zone = alloca (zone_size);
+  else
     {
-      if (y >= edges[i].bottom && y < edges[i].top)
+      zone = xmalloc (zone_size);
+      zone_was_allocated = true;
+    }
+
+  /* Now load the zone with data.  */
+  zone->num_points = num_points + 2;
+  zone->num_contours = num_contours;
+  zone->contour_end_points = (size_t *) (zone + 1);
+  zone->x_points = (sfnt_f26dot6 *) (zone->contour_end_points
+                                    + zone->num_contours);
+  zone->x_current = zone->x_points + zone->num_points;
+  zone->y_points = zone->x_current + zone->num_points;
+  zone->y_current = zone->y_points + zone->num_points;
+  zone->flags = (unsigned char *) (zone->y_current
+                                  + zone->num_points);
+
+  /* Copy and renumber all contour end points to start from
+     base_index.  */
+
+  for (i = 0; i < zone->num_contours; ++i)
+    zone->contour_end_points[i]
+      = (context->contour_end_points[base_contour + i]
+        - base_index);
+
+  /* Now copy over x_points, x_current, y_points and y_current.  */
+
+  for (i = 0; i < num_points; ++i)
+    {
+      zone->x_current[i] = context->x_coordinates[i + base_index];
+      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];
+      zone->y_points[i] = context->y_coordinates[i + base_index];
+
+      /* Set flags.  */
+      zone->flags[i] = (context->flags[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;
+  interpreter->instructions = glyph->compound->instructions;
+  interpreter->num_instructions = glyph->compound->instruction_length;
+  interpreter->glyph_zone = zone;
+
+  /* Copy zone over to this volatile variable.  */
+  preserved_zone = zone;
+
+  if (setjmp (interpreter->trap))
+    {
+      if (zone_was_allocated)
+       xfree (preserved_zone);
+
+      interpreter->glyph_zone = NULL;
+      return interpreter->trap_reason;
+    }
+
+  sfnt_interpret_run (interpreter, SFNT_RUN_CONTEXT_GLYPH_PROGRAM);
+  interpreter->glyph_zone = NULL;
+
+  /* Move preserved_zone back to zone.  */
+  zone = preserved_zone;
+
+  /* Now copy the instructed points back, and add the two phantom
+     points to the end.  */
+
+  for (i = 0; i < num_points; ++i)
+    {
+      context->x_coordinates[base_index + i] = zone->x_current[i];
+      context->y_coordinates[base_index + i] = zone->y_current[i];
+    }
+
+  /* Grow various arrays to fit the phantom points.  */
+  rc = sfnt_expand_compound_glyph_context (context, 0, 2,
+                                          &x_base, &y_base,
+                                          &flags_base,
+                                          &contour_base);
+
+  if (rc)
+    {
+      if (zone_was_allocated)
+       xfree (zone);
+
+      return "Failed to expand arrays for phantom points";
+    }
+
+  /* Copy over the phantom points.  */
+  x_base[0] = zone->x_current[num_points - 2];
+  x_base[1] = zone->x_current[num_points - 1];
+  y_base[0] = zone->y_current[num_points - 2];
+  y_base[1] = zone->y_current[num_points - 1];
+  flags_base[0] = zone->flags[num_points - 2];
+  flags_base[1] = zone->flags[num_points - 1];
+
+  /* Free the zone if needed.  */
+  if (zone_was_allocated)
+    xfree (zone);
+
+  return NULL;
+}
+
+/* Internal helper for sfnt_interpret_compound_glyph.
+   RECURSION_COUNT is the number of times this function has called itself.
+   OFF_X and OFF_Y are the offsets to apply to the glyph outline.
+
+   METRICS are the unscaled metrics of this compound glyph.
+
+   Other arguments mean the same as they do in
+   `sfnt_interpret_compound_glyph'.  */
+
+static const char *
+sfnt_interpret_compound_glyph_1 (struct sfnt_glyph *glyph,
+                                struct sfnt_interpreter *interpreter,
+                                struct sfnt_graphics_state *state,
+                                struct sfnt_compound_glyph_context *context,
+                                sfnt_get_glyph_proc get_glyph,
+                                sfnt_free_glyph_proc free_glyph,
+                                struct sfnt_hmtx_table *hmtx,
+                                struct sfnt_hhea_table *hhea,
+                                struct sfnt_maxp_table *maxp,
+                                struct sfnt_glyph_metrics *metrics,
+                                sfnt_fixed off_x, sfnt_fixed off_y,
+                                int recursion_count,
+                                void *dcontext)
+{
+  struct sfnt_glyph *subglyph;
+  int i, j, rc;
+  const char *error;
+  bool need_free;
+  struct sfnt_compound_glyph_component *component;
+  sfnt_f26dot6 x, y, xtemp, ytemp;
+  size_t point, point2;
+  size_t last_point, number_of_contours;
+  sfnt_f26dot6 *x_base, *y_base;
+  size_t *contour_base;
+  unsigned char *flags_base;
+  size_t base_index, contour_start, base_contour;
+  bool defer_offsets;
+  struct sfnt_instructed_outline *value;
+  struct sfnt_glyph_metrics sub_metrics;
+
+  /* Set up the base index.  This is the index from where on point
+     renumbering starts.
+
+     In other words, point 0 in this glyph will be 0 + base_index,
+     point 1 will be 1 + base_index, and so on.  */
+  base_index = context->num_points;
+
+  /* And this is the index of the first contour in this glyph.  */
+  base_contour = context->num_end_points;
+
+  /* Prevent infinite loops.  */
+  if (recursion_count > 12)
+    return "Overly deep recursion in compound glyph data";
+
+  /* Don't defer offsets.  */
+  defer_offsets = false;
+
+  /* Pacify -Wmaybe-uninitialized.  */
+  point = point2 = 0;
+
+  for (j = 0; j < glyph->compound->num_components; ++j)
+    {
+      /* Look up the associated subglyph.  */
+      component = &glyph->compound->components[j];
+      subglyph = get_glyph (component->glyph_index,
+                           dcontext, &need_free);
+
+      if (!subglyph)
+       return "Failed to obtain component glyph";
+
+      /* Record the size of the point array before expansion.  This
+        will be the base to apply to all points coming from this
+        subglyph.  */
+      contour_start = context->num_points;
+
+      /* Compute the offset for the component.  */
+      if (component->flags & 02) /* ARGS_ARE_XY_VALUES */
+       {
+         /* Component offsets are X/Y values as opposed to points
+            GLYPH.  */
+
+         if (!(component->flags & 01)) /* ARG_1_AND_2_ARE_WORDS */
+           {
+             /* X and Y are signed bytes.  */
+             x = component->argument1.b * 64;
+             y = component->argument2.b * 64;
+           }
+         else
+           {
+             /* X and Y are signed words.  */
+             x = component->argument1.d * 64;
+             y = component->argument2.d * 64;
+           }
+
+         /* Now convert X and Y into device coordinates.  */
+         x = sfnt_mul_f26dot6_fixed (x, interpreter->scale);
+         y = sfnt_mul_f26dot6_fixed (y, interpreter->scale);
+
+         /* If there is some kind of scale and component offsets are
+            scaled, then apply the transform to the offset.  */
+         if (component->flags & 04000) /* SCALED_COMPONENT_OFFSET */
+           sfnt_transform_f26dot6 (component, &x, &y, 1,
+                                   0, 0);
+
+         if (component->flags & 04) /* ROUND_XY_TO_GRID */
+           {
+             x = sfnt_round_f26dot6 (x);
+             y = sfnt_round_f26dot6 (y);
+           }
+       }
+      else
+       {
+         /* The offset is determined by matching a point location in
+            a preceeding component with a point location in the
+            current component.  The index of the point in the
+            previous component can be determined by adding
+            component->argument1.a or component->argument1.c to
+            point.  argument2 contains the index of the point in the
+            current component.  */
+
+         if (!(component->flags & 01)) /* ARG_1_AND_2_ARE_WORDS */
+           {
+             point = base_index + component->argument1.a;
+             point2 = component->argument2.a;
+           }
+         else
+           {
+             point = base_index + component->argument1.c;
+             point2 = component->argument2.c;
+           }
+
+         /* Now, check that the anchor point specified lies inside
+            the glyph.  */
+
+         if (point >= contour_start)
+           {
+             if (need_free)
+               free_glyph (subglyph, dcontext);
+
+             return "Invalid anchor point";
+           }
+
+         if (!subglyph->compound)
+           {
+             if (point2 >= subglyph->simple->number_of_points)
+               {
+                 if (need_free)
+                   free_glyph (subglyph, dcontext);
+
+                 return "Invalid anchored point";
+               }
+
+             /* Get the points and use them to compute the offsets.  */
+             xtemp = context->x_coordinates[point];
+             ytemp = context->y_coordinates[point];
+             x = (xtemp - subglyph->simple->x_coordinates[point2] * 64);
+             y = (ytemp - subglyph->simple->y_coordinates[point2] * 64);
+           }
+         else
+           {
+             /* First, set offsets to 0, because it is not yet
+                possible to determine the position of the anchor
+                point in the child.  */
+             x = 0;
+             y = 0;
+
+             /* Set a flag which indicates that offsets must be
+                resolved from the child glyph after it is loaded, but
+                before it is incorporated into the parent glyph.  */
+             defer_offsets = true;
+           }
+       }
+
+      /* Obtain the glyph metrics.  If doing so fails, then cancel
+        decomposition.  */
+
+      if (sfnt_lookup_glyph_metrics (component->glyph_index,
+                                    -1, &sub_metrics,
+                                    hmtx, hhea, NULL, maxp))
+       {
+         if (need_free)
+           free_glyph (subglyph, dcontext);
+
+         return "Failed to obtain component metrics";
+       }
+
+      if (subglyph->simple)
+       {
+         /* Simple subglyph.  Copy over the points and contours,
+            then transform and instruct them.
+
+            Skip this step for glyphs without contours.  */
+
+         if (subglyph->number_of_contours)
+           {
+             /* Now instruct the simple glyph, and copy it over,
+                including the two phantom points at the end.  */
+             interpreter->state = *state;
+             error = sfnt_interpret_simple_glyph (subglyph, interpreter,
+                                                  &sub_metrics, &value);
+
+             /* Cancel instructing if an error occurs.  */
+
+             if (error)
+               {
+                 if (need_free)
+                   free_glyph (subglyph, dcontext);
+
+                 return error;
+               }
+
+             /* 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;
+             number_of_contours = value->num_contours;
+
+             /* Grow various arrays.  */
+             rc = sfnt_expand_compound_glyph_context (context,
+                                                      /* Number of
+                                                         new contours
+                                                         required.  */
+                                                      number_of_contours,
+                                                      /* Number of new
+                                                         points
+                                                         required.  */
+                                                      last_point,
+                                                      &x_base,
+                                                      &y_base,
+                                                      &flags_base,
+                                                      &contour_base);
+             if (rc)
+               {
+                 xfree (value);
+
+                 if (need_free)
+                   free_glyph (subglyph, dcontext);
+
+                 return "Failed to grow arrays";
+               }
+
+             /* Copy the values in VALUE into the context and free
+                VALUE, including phantom points.  */
+
+             for (i = 0; i < last_point; ++i)
+               {
+                 x_base[i] = value->x_points[i] + off_x + x;
+                 y_base[i] = value->y_points[i] + off_y + y;
+                 flags_base[i] = value->flags[i];
+               }
+
+             /* Copy over the contours.  */
+             for (i = 0; i < number_of_contours; ++i)
+               contour_base[i] = (contour_start
+                                  + value->contour_end_points[i]);
+
+             xfree (value);
+
+             /* Apply the transform to the points.  */
+             sfnt_transform_f26dot6 (component, x_base, y_base,
+                                     last_point, 0, 0);
+           }
+       }
+      else
+       {
+         /* Compound subglyph.  Decompose and instruct the glyph
+            recursively, and then apply the transform.  */
+
+         error = sfnt_interpret_compound_glyph_1 (subglyph, interpreter,
+                                                  state,
+                                                  context, get_glyph,
+                                                  free_glyph, hmtx, hhea,
+                                                  maxp, &sub_metrics,
+                                                  off_x + x, off_y + y,
+                                                  recursion_count + 1,
+                                                  dcontext);
+
+         if (error)
+           {
+             if (need_free)
+               free_glyph (subglyph, dcontext);
+
+             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.
+
+            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;
+
+         if (defer_offsets)
+           {
+             /* Renumber the non renumbered point2 to point into the
+                decomposed component.  */
+             point2 += contour_start;
+
+             /* Next, check that the non-renumbered point being
+                anchored lies inside the glyph data that was
+                decomposed.  */
+
+             if (point2 >= context->num_points)
+               {
+                 if (need_free)
+                   free_glyph (subglyph, dcontext);
+
+                 return "Invalid point2";
+               }
+
+             /* Get the points and use them to compute the
+                offsets.  */
+
+             xtemp = context->x_coordinates[point];
+             ytemp = context->y_coordinates[point];
+             x = (xtemp - context->x_coordinates[point2]);
+             y = (ytemp - context->y_coordinates[point2]);
+           }
+
+         sfnt_transform_f26dot6 (component,
+                                 context->x_coordinates + contour_start,
+                                 context->y_coordinates + contour_start,
+                                 contour_start - context->num_points,
+                                 x, y);
+       }
+
+      /* Finally, free the subglyph.  */
+      if (need_free)
+       free_glyph (subglyph, dcontext);
+    }
+
+  /* Run the program for the entire compound glyph, if any.  */
+
+  if (glyph->compound->instruction_length)
+    {
+      interpreter->state = *state;
+      error = sfnt_interpret_compound_glyph_2 (glyph, interpreter,
+                                              context, base_index,
+                                              base_contour,
+                                              metrics);
+    }
+
+  return error;
+}
+
+/* Interpret the compound glyph GLYPH using the specified INTERPRETER.
+   Load each component of the compound glyph GLYPH.  CONTEXT should be
+   a reference to a `struct sfnt_compound_glyph_context' that is on
+   the stack.
+
+   Use glyph metrics specified in the HMTX, HHEA and MAXP tables, and
+   the unscaled metrics for GLYPH specified in METRICS.
+
+   If the component is a simple glyph, scale and instruct it
+   immediately.
+
+   If the component is a compound glyph, then load it recursively
+   until a predetermined recursion level is exceeded.
+
+   Set INTERPRETER's state to STATE prior to instructing each
+   component.
+
+   Load component glyphs using GET_GLYPH, which should return whether
+   or not FREE_GLYPH should be called with the glyph that was loaded.
+   Call both functions with DCONTEXT as an argument.
+
+   Finally, append the resulting contours, run any compound glyph
+   program, and return the instructed outline in *VALUE.
+
+   Value is NULL upon success, and the type of error upon failure.  */
+
+TEST_STATIC const char *
+sfnt_interpret_compound_glyph (struct sfnt_glyph *glyph,
+                              struct sfnt_interpreter *interpreter,
+                              struct sfnt_graphics_state *state,
+                              sfnt_get_glyph_proc get_glyph,
+                              sfnt_free_glyph_proc free_glyph,
+                              struct sfnt_hmtx_table *hmtx,
+                              struct sfnt_hhea_table *hhea,
+                              struct sfnt_maxp_table *maxp,
+                              struct sfnt_glyph_metrics *metrics,
+                              void *dcontext,
+                              struct sfnt_instructed_outline **value)
+{
+  struct sfnt_compound_glyph_context context;
+  const char *error;
+  struct sfnt_instructed_outline *outline;
+  size_t outline_size, temp;
+
+  /* Set up the glyph decomposition context.  */
+  memset (&context, 0, sizeof context);
+
+  /* Now start decomposing the glyph.  */
+  error = sfnt_interpret_compound_glyph_1 (glyph, interpreter,
+                                          state, &context,
+                                          get_glyph, free_glyph,
+                                          hmtx, hhea, maxp,
+                                          metrics, 0, 0, 0,
+                                          dcontext);
+
+  /* If an error occurs, free the data in the context and return.  */
+
+  if (error)
+    {
+      xfree (context.x_coordinates);
+      xfree (context.y_coordinates);
+      xfree (context.flags);
+      xfree (context.contour_end_points);
+      return error;
+    }
+
+  /* Copy the compound glyph data into an instructed outline.  */
+  outline_size = sizeof (*outline);
+
+  if (INT_MULTIPLY_WRAPV (context.num_end_points,
+                         sizeof *outline->contour_end_points,
+                         &temp)
+      || INT_ADD_WRAPV (outline_size, temp, &outline_size)
+      || INT_MULTIPLY_WRAPV (context.num_points,
+                            sizeof *outline->x_points * 2,
+                            &temp)
+      || INT_ADD_WRAPV (outline_size, temp, &outline_size)
+      || INT_ADD_WRAPV (context.num_points, outline_size,
+                       &outline_size))
+    {
+      xfree (context.x_coordinates);
+      xfree (context.y_coordinates);
+      xfree (context.flags);
+      xfree (context.contour_end_points);
+      return "Glyph exceeds maximum permissible size";
+    }
+
+  /* Allocate the outline.  */
+  outline = xmalloc (outline_size);
+  outline->num_points = context.num_points;
+  outline->num_contours = context.num_end_points;
+  outline->contour_end_points = (size_t *) (outline + 1);
+  outline->x_points = (sfnt_f26dot6 *) (outline->contour_end_points
+                                       + outline->num_contours);
+  outline->y_points = outline->x_points + outline->num_points;
+  outline->flags = (unsigned char *) (outline->y_points
+                                     + outline->num_points);
+
+  /* Copy over the contour endpoints, points, and flags.  */
+  memcpy (outline->contour_end_points, context.contour_end_points,
+         outline->num_contours * sizeof *outline->contour_end_points);
+  memcpy (outline->x_points, context.x_coordinates,
+         outline->num_points * sizeof *outline->x_points);
+  memcpy (outline->y_points, context.y_coordinates,
+         outline->num_points * sizeof *outline->y_points);
+  memcpy (outline->flags, context.flags, context.num_points);
+
+  /* Free the context data.  */
+  xfree (context.x_coordinates);
+  xfree (context.y_coordinates);
+  xfree (context.flags);
+  xfree (context.contour_end_points);
+
+  *value = outline;
+  return NULL;
+}
+
+#endif /* SFNT_ENABLE_HINTING */
+
+
+
+#ifdef TEST
+
+struct sfnt_test_dcontext
+{
+  /* Context for sfnt_test_get_glyph.  */
+  struct sfnt_glyf_table *glyf;
+  struct sfnt_loca_table_short *loca_short;
+  struct sfnt_loca_table_long *loca_long;
+};
+
+/* Global context for test functions.  Height of glyph.  */
+static sfnt_fixed sfnt_test_max;
+
+static void
+sfnt_test_move_to (struct sfnt_point point, void *dcontext)
+{
+  printf ("move_to: %g, %g\n", sfnt_coerce_fixed (point.x),
+         sfnt_coerce_fixed (point.y));
+}
+
+static void
+sfnt_test_line_to (struct sfnt_point point, void *dcontext)
+{
+  printf ("line_to: %g, %g\n", sfnt_coerce_fixed (point.x),
+         sfnt_coerce_fixed (point.y));
+}
+
+static void
+sfnt_test_curve_to (struct sfnt_point control,
+                   struct sfnt_point endpoint,
+                   void *dcontext)
+{
+  printf ("curve_to: %g, %g - %g, %g\n",
+         sfnt_coerce_fixed (control.x),
+         sfnt_coerce_fixed (control.y),
+         sfnt_coerce_fixed (endpoint.x),
+         sfnt_coerce_fixed (endpoint.y));
+}
+
+static struct sfnt_glyph *
+sfnt_test_get_glyph (sfnt_glyph glyph, void *dcontext,
+                    bool *need_free)
+{
+  struct sfnt_test_dcontext *tables;
+
+  tables = dcontext;
+  *need_free = true;
+
+  return sfnt_read_glyph (glyph, tables->glyf,
+                         tables->loca_short,
+                         tables->loca_long);
+}
+
+static void
+sfnt_test_free_glyph (struct sfnt_glyph *glyph, void *dcontext)
+{
+  sfnt_free_glyph (glyph);
+}
+
+static void
+sfnt_test_span (struct sfnt_edge *edge, sfnt_fixed y,
+               void *dcontext)
+{
+#if 1
+  printf ("/* span at %g */\n", sfnt_coerce_fixed (y));
+  for (; edge; edge = edge->next)
+    {
+      if (y >= edge->bottom && y < edge->top)
+       printf ("ctx.fillRect (%g, %g, 1, 1); "
+               "/* %g top: %g bot: %g stepx: %g winding: %d */\n",
+               sfnt_coerce_fixed (edge->x),
+               sfnt_coerce_fixed (sfnt_test_max - y),
+               sfnt_coerce_fixed (y),
+               sfnt_coerce_fixed (edge->top),
+               sfnt_coerce_fixed (edge->bottom),
+               sfnt_coerce_fixed (edge->step_x),
+               edge->winding);
+      else
+       printf ("STRIPPED BAD SPAN!!! %g %g %"PRIi32
+               " %"PRIi32" (winding: %d)\n",
+               sfnt_coerce_fixed (edge->top),
+               sfnt_coerce_fixed (edge->bottom),
+               edge->top, y, edge->winding);
+    }
+#elif 0
+  int winding;
+  short x, dx;
+
+  winding = 0;
+  x = 0;
+
+  for (; edge; edge = edge->next)
+    {
+      dx = (edge->x >> 16) - x;
+      x = edge->x >> 16;
+
+      for (; dx > 0; --dx)
+       putc (winding ? '.' : ' ', stdout);
+
+      winding = !winding;
+    }
+
+  putc ('\n', stdout);
+#elif 0
+  for (; edge; edge = edge->next)
+    printf ("%g-", sfnt_coerce_fixed (edge->x));
+  puts ("");
+#endif
+}
+
+static void
+sfnt_test_edge_ignore (struct sfnt_edge *edges, size_t num_edges,
+                      void *dcontext)
+{
+
+}
+
+/* The same debugger stuff is used here.  */
+static void sfnt_setup_debugger (void);
+
+/* The debugger's X display.  */
+static Display *display;
+
+/* The debugger window.  */
+static Window window;
+
+/* The GC.  */
+static GC point_gc, background_gc;
+
+static void
+sfnt_test_edges (struct sfnt_edge *edges, size_t num_edges)
+{
+  static sfnt_fixed y;
+  size_t i;
+
+  for (i = 0; i < num_edges; ++i)
+    {
+      if (y >= edges[i].bottom && y < edges[i].top)
        {
          XDrawPoint (display, window, point_gc,
                      edges[i].x / 65536, 100 - (y / 65536));
@@ -14743,8 +15533,8 @@ main (int argc, char **argv)
                 data[i]->format);
     }
 
-#define FANCY_PPEM 12
-#define EASY_PPEM  12
+#define FANCY_PPEM 40
+#define EASY_PPEM  40
 
   interpreter = NULL;
   head = sfnt_read_head_table (fd, font);
@@ -15159,17 +15949,35 @@ main (int argc, char **argv)
                          interpreter->pop_hook = sfnt_pop_hook;
                        }
 
-                     if (glyph->simple
-                         && !sfnt_lookup_glyph_metrics (code, -1,
-                                                        &metrics,
-                                                        hmtx, hhea,
-                                                        head, maxp))
+                     if (!sfnt_lookup_glyph_metrics (code, -1,
+                                                     &metrics,
+                                                     hmtx, hhea,
+                                                     head, maxp))
                        {
                          printf ("interpreting glyph\n");
                          interpreter->state = state;
                          clock_gettime (CLOCK_THREAD_CPUTIME_ID, &start);
-                         trap = sfnt_interpret_simple_glyph (glyph, 
interpreter,
-                                                             &metrics, &value);
+                         if (glyph->simple)
+                           trap
+                             = sfnt_interpret_simple_glyph (glyph,
+                                                            interpreter,
+                                                            &metrics,
+                                                            &value);
+                         else
+#define GG sfnt_test_get_glyph
+#define FG sfnt_test_free_glyph
+                           trap
+                             = sfnt_interpret_compound_glyph (glyph,
+                                                              interpreter,
+                                                              &state,
+                                                              GG, FG,
+                                                              hmtx, hhea,
+                                                              maxp,
+                                                              &metrics,
+                                                              &dcontext,
+                                                              &value);
+#undef GG
+#undef FG
                          clock_gettime (CLOCK_THREAD_CPUTIME_ID, &end);
                          sub3 = timespec_sub (end, start);
 
@@ -15197,7 +16005,8 @@ main (int argc, char **argv)
                                }
                            }
 
-                         fprintf (stderr, "execution time: %lld sec %ld 
nsec\n",
+                         fprintf (stderr, "execution time: %lld sec %ld nse"
+                                  "c\n",
                                   (long long) sub3.tv_sec, sub3.tv_nsec);
                        }
 
diff --git a/src/sfnt.h b/src/sfnt.h
index 0845cb5be5..40c77ee123 100644
--- a/src/sfnt.h
+++ b/src/sfnt.h
@@ -1135,6 +1135,11 @@ struct sfnt_interpreter_zone
 
 enum
   {
+    /* Bits 1 stands for X_SHORT_VECTOR on disk and in the tables, but
+       this representation is not useful in memory.  Inside an
+       instructed glyph, this bit is repurposed to mean that the
+       corresponding point is a phantom point.  */
+    SFNT_POINT_PHANTOM = (1 << 1),
     /* Bits 7 and 6 of a glyph point's flags is reserved.  This scaler
        uses it to mean that the point has been touched in one axis or
        another.  */
@@ -1478,6 +1483,23 @@ extern const char *sfnt_interpret_simple_glyph 
(PROTOTYPE);
 
 #undef PROTOTYPE
 
+#define PROTOTYPE                              \
+  struct sfnt_glyph *,                         \
+  struct sfnt_interpreter *,                   \
+  struct sfnt_graphics_state *,                        \
+  sfnt_get_glyph_proc,                         \
+  sfnt_free_glyph_proc,                                \
+  struct sfnt_hmtx_table *,                    \
+  struct sfnt_hhea_table *,                    \
+  struct sfnt_maxp_table *,                    \
+  struct sfnt_glyph_metrics *,                 \
+  void *,                                      \
+  struct sfnt_instructed_outline **
+
+extern const char *sfnt_interpret_compound_glyph (PROTOTYPE);
+
+#undef PROTOTYPE
+
 #endif /* TEST */
 
 
diff --git a/src/sfntfont.c b/src/sfntfont.c
index 9ab76a3082..cc084c7930 100644
--- a/src/sfntfont.c
+++ b/src/sfntfont.c
@@ -1456,6 +1456,9 @@ sfntfont_dereference_outline (struct sfnt_glyph_outline 
*outline)
    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
+   compound glyphs.
+
    If INTERPRETER is non-NULL, then possibly use the unscaled glyph
    metrics in METRICS and the interpreter STATE to instruct the glyph.
 
@@ -1469,6 +1472,9 @@ sfntfont_get_glyph_outline (sfnt_glyph glyph_code,
                            int pixel_size, int *cache_size,
                            struct sfnt_glyf_table *glyf,
                            struct sfnt_head_table *head,
+                           struct sfnt_hmtx_table *hmtx,
+                           struct sfnt_hhea_table *hhea,
+                           struct sfnt_maxp_table *maxp,
                            struct sfnt_loca_table_short *loca_short,
                            struct sfnt_loca_table_long *loca_long,
                            struct sfnt_interpreter *interpreter,
@@ -1517,14 +1523,32 @@ sfntfont_get_glyph_outline (sfnt_glyph glyph_code,
 
   outline = NULL;
 
-  if (interpreter && glyph->simple)
+  dcontext.loca_long = loca_long;
+  dcontext.loca_short = loca_short;
+  dcontext.glyf = glyf;
+
+  if (interpreter)
     {
-      /* Restore the interpreter state from the snapshot taken after
-        loading the preprogram.  */
-      interpreter->state = *state;
+      if (glyph->simple)
+       {
+         /* Restore the interpreter state from the snapshot taken
+            after loading the preprogram.  */
+         interpreter->state = *state;
 
-      error = sfnt_interpret_simple_glyph (glyph, interpreter,
-                                          metrics, &value);
+         error = sfnt_interpret_simple_glyph (glyph, interpreter,
+                                              metrics, &value);
+       }
+      else
+       /* Restoring the interpreter state is done by
+          sfnt_interpret_compound_glyph; all that must be done here
+          is to give the graphics state to that function.  */
+       error = sfnt_interpret_compound_glyph (glyph, interpreter,
+                                              state,
+                                              sfntfont_get_glyph,
+                                              sfntfont_free_glyph,
+                                              hmtx, hhea, maxp,
+                                              metrics, &dcontext,
+                                              &value);
 
       if (!error)
        {
@@ -1533,10 +1557,6 @@ sfntfont_get_glyph_outline (sfnt_glyph glyph_code,
        }
     }
 
-  dcontext.loca_long = loca_long;
-  dcontext.loca_short = loca_short;
-  dcontext.glyf = glyf;
-
   if (!outline)
     outline = sfnt_build_glyph_outline (glyph, head, pixel_size,
                                        sfntfont_get_glyph,
@@ -2272,6 +2292,8 @@ sfntfont_measure_instructed_pcm (struct sfnt_font_info 
*font, sfnt_glyph glyph,
                                        font->font.pixel_size,
                                        &font->outline_cache_size,
                                        font->glyf, font->head,
+                                       font->hmtx, font->hhea,
+                                       font->maxp,
                                        font->loca_short,
                                        font->loca_long,
                                        font->interpreter, &metrics,
@@ -2321,6 +2343,8 @@ sfntfont_measure_pcm (struct sfnt_font_info *font, 
sfnt_glyph glyph,
                                        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, NULL,
                                        NULL);
@@ -2469,6 +2493,8 @@ sfntfont_draw (struct glyph_string *s, int from, int to,
                                            font->pixel_size,
                                            &info->outline_cache_size,
                                            info->glyf, info->head,
+                                           info->hmtx, info->hhea,
+                                           info->maxp,
                                            info->loca_short,
                                            info->loca_long,
                                            info->interpreter,



reply via email to

[Prev in Thread] Current Thread [Next in Thread]