mirror of
https://github.com/masscollaborationlabs/emacs.git
synced 2025-07-16 17:00:06 +00:00
Update Android port
* configure.ac: Add support for HarfBuzz on Android. * java/INSTALL: Document where to get Emacs with HarfBuzz. * lisp/subr.el (overriding-text-conversion-style, y-or-n-p): Correctly set text conversion style if y-or-n-p is called inside the minibuffer. * src/sfnt.c (sfnt_read_cmap_format_8) (sfnt_read_cmap_format_12): Fix typos. (sfnt_read_24, sfnt_read_cmap_format_14): New function. (sfnt_read_cmap_table_1, sfnt_read_cmap_table): Handle format 14 cmap tables. (sfnt_read_default_uvs_table, sfnt_read_nondefault_uvs_table) (sfnt_compare_table_offsets, sfnt_create_uvs_context) (sfnt_free_uvs_context, sfnt_compare_uvs_mapping) (sfnt_variation_glyph_for_char, sfnt_map_table, sfnt_unmap_table) (sfnt_read_table, sfnt_test_uvs): New functions. (main): Add UVS tests. * src/sfnt.h (struct sfnt_cmap_format_14) (struct sfnt_variation_selector_record) (struct sfnt_default_uvs_table, struct sfnt_unicode_value_range) (struct sfnt_nondefault_uvs_table, struct sfnt_uvs_mapping) (struct sfnt_mapped_variation_selector_record) (struct sfnt_table_offset_rec, struct sfnt_uvs_context) (struct sfnt_mapped_table): New structures. Update prototypes. * src/sfntfont-android.c (android_sfntfont_driver): Register HarfBuzz callbacks where required. * src/sfntfont.c (sfntfont_select_cmap): Look for a format 14 table. Save it in new arg FORMAT14. (sfntfont_read_cmap): Adjust accordingly. (struct sfnt_font_info): New field `uvs'. New fields `hb_font', `fd' and `directory'. (sfntfont_open): Open uvs context. Under HarfBuzz, don't close the fd or subtable, but save them in the font info instead. (sfntfont_close): Free UVS context. Close font fd and table directory and HarfBuzz font. (sfntfont_draw): Handle case where s->padding_p. (sfntfont_get_variation_glyphs): New function. (sfntfont_unmap_blob, sfntfont_get_font_table) (sfntfont_begin_hb_font): New functions. * src/sfntfont.h: Update prototypes. * src/textconv.c (Fset_text_conversion_style): Fix doc string.
This commit is contained in:
parent
739558c369
commit
6bd1cfa24f
9 changed files with 1322 additions and 31 deletions
|
@ -1171,6 +1171,7 @@ package will likely install on older systems but crash on startup.])
|
||||||
passthrough="$passthrough --with-lcms2=$with_lcms2"
|
passthrough="$passthrough --with-lcms2=$with_lcms2"
|
||||||
passthrough="$passthrough --with-mailutils=$with_mailutils"
|
passthrough="$passthrough --with-mailutils=$with_mailutils"
|
||||||
passthrough="$passthrough --with-pop=$with_pop"
|
passthrough="$passthrough --with-pop=$with_pop"
|
||||||
|
passthrough="$passthrough --with-harfbuzz=$with_harfbuzz"
|
||||||
|
|
||||||
AS_IF([test "x$with_mailutils" = "xyes"], [emacs_use_mailutils=yes])
|
AS_IF([test "x$with_mailutils" = "xyes"], [emacs_use_mailutils=yes])
|
||||||
AC_SUBST([emacs_use_mailutils])
|
AC_SUBST([emacs_use_mailutils])
|
||||||
|
@ -1255,13 +1256,13 @@ if test "$ANDROID" = "yes"; then
|
||||||
with_lcms2=no
|
with_lcms2=no
|
||||||
with_mailutils=no
|
with_mailutils=no
|
||||||
with_pop=no
|
with_pop=no
|
||||||
|
with_harfbuzz=no
|
||||||
fi
|
fi
|
||||||
|
|
||||||
with_rsvg=no
|
with_rsvg=no
|
||||||
with_libsystemd=no
|
with_libsystemd=no
|
||||||
with_cairo=no
|
with_cairo=no
|
||||||
with_xft=no
|
with_xft=no
|
||||||
with_harfbuzz=no
|
|
||||||
with_libotf=no
|
with_libotf=no
|
||||||
with_gpm=no
|
with_gpm=no
|
||||||
with_dbus=no
|
with_dbus=no
|
||||||
|
@ -4581,7 +4582,8 @@ else
|
||||||
fi
|
fi
|
||||||
if test "${HAVE_X11}" = "yes" && test "${HAVE_FREETYPE}" = "yes" \
|
if test "${HAVE_X11}" = "yes" && test "${HAVE_FREETYPE}" = "yes" \
|
||||||
|| test "$window_system" = "pgtk" \
|
|| test "$window_system" = "pgtk" \
|
||||||
|| test "${HAVE_W32}" = "yes"; then
|
|| test "${HAVE_W32}" = "yes" \
|
||||||
|
|| test "$REALLY_ANDROID" = "yes"; then
|
||||||
if test "${with_harfbuzz}" != "no"; then
|
if test "${with_harfbuzz}" != "no"; then
|
||||||
EMACS_CHECK_MODULES([HARFBUZZ], [harfbuzz >= $harfbuzz_required_ver])
|
EMACS_CHECK_MODULES([HARFBUZZ], [harfbuzz >= $harfbuzz_required_ver])
|
||||||
if test "$HAVE_HARFBUZZ" = "yes"; then
|
if test "$HAVE_HARFBUZZ" = "yes"; then
|
||||||
|
|
16
java/INSTALL
16
java/INSTALL
|
@ -265,6 +265,8 @@ systems:
|
||||||
(Extract and point ``--with-ndk-path'' to tiff-4.5.0-emacs.tar.gz.)
|
(Extract and point ``--with-ndk-path'' to tiff-4.5.0-emacs.tar.gz.)
|
||||||
tree-sitter - https://sourceforge.net/projects/android-ports-for-gnu-emacs
|
tree-sitter - https://sourceforge.net/projects/android-ports-for-gnu-emacs
|
||||||
(Please see the section TREE-SITTER near the end of this file.)
|
(Please see the section TREE-SITTER near the end of this file.)
|
||||||
|
harfbuzz - https://sourceforge.net/projects/android-ports-for-gnu-emacs
|
||||||
|
(Please see the section HARFBUZZ near the end of this file.)
|
||||||
|
|
||||||
And other developers have ported the following dependencies to Android
|
And other developers have ported the following dependencies to Android
|
||||||
systems:
|
systems:
|
||||||
|
@ -305,15 +307,23 @@ should not try to build these packages separately using any
|
||||||
TREE-SITTER
|
TREE-SITTER
|
||||||
|
|
||||||
A copy of tree-sitter modified to build with the ndk-build system can
|
A copy of tree-sitter modified to build with the ndk-build system can
|
||||||
also find that URL. To build Emacs with tree-sitter, you must unpack
|
also be found that URL. To build Emacs with tree-sitter, you must
|
||||||
the following tar archive in that site:
|
unpack the following tar archive in that site:
|
||||||
|
|
||||||
tree-sitter-0.20.7-emacs.tar.gz
|
tree-sitter-0.20.7-emacs.tar.gz
|
||||||
|
|
||||||
and add the resulting folder to ``--with-ndk-build''.
|
and add the resulting folder to ``--with-ndk-build''.
|
||||||
|
|
||||||
|
|
||||||
IMAGEMAGICK
|
HARFBUZZ
|
||||||
|
|
||||||
|
A copy of HarfBuzz modified to build with the ndk-build system can
|
||||||
|
also be found at that URL. To build Emacs with HarfBuzz, you must
|
||||||
|
unpack the following tar archive in that site:
|
||||||
|
|
||||||
|
harfbuzz-7.1.0-emacs.tar.gz
|
||||||
|
|
||||||
|
and add the resulting folder to ``--with-ndk-build''.
|
||||||
|
|
||||||
There is a third party port of ImageMagick to Android. Unfortunately,
|
There is a third party port of ImageMagick to Android. Unfortunately,
|
||||||
the port also uses its own patched versions of libpng, libjpeg,
|
the port also uses its own patched versions of libpng, libjpeg,
|
||||||
|
|
16
lisp/subr.el
16
lisp/subr.el
|
@ -3598,6 +3598,7 @@ character. This is not possible when using `read-key', but using
|
||||||
|
|
||||||
;; Actually in textconv.c.
|
;; Actually in textconv.c.
|
||||||
(defvar overriding-text-conversion-style)
|
(defvar overriding-text-conversion-style)
|
||||||
|
(declare-function set-text-conversion-style "textconv.c")
|
||||||
|
|
||||||
(defun y-or-n-p (prompt)
|
(defun y-or-n-p (prompt)
|
||||||
"Ask user a \"y or n\" question.
|
"Ask user a \"y or n\" question.
|
||||||
|
@ -3674,6 +3675,9 @@ like) while `y-or-n-p' is running)."
|
||||||
(while
|
(while
|
||||||
(let* ((scroll-actions '(recenter scroll-up scroll-down
|
(let* ((scroll-actions '(recenter scroll-up scroll-down
|
||||||
scroll-other-window scroll-other-window-down))
|
scroll-other-window scroll-other-window-down))
|
||||||
|
;; Disable text conversion so that real key events
|
||||||
|
;; are sent.
|
||||||
|
(overriding-text-conversion-style nil)
|
||||||
(key
|
(key
|
||||||
(let ((cursor-in-echo-area t))
|
(let ((cursor-in-echo-area t))
|
||||||
(when minibuffer-auto-raise
|
(when minibuffer-auto-raise
|
||||||
|
@ -3721,9 +3725,15 @@ like) while `y-or-n-p' is running)."
|
||||||
map))
|
map))
|
||||||
;; Protect this-command when called from pre-command-hook (bug#45029)
|
;; Protect this-command when called from pre-command-hook (bug#45029)
|
||||||
(this-command this-command)
|
(this-command this-command)
|
||||||
(str (read-from-minibuffer
|
(str (progn
|
||||||
prompt nil keymap nil
|
(when (active-minibuffer-window)
|
||||||
(or y-or-n-p-history-variable t))))
|
;; If the minibuffer is already active, the
|
||||||
|
;; selected window might not change. Disable
|
||||||
|
;; text conversion by hand.
|
||||||
|
(set-text-conversion-style text-conversion-style))
|
||||||
|
(read-from-minibuffer
|
||||||
|
prompt nil keymap nil
|
||||||
|
(or y-or-n-p-history-variable t)))))
|
||||||
(setq answer (if (member str '("y" "Y")) 'act 'skip)))))
|
(setq answer (if (member str '("y" "Y")) 'act 'skip)))))
|
||||||
(let ((ret (eq answer 'act)))
|
(let ((ret (eq answer 'act)))
|
||||||
(unless noninteractive
|
(unless noninteractive
|
||||||
|
|
741
src/sfnt.c
741
src/sfnt.c
|
@ -601,7 +601,7 @@ sfnt_read_cmap_format_8 (int fd,
|
||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
uint32_t length, i;
|
uint32_t length, i;
|
||||||
|
|
||||||
/* Read the 32-bit lenth field. */
|
/* Read the 32-bit length field. */
|
||||||
if (read (fd, &length, sizeof (length)) < sizeof (length))
|
if (read (fd, &length, sizeof (length)) < sizeof (length))
|
||||||
return (struct sfnt_cmap_format_8 *) -1;
|
return (struct sfnt_cmap_format_8 *) -1;
|
||||||
|
|
||||||
|
@ -693,7 +693,7 @@ sfnt_read_cmap_format_12 (int fd,
|
||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
uint32_t length, i;
|
uint32_t length, i;
|
||||||
|
|
||||||
/* Read the 32-bit lenth field. */
|
/* Read the 32-bit length field. */
|
||||||
if (read (fd, &length, sizeof (length)) < sizeof (length))
|
if (read (fd, &length, sizeof (length)) < sizeof (length))
|
||||||
return (struct sfnt_cmap_format_12 *) -1;
|
return (struct sfnt_cmap_format_12 *) -1;
|
||||||
|
|
||||||
|
@ -773,6 +773,98 @@ sfnt_read_cmap_format_12 (int fd,
|
||||||
return format12;
|
return format12;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Read a 3-byte big endian number from BYTES. */
|
||||||
|
|
||||||
|
static unsigned int
|
||||||
|
sfnt_read_24 (unsigned char *bytes)
|
||||||
|
{
|
||||||
|
return (bytes[0] << 16u) | (bytes[1] << 8u) | bytes[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read a format 14 cmap table from FD. HEADER->format will be 14 and
|
||||||
|
HEADER->length will be 0; the 16-bit length field is not read.
|
||||||
|
OFFSET is the offset of the table's header in the font file.
|
||||||
|
|
||||||
|
Only variation selector records will be read. UVS tables will
|
||||||
|
not. */
|
||||||
|
|
||||||
|
static struct sfnt_cmap_format_14 *
|
||||||
|
sfnt_read_cmap_format_14 (int fd,
|
||||||
|
struct sfnt_cmap_encoding_subtable_data *header,
|
||||||
|
off_t offset)
|
||||||
|
{
|
||||||
|
struct sfnt_cmap_format_14 *format14;
|
||||||
|
uint32_t length;
|
||||||
|
uint32_t num_records;
|
||||||
|
uint32_t buffer1[2];
|
||||||
|
size_t size, temp;
|
||||||
|
char buffer[3 + 4 + 4];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Read the length field and number of variation selector
|
||||||
|
records. */
|
||||||
|
|
||||||
|
if (read (fd, buffer1, sizeof buffer1) < sizeof buffer1)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
length = buffer1[0];
|
||||||
|
num_records = buffer1[1];
|
||||||
|
|
||||||
|
sfnt_swap32 (&length);
|
||||||
|
sfnt_swap32 (&num_records);
|
||||||
|
|
||||||
|
/* Now, the number of records present is known. Allocate the format
|
||||||
|
14 cmap table. */
|
||||||
|
|
||||||
|
size = sizeof *format14;
|
||||||
|
if (INT_MULTIPLY_WRAPV (num_records, sizeof *format14->records,
|
||||||
|
&temp)
|
||||||
|
|| INT_ADD_WRAPV (size, temp, &size))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
format14 = xmalloc (size);
|
||||||
|
|
||||||
|
/* Fill in the data already read. */
|
||||||
|
format14->format = header->format;
|
||||||
|
format14->length = length;
|
||||||
|
format14->num_var_selector_records = num_records;
|
||||||
|
format14->offset = offset;
|
||||||
|
|
||||||
|
/* Set the pointer to the remaining record data. */
|
||||||
|
format14->records
|
||||||
|
= (struct sfnt_variation_selector_record *) (format14 + 1);
|
||||||
|
|
||||||
|
/* Read each variation selector record. */
|
||||||
|
|
||||||
|
for (i = 0; i < num_records; ++i)
|
||||||
|
{
|
||||||
|
if (read (fd, buffer, sizeof buffer) < sizeof buffer)
|
||||||
|
{
|
||||||
|
xfree (format14);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* First, read the 24 bit variation selector. */
|
||||||
|
format14->records[i].var_selector
|
||||||
|
= sfnt_read_24 ((unsigned char *) buffer);
|
||||||
|
|
||||||
|
/* Next, read the two unaligned longs. */
|
||||||
|
memcpy (&format14->records[i].default_uvs_offset,
|
||||||
|
buffer + 3,
|
||||||
|
sizeof format14->records[i].default_uvs_offset);
|
||||||
|
memcpy (&format14->records[i].nondefault_uvs_offset,
|
||||||
|
buffer + 7,
|
||||||
|
sizeof format14->records[i].nondefault_uvs_offset);
|
||||||
|
|
||||||
|
/* And swap them. */
|
||||||
|
sfnt_swap32 (&format14->records[i].default_uvs_offset);
|
||||||
|
sfnt_swap32 (&format14->records[i].nondefault_uvs_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the format 14 character mapping table. */
|
||||||
|
return format14;
|
||||||
|
}
|
||||||
|
|
||||||
/* Read the CMAP subtable data from a given file FD at TABLE_OFFSET
|
/* Read the CMAP subtable data from a given file FD at TABLE_OFFSET
|
||||||
bytes from DIRECTORY_OFFSET. Return the subtable data if it is
|
bytes from DIRECTORY_OFFSET. Return the subtable data if it is
|
||||||
supported. Else, value is NULL if the format is unsupported, or -1
|
supported. Else, value is NULL if the format is unsupported, or -1
|
||||||
|
@ -791,11 +883,26 @@ sfnt_read_cmap_table_1 (int fd, uint32_t directory_offset,
|
||||||
if (lseek (fd, offset, SEEK_SET) == (off_t) -1)
|
if (lseek (fd, offset, SEEK_SET) == (off_t) -1)
|
||||||
return (struct sfnt_cmap_encoding_subtable_data *) -1;
|
return (struct sfnt_cmap_encoding_subtable_data *) -1;
|
||||||
|
|
||||||
if (read (fd, &header, sizeof header) < sizeof header)
|
if (read (fd, &header.format, sizeof header.format)
|
||||||
|
< sizeof header.format)
|
||||||
return (struct sfnt_cmap_encoding_subtable_data *) -1;
|
return (struct sfnt_cmap_encoding_subtable_data *) -1;
|
||||||
|
|
||||||
sfnt_swap16 (&header.format);
|
sfnt_swap16 (&header.format);
|
||||||
sfnt_swap16 (&header.length);
|
|
||||||
|
/* Format 14 tables are rather special: they do not have a 16-bit
|
||||||
|
`length' field. When these tables are encountered, leave reading
|
||||||
|
the rest of the header to `sfnt_read_cmap_table_14'. */
|
||||||
|
|
||||||
|
if (header.format != 14)
|
||||||
|
{
|
||||||
|
if (read (fd, &header.length, sizeof header.length)
|
||||||
|
< sizeof header.length)
|
||||||
|
return (struct sfnt_cmap_encoding_subtable_data *) -1;
|
||||||
|
|
||||||
|
sfnt_swap16 (&header.length);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
header.length = 0;
|
||||||
|
|
||||||
switch (header.format)
|
switch (header.format)
|
||||||
{
|
{
|
||||||
|
@ -828,6 +935,10 @@ sfnt_read_cmap_table_1 (int fd, uint32_t directory_offset,
|
||||||
return ((struct sfnt_cmap_encoding_subtable_data *)
|
return ((struct sfnt_cmap_encoding_subtable_data *)
|
||||||
sfnt_read_cmap_format_12 (fd, &header));
|
sfnt_read_cmap_format_12 (fd, &header));
|
||||||
|
|
||||||
|
case 14:
|
||||||
|
return ((struct sfnt_cmap_encoding_subtable_data *)
|
||||||
|
sfnt_read_cmap_format_14 (fd, &header, offset));
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -909,8 +1020,7 @@ sfnt_read_cmap_table (int fd, struct sfnt_offset_subtable *subtable,
|
||||||
return cmap;
|
return cmap;
|
||||||
|
|
||||||
/* Second, read each encoding subtable itself. */
|
/* Second, read each encoding subtable itself. */
|
||||||
*data = xmalloc (cmap->num_subtables
|
*data = xmalloc (cmap->num_subtables * sizeof *data);
|
||||||
* sizeof *data);
|
|
||||||
|
|
||||||
for (i = 0; i < cmap->num_subtables; ++i)
|
for (i = 0; i < cmap->num_subtables; ++i)
|
||||||
{
|
{
|
||||||
|
@ -1199,7 +1309,10 @@ sfnt_lookup_glyph_12 (sfnt_char character,
|
||||||
|
|
||||||
/* Look up the glyph index corresponding to the character CHARACTER,
|
/* Look up the glyph index corresponding to the character CHARACTER,
|
||||||
which must be in the correct encoding for the cmap table pointed to
|
which must be in the correct encoding for the cmap table pointed to
|
||||||
by DATA. */
|
by DATA.
|
||||||
|
|
||||||
|
DATA must be either a format 0, 2, 4, 6, 8 or 12 cmap table, else
|
||||||
|
behavior is undefined. */
|
||||||
|
|
||||||
TEST_STATIC sfnt_glyph
|
TEST_STATIC sfnt_glyph
|
||||||
sfnt_lookup_glyph (sfnt_char character,
|
sfnt_lookup_glyph (sfnt_char character,
|
||||||
|
@ -11775,6 +11888,551 @@ sfnt_interpret_compound_glyph (struct sfnt_glyph *glyph,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Unicode Variation Sequence (UVS) support.
|
||||||
|
|
||||||
|
Unicode defines a mechanism by which a two-codepoint sequence
|
||||||
|
consisting of a ``base character'' and ``variation selector'' is
|
||||||
|
able to produce a glyph that is a variant of the glyph that would
|
||||||
|
conventionally have been mapped to the ``base character''.
|
||||||
|
|
||||||
|
TrueType describes variation selector sequences through a type of
|
||||||
|
character mapping table that is given the format 14. The character
|
||||||
|
mapping table consists of an array of variation selectors, each of
|
||||||
|
which have a corresponding ``default UVS table'', which describes
|
||||||
|
ranges of ``base characters'' having no special variant glyphs, and
|
||||||
|
a ``non-default UVS table'', which is a map of ``base characters''
|
||||||
|
to their corresponding variant glyphs. */
|
||||||
|
|
||||||
|
/* Read a default UVS table from the font file FD, at the specified
|
||||||
|
OFFSET. Value is the default UVS table upon success, else
|
||||||
|
NULL. */
|
||||||
|
|
||||||
|
static struct sfnt_default_uvs_table *
|
||||||
|
sfnt_read_default_uvs_table (int fd, off_t offset)
|
||||||
|
{
|
||||||
|
struct sfnt_default_uvs_table *uvs;
|
||||||
|
uint32_t num_ranges, i, j;
|
||||||
|
size_t size, temp;
|
||||||
|
char data[512];
|
||||||
|
|
||||||
|
/* First, seek to the given offset. */
|
||||||
|
|
||||||
|
if (lseek (fd, offset, SEEK_SET) != offset)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Next, read the number of ranges present. */
|
||||||
|
|
||||||
|
if (read (fd, &num_ranges, sizeof num_ranges) != sizeof num_ranges)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Swap the number of ranges present. */
|
||||||
|
sfnt_swap32 (&num_ranges);
|
||||||
|
|
||||||
|
/* Now, allocate enough to hold the UVS table. */
|
||||||
|
|
||||||
|
size = sizeof *uvs;
|
||||||
|
if (INT_MULTIPLY_WRAPV (sizeof *uvs->ranges, num_ranges,
|
||||||
|
&temp)
|
||||||
|
|| INT_ADD_WRAPV (temp, size, &size))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
uvs = xmalloc (size);
|
||||||
|
|
||||||
|
/* Fill in the data which was already read. */
|
||||||
|
uvs->num_unicode_value_ranges = num_ranges;
|
||||||
|
|
||||||
|
/* Fill in the pointer to the ranges. */
|
||||||
|
uvs->ranges = (struct sfnt_unicode_value_range *) (uvs + 1);
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
/* Read each default UVS range in multiples of 512 bytes. Then,
|
||||||
|
fill in uvs->ranges. */
|
||||||
|
|
||||||
|
while (num_ranges)
|
||||||
|
{
|
||||||
|
size = (num_ranges > 128 ? 512 : num_ranges * 4);
|
||||||
|
|
||||||
|
if (read (fd, data, size) != size)
|
||||||
|
{
|
||||||
|
xfree (uvs);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (j = 0; j < size / 4; ++j)
|
||||||
|
{
|
||||||
|
uvs->ranges[i + j].start_unicode_value
|
||||||
|
= sfnt_read_24 ((unsigned char *) data + j * 4);
|
||||||
|
uvs->ranges[i + j].additional_count = data[j * 4 + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
i += j;
|
||||||
|
num_ranges -= size / 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the resulting default UVS table. */
|
||||||
|
return uvs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read a non-default UVS table from the font file FD, at the
|
||||||
|
specified OFFSET. Value is the non-default UVS table upon success,
|
||||||
|
else NULL. */
|
||||||
|
|
||||||
|
static struct sfnt_nondefault_uvs_table *
|
||||||
|
sfnt_read_nondefault_uvs_table (int fd, off_t offset)
|
||||||
|
{
|
||||||
|
struct sfnt_nondefault_uvs_table *uvs;
|
||||||
|
uint32_t num_mappings, i, j;
|
||||||
|
size_t size, temp;
|
||||||
|
char data[500];
|
||||||
|
|
||||||
|
/* First, seek to the given offset. */
|
||||||
|
|
||||||
|
if (lseek (fd, offset, SEEK_SET) != offset)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Next, read the number of mappings present. */
|
||||||
|
|
||||||
|
if (read (fd, &num_mappings, sizeof num_mappings)
|
||||||
|
!= sizeof num_mappings)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Swap the number of mappings present. */
|
||||||
|
sfnt_swap32 (&num_mappings);
|
||||||
|
|
||||||
|
/* Now, allocate enough to hold the UVS table. */
|
||||||
|
|
||||||
|
size = sizeof *uvs;
|
||||||
|
if (INT_MULTIPLY_WRAPV (sizeof *uvs->mappings, num_mappings,
|
||||||
|
&temp)
|
||||||
|
|| INT_ADD_WRAPV (temp, size, &size))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
uvs = xmalloc (size);
|
||||||
|
|
||||||
|
/* Fill in the data which was already read. */
|
||||||
|
uvs->num_uvs_mappings = num_mappings;
|
||||||
|
|
||||||
|
/* Fill in the pointer to the mappings. */
|
||||||
|
uvs->mappings = (struct sfnt_uvs_mapping *) (uvs + 1);
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
/* Read each nondefault UVS mapping in multiples of 500 bytes.
|
||||||
|
Then, fill in uvs->ranges. */
|
||||||
|
|
||||||
|
while (num_mappings)
|
||||||
|
{
|
||||||
|
size = (num_mappings > 100 ? 500 : num_mappings * 5);
|
||||||
|
|
||||||
|
if (read (fd, data, size) != size)
|
||||||
|
{
|
||||||
|
xfree (uvs);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (j = 0; j < size / 5; ++j)
|
||||||
|
{
|
||||||
|
uvs->mappings[i + j].unicode_value
|
||||||
|
= sfnt_read_24 ((unsigned char *) data + j * 5);
|
||||||
|
memcpy (&uvs->mappings[i + j].base_character_value,
|
||||||
|
data + j * 5 + 3,
|
||||||
|
sizeof uvs->mappings[i + j].base_character_value);
|
||||||
|
sfnt_swap16 (&uvs->mappings[i + j].base_character_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
i += j;
|
||||||
|
num_mappings -= size / 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the nondefault UVS table. */
|
||||||
|
return uvs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Perform comparison of A and B, two table offsets. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
sfnt_compare_table_offsets (const void *a, const void *b)
|
||||||
|
{
|
||||||
|
const struct sfnt_table_offset_rec *rec_a, *rec_b;
|
||||||
|
|
||||||
|
rec_a = a;
|
||||||
|
rec_b = b;
|
||||||
|
|
||||||
|
if (rec_a->offset < rec_b->offset)
|
||||||
|
return -1;
|
||||||
|
else if (rec_a->offset > rec_b->offset)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a variation selection context based on the format 14 cmap
|
||||||
|
subtable CMAP.
|
||||||
|
|
||||||
|
FD is the font file to which the table belongs.
|
||||||
|
|
||||||
|
Value is the variation selection context upon success, else NULL.
|
||||||
|
The context contains each variation selector record and their
|
||||||
|
associated default and nondefault UVS tables. Free the context
|
||||||
|
with `sfnt_free_uvs_context'. */
|
||||||
|
|
||||||
|
TEST_STATIC struct sfnt_uvs_context *
|
||||||
|
sfnt_create_uvs_context (struct sfnt_cmap_format_14 *cmap, int fd)
|
||||||
|
{
|
||||||
|
struct sfnt_table_offset_rec *table_offsets, *rec, template;
|
||||||
|
size_t size, i, nmemb, j;
|
||||||
|
off_t offset;
|
||||||
|
struct sfnt_uvs_context *context;
|
||||||
|
|
||||||
|
if (INT_MULTIPLY_WRAPV (cmap->num_var_selector_records,
|
||||||
|
sizeof *table_offsets, &size)
|
||||||
|
|| INT_MULTIPLY_WRAPV (size, 2, &size))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
context = NULL;
|
||||||
|
|
||||||
|
/* First, record and sort the UVS and nondefault UVS table offsets
|
||||||
|
in ascending order. */
|
||||||
|
|
||||||
|
table_offsets = xmalloc (size);
|
||||||
|
memset (table_offsets, 0, size);
|
||||||
|
nmemb = cmap->num_var_selector_records * 2;
|
||||||
|
j = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < cmap->num_var_selector_records; ++i)
|
||||||
|
{
|
||||||
|
/* Note that either offset may be 0, meaning there is no such
|
||||||
|
table. */
|
||||||
|
|
||||||
|
if (cmap->records[i].default_uvs_offset)
|
||||||
|
{
|
||||||
|
if (INT_ADD_WRAPV (cmap->offset,
|
||||||
|
cmap->records[i].default_uvs_offset,
|
||||||
|
&table_offsets[j].offset))
|
||||||
|
goto bail;
|
||||||
|
|
||||||
|
table_offsets[j++].is_nondefault_table = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmap->records[i].nondefault_uvs_offset)
|
||||||
|
{
|
||||||
|
if (INT_ADD_WRAPV (cmap->offset,
|
||||||
|
cmap->records[i].nondefault_uvs_offset,
|
||||||
|
&table_offsets[j].offset))
|
||||||
|
goto bail;
|
||||||
|
|
||||||
|
table_offsets[j++].is_nondefault_table = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make nmemb the number of offsets actually looked up. */
|
||||||
|
nmemb = j;
|
||||||
|
|
||||||
|
qsort (table_offsets, nmemb, sizeof *table_offsets,
|
||||||
|
sfnt_compare_table_offsets);
|
||||||
|
|
||||||
|
/* Now go through table_offsets, and read everything. nmemb is the
|
||||||
|
number of elements in table_offsets[i]; it is kept up to date
|
||||||
|
when duplicate members are removed. */
|
||||||
|
offset = -1;
|
||||||
|
|
||||||
|
for (i = 0; i < nmemb; ++i)
|
||||||
|
{
|
||||||
|
/* Skip past duplicate tables. */
|
||||||
|
|
||||||
|
while (table_offsets[i].offset == offset && i < nmemb)
|
||||||
|
{
|
||||||
|
nmemb--;
|
||||||
|
table_offsets[i] = table_offsets[i + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the last element of the array is a duplicate, break out of
|
||||||
|
the loop. */
|
||||||
|
|
||||||
|
if (i == nmemb)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Read the correct type of table depending on
|
||||||
|
table_offsets[i].is_nondefault_table. Then skip past
|
||||||
|
duplicate tables. Don't handle the case where two different
|
||||||
|
kind of tables share the same offset, because that is not
|
||||||
|
possible in a valid variation selector record. */
|
||||||
|
|
||||||
|
offset = table_offsets[i].offset;
|
||||||
|
|
||||||
|
if (table_offsets[i].is_nondefault_table)
|
||||||
|
table_offsets[i].table
|
||||||
|
= sfnt_read_nondefault_uvs_table (fd, offset);
|
||||||
|
else
|
||||||
|
table_offsets[i].table
|
||||||
|
= sfnt_read_default_uvs_table (fd, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now make the context. */
|
||||||
|
context = xmalloc (sizeof *context);
|
||||||
|
context->num_records = cmap->num_var_selector_records;
|
||||||
|
context->nmemb = nmemb;
|
||||||
|
context->records = xmalloc (sizeof *context->records
|
||||||
|
* cmap->num_var_selector_records);
|
||||||
|
|
||||||
|
for (i = 0; i < cmap->num_var_selector_records; ++i)
|
||||||
|
{
|
||||||
|
context->records[i].selector = cmap->records[i].var_selector;
|
||||||
|
|
||||||
|
/* Either offset may be 0, meaning no such table exists. Also,
|
||||||
|
the code below will lose if more than one kind of table
|
||||||
|
shares the same offset, because that is impossible. */
|
||||||
|
|
||||||
|
if (cmap->records[i].default_uvs_offset)
|
||||||
|
{
|
||||||
|
/* Resolve the default table. */
|
||||||
|
template.offset = (cmap->records[i].default_uvs_offset
|
||||||
|
+ cmap->offset);
|
||||||
|
rec = bsearch (&template, table_offsets,
|
||||||
|
nmemb, sizeof *table_offsets,
|
||||||
|
sfnt_compare_table_offsets);
|
||||||
|
|
||||||
|
/* Make sure this record is the right type. */
|
||||||
|
if (!rec || rec->is_nondefault_table || !rec->table)
|
||||||
|
goto bail;
|
||||||
|
|
||||||
|
context->records[i].default_uvs = rec->table;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
context->records[i].default_uvs = NULL;
|
||||||
|
|
||||||
|
if (cmap->records[i].nondefault_uvs_offset)
|
||||||
|
{
|
||||||
|
/* Resolve the nondefault table. */
|
||||||
|
template.offset = (cmap->records[i].nondefault_uvs_offset
|
||||||
|
+ cmap->offset);
|
||||||
|
rec = bsearch (&template, table_offsets,
|
||||||
|
nmemb, sizeof *table_offsets,
|
||||||
|
sfnt_compare_table_offsets);
|
||||||
|
|
||||||
|
if (!rec)
|
||||||
|
goto bail;
|
||||||
|
|
||||||
|
/* Make sure this record is the right type. */
|
||||||
|
if (!rec || !rec->is_nondefault_table || !rec->table)
|
||||||
|
goto bail;
|
||||||
|
|
||||||
|
context->records[i].nondefault_uvs = rec->table;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
context->records[i].nondefault_uvs = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
context->tables = table_offsets;
|
||||||
|
return context;
|
||||||
|
|
||||||
|
bail:
|
||||||
|
|
||||||
|
if (context)
|
||||||
|
{
|
||||||
|
xfree (context->records);
|
||||||
|
xfree (context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loop through and free any tables that might have been read
|
||||||
|
already. */
|
||||||
|
|
||||||
|
for (i = 0; i < nmemb; ++i)
|
||||||
|
xfree (table_offsets[i].table);
|
||||||
|
|
||||||
|
xfree (table_offsets);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free the specified variation selection context C. */
|
||||||
|
|
||||||
|
TEST_STATIC void
|
||||||
|
sfnt_free_uvs_context (struct sfnt_uvs_context *c)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
xfree (c->records);
|
||||||
|
|
||||||
|
for (i = 0; i < c->nmemb; ++i)
|
||||||
|
xfree (c->tables[i].table);
|
||||||
|
|
||||||
|
xfree (c->tables);
|
||||||
|
xfree (c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compare *(sfnt_char *) K to ((struct sfnt_uvs_mapping *)
|
||||||
|
V)->unicode_value appropriately for bsearch. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
sfnt_compare_uvs_mapping (const void *k, const void *v)
|
||||||
|
{
|
||||||
|
const sfnt_char *key;
|
||||||
|
const struct sfnt_uvs_mapping *value;
|
||||||
|
|
||||||
|
key = k;
|
||||||
|
value = v;
|
||||||
|
|
||||||
|
if (*key < value->unicode_value)
|
||||||
|
return -1;
|
||||||
|
else if (*key == value->unicode_value)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the ID of a variation glyph for the character C in the
|
||||||
|
nondefault UVS mapping table UVS.
|
||||||
|
|
||||||
|
Value is the glyph ID upon success, or 0 if there is no variation
|
||||||
|
glyph for the base character C. */
|
||||||
|
|
||||||
|
TEST_STATIC sfnt_glyph
|
||||||
|
sfnt_variation_glyph_for_char (struct sfnt_nondefault_uvs_table *uvs,
|
||||||
|
sfnt_char c)
|
||||||
|
{
|
||||||
|
struct sfnt_uvs_mapping *mapping;
|
||||||
|
|
||||||
|
mapping = bsearch (&c, uvs->mappings, uvs->num_uvs_mappings,
|
||||||
|
sizeof *uvs->mappings,
|
||||||
|
sfnt_compare_uvs_mapping);
|
||||||
|
|
||||||
|
return mapping ? mapping->base_character_value : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if defined HAVE_MMAP && !defined TEST
|
||||||
|
|
||||||
|
/* Memory mapping support.
|
||||||
|
It useful to map OpenType layout tables prior to using them in
|
||||||
|
an external shaping engine such as HarfBuzz. */
|
||||||
|
|
||||||
|
/* Map a table identified by TAG into the structure *TABLE.
|
||||||
|
TAG is swapped into host byte order.
|
||||||
|
|
||||||
|
Use the table directory SUBTABLE, which corresponds to the font
|
||||||
|
file FD.
|
||||||
|
|
||||||
|
Return 0 upon success, and set TABLE->data to the table data,
|
||||||
|
TABLE->mapping to the start of the mapped area, TABLE->length to
|
||||||
|
the length of the table contents, and TABLE->size to the size of
|
||||||
|
the mapping.
|
||||||
|
|
||||||
|
Return 1 upon failure. */
|
||||||
|
|
||||||
|
int
|
||||||
|
sfnt_map_table (int fd, struct sfnt_offset_subtable *subtable,
|
||||||
|
uint32_t tag, struct sfnt_mapped_table *table)
|
||||||
|
{
|
||||||
|
struct sfnt_table_directory *directory;
|
||||||
|
size_t offset, page, map_offset;
|
||||||
|
void *data;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Find the table in the directory. */
|
||||||
|
|
||||||
|
for (i = 0; i < subtable->num_tables; ++i)
|
||||||
|
{
|
||||||
|
if (subtable->subtables[i].tag == tag)
|
||||||
|
{
|
||||||
|
directory = &subtable->subtables[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == subtable->num_tables)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* Now try to map the glyph data. Make sure offset is a multiple of
|
||||||
|
the page size. */
|
||||||
|
|
||||||
|
page = getpagesize ();
|
||||||
|
offset = directory->offset & ~(page - 1);
|
||||||
|
|
||||||
|
/* Figure out how much larger the mapping should be. */
|
||||||
|
map_offset = directory->offset - offset;
|
||||||
|
|
||||||
|
/* Do the mmap. */
|
||||||
|
data = mmap (NULL, directory->length + map_offset,
|
||||||
|
PROT_READ, MAP_PRIVATE, fd, offset);
|
||||||
|
|
||||||
|
if (data == MAP_FAILED)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* Fill in *TABLE. */
|
||||||
|
table->data = (unsigned char *) data + map_offset;
|
||||||
|
table->mapping = data;
|
||||||
|
table->length = directory->length;
|
||||||
|
table->size = directory->length + map_offset;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unmap the table inside *TABLE.
|
||||||
|
Value is 0 upon success, 1 otherwise. */
|
||||||
|
|
||||||
|
int
|
||||||
|
sfnt_unmap_table (struct sfnt_mapped_table *table)
|
||||||
|
{
|
||||||
|
return munmap (table->mapping, table->size) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* HAVE_MMAP && !TEST */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef TEST
|
||||||
|
|
||||||
|
/* Reading table contents. */
|
||||||
|
|
||||||
|
/* Read the table with the specified TAG from the font file FD.
|
||||||
|
Return its length in *LENGTH, and its data upon success, else
|
||||||
|
NULL. */
|
||||||
|
|
||||||
|
void *
|
||||||
|
sfnt_read_table (int fd, struct sfnt_offset_subtable *subtable,
|
||||||
|
uint32_t tag, size_t *length)
|
||||||
|
{
|
||||||
|
struct sfnt_table_directory *directory;
|
||||||
|
void *data;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Find the table in the directory. */
|
||||||
|
|
||||||
|
for (i = 0; i < subtable->num_tables; ++i)
|
||||||
|
{
|
||||||
|
if (subtable->subtables[i].tag == tag)
|
||||||
|
{
|
||||||
|
directory = &subtable->subtables[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == subtable->num_tables)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Seek to the table. */
|
||||||
|
|
||||||
|
if (lseek (fd, directory->offset, SEEK_SET) != directory->offset)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Now allocate enough to hold the data and read into it. */
|
||||||
|
|
||||||
|
data = xmalloc (directory->length);
|
||||||
|
if (read (fd, data, directory->length) != directory->length)
|
||||||
|
{
|
||||||
|
xfree (data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the length and table data. */
|
||||||
|
*length = directory->length;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* !TEST */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef TEST
|
#ifdef TEST
|
||||||
|
|
||||||
struct sfnt_test_dcontext
|
struct sfnt_test_dcontext
|
||||||
|
@ -15494,6 +16152,52 @@ sfnt_pop_hook (struct sfnt_interpreter *interpreter,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
sfnt_test_uvs (int fd, struct sfnt_cmap_format_14 *format14)
|
||||||
|
{
|
||||||
|
struct sfnt_uvs_context *context;
|
||||||
|
size_t i, j;
|
||||||
|
sfnt_glyph glyph;
|
||||||
|
sfnt_char c;
|
||||||
|
struct sfnt_nondefault_uvs_table *uvs;
|
||||||
|
|
||||||
|
context = sfnt_create_uvs_context (format14, fd);
|
||||||
|
|
||||||
|
/* Print each variation selector and its associated ranges. */
|
||||||
|
|
||||||
|
if (!context)
|
||||||
|
fprintf (stderr, "failed to read uvs data\n");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf (stderr, "UVS context with %zu records and %zu tables\n",
|
||||||
|
context->num_records, context->nmemb);
|
||||||
|
|
||||||
|
for (i = 0; i < context->num_records; ++i)
|
||||||
|
{
|
||||||
|
if (!context->records[i].nondefault_uvs)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uvs = context->records[i].nondefault_uvs;
|
||||||
|
|
||||||
|
for (j = 0; j < uvs->num_uvs_mappings; ++j)
|
||||||
|
{
|
||||||
|
c = uvs->mappings[j].unicode_value;
|
||||||
|
glyph = sfnt_variation_glyph_for_char (uvs, c);
|
||||||
|
|
||||||
|
if (glyph != uvs->mappings[j].base_character_value)
|
||||||
|
abort ();
|
||||||
|
|
||||||
|
fprintf (stderr, " UVS: %"PRIx32" (%"PRIx32") -> %"PRIu32"\n",
|
||||||
|
c, context->records[i].selector, glyph);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sfnt_free_uvs_context (context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Main entry point. */
|
/* Main entry point. */
|
||||||
|
|
||||||
/* Simple tests that were used while developing this file. By the
|
/* Simple tests that were used while developing this file. By the
|
||||||
|
@ -15564,7 +16268,7 @@ main (int argc, char **argv)
|
||||||
struct sfnt_raster **rasters;
|
struct sfnt_raster **rasters;
|
||||||
size_t length;
|
size_t length;
|
||||||
|
|
||||||
if (argc != 2)
|
if (argc < 2)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (!strcmp (argv[1], "--check-interpreter"))
|
if (!strcmp (argv[1], "--check-interpreter"))
|
||||||
|
@ -15654,8 +16358,25 @@ main (int argc, char **argv)
|
||||||
data[i]->format);
|
data[i]->format);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define FANCY_PPEM 12
|
if (argc >= 3 && !strcmp (argv[2], "--check-variation-selectors"))
|
||||||
#define EASY_PPEM 12
|
{
|
||||||
|
/* Look for a format 14 cmap table. */
|
||||||
|
|
||||||
|
for (i = 0; i < table->num_subtables; ++i)
|
||||||
|
{
|
||||||
|
if (data[i]->format == 14)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "format 14 subtable found\n");
|
||||||
|
sfnt_test_uvs (fd, (struct sfnt_cmap_format_14 *) data[i]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FANCY_PPEM 25
|
||||||
|
#define EASY_PPEM 25
|
||||||
|
|
||||||
interpreter = NULL;
|
interpreter = NULL;
|
||||||
head = sfnt_read_head_table (fd, font);
|
head = sfnt_read_head_table (fd, font);
|
||||||
|
|
165
src/sfnt.h
165
src/sfnt.h
|
@ -25,6 +25,8 @@ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
#if defined emacs || defined TEST
|
#if defined emacs || defined TEST
|
||||||
#define SFNT_ENABLE_HINTING
|
#define SFNT_ENABLE_HINTING
|
||||||
#endif
|
#endif
|
||||||
|
@ -422,7 +424,7 @@ struct sfnt_cmap_format_8
|
||||||
struct sfnt_cmap_format_8_or_12_group *groups;
|
struct sfnt_cmap_format_8_or_12_group *groups;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* cmap formats 10, 13 and 14 unsupported. */
|
/* cmap formats 10, 13 unsupported. */
|
||||||
|
|
||||||
struct sfnt_cmap_format_12
|
struct sfnt_cmap_format_12
|
||||||
{
|
{
|
||||||
|
@ -445,6 +447,36 @@ struct sfnt_cmap_format_12
|
||||||
struct sfnt_cmap_format_8_or_12_group *groups;
|
struct sfnt_cmap_format_8_or_12_group *groups;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct sfnt_cmap_format_14
|
||||||
|
{
|
||||||
|
/* Format, set to 14. */
|
||||||
|
uint16_t format;
|
||||||
|
|
||||||
|
/* The length of the table in bytes. */
|
||||||
|
uint32_t length;
|
||||||
|
|
||||||
|
/* Number of variation selector records. */
|
||||||
|
uint16_t num_var_selector_records;
|
||||||
|
|
||||||
|
/* The offset of this table in the font file. */
|
||||||
|
off_t offset;
|
||||||
|
|
||||||
|
/* Variable length data. */
|
||||||
|
struct sfnt_variation_selector_record *records;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sfnt_variation_selector_record
|
||||||
|
{
|
||||||
|
/* 24-bit unsigned variation selector. */
|
||||||
|
unsigned int var_selector;
|
||||||
|
|
||||||
|
/* Offset to default UVS table. */
|
||||||
|
uint32_t default_uvs_offset;
|
||||||
|
|
||||||
|
/* Offset to non-default UVS table. */
|
||||||
|
uint32_t nondefault_uvs_offset;
|
||||||
|
};
|
||||||
|
|
||||||
struct sfnt_maxp_table
|
struct sfnt_maxp_table
|
||||||
{
|
{
|
||||||
/* Table version. */
|
/* Table version. */
|
||||||
|
@ -1437,6 +1469,106 @@ struct sfnt_instructed_outline
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Unicode Variation Sequence (UVS) support. */
|
||||||
|
|
||||||
|
struct sfnt_default_uvs_table
|
||||||
|
{
|
||||||
|
/* Number of ranges that follow. */
|
||||||
|
uint32_t num_unicode_value_ranges;
|
||||||
|
|
||||||
|
/* Variable length data. */
|
||||||
|
struct sfnt_unicode_value_range *ranges;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sfnt_unicode_value_range
|
||||||
|
{
|
||||||
|
/* First value in this range. */
|
||||||
|
unsigned int start_unicode_value;
|
||||||
|
|
||||||
|
/* Number of additional values in this range. */
|
||||||
|
unsigned char additional_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sfnt_nondefault_uvs_table
|
||||||
|
{
|
||||||
|
/* Number of UVS mappings which follow. */
|
||||||
|
uint32_t num_uvs_mappings;
|
||||||
|
|
||||||
|
/* Variable length data. */
|
||||||
|
struct sfnt_uvs_mapping *mappings;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sfnt_uvs_mapping
|
||||||
|
{
|
||||||
|
/* Base character value. */
|
||||||
|
unsigned int unicode_value;
|
||||||
|
|
||||||
|
/* Glyph ID of the base character value. */
|
||||||
|
uint16_t base_character_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sfnt_mapped_variation_selector_record
|
||||||
|
{
|
||||||
|
/* The variation selector. */
|
||||||
|
unsigned int selector;
|
||||||
|
|
||||||
|
/* Its default UVS table. */
|
||||||
|
struct sfnt_default_uvs_table *default_uvs;
|
||||||
|
|
||||||
|
/* Its nondefault UVS table. */
|
||||||
|
struct sfnt_nondefault_uvs_table *nondefault_uvs;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Structure describing a single offset to load into a variation
|
||||||
|
selection context. */
|
||||||
|
|
||||||
|
struct sfnt_table_offset_rec
|
||||||
|
{
|
||||||
|
/* The offset from the start of the font file. */
|
||||||
|
off_t offset;
|
||||||
|
|
||||||
|
/* Whether or not the offset points to a non-default UVS table. */
|
||||||
|
bool is_nondefault_table;
|
||||||
|
|
||||||
|
/* Pointer to the UVS table. */
|
||||||
|
void *table;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sfnt_uvs_context
|
||||||
|
{
|
||||||
|
/* Number of records and tables. */
|
||||||
|
size_t num_records, nmemb;
|
||||||
|
|
||||||
|
/* Array of UVS tables. */
|
||||||
|
struct sfnt_table_offset_rec *tables;
|
||||||
|
|
||||||
|
/* Array of variation selector records mapped to
|
||||||
|
their corresponding tables. */
|
||||||
|
struct sfnt_mapped_variation_selector_record *records;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if defined HAVE_MMAP && !defined TEST
|
||||||
|
|
||||||
|
/* Memory mapping support. */
|
||||||
|
|
||||||
|
struct sfnt_mapped_table
|
||||||
|
{
|
||||||
|
/* Pointer to table data. */
|
||||||
|
void *data;
|
||||||
|
|
||||||
|
/* Pointer to table mapping. */
|
||||||
|
void *mapping;
|
||||||
|
|
||||||
|
/* Size of mapped data and size of mapping. */
|
||||||
|
size_t length, size;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* HAVE_MMAP && !TEST */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Functions used to read tables used by the TrueType interpreter. */
|
/* Functions used to read tables used by the TrueType interpreter. */
|
||||||
|
|
||||||
#ifndef TEST
|
#ifndef TEST
|
||||||
|
@ -1509,6 +1641,37 @@ extern const char *sfnt_interpret_compound_glyph (PROTOTYPE);
|
||||||
|
|
||||||
#undef PROTOTYPE
|
#undef PROTOTYPE
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define PROTOTYPE struct sfnt_cmap_format_14 *, int
|
||||||
|
|
||||||
|
extern struct sfnt_uvs_context *sfnt_create_uvs_context (PROTOTYPE);
|
||||||
|
|
||||||
|
#undef PROTOTYPE
|
||||||
|
|
||||||
|
extern void sfnt_free_uvs_context (struct sfnt_uvs_context *);
|
||||||
|
|
||||||
|
#define PROTOTYPE struct sfnt_nondefault_uvs_table *, sfnt_char
|
||||||
|
|
||||||
|
extern sfnt_glyph sfnt_variation_glyph_for_char (PROTOTYPE);
|
||||||
|
|
||||||
|
#undef PROTOTYPE
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAVE_MMAP
|
||||||
|
|
||||||
|
extern int sfnt_map_table (int, struct sfnt_offset_subtable *,
|
||||||
|
uint32_t, struct sfnt_mapped_table *);
|
||||||
|
extern int sfnt_unmap_table (struct sfnt_mapped_table *);
|
||||||
|
|
||||||
|
#endif /* HAVE_MMAP */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
extern void *sfnt_read_table (int, struct sfnt_offset_subtable *,
|
||||||
|
uint32_t, size_t *);
|
||||||
|
|
||||||
#endif /* TEST */
|
#endif /* TEST */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -657,8 +657,16 @@ const struct font_driver android_sfntfont_driver =
|
||||||
.encode_char = sfntfont_encode_char,
|
.encode_char = sfntfont_encode_char,
|
||||||
.text_extents = sfntfont_text_extents,
|
.text_extents = sfntfont_text_extents,
|
||||||
.list_family = sfntfont_list_family,
|
.list_family = sfntfont_list_family,
|
||||||
|
.get_variation_glyphs = sfntfont_get_variation_glyphs,
|
||||||
|
|
||||||
/* TODO: list_family, shaping. */
|
#ifdef HAVE_HARFBUZZ
|
||||||
|
/* HarfBuzz support is enabled transparently on Android without
|
||||||
|
using a separate font driver. */
|
||||||
|
.begin_hb_font = sfntfont_begin_hb_font,
|
||||||
|
.combining_capability = hbfont_combining_capability,
|
||||||
|
.shape = hbfont_shape,
|
||||||
|
.otf_capability = hbfont_otf_capability,
|
||||||
|
#endif /* HAVE_HARFBUZZ */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
384
src/sfntfont.c
384
src/sfntfont.c
|
@ -34,6 +34,11 @@ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||||
#include "sfnt.h"
|
#include "sfnt.h"
|
||||||
#include "sfntfont.h"
|
#include "sfntfont.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_HARFBUZZ
|
||||||
|
#include <hb.h>
|
||||||
|
#include <hb-ot.h>
|
||||||
|
#endif /* HAVE_HARFBUZZ */
|
||||||
|
|
||||||
/* For FRAME_FONT. */
|
/* For FRAME_FONT. */
|
||||||
#include TERM_HEADER
|
#include TERM_HEADER
|
||||||
|
|
||||||
|
@ -1038,15 +1043,20 @@ sfntfont_charset_for_cmap (struct sfnt_cmap_encoding_subtable subtable)
|
||||||
|
|
||||||
/* Pick the best character map in the cmap table CMAP. Use the
|
/* Pick the best character map in the cmap table CMAP. Use the
|
||||||
subtables in SUBTABLES and DATA. Return the subtable data and the
|
subtables in SUBTABLES and DATA. Return the subtable data and the
|
||||||
subtable in *SUBTABLE upon success, NULL otherwise. */
|
subtable in *SUBTABLE upon success, NULL otherwise.
|
||||||
|
|
||||||
|
If FORMAT14 is non-NULL, return any associated format 14 variation
|
||||||
|
selection context in *FORMAT14 should the selected charcter map be
|
||||||
|
a Unicode character map. */
|
||||||
|
|
||||||
static struct sfnt_cmap_encoding_subtable_data *
|
static struct sfnt_cmap_encoding_subtable_data *
|
||||||
sfntfont_select_cmap (struct sfnt_cmap_table *cmap,
|
sfntfont_select_cmap (struct sfnt_cmap_table *cmap,
|
||||||
struct sfnt_cmap_encoding_subtable *subtables,
|
struct sfnt_cmap_encoding_subtable *subtables,
|
||||||
struct sfnt_cmap_encoding_subtable_data **data,
|
struct sfnt_cmap_encoding_subtable_data **data,
|
||||||
struct sfnt_cmap_encoding_subtable *subtable)
|
struct sfnt_cmap_encoding_subtable *subtable,
|
||||||
|
struct sfnt_cmap_format_14 **format14)
|
||||||
{
|
{
|
||||||
int i;
|
int i, j;
|
||||||
|
|
||||||
/* First look for a non-BMP Unicode cmap. */
|
/* First look for a non-BMP Unicode cmap. */
|
||||||
|
|
||||||
|
@ -1055,6 +1065,24 @@ sfntfont_select_cmap (struct sfnt_cmap_table *cmap,
|
||||||
if (data[i] && sfntfont_identify_cmap (subtables[i]) == 2)
|
if (data[i] && sfntfont_identify_cmap (subtables[i]) == 2)
|
||||||
{
|
{
|
||||||
*subtable = subtables[i];
|
*subtable = subtables[i];
|
||||||
|
|
||||||
|
if (!format14)
|
||||||
|
return data[i];
|
||||||
|
|
||||||
|
/* Search for a correspoinding format 14 character map.
|
||||||
|
This is used in conjunction with the selected character
|
||||||
|
map to map variation sequences. */
|
||||||
|
|
||||||
|
for (j = 0; j < cmap->num_subtables; ++j)
|
||||||
|
{
|
||||||
|
if (data[j]
|
||||||
|
&& subtables[j].platform_id == SFNT_PLATFORM_UNICODE
|
||||||
|
&& (subtables[j].platform_specific_id
|
||||||
|
== SFNT_UNICODE_VARIATION_SEQUENCES)
|
||||||
|
&& data[j]->format == 14)
|
||||||
|
*format14 = (struct sfnt_cmap_format_14 *) data[j];
|
||||||
|
}
|
||||||
|
|
||||||
return data[i];
|
return data[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1066,6 +1094,24 @@ sfntfont_select_cmap (struct sfnt_cmap_table *cmap,
|
||||||
if (data[i] && sfntfont_identify_cmap (subtables[i]) == 1)
|
if (data[i] && sfntfont_identify_cmap (subtables[i]) == 1)
|
||||||
{
|
{
|
||||||
*subtable = subtables[i];
|
*subtable = subtables[i];
|
||||||
|
|
||||||
|
if (!format14)
|
||||||
|
return data[i];
|
||||||
|
|
||||||
|
/* Search for a correspoinding format 14 character map.
|
||||||
|
This is used in conjunction with the selected character
|
||||||
|
map to map variation sequences. */
|
||||||
|
|
||||||
|
for (j = 0; j < cmap->num_subtables; ++j)
|
||||||
|
{
|
||||||
|
if (data[j]
|
||||||
|
&& subtables[j].platform_id == SFNT_PLATFORM_UNICODE
|
||||||
|
&& (subtables[j].platform_specific_id
|
||||||
|
== SFNT_UNICODE_VARIATION_SEQUENCES)
|
||||||
|
&& data[j]->format == 14)
|
||||||
|
*format14 = (struct sfnt_cmap_format_14 *) data[j];
|
||||||
|
}
|
||||||
|
|
||||||
return data[i];
|
return data[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1128,7 +1174,7 @@ sfntfont_read_cmap (struct sfnt_font_desc *desc,
|
||||||
/* Now pick the best character map. */
|
/* Now pick the best character map. */
|
||||||
|
|
||||||
*cmap = sfntfont_select_cmap (table, subtables, data,
|
*cmap = sfntfont_select_cmap (table, subtables, data,
|
||||||
subtable);
|
subtable, NULL);
|
||||||
|
|
||||||
/* Free the cmap data. */
|
/* Free the cmap data. */
|
||||||
|
|
||||||
|
@ -1960,6 +2006,9 @@ struct sfnt_font_info
|
||||||
/* Data identifying that character map. */
|
/* Data identifying that character map. */
|
||||||
struct sfnt_cmap_encoding_subtable cmap_subtable;
|
struct sfnt_cmap_encoding_subtable cmap_subtable;
|
||||||
|
|
||||||
|
/* The UVS context. */
|
||||||
|
struct sfnt_uvs_context *uvs;
|
||||||
|
|
||||||
/* Outline cache. */
|
/* Outline cache. */
|
||||||
struct sfnt_outline_cache outline_cache;
|
struct sfnt_outline_cache outline_cache;
|
||||||
|
|
||||||
|
@ -1983,6 +2032,17 @@ struct sfnt_font_info
|
||||||
/* Whether or not the glyph table has been mmapped. */
|
/* Whether or not the glyph table has been mmapped. */
|
||||||
bool glyf_table_mapped;
|
bool glyf_table_mapped;
|
||||||
#endif /* HAVE_MMAP */
|
#endif /* HAVE_MMAP */
|
||||||
|
|
||||||
|
#ifdef HAVE_HARFBUZZ
|
||||||
|
/* HarfBuzz font object. */
|
||||||
|
hb_font_t *hb_font;
|
||||||
|
|
||||||
|
/* File descriptor associated with this font. */
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
/* The table directory of the font file. */
|
||||||
|
struct sfnt_offset_subtable *directory;
|
||||||
|
#endif /* HAVE_HARFBUZZ */
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef HAVE_MMAP
|
#ifdef HAVE_MMAP
|
||||||
|
@ -2198,6 +2258,7 @@ sfntfont_open (struct frame *f, Lisp_Object font_entity,
|
||||||
struct charset *charset;
|
struct charset *charset;
|
||||||
int point_size;
|
int point_size;
|
||||||
Display_Info *dpyinfo;
|
Display_Info *dpyinfo;
|
||||||
|
struct sfnt_cmap_format_14 *format14;
|
||||||
|
|
||||||
if (XFIXNUM (AREF (font_entity, FONT_SIZE_INDEX)) != 0)
|
if (XFIXNUM (AREF (font_entity, FONT_SIZE_INDEX)) != 0)
|
||||||
pixel_size = XFIXNUM (AREF (font_entity, FONT_SIZE_INDEX));
|
pixel_size = XFIXNUM (AREF (font_entity, FONT_SIZE_INDEX));
|
||||||
|
@ -2240,6 +2301,7 @@ sfntfont_open (struct frame *f, Lisp_Object font_entity,
|
||||||
font_info->prep = NULL;
|
font_info->prep = NULL;
|
||||||
font_info->fpgm = NULL;
|
font_info->fpgm = NULL;
|
||||||
font_info->cvt = NULL;
|
font_info->cvt = NULL;
|
||||||
|
font_info->uvs = NULL;
|
||||||
|
|
||||||
font_info->outline_cache.next = &font_info->outline_cache;
|
font_info->outline_cache.next = &font_info->outline_cache;
|
||||||
font_info->outline_cache.last = &font_info->outline_cache;
|
font_info->outline_cache.last = &font_info->outline_cache;
|
||||||
|
@ -2251,6 +2313,11 @@ sfntfont_open (struct frame *f, Lisp_Object font_entity,
|
||||||
#ifdef HAVE_MMAP
|
#ifdef HAVE_MMAP
|
||||||
font_info->glyf_table_mapped = false;
|
font_info->glyf_table_mapped = false;
|
||||||
#endif /* HAVE_MMAP */
|
#endif /* HAVE_MMAP */
|
||||||
|
#ifdef HAVE_HARFBUZZ
|
||||||
|
font_info->hb_font = NULL;
|
||||||
|
font_info->fd = -1;
|
||||||
|
font_info->directory = NULL;
|
||||||
|
#endif /* HAVE_HARFBUZZ */
|
||||||
|
|
||||||
/* Open the font. */
|
/* Open the font. */
|
||||||
fd = emacs_open (desc->path, O_RDONLY, 0);
|
fd = emacs_open (desc->path, O_RDONLY, 0);
|
||||||
|
@ -2280,14 +2347,29 @@ sfntfont_open (struct frame *f, Lisp_Object font_entity,
|
||||||
if (!font_info->cmap)
|
if (!font_info->cmap)
|
||||||
goto bail2;
|
goto bail2;
|
||||||
|
|
||||||
|
format14 = NULL;
|
||||||
font_info->cmap_data
|
font_info->cmap_data
|
||||||
= sfntfont_select_cmap (font_info->cmap,
|
= sfntfont_select_cmap (font_info->cmap,
|
||||||
subtables, data,
|
subtables, data,
|
||||||
&font_info->cmap_subtable);
|
&font_info->cmap_subtable,
|
||||||
|
&format14);
|
||||||
|
|
||||||
|
if (format14)
|
||||||
|
{
|
||||||
|
/* Build a UVS context from this format 14 mapping table. A UVS
|
||||||
|
context contains each variation selector supported by the
|
||||||
|
font, and a list of ``non-default'' mappings between base
|
||||||
|
characters and variation glyph IDs. */
|
||||||
|
|
||||||
|
font_info->uvs = sfnt_create_uvs_context (format14, fd);
|
||||||
|
xfree (format14);
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < font_info->cmap->num_subtables; ++i)
|
for (i = 0; i < font_info->cmap->num_subtables; ++i)
|
||||||
{
|
{
|
||||||
if (data[i] != font_info->cmap_data)
|
if (data[i] != font_info->cmap_data
|
||||||
|
/* format14 has already been freed. */
|
||||||
|
&& data[i] != (struct sfnt_cmap_encoding_subtable_data *) format14)
|
||||||
xfree (data[i]);
|
xfree (data[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2432,11 +2514,19 @@ sfntfont_open (struct frame *f, Lisp_Object font_entity,
|
||||||
sfntfont_setup_interpreter (fd, font_info, subtable,
|
sfntfont_setup_interpreter (fd, font_info, subtable,
|
||||||
point_size);
|
point_size);
|
||||||
|
|
||||||
|
#ifndef HAVE_HARFBUZZ
|
||||||
/* Close the font file descriptor. */
|
/* Close the font file descriptor. */
|
||||||
emacs_close (fd);
|
emacs_close (fd);
|
||||||
|
|
||||||
/* Free the offset subtable. */
|
/* Free the offset subtable. */
|
||||||
xfree (subtable);
|
xfree (subtable);
|
||||||
|
#else /* HAVE_HARFBUZZ */
|
||||||
|
/* HarfBuzz will potentially read font tables after the font has
|
||||||
|
been opened by Emacs. Keep the font open, and record its offset
|
||||||
|
subtable. */
|
||||||
|
font_info->fd = fd;
|
||||||
|
font_info->directory = subtable;
|
||||||
|
#endif /* !HAVE_HARFBUZZ */
|
||||||
|
|
||||||
#ifdef HAVE_MMAP
|
#ifdef HAVE_MMAP
|
||||||
/* Link the font onto the font table. */
|
/* Link the font onto the font table. */
|
||||||
|
@ -2483,6 +2573,10 @@ sfntfont_open (struct frame *f, Lisp_Object font_entity,
|
||||||
xfree (font_info->cmap_data);
|
xfree (font_info->cmap_data);
|
||||||
font_info->cmap_data = NULL;
|
font_info->cmap_data = NULL;
|
||||||
bail3:
|
bail3:
|
||||||
|
|
||||||
|
if (font_info->uvs)
|
||||||
|
sfnt_free_uvs_context (font_info->uvs);
|
||||||
|
|
||||||
xfree (font_info->cmap);
|
xfree (font_info->cmap);
|
||||||
font_info->cmap = NULL;
|
font_info->cmap = NULL;
|
||||||
bail2:
|
bail2:
|
||||||
|
@ -2677,8 +2771,7 @@ sfntfont_close (struct font *font)
|
||||||
xfree (info->hmtx);
|
xfree (info->hmtx);
|
||||||
|
|
||||||
#ifdef HAVE_MMAP
|
#ifdef HAVE_MMAP
|
||||||
if (info->glyf_table_mapped
|
if (info->glyf_table_mapped && info->glyf)
|
||||||
&& info->glyf)
|
|
||||||
{
|
{
|
||||||
rc = sfnt_unmap_glyf_table (info->glyf);
|
rc = sfnt_unmap_glyf_table (info->glyf);
|
||||||
|
|
||||||
|
@ -2697,6 +2790,12 @@ sfntfont_close (struct font *font)
|
||||||
xfree (info->cvt);
|
xfree (info->cvt);
|
||||||
xfree (info->interpreter);
|
xfree (info->interpreter);
|
||||||
|
|
||||||
|
/* Deallocate any UVS context allocated to look up font variation
|
||||||
|
sequences. */
|
||||||
|
|
||||||
|
if (info->uvs)
|
||||||
|
sfnt_free_uvs_context (info->uvs);
|
||||||
|
|
||||||
/* Clear these fields. It seems that close can be called twice,
|
/* Clear these fields. It seems that close can be called twice,
|
||||||
once during font driver destruction, and once during GC. */
|
once during font driver destruction, and once during GC. */
|
||||||
|
|
||||||
|
@ -2713,6 +2812,7 @@ sfntfont_close (struct font *font)
|
||||||
info->fpgm = NULL;
|
info->fpgm = NULL;
|
||||||
info->cvt = NULL;
|
info->cvt = NULL;
|
||||||
info->interpreter = NULL;
|
info->interpreter = NULL;
|
||||||
|
info->uvs = NULL;
|
||||||
|
|
||||||
#ifdef HAVE_MMAP
|
#ifdef HAVE_MMAP
|
||||||
|
|
||||||
|
@ -2728,6 +2828,28 @@ sfntfont_close (struct font *font)
|
||||||
|
|
||||||
#endif /* HAVE_MMAP */
|
#endif /* HAVE_MMAP */
|
||||||
|
|
||||||
|
#ifdef HAVE_HARFBUZZ
|
||||||
|
/* Close the font file. */
|
||||||
|
|
||||||
|
if (info->fd != -1)
|
||||||
|
{
|
||||||
|
emacs_close (info->fd);
|
||||||
|
info->fd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free its table directory. */
|
||||||
|
xfree (info->directory);
|
||||||
|
info->directory = NULL;
|
||||||
|
|
||||||
|
/* Free any hb_font created. */
|
||||||
|
|
||||||
|
if (info->hb_font)
|
||||||
|
{
|
||||||
|
hb_font_destroy (info->hb_font);
|
||||||
|
info->hb_font = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
sfntfont_free_outline_cache (&info->outline_cache);
|
sfntfont_free_outline_cache (&info->outline_cache);
|
||||||
sfntfont_free_raster_cache (&info->raster_cache);
|
sfntfont_free_raster_cache (&info->raster_cache);
|
||||||
}
|
}
|
||||||
|
@ -2821,7 +2943,11 @@ sfntfont_draw (struct glyph_string *s, int from, int to,
|
||||||
|
|
||||||
/* Now work out where to put the outline. */
|
/* Now work out where to put the outline. */
|
||||||
x_coords[i - from] = current_x;
|
x_coords[i - from] = current_x;
|
||||||
current_x += SFNT_CEIL_FIXED (metrics.advance) >> 16;
|
|
||||||
|
if (s->padding_p)
|
||||||
|
current_x += 1;
|
||||||
|
else
|
||||||
|
current_x += SFNT_CEIL_FIXED (metrics.advance) >> 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Call the window system function to put the glyphs to the
|
/* Call the window system function to put the glyphs to the
|
||||||
|
@ -2865,6 +2991,126 @@ sfntfont_list_family (struct frame *f)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Unicode Variation Selector (UVS) support. This is typically
|
||||||
|
required for Harfbuzz. */
|
||||||
|
|
||||||
|
/* Given a FONT object, a character C, and VARIATIONS, return the
|
||||||
|
number of non-default variation glyphs, and their glyph ids in
|
||||||
|
VARIATIONS.
|
||||||
|
|
||||||
|
For each variation selector character K with a non-default glyph in
|
||||||
|
the variation selector range 0xFE00 to 0xFE0F, set variations[K -
|
||||||
|
0xFE0] to its ID.
|
||||||
|
|
||||||
|
For each variation selector character K with a non-default glyph in
|
||||||
|
the variation selector range 0xE0100 to 0xE01EF, set variations[K -
|
||||||
|
0xE0100 + 16] to its ID.
|
||||||
|
|
||||||
|
If value is more than 0, set all other members of VARIATIONS to 0.
|
||||||
|
Else, the contents of VARIATIONS are undefined. */
|
||||||
|
|
||||||
|
int
|
||||||
|
sfntfont_get_variation_glyphs (struct font *font, int c,
|
||||||
|
unsigned variations[256])
|
||||||
|
{
|
||||||
|
struct sfnt_font_info *info;
|
||||||
|
size_t i;
|
||||||
|
int n;
|
||||||
|
struct sfnt_mapped_variation_selector_record *record;
|
||||||
|
|
||||||
|
info = (struct sfnt_font_info *) font;
|
||||||
|
n = 0;
|
||||||
|
|
||||||
|
/* Return 0 if there is no UVS mapping table. */
|
||||||
|
|
||||||
|
if (!info->uvs)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Clear the variations array. */
|
||||||
|
|
||||||
|
memset (variations, 0, sizeof *variations * 256);
|
||||||
|
|
||||||
|
/* Find the first 0xFExx selector. */
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (i < info->uvs->num_records
|
||||||
|
&& info->uvs->records[i].selector < 0xfe00)
|
||||||
|
++i;
|
||||||
|
|
||||||
|
/* Fill in selectors 0 to 15. */
|
||||||
|
|
||||||
|
while (i < info->uvs->num_records
|
||||||
|
&& info->uvs->records[i].selector <= 0xfe0f)
|
||||||
|
{
|
||||||
|
record = &info->uvs->records[i];
|
||||||
|
|
||||||
|
/* If record has no non-default mappings, continue on to the
|
||||||
|
next selector. */
|
||||||
|
|
||||||
|
if (!record->nondefault_uvs)
|
||||||
|
goto next_selector;
|
||||||
|
|
||||||
|
/* Handle invalid unsorted tables. */
|
||||||
|
|
||||||
|
if (record->selector < 0xfe00)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Find the glyph ID associated with C and put it in
|
||||||
|
VARIATIONS. */
|
||||||
|
|
||||||
|
variations[info->uvs->records[i].selector - 0xfe00]
|
||||||
|
= sfnt_variation_glyph_for_char (record->nondefault_uvs, c);
|
||||||
|
|
||||||
|
if (variations[info->uvs->records[i].selector - 0xfe00])
|
||||||
|
++n;
|
||||||
|
|
||||||
|
next_selector:
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find the first 0xE0100 selector. */
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (i < info->uvs->num_records
|
||||||
|
&& info->uvs->records[i].selector < 0xe0100)
|
||||||
|
++i;
|
||||||
|
|
||||||
|
/* Fill in selectors 16 to 255. */
|
||||||
|
|
||||||
|
while (i < info->uvs->num_records
|
||||||
|
&& info->uvs->records[i].selector <= 0xe01ef)
|
||||||
|
{
|
||||||
|
record = &info->uvs->records[i];
|
||||||
|
|
||||||
|
/* If record has no non-default mappings, continue on to the
|
||||||
|
next selector. */
|
||||||
|
|
||||||
|
if (!record->nondefault_uvs)
|
||||||
|
goto next_selector_1;
|
||||||
|
|
||||||
|
/* Handle invalid unsorted tables. */
|
||||||
|
|
||||||
|
if (record->selector < 0xe0100)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Find the glyph ID associated with C and put it in
|
||||||
|
VARIATIONS. */
|
||||||
|
|
||||||
|
variations[info->uvs->records[i].selector - 0xe0100 + 16]
|
||||||
|
= sfnt_variation_glyph_for_char (record->nondefault_uvs, c);
|
||||||
|
|
||||||
|
if (variations[info->uvs->records[i].selector - 0xe0100 + 16])
|
||||||
|
++n;
|
||||||
|
|
||||||
|
next_selector_1:
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* mmap specific stuff. */
|
/* mmap specific stuff. */
|
||||||
|
|
||||||
#ifdef HAVE_MMAP
|
#ifdef HAVE_MMAP
|
||||||
|
@ -2893,6 +3139,126 @@ sfntfont_detect_sigbus (void *addr)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Harfbuzz font support. */
|
||||||
|
|
||||||
|
#ifdef HAVE_HARFBUZZ
|
||||||
|
|
||||||
|
#ifdef HAVE_MMAP
|
||||||
|
|
||||||
|
/* Unmap the specified table. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
sfntfont_unmap_blob (void *ptr)
|
||||||
|
{
|
||||||
|
if (sfnt_unmap_table (ptr))
|
||||||
|
emacs_abort ();
|
||||||
|
|
||||||
|
xfree (ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* HAVE_MMAP */
|
||||||
|
|
||||||
|
/* Given a font DATA and a tag TAG, return the data of the
|
||||||
|
corresponding font table as a HarfBuzz blob. */
|
||||||
|
|
||||||
|
static hb_blob_t *
|
||||||
|
sfntfont_get_font_table (hb_face_t *face, hb_tag_t tag, void *data)
|
||||||
|
{
|
||||||
|
size_t size;
|
||||||
|
struct sfnt_font_info *info;
|
||||||
|
#ifdef HAVE_MMAP
|
||||||
|
struct sfnt_mapped_table *table;
|
||||||
|
hb_blob_t *blob;
|
||||||
|
|
||||||
|
info = data;
|
||||||
|
table = xmalloc (sizeof *table);
|
||||||
|
|
||||||
|
if (!sfnt_map_table (info->fd, info->directory, tag,
|
||||||
|
table))
|
||||||
|
{
|
||||||
|
/* Create an hb_blob_t and return it.
|
||||||
|
TODO: record this mapping properly so that SIGBUS can
|
||||||
|
be handled. */
|
||||||
|
|
||||||
|
blob = hb_blob_create (table->data, table->length,
|
||||||
|
HB_MEMORY_MODE_READONLY,
|
||||||
|
table, sfntfont_unmap_blob);
|
||||||
|
|
||||||
|
/* Note that sfntfont_unmap_blob will be called if the empty
|
||||||
|
blob is returned. */
|
||||||
|
return blob;
|
||||||
|
}
|
||||||
|
|
||||||
|
xfree (table);
|
||||||
|
#else /* !HAVE_MMAP */
|
||||||
|
|
||||||
|
/* Try to read the table conventionally. */
|
||||||
|
info = data;
|
||||||
|
#endif /* HAVE_MMAP */
|
||||||
|
|
||||||
|
data = sfnt_read_table (info->fd, info->directory, tag,
|
||||||
|
&size);
|
||||||
|
|
||||||
|
if (!data)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return hb_blob_create (data, size, HB_MEMORY_MODE_WRITABLE,
|
||||||
|
data, xfree);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create or return a HarfBuzz font object corresponding to the
|
||||||
|
specified FONT. Return the scale to convert between fwords and
|
||||||
|
pixels in POSITION_UNIT. */
|
||||||
|
|
||||||
|
hb_font_t *
|
||||||
|
sfntfont_begin_hb_font (struct font *font, double *position_unit)
|
||||||
|
{
|
||||||
|
struct sfnt_font_info *info;
|
||||||
|
hb_face_t *face;
|
||||||
|
int factor;
|
||||||
|
|
||||||
|
info = (struct sfnt_font_info *) font;
|
||||||
|
|
||||||
|
if (info->hb_font)
|
||||||
|
{
|
||||||
|
/* Calculate the scale factor. */
|
||||||
|
*position_unit = 1.0 / 64.0;
|
||||||
|
return info->hb_font;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a face and then a font. */
|
||||||
|
face = hb_face_create_for_tables (sfntfont_get_font_table, font,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (hb_face_get_glyph_count (face) > 0)
|
||||||
|
{
|
||||||
|
info->hb_font = hb_font_create (face);
|
||||||
|
if (!info->hb_font)
|
||||||
|
goto bail;
|
||||||
|
|
||||||
|
factor = font->pixel_size;
|
||||||
|
|
||||||
|
/* Set the scale and PPEM values. */
|
||||||
|
hb_font_set_scale (info->hb_font, factor * 64, factor * 64);
|
||||||
|
hb_font_set_ppem (info->hb_font, factor, factor);
|
||||||
|
|
||||||
|
/* This is needed for HarfBuzz before 2.0.0; it is the default
|
||||||
|
in later versions. */
|
||||||
|
hb_ot_font_set_funcs (info->hb_font);
|
||||||
|
}
|
||||||
|
|
||||||
|
bail:
|
||||||
|
hb_face_destroy (face);
|
||||||
|
|
||||||
|
/* Calculate the scale factor. */
|
||||||
|
*position_unit = 1.0 / 64.0;
|
||||||
|
return info->hb_font;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* HAVE_HARFBUZZ */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
syms_of_sfntfont (void)
|
syms_of_sfntfont (void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -42,6 +42,7 @@ extern void sfntfont_close (struct font *);
|
||||||
extern int sfntfont_draw (struct glyph_string *, int, int,
|
extern int sfntfont_draw (struct glyph_string *, int, int,
|
||||||
int, int, bool);
|
int, int, bool);
|
||||||
extern Lisp_Object sfntfont_list_family (struct frame *);
|
extern Lisp_Object sfntfont_list_family (struct frame *);
|
||||||
|
extern int sfntfont_get_variation_glyphs (struct font *, int, unsigned[256]);
|
||||||
|
|
||||||
|
|
||||||
/* Initialization functions. */
|
/* Initialization functions. */
|
||||||
|
@ -65,4 +66,14 @@ extern bool sfntfont_detect_sigbus (void *);
|
||||||
|
|
||||||
#endif /* HAVE_MMAP */
|
#endif /* HAVE_MMAP */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* HarfBuzz specific functions. */
|
||||||
|
|
||||||
|
#ifdef HAVE_HARFBUZZ
|
||||||
|
|
||||||
|
extern hb_font_t *sfntfont_begin_hb_font (struct font *, double *);
|
||||||
|
|
||||||
|
#endif /* HAVE_HARFBUZZ */
|
||||||
|
|
||||||
#endif /* _SFNTFONT_H_ */
|
#endif /* _SFNTFONT_H_ */
|
||||||
|
|
|
@ -1723,12 +1723,12 @@ DEFUN ("set-text-conversion-style", Fset_text_conversion_style,
|
||||||
Sset_text_conversion_style, 1, 1, 0,
|
Sset_text_conversion_style, 1, 1, 0,
|
||||||
doc: /* Set the text conversion style in the current buffer.
|
doc: /* Set the text conversion style in the current buffer.
|
||||||
|
|
||||||
Set `text-conversion-mode' to VALUE, then force any input method
|
Set `text-conversion-style' to VALUE, then force any input method
|
||||||
editing frame displaying this buffer to stop itself.
|
editing frame displaying this buffer to stop itself.
|
||||||
|
|
||||||
This can lead to a significant amount of time being taken by the input
|
This can lead to a significant amount of time being taken by the input
|
||||||
method resetting itself, so you should not use this function lightly;
|
method resetting itself, so you should not use this function lightly;
|
||||||
instead, set `text-conversion-mode' before your buffer is displayed,
|
instead, set `text-conversion-style' before your buffer is displayed,
|
||||||
and let redisplay manage the input method appropriately. */)
|
and let redisplay manage the input method appropriately. */)
|
||||||
(Lisp_Object value)
|
(Lisp_Object value)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue