Extract font foundry metadata from the OS/2 table

* src/sfnt.c (sfnt_table_names): Append an entry for OS/2
tables.
(sfnt_read_OS_2_table): New function.
(main): Introduce a new test for the OS/2 table reader.

* src/sfnt.h (sfnt_read_OS_2_table): New declaration.

* src/sfntfont.c (sfnt_decode_foundry_name): Delete function.
(sfnt_enum_font_1): Read the font's OS/2 table and extract the
foundry name from there.  Use `misc' if absent.
(sfntfont_desc_to_entity, sfntfont_open): Cease interning
desc->designer, as that is now a symbol.
(syms_of_sfntfont) <Qmisc>: New defsym Qmisc.  (bug#65865)
This commit is contained in:
Po Lu 2023-09-12 10:37:55 +08:00
parent e25ad6e2a3
commit c465740273
3 changed files with 237 additions and 37 deletions

View file

@ -157,6 +157,7 @@ static uint32_t sfnt_table_names[] =
[SFNT_TABLE_GVAR] = 0x67766172,
[SFNT_TABLE_CVAR] = 0x63766172,
[SFNT_TABLE_AVAR] = 0x61766172,
[SFNT_TABLE_OS_2] = 0x4f532f32,
};
/* Swap values from TrueType to system byte order. */
@ -15296,6 +15297,110 @@ sfnt_vary_interpreter (struct sfnt_interpreter *interpreter,
/* OS/2 metadata retrieval.
A font's `OS/2' table incorporates some miscellaneous information
that is consulted by the font scaler on MS-Windows. Emacs requires
one fragment of this information: the font foundry name. */
/* Read an OS/2 table from the given font FD. Use the table directory
provided in SUBTABLE.
Return the OS/2 table if successful, NULL otherwise. */
TEST_STATIC struct sfnt_OS_2_table *
sfnt_read_OS_2_table (int fd, struct sfnt_offset_subtable *subtable)
{
struct sfnt_OS_2_table *OS_2;
struct sfnt_table_directory *directory;
ssize_t rc;
size_t minimum, wanted;
/* Search for the OS/2 table within SUBTABLE. */
directory = sfnt_find_table (subtable, SFNT_TABLE_OS_2);
if (!directory)
return NULL;
/* Calculate how large the table must be. The field `panose' is the
last field aligned to natural boundaries, and thus contents must
be read twice: once to populate the table with information up to
`panose', and once again to retrieve the information
afterwards. */
minimum = (SFNT_ENDOF (struct sfnt_OS_2_table, panose,
unsigned char[10])
+ SFNT_ENDOF (struct sfnt_OS_2_table, fs_last_char_index,
uint16_t)
- offsetof (struct sfnt_OS_2_table, ul_unicode_range));
/* If the table is too short, return. */
if (directory->length < minimum)
return NULL;
/* Seek to the location given in the directory. */
if (lseek (fd, directory->offset, SEEK_SET) == (off_t) -1)
return NULL;
OS_2 = xmalloc (sizeof *OS_2);
/* Read data up to the end of `panose'. */
wanted = SFNT_ENDOF (struct sfnt_OS_2_table, panose,
unsigned char[10]);
rc = read (fd, OS_2, wanted);
if (rc != wanted)
{
xfree (OS_2);
return NULL;
}
/* Byte swap that data. */
sfnt_swap16 (&OS_2->version);
sfnt_swap16 (&OS_2->x_avg_char_width);
sfnt_swap16 (&OS_2->us_weight_class);
sfnt_swap16 (&OS_2->us_width_class);
sfnt_swap16 (&OS_2->fs_type);
sfnt_swap16 (&OS_2->y_subscript_x_size);
sfnt_swap16 (&OS_2->y_subscript_y_size);
sfnt_swap16 (&OS_2->y_subscript_x_offset);
sfnt_swap16 (&OS_2->y_subscript_y_offset);
sfnt_swap16 (&OS_2->y_superscript_x_size);
sfnt_swap16 (&OS_2->y_superscript_y_size);
sfnt_swap16 (&OS_2->y_superscript_x_offset);
sfnt_swap16 (&OS_2->y_superscript_y_offset);
sfnt_swap16 (&OS_2->y_strikeout_size);
sfnt_swap16 (&OS_2->y_strikeout_position);
sfnt_swap16 (&OS_2->s_family_class);
/* Read fields between ul_unicode_range and fs_last_char_index. */
wanted = (SFNT_ENDOF (struct sfnt_OS_2_table, fs_last_char_index,
uint16_t)
- offsetof (struct sfnt_OS_2_table, ul_unicode_range));
rc = read (fd, &OS_2->ul_unicode_range, wanted);
if (rc != wanted)
{
xfree (OS_2);
return NULL;
}
/* Swap the remainder and return the table. */
sfnt_swap32 (&OS_2->ul_unicode_range[0]);
sfnt_swap32 (&OS_2->ul_unicode_range[1]);
sfnt_swap32 (&OS_2->ul_unicode_range[2]);
sfnt_swap32 (&OS_2->ul_unicode_range[3]);
sfnt_swap16 (&OS_2->fs_selection);
sfnt_swap16 (&OS_2->fs_first_char_index);
sfnt_swap16 (&OS_2->fs_last_char_index);
return OS_2;
}
#ifdef TEST
struct sfnt_test_dcontext
@ -19158,6 +19263,7 @@ main (int argc, char **argv)
struct sfnt_gvar_table *gvar;
struct sfnt_avar_table *avar;
struct sfnt_cvar_table *cvar;
struct sfnt_OS_2_table *OS_2;
sfnt_fixed scale;
char *fancy;
int *advances;
@ -19293,6 +19399,7 @@ main (int argc, char **argv)
fvar = sfnt_read_fvar_table (fd, font);
gvar = sfnt_read_gvar_table (fd, font);
avar = sfnt_read_avar_table (fd, font);
OS_2 = sfnt_read_OS_2_table (fd, font);
cvar = NULL;
hmtx = NULL;
@ -19309,6 +19416,10 @@ main (int argc, char **argv)
loca_long = NULL;
loca_short = NULL;
if (OS_2)
fprintf (stderr, "OS/2 table found!\nach_vendor_id: %.4s\n",
OS_2->ach_vendor_id);
if (fvar)
{
fprintf (stderr, "FVAR table found!\n"
@ -19971,6 +20082,7 @@ main (int argc, char **argv)
xfree (gvar);
xfree (avar);
xfree (cvar);
xfree (OS_2);
return 0;
}

View file

@ -52,6 +52,7 @@ enum sfnt_table
SFNT_TABLE_GVAR,
SFNT_TABLE_CVAR,
SFNT_TABLE_AVAR,
SFNT_TABLE_OS_2,
};
#define SFNT_ENDOF(type, field, type1) \
@ -1333,6 +1334,85 @@ struct sfnt_metrics_distortion
/* OS/2 font metadata. */
struct sfnt_OS_2_table
{
/* Table version number. */
uint16_t version;
/* Average weighted advance width of lower case letters and
space. */
int16_t x_avg_char_width;
/* Wisual weight (degree of blackness or thickness) of stroke in
glyphs. */
uint16_t us_weight_class;
/* Relative change from the normal aspect ratio (width to height
ratio) as specified by a font designer for the glyphs in the
font. */
uint16_t us_width_class;
/* Miscellaneous font attributes. */
int16_t fs_type;
/* Recommended horizontal size in pixels for subscripts. */
int16_t y_subscript_x_size;
/* Recommended vertical subscript size. */
int16_t y_subscript_y_size;
/* Recommended horizontal offset for subscripts. */
int16_t y_subscript_x_offset;
/* Recommended vertical offset from the baseline for subscripts. */
int16_t y_subscript_y_offset;
/* Recommended horizontal size in pixels for superscripts. */
int16_t y_superscript_x_size;
/* Recommended vertical superscript size. */
int16_t y_superscript_y_size;
/* Recommended horizontal offset for superscripts. */
int16_t y_superscript_x_offset;
/* Recommended vertical offset from the baseline for superscripts. */
int16_t y_superscript_y_offset;
/* Width of the strikeout stroke. */
int16_t y_strikeout_size;
/* Position of the strikeout stroke relative to the baseline. */
int16_t y_strikeout_position;
/* Font family classification. */
int16_t s_family_class;
/* Microsoft ``panose'' classification. */
unsigned char panose[10];
/* Alignment boundary! */
/* Unicode range specification. */
uint32_t ul_unicode_range[4];
/* Font foundry name. */
char ach_vendor_id[4];
/* Two byte bitfield providing the nature of font patterns. */
uint16_t fs_selection;
/* The minimum Unicode codepoint covered. */
uint16_t fs_first_char_index;
/* The maximum Unicode codepoint covered. */
uint16_t fs_last_char_index;
};
#define SFNT_CEIL_FIXED(fixed) (((fixed) + 0177777) & 037777600000)
#define SFNT_FLOOR_FIXED(fixed) ((fixed) & 037777600000)
@ -1500,6 +1580,14 @@ extern int sfnt_vary_compound_glyph (struct sfnt_blend *, sfnt_glyph,
struct sfnt_glyph *,
struct sfnt_metrics_distortion *);
#define PROTOTYPE int, struct sfnt_offset_subtable *
extern struct sfnt_OS_2_table *sfnt_read_OS_2_table (PROTOTYPE);
#undef PROTOTYPE
#endif /* TEST */

View file

@ -109,7 +109,7 @@ struct sfnt_font_desc
/* Style name of the font. */
Lisp_Object style;
/* Designer (foundry) of the font. */
/* The font foundry name, or `misc' if not present. */
Lisp_Object designer;
/* Style tokens that could not be parsed. */
@ -365,28 +365,6 @@ sfnt_decode_family_style (struct sfnt_name_table *name,
return (!NILP (*family) && !NILP (*style)) ? 0 : 1;
}
/* Decode the foundry names from the name table NAME. Return the
foundry name, or nil upon failure. */
static Lisp_Object
sfnt_decode_foundry_name (struct sfnt_name_table *name)
{
struct sfnt_name_record designer_rec;
unsigned char *designer_data;
designer_data = sfnt_find_name (name, SFNT_NAME_DESIGNER,
&designer_rec);
if (!designer_data)
return Qnil;
return sfnt_decode_font_string (designer_data,
designer_rec.platform_id,
designer_rec.platform_specific_id,
designer_rec.language_id,
designer_rec.length);
}
/* Decode the name of the specified font INSTANCE using the given NAME
table. Return the name of that instance, or nil upon failure. */
@ -972,9 +950,11 @@ sfnt_enum_font_1 (int fd, const char *file,
struct sfnt_meta_table *meta;
struct sfnt_maxp_table *maxp;
struct sfnt_fvar_table *fvar;
struct sfnt_OS_2_table *OS_2;
struct sfnt_font_desc temp;
Lisp_Object family, style, instance, style1;
int i;
char buffer[5];
/* Create the font desc and copy in the file name. */
desc = xzalloc (sizeof *desc + strlen (file) + 1);
@ -1013,10 +993,33 @@ sfnt_enum_font_1 (int fd, const char *file,
/* Set the family. */
desc->family = family;
desc->designer = sfnt_decode_foundry_name (name);
desc->char_cache = Qnil;
desc->subtable.platform_id = 500;
/* Now set the font foundry name. This information is located
within the OS/2 table's `ach_vendor_id' field, but use `misc' as
a recourse if it is not present. */
OS_2 = sfnt_read_OS_2_table (fd, subtables);
if (OS_2)
{
memcpy (buffer, OS_2->ach_vendor_id,
sizeof OS_2->ach_vendor_id);
buffer[sizeof OS_2->ach_vendor_id] = '\0';
/* If the foundry name is empty, use `misc' instead. */
if (!buffer[0])
desc->designer = Qmisc;
else
desc->designer = intern (buffer);
xfree (OS_2);
}
else
desc->designer = Qmisc;
/* Set the largest glyph identifier. */
desc->num_glyphs = maxp->num_glyphs;
@ -1843,11 +1846,7 @@ sfntfont_desc_to_entity (struct sfnt_font_desc *desc, int instance)
entity = font_make_entity ();
ASET (entity, FONT_TYPE_INDEX, sfnt_vendor_name);
if (!NILP (desc->designer))
ASET (entity, FONT_FOUNDRY_INDEX,
Fintern (desc->designer, Qnil));
ASET (entity, FONT_FOUNDRY_INDEX, desc->designer);
ASET (entity, FONT_FAMILY_INDEX, Fintern (desc->family, Qnil));
ASET (entity, FONT_ADSTYLE_INDEX, Qnil);
ASET (entity, FONT_REGISTRY_INDEX,
@ -3186,10 +3185,12 @@ sfntfont_open (struct frame *f, Lisp_Object font_entity,
/* Figure out the font ascent and descent. */
font->ascent
= ceil (font_info->hhea->ascent
* pixel_size * 1.0 / font_info->head->units_per_em);
* pixel_size
* (1.0 / font_info->head->units_per_em));
font->descent
= -floor (font_info->hhea->descent
* pixel_size * 1.0 / font_info->head->units_per_em);
= ceil ((-font_info->hhea->descent)
* pixel_size
* (1.0 / font_info->head->units_per_em));
font->height = font->ascent + font->descent;
/* Set font->max_width to the maximum advance width. */
@ -3198,11 +3199,7 @@ sfntfont_open (struct frame *f, Lisp_Object font_entity,
/* Set generic attributes such as type and style. */
ASET (font_object, FONT_TYPE_INDEX, sfnt_vendor_name);
if (!NILP (desc->designer))
ASET (font_object, FONT_FOUNDRY_INDEX,
Fintern (desc->designer, Qnil));
ASET (font_object, FONT_FOUNDRY_INDEX, desc->designer);
ASET (font_object, FONT_FAMILY_INDEX, Fintern (desc->family, Qnil));
ASET (font_object, FONT_ADSTYLE_INDEX, Qnil);
ASET (font_object, FONT_REGISTRY_INDEX,
@ -3956,6 +3953,9 @@ syms_of_sfntfont (void)
/* Char-table purpose. */
DEFSYM (Qfont_lookup_cache, "font-lookup-cache");
/* Default foundry name. */
DEFSYM (Qmisc, "misc");
/* Set up staticpros. */
sfnt_vendor_name = Qnil;
staticpro (&sfnt_vendor_name);