emacs-diffs
[Top][All Lists]
Advanced

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

feature/android 1a70941c8e 1/7: Improve text display on Android port


From: Po Lu
Subject: feature/android 1a70941c8e 1/7: Improve text display on Android port
Date: Wed, 8 Feb 2023 10:42:54 -0500 (EST)

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

    Improve text display on Android port
    
    * src/sfnt.c (sfnt_build_glyph_outline): Clear
    build_outline_context.
    (sfnt_poly_coverage): Extend coverage map.
    (sfnt_prepare_raster): Always floor coordinates, since the
    increase in coverage makes this hack unnecessary.
    (sfnt_build_outline_edges): Likewise.
    (sfnt_compare_edges): Remove function.
    (sfnt_edge_sort): New function.  Since edges are already
    partially sorted, and there are not many, insertion sort
    suffices.
    (sfnt_poly_edges): Use sfnt_edge_sort.
    (sfnt_fill_span): Stop rounding x0 and x1 to the grid, and make
    coverage computation static.
    (sfnt_lookup_glyph_metrics): Fix return code for unscaled
    metrics.
    (sfnt_scale_metrics): New function.
    (SFNT_ENABLE_HINTING): Remove define.
    (struct sfnt_cvt_table, struct sfnt_fpgm_table)
    (struct sfnt_prep_table): Move to sfnt.h.
    (sfnt_read_cvt_table):
    (sfnt_read_fpgm_table, sfnt_read_prep_table): Make TEST_STATIC.
    (struct sfnt_unit_vector, struct sfnt_interpreter_definition)
    (struct sfnt_interpreter_zone, struct sfnt_graphics_state):
    (struct sfnt_interpreter): Move to sfnt.h.
    (sfnt_make_interpreter): Make TEST_STATIC.
    (POP, PUSH, DELTAP1, DELTAP2, DELTAP3): When TEST, define to
    regular push and pop.
    (sfnt_deltac):
    (sfnt_deltap): Fix order of arguments.
    (IUP_SINGLE_PAIR): Fix interpolation loop wraparound.
    (sfnt_interpret_font_program):
    (sfnt_interpret_control_value_program): Make TEST_STATIC.
    (struct sfnt_instructed_outline): Move to sfnt.h.
    (sfnt_build_instructed_outline): Make TEST_STATIC.
    (sfnt_interpret_simple_glyph):
    (sfnt_x_raster):
    (sfnt_test_raster):
    (all_tests):
    (sfnt_verbose):
    (main): Improve test code.
    
    * src/sfnt.h (SFNT_ENABLE_HINTING, struct sfnt_cvt_table)
    (struct sfnt_fpgm_table, struct sfnt_prep_table)
    (struct sfnt_unit_vector, struct sfnt_interpreter_definition)
    (struct sfnt_interpreter_zone, struct sfnt_graphics_state)
    (struct sfnt_interpreter, struct sfnt_instructed_outline)
    (PROTOTYPE): New definitions.
    * src/sfntfont-android.c (sfntfont_android_put_glyphs): Make
    coordinate generation more straightforward.
    * src/sfntfont.c (sfntfont_get_glyph_outline): New arguments
    INTERPRETER and METRICS.
    (struct sfnt_font_info): New tables.
    (sfntfont_setup_interpreter): New function.
    (sfntfont_open): Avoid memory leak.  Set up interpreter.
    (sfntfont_measure_instructed_pcm): New function.
    (sfntfont_measure_pcm): Delegate to measure_instructed_pcm where
    appropriate.
    (sfntfont_close): Free new tables.
    (sfntfont_draw): Scale metrics properly.
---
 src/sfnt.c             | 913 ++++++++++++++++++++-----------------------------
 src/sfnt.h             | 483 +++++++++++++++++++++++++-
 src/sfntfont-android.c |   4 +-
 src/sfntfont.c         | 238 ++++++++++++-
 4 files changed, 1078 insertions(+), 560 deletions(-)

diff --git a/src/sfnt.c b/src/sfnt.c
index ab21c41b8a..8dc189919b 100644
--- a/src/sfnt.c
+++ b/src/sfnt.c
@@ -3459,6 +3459,8 @@ sfnt_build_glyph_outline (struct sfnt_glyph *glyph,
   struct sfnt_glyph_outline *outline;
   int rc;
 
+  memset (&build_outline_context, 0, sizeof build_outline_context);
+
   /* Allocate the outline now with enough for 44 words at the end.  */
   outline = xmalloc (sizeof *outline + 40 * sizeof (*outline->outline));
   outline->outline_size = 40;
@@ -3521,12 +3523,16 @@ sfnt_build_glyph_outline (struct sfnt_glyph *glyph,
 /* Coverage table.  This is a four dimensional array indiced by the Y,
    then X axis fractional, shifted down to 2 bits.  */
 
-static unsigned char sfnt_poly_coverage[4][4] =
+static const unsigned char sfnt_poly_coverage[8][9] =
   {
-    { 0x10, 0x10, 0x10, 0x10 },
-    { 0x10, 0x10, 0x10, 0x10 },
-    { 0x0f, 0x10, 0x10, 0x10 },
-    { 0x10, 0x10, 0x10, 0x10 },
+    { 0, 4, 8, 12, 16, 20, 24, 28, 32, },
+    { 0, 4, 8, 12, 16, 20, 24, 28, 32, },
+    { 0, 4, 8, 12, 16, 20, 24, 28, 32, },
+    { 0, 3, 7, 11, 15, 19, 23, 27, 31, },
+    { 0, 4, 8, 12, 16, 20, 24, 28, 32, },
+    { 0, 4, 8, 12, 16, 20, 24, 28, 32, },
+    { 0, 4, 8, 12, 16, 20, 24, 28, 32, },
+    { 0, 4, 8, 12, 16, 20, 24, 28, 32, },
   };
 
 /* Return the nearest coordinate on the sample grid no less than
@@ -3566,7 +3572,7 @@ sfnt_prepare_raster (struct sfnt_raster *raster,
                     + (SFNT_POLY_ALIGNMENT - 1))
                    & ~(SFNT_POLY_ALIGNMENT - 1));
 
-  raster->offx = sfnt_round_fixed (outline->xmin) >> 16;
+  raster->offx = sfnt_floor_fixed (outline->xmin) >> 16;
   raster->offy = sfnt_floor_fixed (outline->ymin) >> 16;
 }
 
@@ -3602,10 +3608,9 @@ sfnt_build_outline_edges (struct sfnt_glyph_outline 
*outline,
   edge = 0;
 
   /* ymin and xmin must be the same as the offset used to set offy and
-     offx in rasters.  However, xmin is not floored; otherwise, glyphs
-     like ``e'' look bad at certain ppem.  */
+     offx in rasters.  */
   ymin = sfnt_floor_fixed (outline->ymin);
-  xmin = outline->xmin;
+  xmin = sfnt_floor_fixed (outline->xmin);
 
   for (i = 0; i < outline->outline_used; ++i)
     {
@@ -3694,15 +3699,31 @@ sfnt_build_outline_edges (struct sfnt_glyph_outline 
*outline,
     edge_proc (edges, edge, dcontext);
 }
 
-static int
-sfnt_compare_edges (const void *a, const void *b)
+/* Sort an array of SIZE edges to increase by bottom Y position, in
+   preparation for building spans.
+
+   Insertion sort is used because there are usually not very many
+   edges, and anything larger would bloat up the code.  */
+
+static void
+sfnt_edge_sort (struct sfnt_edge *edges, size_t size)
 {
-  const struct sfnt_edge *first, *second;
+  ssize_t i, j;
+  struct sfnt_edge edge;
 
-  first = a;
-  second = b;
+  for (i = 1; i < size; ++i)
+    {
+      edge = edges[i];
+      j = i - 1;
+
+      while (j >= 0 && (edges[j].bottom > edge.bottom))
+       {
+         edges[j + 1] = edges[j];
+         j--;
+       }
 
-  return (int) (first->bottom - second->bottom);
+      edges[j + 1] = edge;
+    }
 }
 
 /* Draw EDGES, an unsorted array of polygon edges of size SIZE.  For
@@ -3751,7 +3772,7 @@ sfnt_poly_edges (struct sfnt_edge *edges, size_t size,
 
   /* Sort edges to ascend by Y-order.  Once again, remember: cartesian
      coordinates.  */
-  qsort (edges, size, sizeof *edges, sfnt_compare_edges);
+  sfnt_edge_sort (edges, size);
 
   /* Step down line by line.  Find active edges.  */
 
@@ -3837,10 +3858,10 @@ sfnt_fill_span (struct sfnt_raster *raster, sfnt_fixed 
y,
                sfnt_fixed x0, sfnt_fixed x1)
 {
   unsigned char *start;
-  unsigned char *coverage;
+  const unsigned char *coverage;
   sfnt_fixed left, right, end;
   unsigned short w, a;
-  int row, col;
+  int row;
 
   /* Clip bounds to pixmap.  */
   if (x0 < 0)
@@ -3863,16 +3884,10 @@ sfnt_fill_span (struct sfnt_raster *raster, sfnt_fixed 
y,
     return;
 
   /* Set start, then start filling according to coverage.  left and
-     right are now 16.2.  */
-  left = sfnt_poly_grid_ceil (x0) >> (16 - SFNT_POLY_SHIFT);
-  right = sfnt_poly_grid_ceil (x1) >> (16 - SFNT_POLY_SHIFT);
-#if 7 > __GNUC__
+     right are now .3.  */
+  left = x0 >> (16 - SFNT_POLY_SHIFT);
+  right = x1 >> (16 - SFNT_POLY_SHIFT);
   start = raster->cells + row * raster->stride;
-#else
-  start = __builtin_assume_aligned ((raster->cells
-                                    + row * raster->stride),
-                                   SFNT_POLY_ALIGNMENT);
-#endif
   start += left >> SFNT_POLY_SHIFT;
 
   w = 0;
@@ -3880,25 +3895,25 @@ sfnt_fill_span (struct sfnt_raster *raster, sfnt_fixed 
y,
   /* Compute coverage for first pixel, then poly.  */
   if (left & SFNT_POLY_MASK)
     {
-      /* Note that col is an index into the columns of the coverage
-        map, unlike row which indexes the raster.  */
-      col = 0;
-
-      /* Precompute this to allow for better optimizations.  */
-      end = ((left + SFNT_POLY_SAMPLE - 1) & ~SFNT_POLY_MASK);
+      /* Compute the coverage for the first pixel, and move left past
+        it.  The coverage is a number from 1 to 7 describing how
+        ``partially'' covered this pixel is.  */
 
-      while (left < right && left < end)
-       left++, w += coverage[col++];
+      end = (left + SFNT_POLY_SAMPLE - 1) & ~SFNT_POLY_MASK;
+      end = MIN (right, end);
 
+      w = coverage[end - left];
       a = *start + w;
+
+      /* Now move left past.  */
+      left = end;
+
       *start++ = sfnt_saturate_short (a);
     }
 
   /* Clear coverage info for first pixel.  Compute coverage for center
      pixels.  */
-  w = 0;
-  for (col = 0; col < SFNT_POLY_SAMPLE; ++col)
-    w += coverage[col];
+  w = coverage[SFNT_POLY_MASK];
 
   /* Fill pixels between left and right.  */
   while (left + SFNT_POLY_MASK < right)
@@ -3912,10 +3927,7 @@ sfnt_fill_span (struct sfnt_raster *raster, sfnt_fixed y,
      part.)  */
   if (right & SFNT_POLY_MASK)
     {
-      w = 0;
-      col = 0;
-      while (left < right)
-       left++, w += coverage[col++];
+      w = coverage[right - left];
       a = *start + w;
       *start = sfnt_saturate_short (a);
     }
@@ -4155,20 +4167,34 @@ sfnt_lookup_glyph_metrics (sfnt_glyph glyph, int 
pixel_size,
       /* Return unscaled metrics in this case.  */
       metrics->lbearing = lbearing;
       metrics->advance = advance;
-      return 1;
+      return 0;
     }
 
   /* Now scale lbearing and advance up to the pixel size.  */
   factor = sfnt_div_fixed (pixel_size, head->units_per_em);
 
   /* Save them.  */
-  metrics->lbearing = sfnt_mul_fixed (lbearing << 16, factor);
-  metrics->advance = sfnt_mul_fixed (advance << 16, factor);
+  metrics->lbearing = sfnt_mul_fixed (lbearing * 65536, factor);
+  metrics->advance = sfnt_mul_fixed (advance * 65536, factor);
 
   /* All done.  */
   return 0;
 }
 
+/* Scale the specified glyph metrics by FACTOR.
+   Set METRICS->lbearing and METRICS->advance to their current
+   values times factor.  */
+
+MAYBE_UNUSED TEST_STATIC void
+sfnt_scale_metrics (struct sfnt_glyph_metrics *metrics,
+                   sfnt_fixed factor)
+{
+  metrics->lbearing
+    = sfnt_mul_fixed (metrics->lbearing * 65536, factor);
+  metrics->advance
+    = sfnt_mul_fixed (metrics->advance * 65536, factor);
+}
+
 
 
 /* Font style parsing.  */
@@ -4602,10 +4628,6 @@ sfnt_read_ttc_header (int fd)
 
 
 
-#ifdef TEST
-#define SFNT_ENABLE_HINTING
-#endif
-
 #ifdef SFNT_ENABLE_HINTING
 
 /* TrueType hinting support.
@@ -4649,37 +4671,6 @@ sfnt_read_ttc_header (int fd)
    through one of three ``zone pointer'' registers, and are accessible
    only when a program is being run on behalf of a glyph.  */
 
-/* Structure definitions for tables used by the TrueType
-   interpreter.  */
-
-struct sfnt_cvt_table
-{
-  /* Number of elements in the control value table.  */
-  size_t num_elements;
-
-  /* Pointer to elements in the control value table.  */
-  sfnt_fword *values;
-};
-
-struct sfnt_fpgm_table
-{
-  /* Number of instructions in the font program table.  */
-  size_t num_instructions;
-
-  /* Pointer to elements in the font program table.  */
-  unsigned char *instructions;
-};
-
-struct sfnt_prep_table
-{
-  /* Number of instructions in the control value program (pre-program)
-     table.  */
-  size_t num_instructions;
-
-  /* Pointer to elements in the preprogram table.  */
-  unsigned char *instructions;
-};
-
 
 
 /* Functions for reading tables used by the TrueType interpreter.  */
@@ -4689,7 +4680,7 @@ struct sfnt_prep_table
    in the control value table.  Return NULL upon failure, else the cvt
    table.  */
 
-static struct sfnt_cvt_table *
+TEST_STATIC struct sfnt_cvt_table *
 sfnt_read_cvt_table (int fd, struct sfnt_offset_subtable *subtable)
 {
   struct sfnt_table_directory *directory;
@@ -4740,7 +4731,7 @@ sfnt_read_cvt_table (int fd, struct sfnt_offset_subtable 
*subtable)
    directory specified as SUBTABLE.  Value is NULL upon failure, else
    the fpgm table.  */
 
-static struct sfnt_fpgm_table *
+TEST_STATIC struct sfnt_fpgm_table *
 sfnt_read_fpgm_table (int fd, struct sfnt_offset_subtable *subtable)
 {
   struct sfnt_table_directory *directory;
@@ -4788,7 +4779,7 @@ sfnt_read_fpgm_table (int fd, struct sfnt_offset_subtable 
*subtable)
    directory specified as SUBTABLE.  Value is NULL upon failure, else
    the prep table.  */
 
-static struct sfnt_prep_table *
+TEST_STATIC struct sfnt_prep_table *
 sfnt_read_prep_table (int fd, struct sfnt_offset_subtable *subtable)
 {
   struct sfnt_table_directory *directory;
@@ -4836,344 +4827,6 @@ sfnt_read_prep_table (int fd, struct 
sfnt_offset_subtable *subtable)
 
 /* Interpreter execution environment.  */
 
-/* 26.6 fixed point type used within the interpreter.  */
-typedef int32_t sfnt_f26dot6;
-
-/* 2.14 fixed point type used to represent versors of unit
-   vectors.  */
-typedef int16_t sfnt_f2dot14;
-
-/* 18.14 fixed point type used to calculate rounding details.  */
-typedef int32_t sfnt_f18dot14;
-
-struct sfnt_unit_vector
-{
-  /* X and Y versors of the 2d unit vector.  */
-  sfnt_f2dot14 x, y;
-};
-
-struct sfnt_interpreter_definition
-{
-  /* The opcode of this instruction or function.  */
-  uint16_t opcode;
-
-  /* The number of instructions.  */
-  uint16_t instruction_count;
-
-  /* Pointer to instructions belonging to the definition.  This
-     pointer points directly into the control value or font program.
-     Make sure both programs are kept around as long as the
-     interpreter continues to exist.  */
-  unsigned char *instructions;
-};
-
-/* This structure represents a ``struct sfnt_glyph'' that has been
-   scaled to a given pixel size.
-
-   It can either contain a simple glyph, or a decomposed compound
-   glyph; instructions are interpreted for both simple glyphs, simple
-   glyph components inside a compound glyph, and compound glyphs as a
-   whole.
-
-   In addition to the glyph data itself, it also records various
-   information for the instruction interpretation process:
-
-     - ``current'' point coordinates, which have been modified
-       by the instructing process.
-
-     - two phantom points at the origin and the advance of the
-       glyph.  */
-
-struct sfnt_interpreter_zone
-{
-  /* The number of points in this zone, including the two phantom
-     points at the end.  */
-  size_t num_points;
-
-  /* The number of contours in this zone.  */
-  size_t num_contours;
-
-  /* The end points of each contour.  */
-  size_t *contour_end_points;
-
-  /* Pointer to the X axis point data.  */
-  sfnt_f26dot6 *restrict x_points;
-
-  /* Pointer to the X axis current point data.  */
-  sfnt_f26dot6 *restrict x_current;
-
-  /* Pointer to the Y axis point data.  */
-  sfnt_f26dot6 *restrict y_points;
-
-  /* Pointer to the Y axis current point data.  */
-  sfnt_f26dot6 *restrict y_current;
-
-  /* Pointer to the flags associated with this data.  */
-  unsigned char *flags;
-};
-
-enum
-  {
-    /* 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.  */
-    SFNT_POINT_TOUCHED_X = (1 << 7),
-    SFNT_POINT_TOUCHED_Y = (1 << 6),
-    SFNT_POINT_TOUCHED_BOTH = (SFNT_POINT_TOUCHED_X
-                              | SFNT_POINT_TOUCHED_Y),
-  };
-
-/* This is needed because `round' below needs an interpreter
-   argument.  */
-struct sfnt_interpreter;
-
-struct sfnt_graphics_state
-{
-  /* Pointer to the function used for rounding.  This function is
-     asymmetric, so -0.5 rounds up to 0, not -1.  It is up to the
-     caller to handle negative values.
-
-     Value is undefined unless sfnt_validate_gs has been called, and
-     the second argument may be used to provide detailed rounding
-     information (``super rounding state''.)  */
-  sfnt_f26dot6 (*round) (sfnt_f26dot6, struct sfnt_interpreter *);
-
-  /* Pointer to the function used to project euclidean vectors onto
-     the projection vector.  Value is the magnitude of the projected
-     vector.  */
-  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.  */
-  void (*move) (sfnt_f26dot6 *restrict,
-               sfnt_f26dot6 *restrict, size_t,
-               struct sfnt_interpreter *,
-               sfnt_f26dot6, unsigned char *);
-
-  /* Dot product between the freedom and the projection vectors.  */
-  sfnt_f2dot14 vector_dot_product;
-
-  /* Controls whether the sign of control value table entries will be
-     changed to match the sign of the actual distance measurement with
-     which it is compared.  Setting auto flip to TRUE makes it
-     possible to control distances measured with or against the
-     projection vector with a single control value table entry. When
-     auto flip is set to FALSE, distances must be measured with the
-     projection vector.  */
-  bool auto_flip;
-
-  /* Limits the regularizing effects of control value table entries to
-     cases where the difference between the table value and the
-     measurement taken from the original outline is sufficiently
-     small.  */
-  sfnt_f26dot6 cvt_cut_in;
-
-  /* Establishes the base value used to calculate the range of point
-     sizes to which a given DELTAC[] or DELTAP[] instruction will
-     apply.  The formulas given below are used to calculate the range
-     of the various DELTA instructions.
-
-     DELTAC1 DELTAP1 (delta_base) through (delta_base + 15)
-     DELTAC2 DELTAP2 (delta_base + 16) through (delta_base + 31)
-     DELTAC3 DELTAP3 (delta_base + 32) through (delta_base + 47)
-
-     Please keep this documentation in sync with the TrueType
-     reference manual.  */
-  unsigned short delta_base;
-
-  /* Determines the range of movement and smallest magnitude of
-     movement (the step) in a DELTAC[] or DELTAP[] instruction.
-     Changing the value of the delta shift makes it possible to trade
-     off fine control of point movement for range of movement.  A low
-     delta shift favors range of movement over fine control.  A high
-     delta shift favors fine control over range of movement.  The step
-     has the value 1/2 to the power delta shift.  The range of
-     movement is calculated by taking the number of steps allowed (16)
-     and multiplying it by the step.
-
-     The legal range for delta shift is zero through six.  Negative
-     values are illegal.  */
-  unsigned short delta_shift;
-
-  /* A second projection vector set to a line defined by the original
-     outline location of two points.  The dual projection vector is
-     used when it is necessary to measure distances from the scaled
-     outline before any instructions were executed.  */
-  struct sfnt_unit_vector dual_projection_vector;
-
-  /* A unit vector that establishes an axis along which points can
-     move.  */
-  struct sfnt_unit_vector freedom_vector;
-
-  /* Makes it possible to turn off instructions under some
-     circumstances.  When flag 1 is set, changes to the graphics state
-     made in the control value program will be ignored.  When flag is
-     1, grid fitting instructions will be ignored.  */
-  unsigned char instruct_control;
-
-  /* Makes it possible to repeat certain instructions a designated
-     number of times.  The default value of one assures that unless
-     the value of loop is altered, these instructions will execute one
-     time.  */
-  unsigned short loop;
-
-  /* Establishes the smallest possible value to which a distance will
-     be rounded.  */
-  sfnt_f26dot6 minimum_distance;
-
-  /* A unit vector whose direction establishes an axis along which
-     distances are measured.  */
-  struct sfnt_unit_vector projection_vector;
-
-  /* Determines the manner in which values are rounded. Can be set to
-     a number of predefined states or to a customized state with the
-     SROUND or S45ROUND instructions.  */
-  int round_state;
-
-  /* Reference points.  These reference point numbers, which together
-     with a zone designation, specify a point in either the glyph zone
-     or the twilight zone.  */
-  uint16_t rp0, rp1, rp2;
-
-  /* Flags which determine whether the interpreter will activate
-     dropout control for the current glyph.  */
-  int scan_control;
-
-  /* The distance difference below which the interpreter will replace
-     a CVT distance or an actual distance in favor of the single width
-     value.  */
-  sfnt_f26dot6 sw_cut_in;
-
-  /* The value used in place of the control value table distance or
-     the actual distance value when the difference between that
-     distance and the single width value is less than the single width
-     cut-in.  */
-  sfnt_f26dot6 single_width_value;
-
-  /* Zone pointers, which reference a zone.  */
-  int zp0, zp1, zp2;
-};
-
-struct sfnt_interpreter
-{
-  /* The number of elements in the stack.  */
-  uint16_t max_stack_elements;
-
-  /* The number of instructions in INSTRUCTIONS.  */
-  uint16_t num_instructions;
-
-  /* Size of the storage area.  */
-  uint16_t storage_size;
-
-  /* Size of the function definition area.  */
-  uint16_t function_defs_size;
-
-  /* Size of the instruction definition area.  */
-  uint16_t instruction_defs_size;
-
-  /* Size of the twilight zone.  */
-  uint16_t twilight_zone_size;
-
-  /* The instruction pointer.  This points to the instruction
-     currently being executed.  */
-  int IP;
-
-  /* The current scale.  */
-  sfnt_fixed scale;
-
-  /* The current ppem and point size.  */
-  int ppem, point_size;
-
-  /* The execution stack.  This has at most max_stack_elements
-     elements.  */
-  uint32_t *stack;
-
-  /* Pointer past the top of the stack.  */
-  uint32_t *SP;
-
-  /* The size of the control value table.  */
-  size_t cvt_size;
-
-  /* Pointer to instructions currently being executed.  */
-  unsigned char *restrict instructions;
-
-  /* The twilight zone.  May not be NULL.  */
-  sfnt_f26dot6 *restrict twilight_x, *restrict twilight_y;
-
-  /* The original X positions of points in the twilight zone.  */
-  sfnt_f26dot6 *restrict twilight_original_x;
-
-  /* The original Y positions of points in the twilight zone.
-
-     Apple does not directly say whether or not points in the twilight
-     zone can have their original positions changed.  But this is
-     implied by ``create points in the twilight zone''.  */
-  sfnt_f26dot6 *restrict twilight_original_y;
-
-  /* The scaled outlines being manipulated.  May be NULL.  */
-  struct sfnt_interpreter_zone *glyph_zone;
-
-  /* The glyph advance width.  Value is undefined unless GLYPH_ZONE is
-     set.  */
-  sfnt_f26dot6 advance_width;
-
-  /* The storage area.  */
-  uint32_t *storage;
-
-  /* Control value table values.  */
-  sfnt_f26dot6 *cvt;
-
-  /* Function definitions.  */
-  struct sfnt_interpreter_definition *function_defs;
-
-  /* Instruction definitions.  */
-  struct sfnt_interpreter_definition *instruction_defs;
-
-  /* Interpreter registers.  */
-  struct sfnt_graphics_state state;
-
-  /* Detailed rounding state used when state.round_state indicates
-     that fine grained rounding should be used.
-
-     PERIOD says how often a round value occurs, for numbers
-     increasing from PHASE to infinity.
-
-     THRESHOLD says when to round a value between two increasing
-     periods towards the larger period.  */
-  sfnt_f26dot6 period, phase, threshold;
-
-  /* The depth of any ongoing calls.  */
-  int call_depth;
-
-  /* Jump buffer for traps.  */
-  jmp_buf trap;
-
-  /* What was the trap.  */
-  const char *trap_reason;
-
-#ifdef TEST
-  /* If non-NULL, function called before each instruction is
-     executed.  */
-  void (*run_hook) (struct sfnt_interpreter *);
-
-  /* If non-NULL, function called before each stack element is
-     pushed.  */
-  void (*push_hook) (struct sfnt_interpreter *, uint32_t);
-
-  /* If non-NULL, function called before each stack element is
-     popped.  */
-  void (*pop_hook) (struct sfnt_interpreter *, uint32_t);
-#endif
-};
-
 /* Divide the specified two 26.6 fixed point numbers X and Y.
    Return the result.  */
 
@@ -5409,7 +5062,7 @@ sfnt_init_graphics_state (struct sfnt_graphics_state 
*state)
    Value is the interpreter, with all state initialized to default
    values, or NULL upon failure.  */
 
-static struct sfnt_interpreter *
+TEST_STATIC struct sfnt_interpreter *
 sfnt_make_interpreter (struct sfnt_maxp_table *maxp,
                       struct sfnt_cvt_table *cvt,
                       struct sfnt_head_table *head,
@@ -5661,13 +5314,7 @@ sfnt_interpret_trap (struct sfnt_interpreter 
*interpreter,
                                _value);        \
        _value;}))
 
-#define POP_UNCHECKED()                                \
-  ({uint32_t _value;                           \
-    _value = *(--interpreter->SP);             \
-    if (interpreter->pop_hook)                 \
-      interpreter->pop_hook (interpreter,      \
-                            _value);           \
-    _value;})
+#define POP_UNCHECKED()        POP ()
 
 #endif
 
@@ -5710,15 +5357,7 @@ sfnt_interpret_trap (struct sfnt_interpreter 
*interpreter,
     interpreter->SP++;                         \
   }
 
-#define PUSH_UNCHECKED(value)                  \
-  {                                            \
-    if (interpreter->push_hook)                        \
-      interpreter->push_hook (interpreter,     \
-                             value);           \
-                                               \
-    *interpreter->SP = value;                  \
-    interpreter->SP++;                         \
-  }
+#define PUSH_UNCHECKED(value) PUSH (value)
 
 #endif
 
@@ -6722,8 +6361,8 @@ sfnt_interpret_trap (struct sfnt_interpreter *interpreter,
     if (!n)                                    \
       break;                                   \
                                                \
-    argn = POP ();                             \
     pn = POP ();                               \
+    argn = POP ();                             \
     sfnt_deltap (1, interpreter, argn, pn);    \
     n--;                                       \
     goto deltap1_start;                                \
@@ -6739,8 +6378,8 @@ sfnt_interpret_trap (struct sfnt_interpreter *interpreter,
     if (!n)                                    \
       break;                                   \
                                                \
-    argn = POP ();                             \
     pn = POP ();                               \
+    argn = POP ();                             \
     sfnt_deltap (2, interpreter, argn, pn);    \
     n--;                                       \
     goto deltap2_start;                                \
@@ -6756,8 +6395,8 @@ sfnt_interpret_trap (struct sfnt_interpreter *interpreter,
     if (!n)                                    \
       break;                                   \
                                                \
-    argn = POP ();                             \
     pn = POP ();                               \
+    argn = POP ();                             \
     sfnt_deltap (3, interpreter, argn, pn);    \
     n--;                                       \
     goto deltap3_start;                                \
@@ -8394,7 +8033,7 @@ sfnt_interpret_ip (struct sfnt_interpreter *interpreter)
 
 static void
 sfnt_deltac (int number, struct sfnt_interpreter *interpreter,
-            unsigned char operand, unsigned int index)
+            unsigned int index, unsigned char operand)
 {
   int ppem, delta;
 
@@ -8565,6 +8204,8 @@ sfnt_deltap (int number, struct sfnt_interpreter 
*interpreter,
 {
   int ppem, delta;
 
+  return;
+
   /* Extract the ppem from OPERAND.  The format is the same as in
      sfnt_deltac.  */
 
@@ -9699,26 +9340,31 @@ sfnt_interpret_shp (struct sfnt_interpreter 
*interpreter,
                                                                        \
   i = touch_start + 1;                                                 \
                                                                        \
-  for (; i <= end; ++i)                                                        
\
+  while (i != touch_end)                                               \
     {                                                                  \
-      if (i > end)                                                     \
-       i = start;                                                      \
-                                                                       \
       /* Movement is always relative to the original position of       \
         the point.  */                                                 \
       position = load_original (i);                                    \
                                                                        \
       /* If i is in between touch_start and touch_end...  */           \
       if (position >= original_min_pos                                 \
-         && position <= original_max_pos                               \
-         && original_min_pos != original_max_pos)                      \
+         && position <= original_max_pos)                              \
        {                                                               \
-         /* ... preserve the ratio of i between min_pos and            \
-            max_pos...  */                                             \
-         ratio = sfnt_div_fixed (sfnt_sub (position,                   \
-                                           original_min_pos) * 1024,   \
-                                 sfnt_sub (original_max_pos,           \
-                                           original_min_pos) * 1024);  \
+         /* Handle the degenerate case where original_min_pos and      \
+            original_max_pos have not changed by placing the point in  \
+            the middle.  */                                            \
+         if (original_min_pos == original_max_pos)                     \
+           ratio = 077777;                                             \
+         else                                                          \
+           /* ... preserve the ratio of i between min_pos and          \
+              max_pos...  */                                           \
+           ratio = sfnt_div_fixed ((sfnt_sub (position,                \
+                                              original_min_pos)        \
+                                    * 1024),                           \
+                                   (sfnt_sub (original_max_pos,        \
+                                              original_min_pos)        \
+                                    * 1024));                          \
+                                                                       \
          delta = sfnt_sub (max_pos, min_pos);                          \
          delta = sfnt_mul_fixed (ratio, delta);                        \
          store_point (i, sfnt_add (min_pos, delta));                   \
@@ -9735,6 +9381,9 @@ sfnt_interpret_shp (struct sfnt_interpreter *interpreter,
                                                                        \
          store_point (i, sfnt_add (position, delta));                  \
        }                                                               \
+                                                                       \
+      if (++i > end)                                                   \
+       i = start;                                                      \
     }                                                                  \
 
 /* Interpolate untouched points in the contour between and including
@@ -10711,9 +10360,12 @@ sfnt_interpret_run (struct sfnt_interpreter 
*interpreter,
    undefined.
 
    Value is NULL upon success, else it is a string describing the
-   reason for failure.  */
+   reason for failure.
 
-static const char *
+   The caller must save the graphics state after interpreting the font
+   program and restore it prior to instructing each glyph.  */
+
+TEST_STATIC const char *
 sfnt_interpret_font_program (struct sfnt_interpreter *interpreter,
                             struct sfnt_fpgm_table *fpgm)
 {
@@ -10735,9 +10387,13 @@ sfnt_interpret_font_program (struct sfnt_interpreter 
*interpreter,
 
    Return NULL and the graphics state after the execution of the
    program in *STATE, or a string describing the reason for a failure
-   to interpret the program.  */
+   to interpret the program.
 
-static const char *
+   The caller must save the graphics state after interpreting the
+   control value program and restore it prior to instructing each
+   glyph.  */
+
+TEST_STATIC const char *
 sfnt_interpret_control_value_program (struct sfnt_interpreter *interpreter,
                                      struct sfnt_prep_table *prep,
                                      struct sfnt_graphics_state *state)
@@ -10776,30 +10432,6 @@ sfnt_interpret_control_value_program (struct 
sfnt_interpreter *interpreter,
    scaling separately.  It might be nice to fix that in the
    future.  */
 
-/* Structure describing a single scaled and fitted outline.  */
-
-struct sfnt_instructed_outline
-{
-  /* The number of points in this contour, including the two phantom
-     points at the end.  */
-  size_t num_points;
-
-  /* The number of contours in this outline.  */
-  size_t num_contours;
-
-  /* The end points of each contour.  */
-  size_t *contour_end_points;
-
-  /* The points of each contour, with two additional phantom points at
-     the end.  */
-  sfnt_f26dot6 *restrict x_points, *restrict y_points;
-
-  /* The flags of each point.  */
-  unsigned char *flags;
-};
-
-
-
 /* Instructed glyph outline decomposition.  This is separate from
    sfnt_decompose_glyph because this file should be able to be built
    with instructions disabled.  */
@@ -10958,12 +10590,14 @@ sfnt_decompose_instructed_outline (struct 
sfnt_instructed_outline *outline,
 
    This function is not reentrant.  */
 
-static struct sfnt_glyph_outline *
+TEST_STATIC struct sfnt_glyph_outline *
 sfnt_build_instructed_outline (struct sfnt_instructed_outline *instructed)
 {
   struct sfnt_glyph_outline *outline;
   int rc;
 
+  memset (&build_outline_context, 0, sizeof build_outline_context);
+
   /* Allocate the outline now with enough for 44 words at the end.  */
   outline = xmalloc (sizeof *outline + 40 * sizeof (*outline->outline));
   outline->outline_size = 40;
@@ -11047,7 +10681,7 @@ sfnt_compute_phantom_points (struct sfnt_glyph *glyph,
    Upon success, return NULL and the resulting points and contours in
    *VALUE.  Else, value is the reason interpretation failed.  */
 
-static const char *
+TEST_STATIC const char *
 sfnt_interpret_simple_glyph (struct sfnt_glyph *glyph,
                             struct sfnt_interpreter *interpreter,
                             struct sfnt_glyph_metrics *metrics,
@@ -11445,12 +11079,16 @@ sfnt_test_edge (struct sfnt_edge *edges, size_t 
num_edges,
 }
 
 static void
-sfnt_x_raster (struct sfnt_raster *raster)
+sfnt_x_raster (struct sfnt_raster **rasters,
+              int *advances,
+              int nrasters,
+              struct sfnt_hhea_table *hhea,
+              sfnt_fixed scale)
 {
   Display *display;
   Window window;
-  Pixmap pixmap;
-  Picture glyph, drawable, solid;
+  Pixmap *pixmaps;
+  Picture *glyphs, drawable, solid;
   int event_base, error_base;
   int major, minor, *depths, count;
   XRenderPictFormat *format, *glyph_format;
@@ -11460,7 +11098,11 @@ sfnt_x_raster (struct sfnt_raster *raster)
   XGCValues gcvalues;
   XEvent event;
   XRenderColor white, black;
-  int i;
+  int i, ascent, origin, x, y;
+  Font font;
+
+  if (!nrasters)
+    exit (0);
 
   display = XOpenDisplay (NULL);
 
@@ -11475,7 +11117,7 @@ sfnt_x_raster (struct sfnt_raster *raster)
     exit (0);
 
   window = XCreateSimpleWindow (display, DefaultRootWindow (display),
-                               0, 0, 40, 40, 0, 0,
+                               0, 0, 100, 150, 0, 0,
                                WhitePixel (display,
                                            DefaultScreen (display)));
   XSelectInput (display, window, ExposureMask);
@@ -11501,37 +11143,57 @@ sfnt_x_raster (struct sfnt_raster *raster)
  depth_found:
 
   XFree (depths);
-  pixmap = XCreatePixmap (display, DefaultRootWindow (display),
-                         raster->width, raster->height, 8);
-
-  /* Upload the raster.  */
-  image.width = raster->width;
-  image.height = raster->height;
-  image.xoffset = 0;
-  image.format = ZPixmap;
-  image.data = (char *) raster->cells;
-  image.byte_order = MSBFirst;
-  image.bitmap_unit = 8;
-  image.bitmap_bit_order = LSBFirst;
-  image.bitmap_pad = SFNT_POLY_ALIGNMENT * 8;
-  image.depth = 8;
-  image.bytes_per_line = raster->stride;
-  image.bits_per_pixel = 8;
-  image.red_mask = 0;
-  image.green_mask = 0;
-  image.blue_mask = 0;
-
-  if (!XInitImage (&image))
-    abort ();
+  pixmaps = alloca (sizeof *pixmaps * nrasters);
+  glyphs = alloca (sizeof *glyphs * nrasters);
+  gc = None;
+
+  for (i = 0; i < nrasters; ++i)
+    {
+      pixmaps[i] = XCreatePixmap (display, DefaultRootWindow (display),
+                                 rasters[i]->width, rasters[i]->height, 8);
+      if (!gc)
+       gc = XCreateGC (display, pixmaps[i], 0, &gcvalues);
+
+      /* Upload the raster.  */
+      image.width = rasters[i]->width;
+      image.height = rasters[i]->height;
+      image.xoffset = 0;
+      image.format = ZPixmap;
+      image.data = (char *) rasters[i]->cells;
+      image.byte_order = MSBFirst;
+      image.bitmap_unit = 8;
+      image.bitmap_bit_order = LSBFirst;
+      image.bitmap_pad = SFNT_POLY_ALIGNMENT * 8;
+      image.depth = 8;
+      image.bytes_per_line = rasters[i]->stride;
+      image.bits_per_pixel = 8;
+      image.red_mask = 0;
+      image.green_mask = 0;
+      image.blue_mask = 0;
+
+      if (!XInitImage (&image))
+       abort ();
+
+      XPutImage (display, pixmaps[i], gc, &image,
+                0, 0, 0, 0, image.width, image.height);
+
+      glyphs[i] = XRenderCreatePicture (display, pixmaps[i],
+                                       glyph_format, 0, NULL);
+    }
 
-  gc = XCreateGC (display, pixmap, 0, &gcvalues);
-  XPutImage (display, pixmap, gc, &image,
-            0, 0, 0, 0, image.width, image.height);
+  XFreeGC (display, gc);
+
+  font = XLoadFont (display, "6x13");
+
+  if (!font)
+    exit (1);
+
+  gcvalues.font = font;
+  gcvalues.foreground = BlackPixel (display, DefaultScreen (display));
+  gc = XCreateGC (display, window, GCForeground | GCFont, &gcvalues);
 
   drawable = XRenderCreatePicture (display, window, format,
                                   0, NULL);
-  glyph = XRenderCreatePicture (display, pixmap, glyph_format,
-                               0, NULL);
   memset (&black, 0, sizeof black);
   black.alpha = 65535;
 
@@ -11552,18 +11214,35 @@ sfnt_x_raster (struct sfnt_raster *raster)
          XRenderFillRectangle (display, PictOpSrc, drawable,
                                &white, 0, 0, 65535, 65535);
 
-         /* Draw the solid fill with the glyph as clip mask.  */
-         XRenderComposite (display, PictOpOver, solid, glyph,
-                           drawable, 0, 0, 0, 0, 0, 0,
-                           raster->width, raster->height);
+         /* Compute ascent line.  */
+         ascent = sfnt_mul_fixed (hhea->ascent * 65536,
+                                  scale) / 65536;
+
+         origin = 0;
+
+         for (i = 0; i < nrasters; ++i)
+           {
+             /* Compute the base position.  */
+             x = origin + rasters[i]->offx;
+             y = ascent - rasters[i]->height - rasters[i]->offy;
+
+             /* Draw the solid fill with the glyph as clip mask.  */
+             XRenderComposite (display, PictOpOver, solid, glyphs[i],
+                               drawable, 0, 0, 0, 0, x, y,
+                               rasters[i]->width, rasters[i]->height);
+
+             origin += advances[i];
+           }
        }
     }
 }
 
 static void
-sfnt_test_raster (struct sfnt_raster *raster)
+sfnt_test_raster (struct sfnt_raster *raster,
+                 struct sfnt_hhea_table *hhea,
+                 sfnt_fixed scale)
 {
-  int x, y;
+  int x, y, i;
 
   for (y = 0; y < raster->height; ++y)
     {
@@ -11572,10 +11251,12 @@ sfnt_test_raster (struct sfnt_raster *raster)
       puts ("");
     }
 
-  if (getenv ("SFNT_X"))
+  if (hhea && getenv ("SFNT_X"))
     {
+      i = 0;
+
       if (!fork ())
-       sfnt_x_raster (raster);
+       sfnt_x_raster (&raster, &i, 1, hhea, scale);
     }
 }
 
@@ -14074,12 +13755,12 @@ static struct sfnt_interpreter_test all_tests[] =
         SDB[] ; delta base now 2
         PUSHB[0] 6
         SDS[] ; delta shift now 6
-        PUSHB[2] 1 0xff 1 ; CVT index 5, ppem 15 + 2, magnitude 15
+        PUSHB[2] 0xff 5 1 ; CVT index 5, ppem 15 + 2, magnitude 15
          DELTAC1[]
         PUSHB[0] 1
          RCVT[] ; CVT index 5 should now be greater by 8 / 64
 
-         PUSHB[2] 1 0xef 1 ; CVT index 5, ppem 14 + 2, magnitude 15
+         PUSHB[2] 0xef 5 1 ; CVT index 5, ppem 14 + 2, magnitude 15
          DELTAC1[]
          PUSHB[0] 1
          RCVT[] ; CVT index 5 should be unchanged */
@@ -14087,11 +13768,11 @@ static struct sfnt_interpreter_test all_tests[] =
                           0x5e,
                           0xb0, 6,
                           0x5f,
-                          0xb2, 5, 255, 1,
+                          0xb2, 255, 5, 1,
                           0x73,
                           0xb0, 5,
                           0x45,
-                          0xb2, 5, 239, 1,
+                          0xb2, 239, 5, 1,
                           0x73,
                           0xb0, 5,
                           0x45, },
@@ -14105,12 +13786,12 @@ static struct sfnt_interpreter_test all_tests[] =
         SDB[] ; delta base now 2
         PUSHB[0] 6
         SDS[] ; delta shift now 6
-        PUSHB[2] 1 0xff 1 ; CVT index 5, ppem 15 + 2 + 16, magnitude 15
+        PUSHB[2] 0xff 5 1 ; CVT index 5, ppem 15 + 2 + 16, magnitude 15
          DELTAC2[]
         PUSHB[0] 1
          RCVT[] ; CVT index 5 should be unchanged
 
-         PUSHB[2] 1 0xef 1 ; CVT index 5, ppem 14 + 2 + 16, magnitude 15
+         PUSHB[2] 0xef 5 1 ; CVT index 5, ppem 14 + 2 + 16, magnitude 15
          DELTAC2[]
          PUSHB[0] 1
          RCVT[] ; CVT index 5 should be unchanged */
@@ -14118,11 +13799,11 @@ static struct sfnt_interpreter_test all_tests[] =
                           0x5e,
                           0xb0, 6,
                           0x5f,
-                          0xb2, 5, 255, 1,
+                          0xb2, 255, 5, 1,
                           0x74,
                           0xb0, 5,
                           0x45,
-                          0xb2, 5, 239, 1,
+                          0xb2, 239, 5, 1,
                           0x74,
                           0xb0, 5,
                           0x45, },
@@ -14136,12 +13817,12 @@ static struct sfnt_interpreter_test all_tests[] =
         SDB[] ; delta base now 2
         PUSHB[0] 6
         SDS[] ; delta shift now 6
-        PUSHB[2] 1 0xff 1 ; CVT index 5, ppem 15 + 2 + 32, magnitude 15
+        PUSHB[2] 0xff 5 1 ; CVT index 5, ppem 15 + 2 + 32, magnitude 15
          DELTAC3[]
         PUSHB[0] 1
          RCVT[] ; CVT index 5 should be unchanged
 
-         PUSHB[2] 1 0xef 1 ; CVT index 5, ppem 14 + 2 + 32, magnitude 15
+         PUSHB[2] 0xef 5 1 ; CVT index 5, ppem 14 + 2 + 32, magnitude 15
          DELTAC3[]
          PUSHB[0] 1
          RCVT[] ; CVT index 5 should be unchanged */
@@ -14149,11 +13830,11 @@ static struct sfnt_interpreter_test all_tests[] =
                           0x5e,
                           0xb0, 6,
                           0x5f,
-                          0xb2, 5, 255, 1,
+                          0xb2, 255, 5, 1,
                           0x75,
                           0xb0, 5,
                           0x45,
-                          0xb2, 5, 239, 1,
+                          0xb2, 239, 5, 1,
                           0x75,
                           0xb0, 5,
                           0x45, },
@@ -14818,15 +14499,22 @@ sfnt_verbose (struct sfnt_interpreter *interpreter)
   temp.x_points = interpreter->glyph_zone->x_current;
   temp.y_points = interpreter->glyph_zone->y_current;
   temp.flags = interpreter->glyph_zone->flags;
+
   outline = sfnt_build_instructed_outline (&temp);
 
   if (!outline)
     return;
 
+  printf ("outline bounds: %g %g, %g %g\n",
+         sfnt_coerce_fixed (outline->xmin),
+         sfnt_coerce_fixed (outline->ymin),
+         sfnt_coerce_fixed (outline->xmax),
+         sfnt_coerce_fixed (outline->ymax));
+
   raster = sfnt_raster_glyph_outline (outline);
 
   if (raster)
-    sfnt_test_raster (raster);
+    sfnt_test_raster (raster, NULL, 0);
 
   xfree (outline);
   xfree (raster);
@@ -14937,6 +14625,11 @@ main (int argc, char **argv)
   struct sfnt_prep_table *prep;
   struct sfnt_graphics_state state;
   struct sfnt_instructed_outline *value;
+  sfnt_fixed scale;
+  char *fancy;
+  int *advances;
+  struct sfnt_raster **rasters;
+  size_t length;
 
   if (argc != 2)
     return 1;
@@ -15025,6 +14718,9 @@ main (int argc, char **argv)
                 data[i]->format);
     }
 
+#define FANCY_PPEM 30
+#define EASY_PPEM  30
+
   interpreter = NULL;
   head = sfnt_read_head_table (fd, font);
   hhea = sfnt_read_hhea_table (fd, font);
@@ -15040,6 +14736,123 @@ main (int argc, char **argv)
   exec_prep = prep;
   exec_fpgm = fpgm;
 
+  if (getenv ("SFNT_FANCY_TEST"))
+    {
+      loca_long = NULL;
+      loca_short = NULL;
+      fancy = getenv ("SFNT_FANCY_TEST");
+      length = strlen (fancy);
+      scale = sfnt_div_fixed (FANCY_PPEM, head->units_per_em);
+
+      if (hhea && maxp)
+       hmtx = sfnt_read_hmtx_table (fd, font, hhea, maxp);
+
+      if (!maxp || !head || !prep || !hmtx || !hhea
+         || table->num_subtables < 1)
+       exit (1);
+
+      if (head->index_to_loc_format)
+       {
+         loca_long = sfnt_read_loca_table_long (fd, font);
+         if (!loca_long)
+           return 1;
+
+         fprintf (stderr, "long loca table has %zu glyphs\n",
+                  loca_long->num_offsets);
+       }
+      else
+       {
+         loca_short = sfnt_read_loca_table_short (fd, font);
+         if (!loca_short)
+           return 1;
+
+         fprintf (stderr, "short loca table has %zu glyphs\n",
+                  loca_short->num_offsets);
+       }
+
+      interpreter = sfnt_make_interpreter (maxp, cvt, head,
+                                          FANCY_PPEM, FANCY_PPEM);
+
+      if (!interpreter)
+       exit (1);
+
+      if (fpgm)
+       {
+         fprintf (stderr, "interpreting the font program, with"
+                  " %zu instructions\n", fpgm->num_instructions);
+         trap = sfnt_interpret_font_program (interpreter, fpgm);
+
+         if (trap)
+           fprintf (stderr, "**TRAP**: %s\n", trap);
+       }
+
+      if (prep)
+       {
+         fprintf (stderr, "interpreting the control value program, with"
+                  " %zu instructions\n", prep->num_instructions);
+         trap = sfnt_interpret_control_value_program (interpreter, prep,
+                                                      &state);
+
+         if (trap)
+           fprintf (stderr, "**TRAP**: %s\n", trap);
+       }
+
+      state = interpreter->state;
+
+      advances = alloca (sizeof *advances * length);
+      rasters = alloca (sizeof *rasters * length);
+
+      for (i = 0; i < length; ++i)
+       {
+         code = sfnt_lookup_glyph (fancy[i], data[0]);
+
+         if (!code)
+           exit (2);
+
+         glyph = sfnt_read_glyph (code, glyf, loca_short,
+                                  loca_long);
+
+         if (!glyph || !glyph->simple)
+           exit (3);
+
+         if (sfnt_lookup_glyph_metrics (code, -1,
+                                        &metrics,
+                                        hmtx, hhea,
+                                        head, maxp))
+           exit (4);
+
+         interpreter->state = state;
+         trap = sfnt_interpret_simple_glyph (glyph, interpreter,
+                                             &metrics, &value);
+
+         if (trap)
+           {
+             fprintf (stderr, "*TRAP*: %s\n", trap);
+             exit (5);
+           }
+
+         outline = sfnt_build_instructed_outline (value);
+
+         if (!outline)
+           exit (6);
+
+         xfree (value);
+
+         raster = sfnt_raster_glyph_outline (outline);
+
+         if (!raster)
+           exit (7);
+
+         xfree (outline);
+
+         rasters[i] = raster;
+         advances[i] = sfnt_mul_fixed (metrics.advance, scale);
+       }
+
+      sfnt_x_raster (rasters, advances, length, hhea, scale);
+      exit (0);
+    }
+
   if (head && maxp && maxp->version >= 0x00010000)
     {
       fprintf (stderr, "creating interpreter\n"
@@ -15057,7 +14870,8 @@ main (int argc, char **argv)
               cvt ? cvt->num_elements : 0ul);
 
       interpreter = sfnt_make_interpreter (maxp, cvt, head,
-                                          20, 20);
+                                          FANCY_PPEM,
+                                          FANCY_PPEM);
       state = interpreter->state;
 
       if (fpgm)
@@ -15210,6 +15024,7 @@ main (int argc, char **argv)
 
       if ((loca_long || loca_short) && glyf)
        {
+         scale = sfnt_div_fixed (EASY_PPEM, head->units_per_em);
          glyph = sfnt_read_glyph (code, glyf, loca_short,
                                   loca_long);
 
@@ -15233,7 +15048,7 @@ main (int argc, char **argv)
              /* Time this important bit.  */
              clock_gettime (CLOCK_THREAD_CPUTIME_ID, &start);
              outline = sfnt_build_glyph_outline (glyph, head,
-                                                 20,
+                                                 EASY_PPEM,
                                                  sfnt_test_get_glyph,
                                                  sfnt_test_free_glyph,
                                                  &dcontext);
@@ -15275,7 +15090,7 @@ main (int argc, char **argv)
 
                  clock_gettime (CLOCK_THREAD_CPUTIME_ID, &start);
 
-                 for (i = 0; i < 400; ++i)
+                 for (i = 0; i < 120; ++i)
                    {
                      xfree (raster);
                      raster = sfnt_raster_glyph_outline (outline);
@@ -15285,7 +15100,7 @@ main (int argc, char **argv)
                  sub2 = timespec_sub (end, start);
 
                  /* Print out the raster.  */
-                 sfnt_test_raster (raster);
+                 sfnt_test_raster (raster, hhea, scale);
                  printf ("raster offsets: %d, %d\n",
                          raster->offx, raster->offy);
 
@@ -15300,7 +15115,7 @@ main (int argc, char **argv)
 
              if (hmtx && head)
                {
-                 if (!sfnt_lookup_glyph_metrics (code, 20,
+                 if (!sfnt_lookup_glyph_metrics (code, EASY_PPEM,
                                                  &metrics,
                                                  hmtx, hhea,
                                                  head, maxp))
@@ -15320,10 +15135,10 @@ main (int argc, char **argv)
                        }
 
                      if (glyph->simple
-                         && sfnt_lookup_glyph_metrics (code, -1,
-                                                       &metrics,
-                                                       hmtx, hhea,
-                                                       head, maxp))
+                         && !sfnt_lookup_glyph_metrics (code, -1,
+                                                        &metrics,
+                                                        hmtx, hhea,
+                                                        head, maxp))
                        {
                          printf ("interpreting glyph\n");
                          interpreter->state = state;
@@ -15349,7 +15164,9 @@ main (int argc, char **argv)
 
                                  if (raster)
                                    {
-                                     sfnt_test_raster (raster);
+                                     sfnt_test_raster (raster, hhea, scale);
+                                     printf ("raster offsets: %d, %d\n",
+                                             raster->offx, raster->offy);
                                      xfree (raster);
                                    }
                                }
@@ -15368,7 +15185,7 @@ main (int argc, char **argv)
              printf ("time spent building edges: %lld sec %ld nsec\n",
                      (long long) sub1.tv_sec, sub1.tv_nsec);
              printf ("time spent rasterizing: %lld sec %ld nsec\n",
-                     (long long) sub2.tv_sec / 400, sub2.tv_nsec / 400);
+                     (long long) sub2.tv_sec / 120, sub2.tv_nsec / 120);
 
              xfree (outline);
            }
diff --git a/src/sfnt.h b/src/sfnt.h
index 409c45085b..0845cb5be5 100644
--- a/src/sfnt.h
+++ b/src/sfnt.h
@@ -23,6 +23,11 @@ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 
USA.  */
 
 #include <stdint.h>
 #include <stddef.h>
+#include <setjmp.h>
+
+#if defined emacs || defined TEST
+#define SFNT_ENABLE_HINTING
+#endif
 
 
 
@@ -719,7 +724,7 @@ struct sfnt_edge
 
 enum
   {
-    SFNT_POLY_SHIFT  = 2,
+    SFNT_POLY_SHIFT  = 3,
     SFNT_POLY_SAMPLE = (1 << SFNT_POLY_SHIFT),
     SFNT_POLY_MASK   = (SFNT_POLY_SAMPLE - 1),
     SFNT_POLY_STEP   = (0x10000 >> SFNT_POLY_SHIFT),
@@ -984,6 +989,9 @@ extern int sfnt_lookup_glyph_metrics (sfnt_glyph, int,
                                      struct sfnt_head_table *,
                                      struct sfnt_maxp_table *);
 
+extern void sfnt_scale_metrics (struct sfnt_glyph_metrics *,
+                               sfnt_fixed);
+
 #define PROTOTYPE int, struct sfnt_offset_subtable *
 extern struct sfnt_name_table *sfnt_read_name_table (PROTOTYPE);
 #undef PROTOTYPE
@@ -1003,4 +1011,477 @@ extern char *sfnt_find_metadata (struct sfnt_meta_table 
*,
 extern struct sfnt_ttc_header *sfnt_read_ttc_header (int);
 
 #endif /* TEST */
+
+
+
+/* TrueType hinting support.  */
+
+#ifdef SFNT_ENABLE_HINTING
+
+/* Structure definitions for tables used by the TrueType
+   interpreter.  */
+
+struct sfnt_cvt_table
+{
+  /* Number of elements in the control value table.  */
+  size_t num_elements;
+
+  /* Pointer to elements in the control value table.  */
+  sfnt_fword *values;
+};
+
+struct sfnt_fpgm_table
+{
+  /* Number of instructions in the font program table.  */
+  size_t num_instructions;
+
+  /* Pointer to elements in the font program table.  */
+  unsigned char *instructions;
+};
+
+struct sfnt_prep_table
+{
+  /* Number of instructions in the control value program (pre-program)
+     table.  */
+  size_t num_instructions;
+
+  /* Pointer to elements in the preprogram table.  */
+  unsigned char *instructions;
+};
+
+
+
+/* Fixed point types used by the TrueType interpreter.  */
+
+/* 26.6 fixed point type used within the interpreter.  */
+typedef int32_t sfnt_f26dot6;
+
+/* 2.14 fixed point type used to represent versors of unit
+   vectors.  */
+typedef int16_t sfnt_f2dot14;
+
+/* 18.14 fixed point type used to calculate rounding details.  */
+typedef int32_t sfnt_f18dot14;
+
+
+
+/* Interpreter execution environment.  */
+
+struct sfnt_unit_vector
+{
+  /* X and Y versors of the 2d unit vector.  */
+  sfnt_f2dot14 x, y;
+};
+
+struct sfnt_interpreter_definition
+{
+  /* The opcode of this instruction or function.  */
+  uint16_t opcode;
+
+  /* The number of instructions.  */
+  uint16_t instruction_count;
+
+  /* Pointer to instructions belonging to the definition.  This
+     pointer points directly into the control value or font program.
+     Make sure both programs are kept around as long as the
+     interpreter continues to exist.  */
+  unsigned char *instructions;
+};
+
+/* This structure represents a ``struct sfnt_glyph'' that has been
+   scaled to a given pixel size.
+
+   It can either contain a simple glyph, or a decomposed compound
+   glyph; instructions are interpreted for both simple glyphs, simple
+   glyph components inside a compound glyph, and compound glyphs as a
+   whole.
+
+   In addition to the glyph data itself, it also records various
+   information for the instruction interpretation process:
+
+     - ``current'' point coordinates, which have been modified
+       by the instructing process.
+
+     - two phantom points at the origin and the advance of the
+       glyph.  */
+
+struct sfnt_interpreter_zone
+{
+  /* The number of points in this zone, including the two phantom
+     points at the end.  */
+  size_t num_points;
+
+  /* The number of contours in this zone.  */
+  size_t num_contours;
+
+  /* The end points of each contour.  */
+  size_t *contour_end_points;
+
+  /* Pointer to the X axis point data.  */
+  sfnt_f26dot6 *restrict x_points;
+
+  /* Pointer to the X axis current point data.  */
+  sfnt_f26dot6 *restrict x_current;
+
+  /* Pointer to the Y axis point data.  */
+  sfnt_f26dot6 *restrict y_points;
+
+  /* Pointer to the Y axis current point data.  */
+  sfnt_f26dot6 *restrict y_current;
+
+  /* Pointer to the flags associated with this data.  */
+  unsigned char *flags;
+};
+
+enum
+  {
+    /* 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.  */
+    SFNT_POINT_TOUCHED_X = (1 << 7),
+    SFNT_POINT_TOUCHED_Y = (1 << 6),
+    SFNT_POINT_TOUCHED_BOTH = (SFNT_POINT_TOUCHED_X
+                              | SFNT_POINT_TOUCHED_Y),
+  };
+
+/* This is needed because `round' below needs an interpreter
+   argument.  */
+struct sfnt_interpreter;
+
+struct sfnt_graphics_state
+{
+  /* Pointer to the function used for rounding.  This function is
+     asymmetric, so -0.5 rounds up to 0, not -1.  It is up to the
+     caller to handle negative values.
+
+     Value is undefined unless sfnt_validate_gs has been called, and
+     the second argument may be used to provide detailed rounding
+     information (``super rounding state''.)  */
+  sfnt_f26dot6 (*round) (sfnt_f26dot6, struct sfnt_interpreter *);
+
+  /* Pointer to the function used to project euclidean vectors onto
+     the projection vector.  Value is the magnitude of the projected
+     vector.  */
+  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.  */
+  void (*move) (sfnt_f26dot6 *restrict,
+               sfnt_f26dot6 *restrict, size_t,
+               struct sfnt_interpreter *,
+               sfnt_f26dot6, unsigned char *);
+
+  /* Dot product between the freedom and the projection vectors.  */
+  sfnt_f2dot14 vector_dot_product;
+
+  /* Controls whether the sign of control value table entries will be
+     changed to match the sign of the actual distance measurement with
+     which it is compared.  Setting auto flip to TRUE makes it
+     possible to control distances measured with or against the
+     projection vector with a single control value table entry. When
+     auto flip is set to FALSE, distances must be measured with the
+     projection vector.  */
+  bool auto_flip;
+
+  /* Limits the regularizing effects of control value table entries to
+     cases where the difference between the table value and the
+     measurement taken from the original outline is sufficiently
+     small.  */
+  sfnt_f26dot6 cvt_cut_in;
+
+  /* Establishes the base value used to calculate the range of point
+     sizes to which a given DELTAC[] or DELTAP[] instruction will
+     apply.  The formulas given below are used to calculate the range
+     of the various DELTA instructions.
+
+     DELTAC1 DELTAP1 (delta_base) through (delta_base + 15)
+     DELTAC2 DELTAP2 (delta_base + 16) through (delta_base + 31)
+     DELTAC3 DELTAP3 (delta_base + 32) through (delta_base + 47)
+
+     Please keep this documentation in sync with the TrueType
+     reference manual.  */
+  unsigned short delta_base;
+
+  /* Determines the range of movement and smallest magnitude of
+     movement (the step) in a DELTAC[] or DELTAP[] instruction.
+     Changing the value of the delta shift makes it possible to trade
+     off fine control of point movement for range of movement.  A low
+     delta shift favors range of movement over fine control.  A high
+     delta shift favors fine control over range of movement.  The step
+     has the value 1/2 to the power delta shift.  The range of
+     movement is calculated by taking the number of steps allowed (16)
+     and multiplying it by the step.
+
+     The legal range for delta shift is zero through six.  Negative
+     values are illegal.  */
+  unsigned short delta_shift;
+
+  /* A second projection vector set to a line defined by the original
+     outline location of two points.  The dual projection vector is
+     used when it is necessary to measure distances from the scaled
+     outline before any instructions were executed.  */
+  struct sfnt_unit_vector dual_projection_vector;
+
+  /* A unit vector that establishes an axis along which points can
+     move.  */
+  struct sfnt_unit_vector freedom_vector;
+
+  /* Makes it possible to turn off instructions under some
+     circumstances.  When flag 1 is set, changes to the graphics state
+     made in the control value program will be ignored.  When flag is
+     1, grid fitting instructions will be ignored.  */
+  unsigned char instruct_control;
+
+  /* Makes it possible to repeat certain instructions a designated
+     number of times.  The default value of one assures that unless
+     the value of loop is altered, these instructions will execute one
+     time.  */
+  unsigned short loop;
+
+  /* Establishes the smallest possible value to which a distance will
+     be rounded.  */
+  sfnt_f26dot6 minimum_distance;
+
+  /* A unit vector whose direction establishes an axis along which
+     distances are measured.  */
+  struct sfnt_unit_vector projection_vector;
+
+  /* Determines the manner in which values are rounded. Can be set to
+     a number of predefined states or to a customized state with the
+     SROUND or S45ROUND instructions.  */
+  int round_state;
+
+  /* Reference points.  These reference point numbers, which together
+     with a zone designation, specify a point in either the glyph zone
+     or the twilight zone.  */
+  uint16_t rp0, rp1, rp2;
+
+  /* Flags which determine whether the interpreter will activate
+     dropout control for the current glyph.  */
+  int scan_control;
+
+  /* The distance difference below which the interpreter will replace
+     a CVT distance or an actual distance in favor of the single width
+     value.  */
+  sfnt_f26dot6 sw_cut_in;
+
+  /* The value used in place of the control value table distance or
+     the actual distance value when the difference between that
+     distance and the single width value is less than the single width
+     cut-in.  */
+  sfnt_f26dot6 single_width_value;
+
+  /* Zone pointers, which reference a zone.  */
+  int zp0, zp1, zp2;
+};
+
+struct sfnt_interpreter
+{
+  /* The number of elements in the stack.  */
+  uint16_t max_stack_elements;
+
+  /* The number of instructions in INSTRUCTIONS.  */
+  uint16_t num_instructions;
+
+  /* Size of the storage area.  */
+  uint16_t storage_size;
+
+  /* Size of the function definition area.  */
+  uint16_t function_defs_size;
+
+  /* Size of the instruction definition area.  */
+  uint16_t instruction_defs_size;
+
+  /* Size of the twilight zone.  */
+  uint16_t twilight_zone_size;
+
+  /* The instruction pointer.  This points to the instruction
+     currently being executed.  */
+  int IP;
+
+  /* The current scale.  */
+  sfnt_fixed scale;
+
+  /* The current ppem and point size.  */
+  int ppem, point_size;
+
+  /* The execution stack.  This has at most max_stack_elements
+     elements.  */
+  uint32_t *stack;
+
+  /* Pointer past the top of the stack.  */
+  uint32_t *SP;
+
+  /* The size of the control value table.  */
+  size_t cvt_size;
+
+  /* Pointer to instructions currently being executed.  */
+  unsigned char *restrict instructions;
+
+  /* The twilight zone.  May not be NULL.  */
+  sfnt_f26dot6 *restrict twilight_x, *restrict twilight_y;
+
+  /* The original X positions of points in the twilight zone.  */
+  sfnt_f26dot6 *restrict twilight_original_x;
+
+  /* The original Y positions of points in the twilight zone.
+
+     Apple does not directly say whether or not points in the twilight
+     zone can have their original positions changed.  But this is
+     implied by ``create points in the twilight zone''.  */
+  sfnt_f26dot6 *restrict twilight_original_y;
+
+  /* The scaled outlines being manipulated.  May be NULL.  */
+  struct sfnt_interpreter_zone *glyph_zone;
+
+  /* The glyph advance width.  Value is undefined unless GLYPH_ZONE is
+     set.  */
+  sfnt_f26dot6 advance_width;
+
+  /* The storage area.  */
+  uint32_t *storage;
+
+  /* Control value table values.  */
+  sfnt_f26dot6 *cvt;
+
+  /* Function definitions.  */
+  struct sfnt_interpreter_definition *function_defs;
+
+  /* Instruction definitions.  */
+  struct sfnt_interpreter_definition *instruction_defs;
+
+  /* Interpreter registers.  */
+  struct sfnt_graphics_state state;
+
+  /* Detailed rounding state used when state.round_state indicates
+     that fine grained rounding should be used.
+
+     PERIOD says how often a round value occurs, for numbers
+     increasing from PHASE to infinity.
+
+     THRESHOLD says when to round a value between two increasing
+     periods towards the larger period.  */
+  sfnt_f26dot6 period, phase, threshold;
+
+  /* The depth of any ongoing calls.  */
+  int call_depth;
+
+  /* Jump buffer for traps.  */
+  jmp_buf trap;
+
+  /* What was the trap.  */
+  const char *trap_reason;
+
+#ifdef TEST
+  /* If non-NULL, function called before each instruction is
+     executed.  */
+  void (*run_hook) (struct sfnt_interpreter *);
+
+  /* If non-NULL, function called before each stack element is
+     pushed.  */
+  void (*push_hook) (struct sfnt_interpreter *, uint32_t);
+
+  /* If non-NULL, function called before each stack element is
+     popped.  */
+  void (*pop_hook) (struct sfnt_interpreter *, uint32_t);
+#endif
+};
+
+
+
+/* Glyph hinting.  */
+
+/* Structure describing a single scaled and fitted outline.  */
+
+struct sfnt_instructed_outline
+{
+  /* The number of points in this contour, including the two phantom
+     points at the end.  */
+  size_t num_points;
+
+  /* The number of contours in this outline.  */
+  size_t num_contours;
+
+  /* The end points of each contour.  */
+  size_t *contour_end_points;
+
+  /* The points of each contour, with two additional phantom points at
+     the end.  */
+  sfnt_f26dot6 *restrict x_points, *restrict y_points;
+
+  /* The flags of each point.  */
+  unsigned char *flags;
+};
+
+
+
+/* Functions used to read tables used by the TrueType interpreter.  */
+
+#ifndef TEST
+
+#define PROTOTYPE int, struct sfnt_offset_subtable *
+
+extern struct sfnt_cvt_table *sfnt_read_cvt_table (PROTOTYPE);
+extern struct sfnt_fpgm_table *sfnt_read_fpgm_table (PROTOTYPE);
+extern struct sfnt_prep_table *sfnt_read_prep_table (PROTOTYPE);
+
+#undef PROTOTYPE
+
+#define PROTOTYPE                              \
+  struct sfnt_maxp_table *,                    \
+  struct sfnt_cvt_table *,                     \
+  struct sfnt_head_table *,                    \
+  int, int
+
+extern struct sfnt_interpreter *sfnt_make_interpreter (PROTOTYPE);
+
+#undef PROTOTYPE
+
+#define PROTOTYPE                              \
+  struct sfnt_interpreter *,                   \
+  struct sfnt_fpgm_table *
+
+extern const char *sfnt_interpret_font_program (PROTOTYPE);
+
+#undef PROTOTYPE
+
+#define PROTOTYPE                              \
+  struct sfnt_interpreter *,                   \
+  struct sfnt_prep_table *,                    \
+  struct sfnt_graphics_state *
+
+extern const char *sfnt_interpret_control_value_program (PROTOTYPE);
+
+#undef PROTOTYPE
+
+#define PROTOTYPE struct sfnt_instructed_outline *
+
+extern struct sfnt_glyph_outline *sfnt_build_instructed_outline (PROTOTYPE);
+
+#undef PROTOTYPE
+
+#define PROTOTYPE                              \
+  struct sfnt_glyph *,                         \
+  struct sfnt_interpreter *,                   \
+  struct sfnt_glyph_metrics *,                 \
+  struct sfnt_instructed_outline **
+
+extern const char *sfnt_interpret_simple_glyph (PROTOTYPE);
+
+#undef PROTOTYPE
+
+#endif /* TEST */
+
+
+
+#endif /* SFNT_ENABLE_HINTING */
+
 #endif /* _SFNT_H_ */
diff --git a/src/sfntfont-android.c b/src/sfntfont-android.c
index d8f598fd33..feea92827d 100644
--- a/src/sfntfont-android.c
+++ b/src/sfntfont-android.c
@@ -454,7 +454,7 @@ sfntfont_android_put_glyphs (struct glyph_string *s, int 
from,
     {
       text.x1 = x_coords[0] + rasters[0]->offx;
       text.x2 = text.x1 + rasters[0]->width;
-      text.y1 = y - (rasters[0]->height + rasters[0]->offy);
+      text.y1 = y - rasters[0]->height - rasters[0]->offy;
       text.y2 = y - rasters[0]->offy;
     }
   else
@@ -469,7 +469,7 @@ sfntfont_android_put_glyphs (struct glyph_string *s, int 
from,
 
       character.x1 = x_coords[i] + rasters[i]->offx;
       character.x2 = character.x1 + rasters[i]->width;
-      character.y1 = y - (rasters[i]->height + rasters[i]->offy);
+      character.y1 = y - rasters[i]->height - rasters[i]->offy;
       character.y2 = y - rasters[i]->offy;
 
       sfntfont_android_union_boxes (text, character, &text);
diff --git a/src/sfntfont.c b/src/sfntfont.c
index d9b152e27e..dbd1a037f4 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.
 
+   If INTERPRETER is non-NULL, then possibly use the unscaled glyph
+   metrics in METRICS when instructing the glyph.
+
    Return the outline with an incremented reference count and enter
    the generated outline into CACHE upon success, possibly discarding
    any older outlines, or NULL on failure.  */
@@ -1467,12 +1470,16 @@ sfntfont_get_glyph_outline (sfnt_glyph glyph_code,
                            struct sfnt_glyf_table *glyf,
                            struct sfnt_head_table *head,
                            struct sfnt_loca_table_short *loca_short,
-                           struct sfnt_loca_table_long *loca_long)
+                           struct sfnt_loca_table_long *loca_long,
+                           struct sfnt_interpreter *interpreter,
+                           struct sfnt_glyph_metrics *metrics)
 {
   struct sfnt_outline_cache *start;
   struct sfnt_glyph_outline *outline;
   struct sfnt_glyph *glyph;
   struct sfntfont_get_glyph_outline_dcontext dcontext;
+  struct sfnt_instructed_outline *value;
+  const char *error;
 
   start = cache->next;
 
@@ -1504,14 +1511,32 @@ sfntfont_get_glyph_outline (sfnt_glyph glyph_code,
   if (!glyph)
     return NULL;
 
+  /* Try to instruct the glyph if INTERPRETER is specified.
+     TODO: support compound glyphs.  */
+
+  outline = NULL;
+
+  if (interpreter && glyph->simple)
+    {
+      error = sfnt_interpret_simple_glyph (glyph, interpreter,
+                                          metrics, &value);
+
+      if (!error)
+       {
+         outline = sfnt_build_instructed_outline (value);
+         xfree (value);
+       }
+    }
+
   dcontext.loca_long = loca_long;
   dcontext.loca_short = loca_short;
   dcontext.glyf = glyf;
 
-  outline = sfnt_build_glyph_outline (glyph, head, pixel_size,
-                                     sfntfont_get_glyph,
-                                     sfntfont_free_glyph,
-                                     &dcontext);
+  if (!outline)
+    outline = sfnt_build_glyph_outline (glyph, head, pixel_size,
+                                       sfntfont_get_glyph,
+                                       sfntfont_free_glyph,
+                                       &dcontext);
   xfree (glyph);
 
   if (!outline)
@@ -1709,6 +1734,9 @@ struct sfnt_font_info
   struct sfnt_glyf_table *glyf;
   struct sfnt_loca_table_short *loca_short;
   struct sfnt_loca_table_long *loca_long;
+  struct sfnt_prep_table *prep;
+  struct sfnt_fpgm_table *fpgm;
+  struct sfnt_cvt_table *cvt;
 
   /* The selected character map.  */
   struct sfnt_cmap_encoding_subtable_data *cmap_data;
@@ -1727,6 +1755,13 @@ struct sfnt_font_info
 
   /* Number of elements in the raster cache.  */
   int raster_cache_size;
+
+  /* Interpreter for grid fitting (if enabled).  */
+  struct sfnt_interpreter *interpreter;
+
+  /* Graphics state after the execution of the font and control value
+     programs.  */
+  struct sfnt_graphics_state state;
 };
 
 /* Look up the glyph corresponding to the character C in FONT.  Return
@@ -1813,6 +1848,106 @@ sfntfont_probe_widths (struct sfnt_font_info *font_info)
     font_info->font.average_width = total_width / num_characters;
 }
 
+/* Initialize the instruction interpreter for INFO, whose file and
+   offset subtable should be respectively FD and SUBTABLE.  Load the
+   font and preprogram for the pixel size in INFO and its
+   corresponding point size POINT_SIZE.
+
+   The font tables in INFO must already have been initialized.
+
+   Set INFO->interpreter, INFO->cvt, INFO->prep, INFO->fpgm and
+   INFO->state upon success, and leave those fields intact
+   otherwise.  */
+
+static void
+sfntfont_setup_interpreter (int fd, struct sfnt_font_info *info,
+                           struct sfnt_offset_subtable *subtable,
+                           int point_size)
+{
+  struct sfnt_cvt_table *cvt;
+  struct sfnt_fpgm_table *fpgm;
+  struct sfnt_prep_table *prep;
+  struct sfnt_interpreter *interpreter;
+  const char *error;
+  struct sfnt_graphics_state state;
+
+  /* Try to read the control value program, cvt, and font program
+     tables.  */
+
+  cvt = sfnt_read_cvt_table (fd, subtable);
+  fpgm = sfnt_read_fpgm_table (fd, subtable);
+  prep = sfnt_read_prep_table (fd, subtable);
+
+  /* If both fpgm and prep are NULL, this font likely has no
+     instructions, so don't bother setting up the interpreter.  */
+
+  if (!fpgm && !prep)
+    goto bail;
+
+  /* Now, create the interpreter using the limits in info->maxp and
+     info->head.  CVT can be NULL.  */
+  interpreter = sfnt_make_interpreter (info->maxp, cvt, info->head,
+                                      info->font.pixel_size,
+                                      point_size);
+
+  /* Bail if the interpreter couldn't be created.  */
+  if (!interpreter)
+    goto bail;
+
+  if (fpgm)
+    {
+      /* Otherwise, evaluate the font and cvt programs.
+
+        FIXME: make sure infinite loops inside these programs
+        cannot lock up Emacs.  */
+
+      error = sfnt_interpret_font_program (interpreter, fpgm);
+
+      if (error)
+       {
+         /* If an error occurs, log it to the *Messages* buffer.  */
+         message_with_string ("While interpreting font program: %s",
+                              build_string (error), true);
+         goto bail1;
+       }
+
+      /* Save the graphics state.  */
+      state = interpreter->state;
+    }
+
+  if (prep)
+    {
+      /* This will overwrite state if the instruction control is set
+        appropriately.  */
+      error = sfnt_interpret_control_value_program (interpreter, prep,
+                                                   &state);
+
+      if (error)
+       {
+         /* If an error occurs, log it to the *Messages* buffer.  */
+         message_with_string ("While interpreting preprogram: %s",
+                              build_string (error), true);
+         goto bail1;
+       }
+    }
+
+  /* The interpreter has been properly set up.  */
+  info->fpgm = fpgm;
+  info->prep = prep;
+  info->cvt = cvt;
+  info->state = state;
+  info->interpreter = interpreter;
+
+  return;
+
+ bail1:
+  xfree (interpreter);
+ bail:
+  xfree (cvt);
+  xfree (fpgm);
+  xfree (prep);
+}
+
 /* Open the font corresponding to the font-entity FONT_ENTITY.  Return
    nil upon failure, else the opened font-object.  */
 
@@ -1829,6 +1964,8 @@ sfntfont_open (struct frame *f, Lisp_Object font_entity,
   struct sfnt_cmap_encoding_subtable *subtables;
   struct sfnt_cmap_encoding_subtable_data **data;
   struct charset *charset;
+  int point_size;
+  Display_Info *dpyinfo;
 
   if (XFIXNUM (AREF (font_entity, FONT_SIZE_INDEX)) != 0)
     pixel_size = XFIXNUM (AREF (font_entity, FONT_SIZE_INDEX));
@@ -1868,6 +2005,9 @@ sfntfont_open (struct frame *f, Lisp_Object font_entity,
   font_info->loca_short = NULL;
   font_info->loca_long = NULL;
   font_info->cmap_data = NULL;
+  font_info->prep = NULL;
+  font_info->fpgm = NULL;
+  font_info->cvt = NULL;
 
   font_info->outline_cache.next = &font_info->outline_cache;
   font_info->outline_cache.last = &font_info->outline_cache;
@@ -1875,6 +2015,7 @@ sfntfont_open (struct frame *f, Lisp_Object font_entity,
   font_info->raster_cache.next = &font_info->raster_cache;
   font_info->raster_cache.last = &font_info->raster_cache;
   font_info->raster_cache_size = 0;
+  font_info->interpreter = NULL;
 
   /* Open the font.  */
   fd = emacs_open (desc->path, O_RDONLY, 0);
@@ -2027,9 +2168,20 @@ sfntfont_open (struct frame *f, Lisp_Object font_entity,
   /* Calculate the xfld name.  */
   font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil);
 
+  /* Now try to set up grid fitting for this font.  */
+  dpyinfo = FRAME_DISPLAY_INFO (f);
+  point_size = PIXEL_TO_POINT (pixel_size, (dpyinfo->resx
+                                           * dpyinfo->resy
+                                           / 2));
+  sfntfont_setup_interpreter (fd, font_info, subtable,
+                             point_size);
+
   /* Close the font file descriptor.  */
   emacs_close (fd);
 
+  /* Free the offset subtable.  */
+  xfree (subtable);
+
   /* All done.  */
   unblock_input ();
   return font_object;
@@ -2090,6 +2242,54 @@ sfntfont_encode_char (struct font *font, int c)
   return glyph;
 }
 
+/* Measure the single glyph GLYPH in the font FONT and return its
+   metrics in *PCM.
+
+   Instruct the glyph if possible.
+
+   Value is 0 upon success, 1 otherwise.  */
+
+static int
+sfntfont_measure_instructed_pcm (struct sfnt_font_info *font, sfnt_glyph glyph,
+                                struct font_metrics *pcm)
+{
+  struct sfnt_glyph_metrics metrics;
+  struct sfnt_glyph_outline *outline;
+
+  /* Ask for unscaled metrics.  */
+  if (sfnt_lookup_glyph_metrics (glyph, -1, &metrics, font->hmtx,
+                                font->hhea, font->head, font->maxp))
+    return 1;
+
+  /* Now get the glyph outline, which is required to obtain the rsb,
+     ascent and descent.  */
+  outline = sfntfont_get_glyph_outline (glyph, &font->outline_cache,
+                                       font->font.pixel_size,
+                                       &font->outline_cache_size,
+                                       font->glyf, font->head,
+                                       font->loca_short,
+                                       font->loca_long,
+                                       font->interpreter, &metrics);
+
+  if (!outline)
+    return 1;
+
+  /* Scale the metrics by the interpreter's scale.  */
+  sfnt_scale_metrics (&metrics, font->interpreter->scale);
+
+  /* How to round lbearing and rbearing? */
+  pcm->lbearing = metrics.lbearing >> 16;
+  pcm->rbearing = outline->xmax >> 16;
+
+  /* Round the advance, ascent and descent upwards.  */
+  pcm->width = SFNT_CEIL_FIXED (metrics.advance) >> 16;
+  pcm->ascent = SFNT_CEIL_FIXED (outline->ymax) >> 16;
+  pcm->descent = SFNT_CEIL_FIXED (-outline->ymin) >> 16;
+
+  sfntfont_dereference_outline (outline);
+  return 0;
+}
+
 /* Measure the single glyph GLYPH in the font FONT and return its
    metrics in *PCM.  Value is 0 upon success, 1 otherwise.  */
 
@@ -2100,6 +2300,10 @@ sfntfont_measure_pcm (struct sfnt_font_info *font, 
sfnt_glyph glyph,
   struct sfnt_glyph_metrics metrics;
   struct sfnt_glyph_outline *outline;
 
+  if (font->interpreter)
+    /* Use a function which instructs the glyph.  */
+    return sfntfont_measure_instructed_pcm (font, glyph, pcm);
+
   /* Get the glyph metrics first.  */
   if (sfnt_lookup_glyph_metrics (glyph, font->font.pixel_size,
                                 &metrics, font->hmtx, font->hhea,
@@ -2113,7 +2317,7 @@ sfntfont_measure_pcm (struct sfnt_font_info *font, 
sfnt_glyph glyph,
                                        &font->outline_cache_size,
                                        font->glyf, font->head,
                                        font->loca_short,
-                                       font->loca_long);
+                                       font->loca_long, NULL, NULL);
 
   if (!outline)
     return 1;
@@ -2192,6 +2396,10 @@ sfntfont_close (struct font *font)
   xfree (info->loca_short);
   xfree (info->loca_long);
   xfree (info->cmap_data);
+  xfree (info->prep);
+  xfree (info->fpgm);
+  xfree (info->cvt);
+  xfree (info->interpreter);
 
   sfntfont_free_outline_cache (&info->outline_cache);
   sfntfont_free_raster_cache (&info->raster_cache);
@@ -2221,10 +2429,15 @@ sfntfont_draw (struct glyph_string *s, int from, int to,
   struct font *font;
   struct sfnt_font_info *info;
   struct sfnt_glyph_metrics metrics;
+  int pixel_size;
 
   length = to - from;
   font = s->font;
   info = (struct sfnt_font_info *) font;
+  pixel_size = font->pixel_size;
+
+  if (info->interpreter)
+    pixel_size = -1;
 
   rasters = alloca (length * sizeof *rasters);
   x_coords = alloca (length * sizeof *x_coords);
@@ -2233,8 +2446,9 @@ sfntfont_draw (struct glyph_string *s, int from, int to,
   /* Get rasters and outlines for them.  */
   for (i = from; i < to; ++i)
     {
-      /* Look up the metrics for this glyph.  */
-      if (sfnt_lookup_glyph_metrics (s->char2b[i], font->pixel_size,
+      /* Look up the metrics for this glyph.  The metrics are unscaled
+        if INFO->interpreter is set.  */
+      if (sfnt_lookup_glyph_metrics (s->char2b[i], pixel_size,
                                     &metrics, info->hmtx, info->hhea,
                                     info->head, info->maxp))
        {
@@ -2250,7 +2464,9 @@ sfntfont_draw (struct glyph_string *s, int from, int to,
                                            &info->outline_cache_size,
                                            info->glyf, info->head,
                                            info->loca_short,
-                                           info->loca_long);
+                                           info->loca_long,
+                                           info->interpreter,
+                                           &metrics);
       x_coords[i - from] = 0;
 
       if (!outline)
@@ -2259,6 +2475,10 @@ sfntfont_draw (struct glyph_string *s, int from, int to,
          continue;
        }
 
+      /* Scale the metrics if info->interpreter is set.  */
+      if (info->interpreter)
+       sfnt_scale_metrics (&metrics, info->interpreter->scale);
+
       /* Rasterize the outline.  */
       rasters[i - from] = sfntfont_get_glyph_raster (s->char2b[i],
                                                     &info->raster_cache,



reply via email to

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