]> git.eshelyaron.com Git - emacs.git/commitdiff
Respect glyph metrics modified by instruction code
authorPo Lu <luangruo@yahoo.com>
Sat, 23 Dec 2023 03:22:21 +0000 (11:22 +0800)
committerPo Lu <luangruo@yahoo.com>
Sat, 23 Dec 2023 03:22:21 +0000 (11:22 +0800)
* src/sfnt.c (sfnt_read_glyph): Clear advance and origin
distortion returning an empty glyph.
(sfnt_build_instructed_outline): New parameter *ADVANCE_WIDTH,
in which the glyph's advance width is saved.
(sfnt_interpret_compound_glyph_1): Refine commentary.
(sfnt_verbose, main): Adjust tests.

* src/sfnt.h: Update prototypes correspondingly.

* src/sfntfont.c (sfntfont_get_glyph_outline): If an instructed
outline is available, derive the advance and lbearing from the
measurements within.
(sfntfont_probe_widths): Call sfntfont_measure_pcm to establish
average widths.
(sfntfont_open): Do so after instruction code initialization
completes.
(sfntfont_measure_pcm): Revise commentary.

src/sfnt.c
src/sfnt.h
src/sfntfont.c

index 1397e341aa8a7800f24b0488014963b97ae322cc..6698c9c27df83dc07ab5384efb952676ee854ed6 100644 (file)
@@ -2421,6 +2421,8 @@ sfnt_read_glyph (sfnt_glyph glyph_code,
       glyph.ymin = 0;
       glyph.xmax = 0;
       glyph.ymax = 0;
+      glyph.advance_distortion = 0;
+      glyph.origin_distortion = 0;
       glyph.simple = xmalloc (sizeof *glyph.simple);
       glyph.compound = NULL;
       memset (glyph.simple, 0, sizeof *glyph.simple);
@@ -12202,15 +12204,18 @@ sfnt_decompose_instructed_outline (struct sfnt_instructed_outline *outline,
 
 /* Decompose and build an outline for the specified instructed outline
    INSTRUCTED.  Return the outline data with a refcount of 0 upon
-   success, or NULL upon failure.
+   success, and the advance width of the instructed glyph in
+   *ADVANCE_WIDTH, or NULL upon failure.
 
    This function is not reentrant.  */
 
 TEST_STATIC struct sfnt_glyph_outline *
-sfnt_build_instructed_outline (struct sfnt_instructed_outline *instructed)
+sfnt_build_instructed_outline (struct sfnt_instructed_outline *instructed,
+                              sfnt_fixed *advance_width)
 {
   struct sfnt_glyph_outline *outline;
   int rc;
+  sfnt_f26dot6 x1, x2;
 
   memset (&build_outline_context, 0, sizeof build_outline_context);
 
@@ -12247,10 +12252,23 @@ sfnt_build_instructed_outline (struct sfnt_instructed_outline *instructed)
      instructed.  */
 
   if (instructed->num_points > 1)
-    outline->origin
-      = instructed->x_points[instructed->num_points - 2];
+    {
+      x1 = instructed->x_points[instructed->num_points - 2];
+      x2 = instructed->x_points[instructed->num_points - 1];
+
+      /* Convert the origin point to a 16.16 fixed point number.  */
+      outline->origin = x1 * 1024;
+
+      /* Do the same for the advance width.  */
+      *advance_width = (x2 - x1) * 1024;
+    }
   else
-    outline->origin = 0;
+    {
+      /* Phantom points are absent from this outline, which is
+        impossible.  */
+      *advance_width = 0;
+      outline->origin = 0;
+    }
 
   if (rc)
     {
@@ -13133,8 +13151,8 @@ sfnt_interpret_compound_glyph_1 (struct sfnt_glyph *glyph,
     }
 
   /* Run the program for the entire compound glyph, if any.  CONTEXT
-     should not contain phantom points by this point, so append its
-     own.  */
+     should not contain phantom points by this point, so append the
+     points for this glyph as a whole.  */
 
   /* Compute phantom points.  */
   sfnt_compute_phantom_points (glyph, metrics, interpreter->scale,
@@ -20216,6 +20234,7 @@ sfnt_verbose (struct sfnt_interpreter *interpreter)
   unsigned char opcode;
   const char *name;
   static unsigned int instructions;
+  sfnt_fixed advance;
 
   /* Build a temporary outline containing the values of the
      interpreter's glyph zone.  */
@@ -20229,7 +20248,7 @@ sfnt_verbose (struct sfnt_interpreter *interpreter)
       temp.y_points = interpreter->glyph_zone->y_current;
       temp.flags = interpreter->glyph_zone->flags;
 
-      outline = sfnt_build_instructed_outline (&temp);
+      outline = sfnt_build_instructed_outline (&temp, &advance);
 
       if (!outline)
        return;
@@ -20444,6 +20463,7 @@ main (int argc, char **argv)
   struct sfnt_instance *instance;
   struct sfnt_blend blend;
   struct sfnt_metrics_distortion distortion;
+  sfnt_fixed advance;
 
   if (argc < 2)
     return 1;
@@ -20559,8 +20579,8 @@ main (int argc, char **argv)
       return 1;
     }
 
-#define FANCY_PPEM 14
-#define EASY_PPEM  14
+#define FANCY_PPEM 12
+#define EASY_PPEM  12
 
   interpreter = NULL;
   head = sfnt_read_head_table (fd, font);
@@ -20787,6 +20807,8 @@ main (int argc, char **argv)
          if (instance && gvar)
            sfnt_vary_simple_glyph (&blend, code, glyph,
                                    &distortion);
+         else
+           memset (&distortion, 0, sizeof distortion);
 
          if (sfnt_lookup_glyph_metrics (code, -1,
                                         &metrics,
@@ -20804,7 +20826,10 @@ main (int argc, char **argv)
              exit (5);
            }
 
-         outline = sfnt_build_instructed_outline (value);
+         outline = sfnt_build_instructed_outline (value, &advance);
+         advances[i] = (advance / 65536);
+
+         fprintf (stderr, "advance: %d\n", advances[i]);
 
          if (!outline)
            exit (6);
@@ -20819,8 +20844,6 @@ main (int argc, char **argv)
          xfree (outline);
 
          rasters[i] = raster;
-         advances[i] = (sfnt_mul_fixed (metrics.advance, scale)
-                        + sfnt_mul_fixed (distortion.advance, scale));
        }
 
       sfnt_x_raster (rasters, advances, length, hhea, scale);
@@ -21085,7 +21108,7 @@ main (int argc, char **argv)
                  fprintf (stderr, "outline origin, rbearing: %"
                           PRIi32" %"PRIi32"\n",
                           outline->origin,
-                          outline->ymax - outline->origin);
+                          outline->xmax - outline->origin);
                  sfnt_test_max = outline->ymax - outline->ymin;
 
                  for (i = 0; i < outline->outline_used; i++)
@@ -21199,9 +21222,20 @@ main (int argc, char **argv)
                              printf ("rasterizing instructed outline\n");
                              if (outline)
                                xfree (outline);
-                             outline = sfnt_build_instructed_outline (value);
+                             outline
+                               = sfnt_build_instructed_outline (value,
+                                                                &advance);
                              xfree (value);
 
+#define LB outline->xmin - outline->origin
+#define RB outline->xmax - outline->origin
+                             printf ("instructed advance, lb, rb: %g %g %g\n",
+                                     sfnt_coerce_fixed (advance),
+                                     sfnt_coerce_fixed (LB),
+                                     sfnt_coerce_fixed (RB));
+#undef LB
+#undef RB
+
                              if (outline)
                                {
                                  raster
index 2ae47ad30cea72cb7c0a071bea818d08604196fc..7baed3722126cccb36e23591f89d7f50faa80977 100644 (file)
@@ -2102,7 +2102,7 @@ extern const char *sfnt_interpret_control_value_program (PROTOTYPE);
 
 #undef PROTOTYPE
 
-#define PROTOTYPE struct sfnt_instructed_outline *
+#define PROTOTYPE struct sfnt_instructed_outline *, sfnt_fixed *
 
 extern struct sfnt_glyph_outline *sfnt_build_instructed_outline (PROTOTYPE);
 
index cecdbeafb8dba2bbbfd13e3dba0d369de4db32e4..078fe6083a65253a324be911409225f4646e1a73 100644 (file)
@@ -2182,6 +2182,7 @@ sfntfont_get_glyph_outline (sfnt_glyph glyph_code,
   const char *error;
   struct sfnt_glyph_metrics temp;
   struct sfnt_metrics_distortion distortion;
+  sfnt_fixed advance;
 
   start = cache->next;
   distortion.advance = 0;
@@ -2284,23 +2285,52 @@ sfntfont_get_glyph_outline (sfnt_glyph glyph_code,
 
       if (!error)
        {
-         outline = sfnt_build_instructed_outline (value);
+         /* Now record the advance with that measured from the
+            phantom points within the instructed glyph outline, and
+            subsequently replace it once metrics are scaled.  */
+
+         outline = sfnt_build_instructed_outline (value,
+                                                  &advance);
          xfree (value);
+
+         if (outline)
+           {
+             /* Save the new advance width.  */
+             temp.advance = advance;
+
+             /* Finally, adjust the left side bearing of the glyph
+                metrics by the origin point of the outline, should a
+                transformation have been applied by either
+                instruction code or glyph variation.  The left side
+                bearing is the distance from the origin point to the
+                left most point on the X axis.  */
+             temp.lbearing = outline->xmin - outline->origin;
+           }
        }
     }
 
   if (!outline)
-    outline = sfnt_build_glyph_outline (glyph, scale,
-                                       &temp,
-                                       sfntfont_get_glyph,
-                                       sfntfont_free_glyph,
-                                       sfntfont_get_metrics,
-                                       &dcontext);
-
-  /* At this point, the glyph metrics are unscaled.  Scale them up.
-     If INTERPRETER is set, use the scale placed within.  */
-
-  sfnt_scale_metrics (&temp, scale);
+    {
+      outline = sfnt_build_glyph_outline (glyph, scale,
+                                         &temp,
+                                         sfntfont_get_glyph,
+                                         sfntfont_free_glyph,
+                                         sfntfont_get_metrics,
+                                         &dcontext);
+
+      /* At this point, the glyph metrics are unscaled.  Scale them
+        up.  If INTERPRETER is set, use the scale placed within.  */
+      sfnt_scale_metrics (&temp, scale);
+
+      /* Finally, adjust the left side bearing of the glyph metrics by
+        the origin point of the outline, should a transformation have
+        been applied by either instruction code or glyph variation.
+        The left side bearing is the distance from the origin point
+        to the left most point on the X axis.  */
+
+      if (index != -1)
+       temp.lbearing = outline->xmin - outline->origin;
+    }
 
  fail:
 
@@ -2309,13 +2339,6 @@ sfntfont_get_glyph_outline (sfnt_glyph glyph_code,
   if (!outline)
     return NULL;
 
-  if (index != -1)
-    /* Finally, adjust the left side bearing of the glyph metrics by
-       the origin point of the outline, should a distortion have been
-       applied.  The left side bearing is the distance from the origin
-       point to the left most point on the X axis.  */
-    temp.lbearing = outline->xmin - outline->origin;
-
   start = xmalloc (sizeof *start);
   start->glyph = glyph_code;
   start->outline = outline;
@@ -2625,16 +2648,23 @@ sfntfont_lookup_glyph (struct sfnt_font_info *font_info, int c)
   return glyph;
 }
 
+static int sfntfont_measure_pcm (struct sfnt_font_info *, sfnt_glyph,
+                                struct font_metrics *);
+
 /* Probe and set FONT_INFO->font.average_width,
    FONT_INFO->font.space_width, and FONT_INFO->font.min_width
-   according to the tables contained therein.  */
+   according to the tables contained therein.
+
+   As this function generates outlines for all glyphs, outlines for
+   all ASCII characters will be entered into the outline cache as
+   well.  */
 
 static void
 sfntfont_probe_widths (struct sfnt_font_info *font_info)
 {
   int i, num_characters, total_width;
   sfnt_glyph glyph;
-  struct sfnt_glyph_metrics metrics;
+  struct font_metrics pcm;
 
   num_characters = 0;
   total_width = 0;
@@ -2653,29 +2683,27 @@ sfntfont_probe_widths (struct sfnt_font_info *font_info)
       if (!glyph)
        continue;
 
-      /* Now look up the metrics of this glyph.  */
-      if (sfnt_lookup_glyph_metrics (glyph, font_info->font.pixel_size,
-                                    &metrics, font_info->hmtx,
-                                    font_info->hhea, font_info->head,
-                                    font_info->maxp))
+      /* Now look up the metrics of this glyph.  Data from the metrics
+        table doesn't fit the bill, since variations and instruction
+        code is not applied to it.  */
+      if (sfntfont_measure_pcm (font_info, glyph, &pcm))
        continue;
 
       /* Increase the number of characters.  */
       num_characters++;
 
       /* Add the advance to total_width.  */
-      total_width += SFNT_CEIL_FIXED (metrics.advance) / 65536;
+      total_width += pcm.width;
 
       /* Update min_width if it hasn't been set yet or is wider.  */
       if (font_info->font.min_width == 1
-         || font_info->font.min_width > metrics.advance / 65536)
-       font_info->font.min_width = metrics.advance / 65536;
+         || font_info->font.min_width > pcm.width)
+       font_info->font.min_width = pcm.width;
 
       /* If i is the space character, set the space width.  Make sure
         to round this up.  */
       if (i == 32)
-       font_info->font.space_width
-         = SFNT_CEIL_FIXED (metrics.advance) / 65536;
+       font_info->font.space_width = pcm.width;
     }
 
   /* Now, if characters were found, set average_width.  */
@@ -3263,9 +3291,6 @@ sfntfont_open (struct frame *f, Lisp_Object font_entity,
 
   ASET (font_object, FONT_ADSTYLE_INDEX, Qnil);
 
-  /* Find out the minimum, maximum and average widths.  */
-  sfntfont_probe_widths (font_info);
-
   /* Clear various offsets.  */
   font_info->font.baseline_offset = 0;
   font_info->font.relative_compose = 0;
@@ -3355,6 +3380,10 @@ sfntfont_open (struct frame *f, Lisp_Object font_entity,
     }
 
  cancel_blend:
+
+  /* Find out the minimum, maximum and average widths.  */
+  sfntfont_probe_widths (font_info);
+
   /* Calculate the xfld name.  */
   font->props[FONT_NAME_INDEX] = Ffont_xlfd_name (font_object, Qnil, Qt);
 
@@ -3468,7 +3497,7 @@ sfntfont_measure_pcm (struct sfnt_font_info *font, sfnt_glyph glyph,
   if (!outline)
     return 1;
 
-  /* Round the left side bearing downwards.  */
+  /* Round the left side bearing down.  */
   pcm->lbearing = SFNT_FLOOR_FIXED (metrics.lbearing) / 65536;
   pcm->rbearing = SFNT_CEIL_FIXED (outline->xmax) / 65536;