]> git.eshelyaron.com Git - emacs.git/commitdiff
Ascertain font spacing from post table if present
authorPo Lu <luangruo@yahoo.com>
Mon, 30 Oct 2023 07:32:58 +0000 (15:32 +0800)
committerPo Lu <luangruo@yahoo.com>
Mon, 30 Oct 2023 07:33:27 +0000 (15:33 +0800)
* src/sfnt.c (sfnt_table_names): Introduce name of post table.
(sfnt_read_post_table): New function.
(main): New tests.

* src/sfnt.h (struct sfnt_post_table): New struct.

* src/sfntfont.c (sfnt_enum_font_1): Read post table, and set
spacing from its is_fixed_pitch value.
(sfntfont_list_1): Compare spacing between both fonts if
supplied in the font spec.
(sfntfont_open): Set FONT_FILE_INDEX as well as
FONT_FULLNAME_INDEX.

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

index 7559055e8c27a7ed4789bfb542182469609bf28c..8ec19290859efa220d4c14453709fb8190951b06 100644 (file)
@@ -158,6 +158,7 @@ static uint32_t sfnt_table_names[] =
     [SFNT_TABLE_CVAR] = 0x63766172,
     [SFNT_TABLE_AVAR] = 0x61766172,
     [SFNT_TABLE_OS_2] = 0x4f532f32,
+    [SFNT_TABLE_POST] = 0x706f7374,
   };
 
 /* Swap values from TrueType to system byte order.  */
@@ -15474,6 +15475,69 @@ sfnt_read_OS_2_table (int fd, struct sfnt_offset_subtable *subtable)
 
 \f
 
+/* PostScript metadata retrieval.
+
+   TrueType fonts electively incorporate a table of miscellaneous
+   information concerning such matters as the underline position or
+   whether the font is fixed pitch.  This table also assigns
+   human-readable names to glyphs, subject to the table format, but
+   these names are not read by the functions defined below.  */
+
+/* Read the header of a post table from the given font FD.  Refer to
+   the table directory SUBTABLE for its location.
+
+   Return the post table header if successful, NULL otherwise.  */
+
+TEST_STATIC struct sfnt_post_table *
+sfnt_read_post_table (int fd, struct sfnt_offset_subtable *subtable)
+{
+  struct sfnt_post_table *post;
+  struct sfnt_table_directory *directory;
+  ssize_t rc;
+
+  /* Search for the post table within SUBTABLE.  */
+
+  directory = sfnt_find_table (subtable, SFNT_TABLE_POST);
+
+  if (!directory)
+    return NULL;
+
+  /* Although the size of the table is affected by its format, this
+     function is meant to read only its header; guarantee that the
+     directory is that large.  */
+
+  if (directory->length < sizeof *post)
+    return NULL;
+
+  /* Seek to the location given in the directory.  */
+  if (lseek (fd, directory->offset, SEEK_SET) == (off_t) -1)
+    return NULL;
+
+  post = xmalloc (sizeof *post);
+  rc = read (fd, post, sizeof *post);
+
+  if (rc == -1 || rc != sizeof *post)
+    {
+      xfree (post);
+      return NULL;
+    }
+
+  /* Byte swap the data retrieved.  */
+  sfnt_swap32 (&post->format);
+  sfnt_swap32 (&post->italic_angle);
+  sfnt_swap16 (&post->underline_position);
+  sfnt_swap16 (&post->underline_thickness);
+  sfnt_swap32 (&post->is_fixed_pitch);
+  sfnt_swap32 (&post->min_mem_type_42);
+  sfnt_swap32 (&post->max_mem_type_42);
+  sfnt_swap32 (&post->min_mem_type_1);
+  sfnt_swap32 (&post->max_mem_type_1);
+
+  return post;
+}
+
+\f
+
 #ifdef TEST
 
 struct sfnt_test_dcontext
@@ -19359,6 +19423,7 @@ main (int argc, char **argv)
   struct sfnt_avar_table *avar;
   struct sfnt_cvar_table *cvar;
   struct sfnt_OS_2_table *OS_2;
+  struct sfnt_post_table *post;
   sfnt_fixed scale;
   char *fancy;
   int *advances;
@@ -19495,6 +19560,7 @@ main (int argc, char **argv)
   gvar = sfnt_read_gvar_table (fd, font);
   avar = sfnt_read_avar_table (fd, font);
   OS_2 = sfnt_read_OS_2_table (fd, font);
+  post = sfnt_read_post_table (fd, font);
   cvar = NULL;
   hmtx = NULL;
 
@@ -19515,6 +19581,17 @@ main (int argc, char **argv)
     fprintf (stderr, "OS/2 table found!\nach_vendor_id: %.4s\n",
             OS_2->ach_vendor_id);
 
+  if (post)
+    fprintf (stderr, "post table: format: %g; italic-angle: %g;\n"
+            "underline_position: %"PRIi16"; underline_thickness: %"
+            PRIi16";\n"
+            "is_fixed_pitch: %"PRIu32"\n",
+            sfnt_coerce_fixed (post->format),
+            sfnt_coerce_fixed (post->italic_angle),
+            post->underline_position,
+            post->underline_thickness,
+            post->is_fixed_pitch);
+
   if (fvar)
     {
       fprintf (stderr, "FVAR table found!\n"
@@ -20178,6 +20255,7 @@ main (int argc, char **argv)
   xfree (avar);
   xfree (cvar);
   xfree (OS_2);
+  xfree (post);
 
   return 0;
 }
index 41c1f6f74e8666ac218e837d3ab6c6c76dac4479..f6ab6a6eebd30bd40a0101014a061e4ec635f9d2 100644 (file)
@@ -53,6 +53,7 @@ enum sfnt_table
     SFNT_TABLE_CVAR,
     SFNT_TABLE_AVAR,
     SFNT_TABLE_OS_2,
+    SFNT_TABLE_POST,
   };
 
 #define SFNT_ENDOF(type, field, type1)                 \
@@ -1413,6 +1414,45 @@ struct sfnt_OS_2_table
 
 \f
 
+/* PostScript metadata.  */
+
+struct sfnt_post_table
+{
+  /* Format of this table.  This is a fixed point number rather than
+     an integer.  */
+  sfnt_fixed format;
+
+  /* Italic angle in degrees.  */
+  sfnt_fixed italic_angle;
+
+  /* Underline position.  */
+  sfnt_fword underline_position;
+
+  /* Underline thickness.  */
+  sfnt_fword underline_thickness;
+
+  /* Whether the font is monospaced.  */
+  uint32_t is_fixed_pitch;
+
+  /* Minimum memory usage (on a PostScript printer) when a TrueType
+     font is downloaded as a Type 42 font.  */
+  uint32_t min_mem_type_42;
+
+  /* Maximum memory usage (on a PostScript printer) when a TrueType
+     font is downloaded as a Type 42 font.  */
+  uint32_t max_mem_type_42;
+
+  /* Minimum memory usage (on a PostScript printer) when a TrueType
+     font is downloaded as a Type 42 font.  */
+  uint32_t min_mem_type_1;
+
+  /* Maximum memory usage (on a PostScript printer) when a TrueType
+     font is downloaded as a Type 42 font.  */
+  uint32_t max_mem_type_1;
+};
+
+\f
+
 #define SFNT_CEIL_FIXED(fixed) (((fixed) + 0177777) & 037777600000)
 #define SFNT_FLOOR_FIXED(fixed) ((fixed) & 037777600000)
 
@@ -1594,6 +1634,14 @@ extern struct sfnt_OS_2_table *sfnt_read_OS_2_table (PROTOTYPE);
 
 #undef PROTOTYPE
 
+\f
+
+#define PROTOTYPE int, struct sfnt_offset_subtable *
+
+extern struct sfnt_post_table *sfnt_read_post_table (PROTOTYPE);
+
+#undef PROTOTYPE
+
 #endif /* TEST */
 
 \f
index 35b37396ccdddaa5f6459ae3b933d1a520fa41a2..8d87df477eab8f71df5179569cbf5543ef3e303b 100644 (file)
@@ -962,6 +962,7 @@ sfnt_enum_font_1 (int fd, const char *file,
   struct sfnt_maxp_table *maxp;
   struct sfnt_fvar_table *fvar;
   struct sfnt_OS_2_table *OS_2;
+  struct sfnt_post_table *post;
   struct sfnt_font_desc temp;
   Lisp_Object family, style, instance, style1;
   int i;
@@ -1041,12 +1042,25 @@ sfnt_enum_font_1 (int fd, const char *file,
   if (meta)
     sfnt_parse_languages (meta, desc);
 
-  /* Figure out the spacing.  Some fancy test like what Fontconfig
-     does is probably in order but not really necessary.  */
-  if (!NILP (Fstring_search (Fdowncase (family),
-                            build_string ("mono"),
-                            Qnil)))
-    desc->spacing = 100; /* FC_MONO */
+  /* Check whether the font claims to be a fixed pitch font and forgo
+     the rudimentary detection below if so.  */
+
+  post = sfnt_read_post_table (fd, subtables);
+
+  if (post)
+    {
+      desc->spacing = (post->is_fixed_pitch ? 100 : 0);
+      xfree (post);
+    }
+  else
+    {
+      /* Figure out the spacing.  Some fancy test like what Fontconfig
+        does is probably in order but not really necessary.  */
+      if (!NILP (Fstring_search (Fdowncase (family),
+                                build_string ("mono"),
+                                Qnil)))
+       desc->spacing = 100; /* FC_MONO */
+    }
 
   /* Finally add mac-style flags.  Allow them to override styles that
      have not been found.  */
@@ -1654,6 +1668,12 @@ sfntfont_list_1 (struct sfnt_font_desc *desc, Lisp_Object spec,
       && !sfntfont_registries_compatible_p (tem, desc->registry))
     return 0;
 
+  /* If the font spacings disagree, reject this font also.  */
+
+  tem = AREF (spec, FONT_SPACING_INDEX);
+  if (FIXNUMP (tem) && (XFIXNUM (tem) != desc->spacing))
+    return 0;
+
   /* Check the style.  If DESC is a fixed font, just check once.
      Otherwise, check each instance.  */
 
@@ -1869,8 +1889,7 @@ sfntfont_desc_to_entity (struct sfnt_font_desc *desc, int instance)
   /* Size of 0 means the font is scalable.  */
   ASET (entity, FONT_SIZE_INDEX, make_fixnum (0));
   ASET (entity, FONT_AVGWIDTH_INDEX, make_fixnum (0));
-  ASET (entity, FONT_SPACING_INDEX,
-       make_fixnum (desc->spacing));
+  ASET (entity, FONT_SPACING_INDEX, make_fixnum (desc->spacing));
 
   if (instance >= 1)
     {
@@ -3227,8 +3246,7 @@ sfntfont_open (struct frame *f, Lisp_Object font_entity,
   /* Size of 0 means the font is scalable.  */
   ASET (font_object, FONT_SIZE_INDEX, make_fixnum (0));
   ASET (font_object, FONT_AVGWIDTH_INDEX, make_fixnum (0));
-  ASET (font_object, FONT_SPACING_INDEX,
-       make_fixnum (desc->spacing));
+  ASET (font_object, FONT_SPACING_INDEX, make_fixnum (desc->spacing));
 
   /* Set the font style.  */
 
@@ -3354,6 +3372,7 @@ sfntfont_open (struct frame *f, Lisp_Object font_entity,
   /* And set a reasonable full name, namely the name of the font
      file.  */
   font->props[FONT_FULLNAME_INDEX]
+    = font->props[FONT_FILE_INDEX]
     = DECODE_FILE (build_unibyte_string (desc->path));
 
   /* All done.  */