emacs-diffs
[Top][All Lists]
Advanced

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

master 2656d756851 2/3: Properly instruct Italic Arial or BS Mono at sma


From: Po Lu
Subject: master 2656d756851 2/3: Properly instruct Italic Arial or BS Mono at small PPEM sizes
Date: Mon, 8 Jan 2024 02:52:10 -0500 (EST)

branch: master
commit 2656d756851d97434da7846a5a30202baafb2241
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Properly instruct Italic Arial or BS Mono at small PPEM sizes
    
    * src/sfnt.c (sfnt_read_simple_glyph): Correct alignment errors.
    (PUSH2_UNCHECKED): Don't shift negative signed value to the
    left.
    (SLOOP): Permit LOOP to be set to 0, which inhibits the
    execution of instructions it affects.
    (sfnt_address_zp2, sfnt_address_zp1, sfnt_address_zp0): Permit X
    and Y to be NULL.
    (sfnt_dot_fix_14): Guarantee that the final value is rounded to
    negative infinity, not zero.
    (sfnt_project_zp1_zp0_org): New function.
    (sfnt_interpret_mdrp): Avoid rounding issues by computing
    original distance from unscaled coordinates, if at all possible.
    (sfnt_interpret_simple_glyph, sfnt_interpret_compound_glyph_2):
    Set zone->simple.
    (all_tests) <LOOP>: Update test.
    (sfnt_identify_instruction, main): Adjust tests.
    
    * src/sfnt.h (struct sfnt_interpreter_zone): New field simple.
---
 src/sfnt.c | 161 +++++++++++++++++++++++++++++++++++++++++++++++--------------
 src/sfnt.h |   4 ++
 2 files changed, 128 insertions(+), 37 deletions(-)

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



reply via email to

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