From ee256d1e25b8ab080a2715c5fc792fee516e83d1 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sun, 8 Jan 2023 15:43:09 +0800 Subject: [PATCH] Check in new files * src/sfnt.h: * src/sfntfont-android.c: * src/sfntfont.c: * src/sfntfont.h: New files. --- src/sfnt.h | 957 +++++++++++++++++++++++++++++++++++++++++ src/sfntfont-android.c | 36 ++ src/sfntfont.c | 493 +++++++++++++++++++++ src/sfntfont.h | 26 ++ 4 files changed, 1512 insertions(+) create mode 100644 src/sfnt.h create mode 100644 src/sfntfont-android.c create mode 100644 src/sfntfont.c create mode 100644 src/sfntfont.h diff --git a/src/sfnt.h b/src/sfnt.h new file mode 100644 index 00000000000..868d0f9b5a9 --- /dev/null +++ b/src/sfnt.h @@ -0,0 +1,957 @@ +/* sfnt format font support for GNU Emacs. + +Copyright (C) 2023 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at +your option) any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs. If not, write to the Free Software Foundation, +Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _SFNT_H_ +#define _SFNT_H_ + +#include +#include + + + +/* Container structure and enumerator definitions. */ + +/* The sfnt container format is organized into different tables, such + as ``cmap'' or ``glyf''. Each of these tables has a specific + format and use. These are all the tables known to Emacs. */ + +enum sfnt_table + { + SFNT_TABLE_CMAP, + SFNT_TABLE_GLYF, + SFNT_TABLE_HEAD, + SFNT_TABLE_HHEA, + SFNT_TABLE_HMTX, + SFNT_TABLE_LOCA, + SFNT_TABLE_MAXP, + SFNT_TABLE_NAME, + SFNT_TABLE_META, + }; + +#define SFNT_ENDOF(type, field, type1) \ + ((size_t) offsetof (type, field) + sizeof (type1)) + +/* Each of these structures must be aligned so that no compiler will + ever generate padding bytes on platforms where the alignment + requirements for uint32_t and uint16_t are no larger than 4 and 2 + bytes respectively. */ + +struct sfnt_offset_subtable +{ + /* The scaler type. */ + uint32_t scaler_type; + + /* The number of tables. */ + uint16_t num_tables; + + /* (Maximum power of 2 <= numTables) * 16. */ + uint16_t search_range; + + /* log2 (maximum power of 2 <= numTables) */ + uint16_t entry_selector; + + /* numTables * 16 - searchRange. */ + uint16_t range_shift; + + /* Variable length data. */ + struct sfnt_table_directory *subtables; +}; + +/* The table directory. Follows the offset subtable, with one for + each table. */ + +struct sfnt_table_directory +{ + /* 4-byte identifier for each table. See sfnt_table_names. */ + uint32_t tag; + + /* Table checksum. */ + uint32_t checksum; + + /* Offset from the start of the file. */ + uint32_t offset; + + /* Length of the table in bytes, not subject to padding. */ + uint32_t length; +}; + +enum sfnt_scaler_type + { + SFNT_SCALER_TRUE = 0x74727565, + SFNT_SCALER_VER1 = 0x00010000, + SFNT_SCALER_TYP1 = 0x74797031, + SFNT_SCALER_OTTO = 0x4F54544F, + }; + +typedef int32_t sfnt_fixed; +typedef int16_t sfnt_fword; +typedef uint16_t sfnt_ufword; + +#define sfnt_coerce_fixed(fixed) ((sfnt_fixed) (fixed) / 65535.0) + +typedef unsigned int sfnt_glyph; +typedef unsigned int sfnt_char; + +struct sfnt_head_table +{ + /* The version. This is a 16.16 fixed point number. */ + sfnt_fixed version; + + /* The revision. */ + sfnt_fixed revision; + + /* Checksum adjustment. */ + uint32_t checksum_adjustment; + + /* Magic number, should be 0x5F0F3CF5. */ + uint32_t magic; + + /* Flags for the font. */ + uint16_t flags; + + /* Units per em. */ + uint16_t units_per_em; + + /* Time of creation. */ + uint32_t created_high, created_low; + + /* Time of modification. */ + uint32_t modified_high, modified_low; + + /* Minimum bounds. */ + sfnt_fword xmin, ymin, xmax, ymax; + + /* Mac specific stuff. */ + uint16_t mac_style; + + /* Smallest readable size in pixels. */ + uint16_t lowest_rec_ppem; + + /* Font direction hint. */ + int16_t font_direction_hint; + + /* Index to loc format. 0 for short offsets, 1 for long. */ + int16_t index_to_loc_format; + + /* Unused. */ + int16_t glyph_data_format; +}; + +struct sfnt_hhea_table +{ + /* The version. This is a 16.16 fixed point number. */ + sfnt_fixed version; + + /* The maximum ascent and descent values for this font. */ + sfnt_fword ascent, descent; + + /* The typographic line gap. */ + sfnt_fword line_gap; + + /* The maximum advance width. */ + sfnt_ufword advance_width_max; + + /* The minimum bearings on either side. */ + sfnt_fword min_left_side_bearing, min_right_side_bearing; + + /* The maximum extent. */ + sfnt_fword x_max_extent; + + /* Caret slope. */ + int16_t caret_slope_rise, caret_slope_run; + + /* Caret offset for non slanted fonts. */ + sfnt_fword caret_offset; + + /* Reserved values. */ + int16_t reserved1, reserved2, reserved3, reserved4; + + /* Should always be zero. */ + int16_t metric_data_format; + + /* Number of advanced widths in metrics table. */ + uint16_t num_of_long_hor_metrics; +}; + +struct sfnt_cmap_table +{ + /* Should be zero. */ + uint16_t version; + + /* Number of subtables. */ + uint16_t num_subtables; +}; + +enum sfnt_platform_id + { + SFNT_PLATFORM_UNICODE = 0, + SFNT_PLATFORM_MACINTOSH = 1, + SFNT_PLATFORM_RESERVED = 2, + SFNT_PLATFORM_MICROSOFT = 3, + }; + +enum sfnt_unicode_platform_specific_id + { + SFNT_UNICODE_1_0 = 0, + SFNT_UNICODE_1_1 = 1, + SFNT_UNICODE_ISO_10646_1993 = 2, + SFNT_UNICODE_2_0_BMP = 3, + SFNT_UNICODE_2_0 = 4, + SFNT_UNICODE_VARIATION_SEQUENCES = 5, + SFNT_UNICODE_LAST_RESORT = 6, + }; + +enum sfnt_macintosh_platform_specific_id + { + SFNT_MACINTOSH_ROMAN = 0, + SFNT_MACINTOSH_JAPANESE = 1, + SFNT_MACINTOSH_TRADITIONAL_CHINESE = 2, + SFNT_MACINTOSH_KOREAN = 3, + SFNT_MACINTOSH_ARABIC = 4, + SFNT_MACINTOSH_HEBREW = 5, + SFNT_MACINTOSH_GREEK = 6, + SFNT_MACINTOSH_RUSSIAN = 7, + SFNT_MACINTOSH_RSYMBOL = 8, + SFNT_MACINTOSH_DEVANGARI = 9, + SFNT_MACINTOSH_GURMUKHI = 10, + SFNT_MACINTOSH_GUJARATI = 11, + SFNT_MACINTOSH_ORIYA = 12, + SFNT_MACINTOSH_BENGALI = 13, + SFNT_MACINTOSH_TAMIL = 14, + SFNT_MACINTOSH_TELUGU = 15, + SFNT_MACINTOSH_KANNADA = 16, + SFNT_MACINTOSH_MALAYALAM = 17, + SFNT_MACINTOSH_SINHALESE = 18, + SFNT_MACINTOSH_BURMESE = 19, + SFNT_MACINTOSH_KHMER = 20, + SFNT_MACINTOSH_THAI = 21, + SFNT_MACINTOSH_LAOTIAN = 22, + SFNT_MACINTOSH_GEORGIAN = 23, + SFNT_MACINTOSH_ARMENIAN = 24, + SFNT_MACINTOSH_SIMPLIFIED_CHINESE = 25, + SFNT_MACINTOSH_TIBETIAN = 26, + SFNT_MACINTOSH_MONGOLIAN = 27, + SFNT_MACINTOSH_GEEZ = 28, + SFNT_MACINTOSH_SLAVIC = 29, + SFNT_MACINTOSH_VIETNAMESE = 30, + SFNT_MACINTOSH_SINDHI = 31, + SFNT_MACINTOSH_UNINTERPRETED = 32, + }; + +enum sfnt_microsoft_platform_specific_id + { + SFNT_MICROSOFT_SYMBOL = 0, + SFNT_MICROSOFT_UNICODE_BMP = 1, + SFNT_MICROSOFT_SHIFT_JIS = 2, + SFNT_MICROSOFT_PRC = 3, + SFNT_MICROSOFT_BIG_FIVE = 4, + SFNT_MICROSOFT_WANSUNG = 5, + SFNT_MICROSOFT_JOHAB = 6, + SFNT_MICROSOFT_UNICODE_UCS_4 = 10, + }; + +struct sfnt_cmap_encoding_subtable +{ + /* The platform ID. */ + uint16_t platform_id; + + /* Platform specific ID. */ + uint16_t platform_specific_id; + + /* Mapping table offset. */ + uint32_t offset; +}; + +struct sfnt_cmap_encoding_subtable_data +{ + /* Format and possibly the length in bytes. */ + uint16_t format, length; +}; + +struct sfnt_cmap_format_0 +{ + /* Format, set to 0. */ + uint16_t format; + + /* Length in bytes. Should be 262. */ + uint16_t length; + + /* Language code. */ + uint16_t language; + + /* Character code to glyph index map. */ + uint8_t glyph_index_array[256]; +}; + +struct sfnt_cmap_format_2_subheader +{ + uint16_t first_code; + uint16_t entry_count; + int16_t id_delta; + uint16_t id_range_offset; +}; + +struct sfnt_cmap_format_2 +{ + /* Format, set to 2. */ + uint16_t format; + + /* Length in bytes. */ + uint16_t length; + + /* Language code. */ + uint16_t language; + + /* Array mapping high bytes to subheaders. */ + uint16_t sub_header_keys[256]; + + /* Variable length data. */ + struct sfnt_cmap_format_2_subheader *subheaders; + uint16_t *glyph_index_array; + uint16_t num_glyphs; +}; + +struct sfnt_cmap_format_4 +{ + /* Format, set to 4. */ + uint16_t format; + + /* Length in bytes. */ + uint16_t length; + + /* Language code. */ + uint16_t language; + + /* 2 * seg_count. */ + uint16_t seg_count_x2; + + /* 2 * (2**FLOOR(log2(segCount))) */ + uint16_t search_range; + + /* log2(searchRange/2) */ + uint16_t entry_selector; + + /* Variable-length data. */ + uint16_t *end_code; + uint16_t *reserved_pad; + uint16_t *start_code; + int16_t *id_delta; + int16_t *id_range_offset; + uint16_t *glyph_index_array; + + /* The number of elements in glyph_index_array. */ + size_t glyph_index_size; +}; + +struct sfnt_cmap_format_6 +{ + /* Format, set to 6. */ + uint16_t format; + + /* Length in bytes. */ + uint16_t length; + + /* Language code. */ + uint16_t language; + + /* First character code in subrange. */ + uint16_t first_code; + + /* Number of character codes. */ + uint16_t entry_count; + + /* Variable-length data. */ + uint16_t *glyph_index_array; +}; + +struct sfnt_cmap_format_8_or_12_group +{ + uint32_t start_char_code; + uint32_t end_char_code; + uint32_t start_glyph_code; +}; + +struct sfnt_cmap_format_8 +{ + /* Format, set to 8. */ + uint16_t format; + + /* Reserved. */ + uint16_t reserved; + + /* Length in bytes. */ + uint32_t length; + + /* Language code. */ + uint32_t language; + + /* Tightly packed array of bits (8K bytes total) indicating whether + the particular 16-bit (index) value is the start of a 32-bit + character code. */ + uint8_t is32[65536]; + + /* Number of groups. */ + uint32_t num_groups; + + /* Variable length data. */ + struct sfnt_cmap_format_8_or_12_group *groups; +}; + +/* cmap formats 10, 13 and 14 unsupported. */ + +struct sfnt_cmap_format_12 +{ + /* Format, set to 12. */ + uint16_t format; + + /* Reserved. */ + uint16_t reserved; + + /* Length in bytes. */ + uint32_t length; + + /* Language code. */ + uint32_t language; + + /* Number of groups. */ + uint32_t num_groups; + + /* Variable length data. */ + struct sfnt_cmap_format_8_or_12_group *groups; +}; + +struct sfnt_maxp_table +{ + /* Table version. */ + sfnt_fixed version; + + /* The number of glyphs in this font - 1. Set at version 0.5 or + later. */ + uint16_t num_glyphs; + + /* These fields are only set in version 1.0 or later. Maximum + points in a non-composite glyph. */ + uint16_t max_points; + + /* Maximum contours in a non-composite glyph. */ + uint16_t max_contours; + + /* Maximum points in a composite glyph. */ + uint16_t max_composite_points; + + /* Maximum contours in a composite glyph. */ + uint16_t max_composite_contours; + + /* 1 if instructions do not use the twilight zone (Z0), or 2 if + instructions do use Z0; should be set to 2 in most cases. */ + uint16_t max_zones; + + /* Maximum points used in Z0. */ + uint16_t max_twilight_points; + + /* Number of Storage Area locations. */ + uint16_t max_storage; + + /* Number of FDEFs, equal to the highest function number + 1. */ + uint16_t max_function_defs; + + /* Number of IDEFs. */ + uint16_t max_instruction_defs; + + /* Maximum stack depth across Font Program ('fpgm' table), CVT + Program ('prep' table) and all glyph instructions (in the 'glyf' + table). */ + uint16_t max_stack_elements; + + /* Maximum byte count for glyph instructions. */ + uint16_t max_size_of_instructions; + + /* Maximum number of components referenced at ``top level'' for any + composite glyph. */ + uint16_t max_component_elements; + + /* Maximum levels of recursion; 1 for simple components. */ + uint16_t max_component_depth; +}; + +struct sfnt_loca_table_short +{ + /* Offsets to glyph data divided by two. */ + uint16_t *offsets; + + /* Size of the offsets list. */ + size_t num_offsets; +}; + +struct sfnt_loca_table_long +{ + /* Offsets to glyph data. */ + uint32_t *offsets; + + /* Size of the offsets list. */ + size_t num_offsets; +}; + +struct sfnt_glyf_table +{ + /* Size of the glyph data. */ + size_t size; + + /* Pointer to possibly unaligned glyph data. */ + unsigned char *glyphs; +}; + +struct sfnt_simple_glyph +{ + /* The total number of points in this glyph. */ + size_t number_of_points; + + /* Array containing the last points of each contour. */ + uint16_t *end_pts_of_contours; + + /* Total number of bytes needed for instructions. */ + uint16_t instruction_length; + + /* Instruction data. */ + uint8_t *instructions; + + /* Array of flags. */ + uint8_t *flags; + + /* Array of X coordinates. */ + int16_t *x_coordinates; + + /* Array of Y coordinates. */ + int16_t *y_coordinates; + + /* Pointer to the end of that array. */ + int16_t *y_coordinates_end; +}; + +struct sfnt_compound_glyph_component +{ + /* Compound glyph flags. */ + uint16_t flags; + + /* Component glyph index. */ + uint16_t glyph_index; + + /* X-offset for component or point number; type depends on bits 0 + and 1 in component flags. */ + union { + uint8_t a; + int8_t b; + uint16_t c; + int16_t d; + } argument1; + + /* Y-offset for component or point number; type depends on bits 0 + and 1 in component flags. */ + union { + uint8_t a; + int8_t b; + uint16_t c; + int16_t d; + } argument2; + + /* Various scale formats. */ + union { + uint16_t scale; + struct { + uint16_t xscale; + uint16_t yscale; + } a; + struct { + uint16_t xscale; + uint16_t scale01; + uint16_t scale10; + uint16_t yscale; + } b; + } u; +}; + +struct sfnt_compound_glyph +{ + /* Pointer to array of components. */ + struct sfnt_compound_glyph_component *components; + + /* Number of elements in that array. */ + size_t num_components; + + /* Instruction data. */ + uint8_t *instructions; + + /* Length of instructions. */ + uint16_t instruction_length; +}; + +struct sfnt_glyph +{ + /* Number of contours in this glyph. */ + int16_t number_of_contours; + + /* Coordinate bounds. */ + sfnt_fword xmin, ymin, xmax, ymax; + + /* Either a simple glyph or a compound glyph, depending on which is + set. */ + struct sfnt_simple_glyph *simple; + struct sfnt_compound_glyph *compound; +}; + + + +/* Glyph outline decomposition. */ + +struct sfnt_point +{ + /* X and Y in em space. */ + sfnt_fixed x, y; +}; + +typedef void (*sfnt_move_to_proc) (struct sfnt_point, void *); +typedef void (*sfnt_line_to_proc) (struct sfnt_point, void *); +typedef void (*sfnt_curve_to_proc) (struct sfnt_point, + struct sfnt_point, + void *); + +typedef struct sfnt_glyph *(*sfnt_get_glyph_proc) (sfnt_glyph, void *, + bool *); +typedef void (*sfnt_free_glyph_proc) (struct sfnt_glyph *, void *); + + + +/* Decomposed glyph outline. */ + +struct sfnt_glyph_outline_command +{ + /* Flags for this outline command. */ + int flags; + + /* X and Y position of this command. */ + sfnt_fixed x, y; +}; + +/* Structure describing a single recorded outline in fixed pixel + space. */ + +struct sfnt_glyph_outline +{ + /* Array of outlines elements. */ + struct sfnt_glyph_outline_command *outline; + + /* Size of the outline data, and how much is full. */ + size_t outline_size, outline_used; + + /* Rectangle defining bounds of the outline. Namely, the minimum + and maximum X and Y positions. */ + sfnt_fixed xmin, ymin, xmax, ymax; +}; + +enum sfnt_glyph_outline_flags + { + SFNT_GLYPH_OUTLINE_LINETO = (1 << 1), + }; + +struct sfnt_build_glyph_outline_context +{ + /* The outline being built. */ + struct sfnt_glyph_outline *outline; + + /* The head table. */ + struct sfnt_head_table *head; + + /* The pixel size being used, and any extra flags to apply to the + outline at this point. */ + int pixel_size; + + /* Factor to multiply positions by to get the pixel width. */ + double factor; + + /* The position of the pen in 16.16 fixed point format. */ + sfnt_fixed x, y; +}; + + + +/* Glyph rasterization. */ + +struct sfnt_raster +{ + /* Basic dimensions of the raster. */ + unsigned short width, height; + + /* Integer offset to apply to positions in the raster. */ + unsigned short offx, offy; + + /* Pointer to coverage data. */ + unsigned char *cells; +}; + +struct sfnt_edge +{ + /* Next edge in this chain. */ + struct sfnt_edge *next; + + /* Winding direction. 1 if clockwise, -1 if counterclockwise. */ + int winding; + + /* X position, top and bottom of edges. */ + sfnt_fixed x, top, bottom; + + /* step_x is how many pixels to move for each increase in Y. */ + sfnt_fixed step_x; +}; + + + +/* Polygon rasterization constants. */ + +enum + { + SFNT_POLY_SHIFT = 2, + SFNT_POLY_SAMPLE = (1 << SFNT_POLY_SHIFT), + SFNT_POLY_MASK = (SFNT_POLY_SAMPLE - 1), + SFNT_POLY_STEP = (0x10000 >> SFNT_POLY_SHIFT), + SFNT_POLY_START = (SFNT_POLY_STEP >> 1), + }; + + + +/* Glyph metrics computation. */ + +struct sfnt_long_hor_metric +{ + uint16_t advance_width; + int16_t left_side_bearing; +}; + +struct sfnt_hmtx_table +{ + /* Array of horizontal metrics for each glyph. */ + struct sfnt_long_hor_metric *h_metrics; + + /* Lbearing for remaining glyphs. */ + int16_t *left_side_bearing; +}; + +/* Structure describing the metrics of a single glyph. The fields + mean the same as in XCharStruct, except they are 16.16 fixed point + values, and are missing significant information. */ + +struct sfnt_glyph_metrics +{ + /* Distance between origin and left edge of raster. Positive + changes move rightwards. */ + sfnt_fixed lbearing; + + /* Advance to next glyph's origin. */ + sfnt_fixed advance; +}; + + + +/* Font style parsing. */ + +struct sfnt_name_record +{ + /* Platform identifier code. */ + uint16_t platform_id; + + /* Platform specific ID. */ + uint16_t platform_specific_id; + + /* Language identifier. */ + uint16_t language_id; + + /* Name identifier. */ + uint16_t name_id; + + /* String length in bytes. */ + uint16_t length; + + /* Offset from start of storage area. */ + uint16_t offset; +}; + +struct sfnt_name_table +{ + /* Format selector of name table. */ + uint16_t format; + + /* Number of name records. */ + uint16_t count; + + /* Offset to start of string data. */ + uint16_t string_offset; + + /* Variable length data. */ + struct sfnt_name_record *name_records; + + /* Start of string data. */ + unsigned char *data; +}; + +/* Name identifier codes. These are Apple's codes, not + Microsoft's. */ + +enum sfnt_name_identifier_code + { + SFNT_NAME_COPYRIGHT_NOTICE = 0, + SFNT_NAME_FONT_FAMILY = 1, + SFNT_NAME_FONT_SUBFAMILY = 2, + SFNT_NAME_UNIQUE_SUBFAMILY_IDENTIFICATION = 3, + SFNT_NAME_FULL_NAME = 4, + SFNT_NAME_NAME_TABLE_VERSION = 5, + SFNT_NAME_POSTSCRIPT_NAME = 6, + SFNT_NAME_TRADEMARK_NOTICE = 7, + SFNT_NAME_MANUFACTURER_NAME = 8, + SFNT_NAME_DESIGNER = 9, + SFNT_NAME_DESCRIPTION = 10, + SFNT_NAME_FONT_VENDOR_URL = 11, + SFNT_NAME_FONT_DESIGNER_URL = 12, + SFNT_NAME_LICENSE_DESCRIPTION = 13, + SFNT_NAME_LICENSE_INFORMATION_URL = 14, + SFNT_NAME_PREFERRED_FAMILY = 16, + SFNT_NAME_PREFERRED_SUBFAMILY = 17, + SFNT_NAME_COMPATIBLE_FULL = 18, + SFNT_NAME_SAMPLE_TEXT = 19, + SFNT_NAME_VARIATIONS_POSTSCRIPT_NAME_PREFIX = 25, + }; + +struct sfnt_meta_data_map +{ + /* Identifier for the tag. */ + uint32_t tag; + + /* Offset from start of table to data. */ + uint32_t data_offset; + + /* Length of the data. */ + uint32_t data_length; +}; + +struct sfnt_meta_table +{ + /* Version of the table. Currently set to 1. */ + uint32_t version; + + /* Flags. Currently 0. */ + uint32_t flags; + + /* Offset from start of table to beginning of variable length + data. */ + uint32_t data_offset; + + /* Number of data maps in the table. */ + uint32_t num_data_maps; + + /* Beginning of variable length data. */ + struct sfnt_meta_data_map *data_maps; + + /* The whole table contents. */ + unsigned char *data; +}; + +enum sfnt_meta_data_tag + { + SFNT_META_DATA_TAG_DLNG = 0x646c6e67, + SFNT_META_DATA_TAG_SLNG = 0x736c6e67, + }; + + + +/* Function declarations. Keep these sorted by the order in which + they appear in sfnt.c. Keep each line no longer than 80 + columns. */ + +#ifndef TEST + +extern struct sfnt_offset_subtable *sfnt_read_table_directory (int); + +#define PROTOTYPE \ + int, struct sfnt_offset_subtable *, \ + struct sfnt_cmap_encoding_subtable **, \ + struct sfnt_cmap_encoding_subtable_data *** +static struct sfnt_cmap_table *sfnt_read_cmap_table (PROTOTYPE); +#undef PROTOTYPE + +#define PROTOTYPE int, struct sfnt_offset_subtable * +extern struct sfnt_head_table *sfnt_read_head_table (PROTOTYPE); +extern struct sfnt_hhea_table *sfnt_read_hhea_table (PROTOTYPE); +extern struct sfnt_loca_table_short *sfnt_read_loca_table_short (PROTOTYPE); +extern struct sfnt_loca_table_long *sfnt_read_loca_table_long (PROTOTYPE); +extern struct sfnt_maxp_table *sfnt_read_maxp_table (PROTOTYPE); +extern struct sfnt_glyf_table *sfnt_read_glyf_table (PROTOTYPE); +#undef PROTOTYPE + +extern struct sfnt_glyph *sfnt_read_glyph (sfnt_glyph, struct sfnt_glyf_table *, + struct sfnt_loca_table_short *, + struct sfnt_loca_table_long *); + +#define PROTOTYPE \ + struct sfnt_glyph *, \ + struct sfnt_head_table *, \ + int, sfnt_get_glyph_proc, \ + sfnt_free_glyph_proc, \ + void * +extern struct sfnt_glyph_outline *sfnt_build_glyph_outline (PROTOTYPE); +#undef PROTOTYPE + +extern void sfnt_prepare_raster (struct sfnt_raster *, + struct sfnt_glyph_outline *); + +#define PROTOTYPE struct sfnt_glyph_outline * +extern struct sfnt_raster *sfnt_raster_glyph_outline (PROTOTYPE); +#undef PROTOTYPE + +#define PROTOTYPE \ + int, \ + struct sfnt_offset_subtable *, \ + struct sfnt_hhea_table *, \ + struct sfnt_maxp_table * +extern struct sfnt_hmtx_table *sfnt_read_hmtx_table (PROTOTYPE); +#undef PROTOTYPE + +extern int sfnt_lookup_glyph_metrics (sfnt_glyph, int, + struct sfnt_glyph_metrics *, + struct sfnt_hmtx_table *, + struct sfnt_hhea_table *, + struct sfnt_head_table *, + struct sfnt_maxp_table *); + +#define PROTOTYPE int, struct sfnt_offset_subtable * +extern struct sfnt_name_table *sfnt_read_name_table (PROTOTYPE); +#undef PROTOTYPE + +extern unsigned char *sfnt_find_name (struct sfnt_name_table *, + enum sfnt_name_identifier_code, + struct sfnt_name_record *); + +#define PROTOTYPE int, struct sfnt_offset_subtable * +extern struct sfnt_meta_table *sfnt_read_meta_table (PROTOTYPE); +#undef PROTOTYPE + +extern char *sfnt_find_metadata (struct sfnt_meta_table *, + enum sfnt_meta_data_tag, + struct sfnt_meta_data_map *); + +#endif /* TEST */ +#endif /* _SFNT_H_ */ diff --git a/src/sfntfont-android.c b/src/sfntfont-android.c new file mode 100644 index 00000000000..d3c05fa4ac7 --- /dev/null +++ b/src/sfntfont-android.c @@ -0,0 +1,36 @@ +/* sfnt format font driver for Android. + +Copyright (C) 2023 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at +your option) any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs. If not, write to the Free Software Foundation, +Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include + +#include "androidterm.h" +#include "sfntfont.h" + +void +init_sfntfont_android (void) +{ + +} + +void +syms_of_sfntfont_android (void) +{ + +} diff --git a/src/sfntfont.c b/src/sfntfont.c new file mode 100644 index 00000000000..a9cc6d11b45 --- /dev/null +++ b/src/sfntfont.c @@ -0,0 +1,493 @@ +/* sfnt format font driver for GNU Emacs. + +Copyright (C) 2023 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at +your option) any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs. If not, write to the Free Software Foundation, +Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include + +#include "lisp.h" +#include "sfnt.h" +#include "coding.h" + +/* Generic font driver for sfnt-based fonts (currently TrueType, but + it would be easy to add CFF support in the future.) + + This is not a complete font driver. Hooks must be supplied by the + platform implementer to draw glyphs. */ + + + +/* Description of a font that hasn't been opened. */ + +struct sfnt_font_desc +{ + /* Next font in this list. */ + struct sfnt_font_desc *next; + + /* Family name of the font. */ + Lisp_Object family; + + /* Style name of the font. */ + Lisp_Object style; + + /* Numeric width, weight, slant and spacing. */ + int width, weight, slant, spacing; + + /* Path to the font file. */ + char *path; +}; + +/* List of fonts. */ + +static struct sfnt_font_desc *system_fonts; + +/* Font enumeration and matching. The sfnt driver assumes it can read + data from each font at startup. It then reads the head, meta and + name tables to determine font data, and records the font in a list + of system fonts that is then matched against. */ + +/* Set up the coding system CODING to decode string data from the + given platform id ID and platform specific id PLATFORM_SPECIFIC_ID. + Value is 0 upon success, 1 upon failure. */ + +static int +sfnt_setup_coding_system (enum sfnt_platform_id id, int platform_specific_id, + struct coding_system *coding) +{ + Lisp_Object system; + + system = Qnil; + + /* Figure out what coding system to use. */ + + switch (id) + { + case SFNT_PLATFORM_UNICODE: + system = Qutf_16be; + break; + + case SFNT_PLATFORM_MACINTOSH: + + if (platform_specific_id == SFNT_MACINTOSH_ROMAN) + system = Qmac_roman; + else + /* MULE doesn't support the rest... */ + system = Qnil; + + break; + + case SFNT_PLATFORM_MICROSOFT: + system = Qutf_16be; + + /* FIXME will someone look at the MS spec and see if this + right. */ + if (platform_specific_id + == SFNT_MICROSOFT_BIG_FIVE) + system = Qchinese_big5; + + break; + } + + if (NILP (system)) + return 1; + + setup_coding_system (system, coding); +} + +/* Globals used to communicate inside the condition-case wrapper. */ +static struct coding_system *sfnt_font_coding; + +/* The src_object being encoded from. This should be on the stack as + well, or it will get garbage collected. */ +static Lisp_Object sfnt_font_src_object; + +/* From-position. */ +static ptrdiff_t sfnt_font_from, sfnt_font_from_byte; + +/* To-position. */ +static ptrdiff_t sfnt_font_to, sfnt_font_to_byte; + +/* Destination object. Once again, this should also be on the + stack. */ +static Lisp_Object sfnt_font_dst_object; + +/* Error flag. Set to true if a signal was caught. */ +static bool sfnt_font_signal; + +static Lisp_Object +sfnt_safe_encode_coding_object_1 (void) +{ + encode_coding_object (sfnt_font_coding, + sfnt_font_src_object, + sfnt_font_from, + sfnt_font_from_byte, + sfnt_font_to, + sfnt_font_to_byte, + sfnt_font_dst_object); + return Qnil; +} + +static Lisp_Object +sfnt_safe_encode_coding_object_2 (void) +{ + sfnt_font_signal = true; + + return Qnil; +} + +/* Like encode_coding_object, but return 1 if a signal happens. Value + is otherwise 0. */ + +static int +sfnt_safe_encode_coding_object (struct coding_system *coding, + Lisp_Object src_object, + ptrdiff_t from, ptrdiff_t from_byte, + ptrdiff_t to, ptrdiff_t to_byte, + Lisp_Object dst_object) +{ + sfnt_font_coding = coding; + sfnt_font_src_object = src_object; + sfnt_font_from = from; + sfnt_font_from_byte = from_byte; + sfnt_font_to = to; + sfnt_font_to_byte = to_byte; + sfnt_font_dst_object = dst_object; + sfnt_font_signal = false; + + internal_condition_case (sfnt_safe_encode_coding_object_1, + Qt, + sfnt_safe_encode_coding_object_2); + + return (int) sfnt_font_signal; +} + +/* Decode the specified string DATA. The encoding is determined based + on PLATFORM_ID, PLATFORM_SPECIFIC_ID and LANGUAGE_ID. Consult + sfnt.h and the TrueType Reference Manual for more details. LENGTH + is the length of DATA in bytes. + + Value is nil upon failure, else the decoded string. */ + +static Lisp_Object +sfnt_decode_font_string (unsigned char *data, enum sfnt_platform_id id, + int platform_specific_id, int language_id, + size_t length) +{ + struct coding_system coding; + + memset (&coding, 0, sizeof coding); + sfnt_setup_coding_system (id, platform_specific_id, &coding); + coding.mode |= CODING_MODE_SAFE_ENCODING; + coding.mode |= CODING_MODE_LAST_BLOCK; + /* Suppress producing escape sequences for composition. */ + coding.common_flags &= ~CODING_ANNOTATION_MASK; + coding.source = data; + + if (sfnt_safe_encode_coding_object (&coding, Qnil, 0, 0, + 0, 0, length, length, + Qnil)) + return Qnil; + + return coding.dst_object; +} + +/* Decode the family and style names from the name table NAME. Return + 0 and the family and style names upon success, else 1. */ + +static int +sfnt_decode_family_style (struct sfnt_name_table *name, + Lisp_Object *family, Lisp_Object *style) +{ + struct sfnt_name_record family_rec, style_rec; + unsigned char *family_data, *style_data; + + family_data = sfnt_find_name (name, SFNT_NAME_FONT_FAMILY, + &family_rec); + style_data = sfnt_find_name (name, SFNT_NAME_FONT_SUBFAMILY, + &style_rec); + + if (!family_data || !style_data) + return 1; + + /* Now decode the data. */ + *family = sfnt_decode_font_string (family_data, + family_rec.platform_id, + family_rec.platform_specific_id, + family_rec.language_id, + family_rec.length); + *style = sfnt_decode_font_string (style_data, + style_rec.platform_id, + style_rec.platform_specific_id, + style_rec.language_id, + style_rec.length); + + /* Return whether or not it was successful. */ + return (!NILP (*family) && !NILP (*style)) ? 0 : 1; +} + +struct sfnt_style_desc +{ + /* The C string to match against. */ + const char *c_string; + + /* The value of the style field. */ + int value; +}; + +/* Array of style descriptions describing weight. */ +static struct sfnt_style_desc sfnt_weight_descriptions = + { + { "thin", 0, }, + { "extralight", 40, }, + { "ultralight", 40, }, + { "demilight", 55, }, + { "semilight", 55, }, + { "book", 75, }, + { "medium", 100, }, + { "demibold", 180, }, + { "semibold", 180, }, + { "bold", 200, }, + { "extrabold", 205, }, + { "ultrabold", 205, }, + { "black", 210, }, + { "heavy", 210, }, + { "extrablack", 215, }, + { "ultrablack", 215, }, + }; + +/* Array of style descriptions describing slant. */ +static struct sfnt_style_desc sfnt_slant_descriptions = + { + { "italic", 100, }, + { "oblique", 110, }, + }; + +/* Array of style descriptions describing width. */ +static struct sfnt_width_desc sfnt_width_descriptions = + { + { "ultracondensed", 50, }, + { "extracondensed", 63, }, + { "condensed", 75, }, + { "semicondensed", 87, }, + { "semiexpanded", 113, }, + { "expanded", 125, }, + { "extraexpanded", 150, }, + { "ultraexpanded", 200, }, + }; + +/* Figure out DESC->width, DESC->weight, DESC->slant and DESC->spacing + based on the style name passed as STYLE. */ + +static void +sfnt_parse_style (Lisp_Object style, struct sfnt_font_desc *desc) +{ + char *style, single, *saveptr; + int i; + + /* Fill in default values. */ + desc->weight = 80; + desc->slant = 0; + desc->width = 100; + + /* Split the style into spaces. As long as no weight, slant, or + width is encountered, look in the corresponding descriptions + array. GC must not happen inside this block. */ + style = SSDATA (Fdowncase (style)); + saveptr = NULL; + + while ((single = strtok_r (style, " ", &saveptr))) + { + style = NULL; + + if (desc->weight == 80) + { + /* Weight hasn't been found yet. Scan through the weight + table. */ + for (i = 0; i < ARRAYELTS (sfnt_weight_descriptions); ++i) + { + if (!strcmp (sfnt_weight_descriptions[i].c_string, + single)) + { + /* Weight found. Continue on reading the slant and + width. */ + desc->weight = sfnt_weight_descriptions[i].value; + goto next; + } + } + } + + if (!desc->slant) + { + /* Slant hasn't been found yet. Scan through the slant + table. */ + for (i = 0; i < ARRAYELTS (sfnt_slant_descriptions); ++i) + { + if (!strcmp (sfnt_weight_descriptions[i].c_string, + single)) + { + /* Slant found. Continue on reading the weight and + width. */ + desc->slant = sfnt_weight_descriptions[i].value; + goto next; + } + } + } + + if (desc->width == 100) + { + /* Width hasn't been found yet. Scan through the width + table. */ + for (i = 0; i < ARRAYELTS (sfnt_width_descriptions); ++i) + { + if (!strcmp (sfnt_width_descriptions[i].c_string, + single)) + { + /* Width found. Continue on reading the slant and + weight. */ + desc->slant = sfnt_width_descriptions[i].value; + goto next; + } + } + } + + next: + + /* Break early if everything has been found. */ + if (desc->slant && desc->width != 100 && desc->weight != 80) + break; + + continue; + } +} + +/* Enumerate the font FILE into the list of system fonts. Return 1 if + it could not be enumerated, 0 otherwise. */ + +int +sfnt_enum_font (const char *file) +{ + struct sfnt_font_desc *desc; + int fd; + struct sfnt_offset_subtable *subtables; + struct sfnt_head_table *head; + struct sfnt_name_table *name; + struct sfnt_meta_table *meta; + Lisp_Object family, style; + + /* Create the font desc and copy in the file name. */ + desc = xzalloc (sizeof *desc + strlen (file) + 1); + desc->path = (char *) (desc + 1); + memcpy (desc->path, file, strlen (file) + 1); + + /* Now open the font for reading. */ + fd = emacs_open (file, O_RDWR); + + /* Read the table directory. */ + subtables = sfnt_read_table_directory (fd); + + if (!subtables) + goto bail0; + + /* Check that this is a TrueType font. */ + if (subtables->scaler_type != SFNT_SCALER_TRUE + && subtables->scaler_type != SFNT_SCALER_VER1) + goto bail1; + + /* Read required tables. */ + head = sfnt_read_head_table (fd, subtables); + if (!head) + goto bail1; + + name = sfnt_read_name_table (fd, subtables); + if (!name) + goto bail2; + + /* meta is not required, nor present on many non-Apple fonts. */ + meta = sfnt_read_meta_table (fd, subtables); + + /* Decode the family and style from the name table. */ + if (sfnt_decode_family_style (name, &family, &style)) + goto bail3; + + /* Set the family. */ + desc->family = family; + + /* Parse the style. */ + sfnt_parse_style (style, 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 */ + + /* Finally add mac-style flags. Allow them to override styles that + have not been found. */ + + if (head->mac_style & 01 && desc->weight == 80) /* Bold */ + desc->weight = 200; + + if (head->mac_style & 02 && desc->slant == 0) /* Italic */ + desc->slant = 100; + + /* Set the style, link the desc onto system_fonts and return. */ + desc->style = style; + desc->next = system_fonts; + system_fonts = desc; + + xfree (meta); + xfree (name); + xfree (head); + xfree (subtables); + emacs_close (fd); + return 0; + + bail3: + xfree (meta); + xfree (name); + bail2: + xfree (head); + bail1: + xfree (subtables); + bail0: + emacs_close (fd); + return 1; +} + + + +void +syms_of_sfntfont (void) +{ + DEFSYM (Qutf_16be, "utf-16be"); + DEFSYM (Qmac_roman, "mac-roman"); +} + +void +mark_sfntfont (void) +{ + struct sfnt_font_desc *desc; + + /* Mark each font desc. */ + for (desc = system_fonts; ++desc; desc = desc->next) + { + mark_object (desc->family); + mark_object (desc->style); + } +} diff --git a/src/sfntfont.h b/src/sfntfont.h new file mode 100644 index 00000000000..3ce60f83984 --- /dev/null +++ b/src/sfntfont.h @@ -0,0 +1,26 @@ +/* sfnt format font driver for GNU Emacs. + +Copyright (C) 2023 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or (at +your option) any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs. If not, write to the Free Software Foundation, +Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _SFNTFONT_H_ +#define _SFNTFONT_H_ + +extern int sfnt_enum_font (const char *); + +#endif /* _SFNTFONT_H_ */ -- 2.39.5