aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPo Lu2023-03-20 14:47:39 +0800
committerPo Lu2023-03-20 14:47:39 +0800
commit6bd1cfa24fd04de855e53e74b46cdf4047bced4c (patch)
treeb652dff0db980c71d94fa6215138e51ede9ae174
parent739558c36958d9ec9f221ce168e15467b4579111 (diff)
downloademacs-6bd1cfa24fd04de855e53e74b46cdf4047bced4c.tar.gz
emacs-6bd1cfa24fd04de855e53e74b46cdf4047bced4c.zip
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.
-rw-r--r--configure.ac6
-rw-r--r--java/INSTALL16
-rw-r--r--lisp/subr.el16
-rw-r--r--src/sfnt.c741
-rw-r--r--src/sfnt.h165
-rw-r--r--src/sfntfont-android.c12
-rw-r--r--src/sfntfont.c384
-rw-r--r--src/sfntfont.h11
-rw-r--r--src/textconv.c4
9 files changed, 1323 insertions, 32 deletions
diff --git a/configure.ac b/configure.ac
index 44dbf60f938..47e5227a148 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1171,6 +1171,7 @@ package will likely install on older systems but crash on startup.])
1171 passthrough="$passthrough --with-lcms2=$with_lcms2" 1171 passthrough="$passthrough --with-lcms2=$with_lcms2"
1172 passthrough="$passthrough --with-mailutils=$with_mailutils" 1172 passthrough="$passthrough --with-mailutils=$with_mailutils"
1173 passthrough="$passthrough --with-pop=$with_pop" 1173 passthrough="$passthrough --with-pop=$with_pop"
1174 passthrough="$passthrough --with-harfbuzz=$with_harfbuzz"
1174 1175
1175 AS_IF([test "x$with_mailutils" = "xyes"], [emacs_use_mailutils=yes]) 1176 AS_IF([test "x$with_mailutils" = "xyes"], [emacs_use_mailutils=yes])
1176 AC_SUBST([emacs_use_mailutils]) 1177 AC_SUBST([emacs_use_mailutils])
@@ -1255,13 +1256,13 @@ if test "$ANDROID" = "yes"; then
1255 with_lcms2=no 1256 with_lcms2=no
1256 with_mailutils=no 1257 with_mailutils=no
1257 with_pop=no 1258 with_pop=no
1259 with_harfbuzz=no
1258 fi 1260 fi
1259 1261
1260 with_rsvg=no 1262 with_rsvg=no
1261 with_libsystemd=no 1263 with_libsystemd=no
1262 with_cairo=no 1264 with_cairo=no
1263 with_xft=no 1265 with_xft=no
1264 with_harfbuzz=no
1265 with_libotf=no 1266 with_libotf=no
1266 with_gpm=no 1267 with_gpm=no
1267 with_dbus=no 1268 with_dbus=no
@@ -4581,7 +4582,8 @@ else
4581fi 4582fi
4582if test "${HAVE_X11}" = "yes" && test "${HAVE_FREETYPE}" = "yes" \ 4583if test "${HAVE_X11}" = "yes" && test "${HAVE_FREETYPE}" = "yes" \
4583 || test "$window_system" = "pgtk" \ 4584 || test "$window_system" = "pgtk" \
4584 || test "${HAVE_W32}" = "yes"; then 4585 || test "${HAVE_W32}" = "yes" \
4586 || test "$REALLY_ANDROID" = "yes"; then
4585 if test "${with_harfbuzz}" != "no"; then 4587 if test "${with_harfbuzz}" != "no"; then
4586 EMACS_CHECK_MODULES([HARFBUZZ], [harfbuzz >= $harfbuzz_required_ver]) 4588 EMACS_CHECK_MODULES([HARFBUZZ], [harfbuzz >= $harfbuzz_required_ver])
4587 if test "$HAVE_HARFBUZZ" = "yes"; then 4589 if test "$HAVE_HARFBUZZ" = "yes"; then
diff --git a/java/INSTALL b/java/INSTALL
index 676c63a3cda..87d8979eb47 100644
--- a/java/INSTALL
+++ b/java/INSTALL
@@ -265,6 +265,8 @@ systems:
265 (Extract and point ``--with-ndk-path'' to tiff-4.5.0-emacs.tar.gz.) 265 (Extract and point ``--with-ndk-path'' to tiff-4.5.0-emacs.tar.gz.)
266 tree-sitter - https://sourceforge.net/projects/android-ports-for-gnu-emacs 266 tree-sitter - https://sourceforge.net/projects/android-ports-for-gnu-emacs
267 (Please see the section TREE-SITTER near the end of this file.) 267 (Please see the section TREE-SITTER near the end of this file.)
268 harfbuzz - https://sourceforge.net/projects/android-ports-for-gnu-emacs
269 (Please see the section HARFBUZZ near the end of this file.)
268 270
269And other developers have ported the following dependencies to Android 271And other developers have ported the following dependencies to Android
270systems: 272systems:
@@ -305,15 +307,23 @@ should not try to build these packages separately using any
305TREE-SITTER 307TREE-SITTER
306 308
307A copy of tree-sitter modified to build with the ndk-build system can 309A copy of tree-sitter modified to build with the ndk-build system can
308also find that URL. To build Emacs with tree-sitter, you must unpack 310also be found that URL. To build Emacs with tree-sitter, you must
309the following tar archive in that site: 311unpack the following tar archive in that site:
310 312
311 tree-sitter-0.20.7-emacs.tar.gz 313 tree-sitter-0.20.7-emacs.tar.gz
312 314
313and add the resulting folder to ``--with-ndk-build''. 315and add the resulting folder to ``--with-ndk-build''.
314 316
315 317
316IMAGEMAGICK 318HARFBUZZ
319
320A copy of HarfBuzz modified to build with the ndk-build system can
321also be found at that URL. To build Emacs with HarfBuzz, you must
322unpack the following tar archive in that site:
323
324 harfbuzz-7.1.0-emacs.tar.gz
325
326and add the resulting folder to ``--with-ndk-build''.
317 327
318There is a third party port of ImageMagick to Android. Unfortunately, 328There is a third party port of ImageMagick to Android. Unfortunately,
319the port also uses its own patched versions of libpng, libjpeg, 329the port also uses its own patched versions of libpng, libjpeg,
diff --git a/lisp/subr.el b/lisp/subr.el
index e035ce51217..2f72945789b 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -3598,6 +3598,7 @@ character. This is not possible when using `read-key', but using
3598 3598
3599;; Actually in textconv.c. 3599;; Actually in textconv.c.
3600(defvar overriding-text-conversion-style) 3600(defvar overriding-text-conversion-style)
3601(declare-function set-text-conversion-style "textconv.c")
3601 3602
3602(defun y-or-n-p (prompt) 3603(defun y-or-n-p (prompt)
3603 "Ask user a \"y or n\" question. 3604 "Ask user a \"y or n\" question.
@@ -3674,6 +3675,9 @@ like) while `y-or-n-p' is running)."
3674 (while 3675 (while
3675 (let* ((scroll-actions '(recenter scroll-up scroll-down 3676 (let* ((scroll-actions '(recenter scroll-up scroll-down
3676 scroll-other-window scroll-other-window-down)) 3677 scroll-other-window scroll-other-window-down))
3678 ;; Disable text conversion so that real key events
3679 ;; are sent.
3680 (overriding-text-conversion-style nil)
3677 (key 3681 (key
3678 (let ((cursor-in-echo-area t)) 3682 (let ((cursor-in-echo-area t))
3679 (when minibuffer-auto-raise 3683 (when minibuffer-auto-raise
@@ -3721,9 +3725,15 @@ like) while `y-or-n-p' is running)."
3721 map)) 3725 map))
3722 ;; Protect this-command when called from pre-command-hook (bug#45029) 3726 ;; Protect this-command when called from pre-command-hook (bug#45029)
3723 (this-command this-command) 3727 (this-command this-command)
3724 (str (read-from-minibuffer 3728 (str (progn
3725 prompt nil keymap nil 3729 (when (active-minibuffer-window)
3726 (or y-or-n-p-history-variable t)))) 3730 ;; If the minibuffer is already active, the
3731 ;; selected window might not change. Disable
3732 ;; text conversion by hand.
3733 (set-text-conversion-style text-conversion-style))
3734 (read-from-minibuffer
3735 prompt nil keymap nil
3736 (or y-or-n-p-history-variable t)))))
3727 (setq answer (if (member str '("y" "Y")) 'act 'skip))))) 3737 (setq answer (if (member str '("y" "Y")) 'act 'skip)))))
3728 (let ((ret (eq answer 'act))) 3738 (let ((ret (eq answer 'act)))
3729 (unless noninteractive 3739 (unless noninteractive
diff --git a/src/sfnt.c b/src/sfnt.c
index 5b219bf6369..bdd713aa016 100644
--- a/src/sfnt.c
+++ b/src/sfnt.c
@@ -601,7 +601,7 @@ sfnt_read_cmap_format_8 (int fd,
601 ssize_t rc; 601 ssize_t rc;
602 uint32_t length, i; 602 uint32_t length, i;
603 603
604 /* Read the 32-bit lenth field. */ 604 /* Read the 32-bit length field. */
605 if (read (fd, &length, sizeof (length)) < sizeof (length)) 605 if (read (fd, &length, sizeof (length)) < sizeof (length))
606 return (struct sfnt_cmap_format_8 *) -1; 606 return (struct sfnt_cmap_format_8 *) -1;
607 607
@@ -693,7 +693,7 @@ sfnt_read_cmap_format_12 (int fd,
693 ssize_t rc; 693 ssize_t rc;
694 uint32_t length, i; 694 uint32_t length, i;
695 695
696 /* Read the 32-bit lenth field. */ 696 /* Read the 32-bit length field. */
697 if (read (fd, &length, sizeof (length)) < sizeof (length)) 697 if (read (fd, &length, sizeof (length)) < sizeof (length))
698 return (struct sfnt_cmap_format_12 *) -1; 698 return (struct sfnt_cmap_format_12 *) -1;
699 699
@@ -773,6 +773,98 @@ sfnt_read_cmap_format_12 (int fd,
773 return format12; 773 return format12;
774} 774}
775 775
776/* Read a 3-byte big endian number from BYTES. */
777
778static unsigned int
779sfnt_read_24 (unsigned char *bytes)
780{
781 return (bytes[0] << 16u) | (bytes[1] << 8u) | bytes[2];
782}
783
784/* Read a format 14 cmap table from FD. HEADER->format will be 14 and
785 HEADER->length will be 0; the 16-bit length field is not read.
786 OFFSET is the offset of the table's header in the font file.
787
788 Only variation selector records will be read. UVS tables will
789 not. */
790
791static struct sfnt_cmap_format_14 *
792sfnt_read_cmap_format_14 (int fd,
793 struct sfnt_cmap_encoding_subtable_data *header,
794 off_t offset)
795{
796 struct sfnt_cmap_format_14 *format14;
797 uint32_t length;
798 uint32_t num_records;
799 uint32_t buffer1[2];
800 size_t size, temp;
801 char buffer[3 + 4 + 4];
802 int i;
803
804 /* Read the length field and number of variation selector
805 records. */
806
807 if (read (fd, buffer1, sizeof buffer1) < sizeof buffer1)
808 return NULL;
809
810 length = buffer1[0];
811 num_records = buffer1[1];
812
813 sfnt_swap32 (&length);
814 sfnt_swap32 (&num_records);
815
816 /* Now, the number of records present is known. Allocate the format
817 14 cmap table. */
818
819 size = sizeof *format14;
820 if (INT_MULTIPLY_WRAPV (num_records, sizeof *format14->records,
821 &temp)
822 || INT_ADD_WRAPV (size, temp, &size))
823 return NULL;
824
825 format14 = xmalloc (size);
826
827 /* Fill in the data already read. */
828 format14->format = header->format;
829 format14->length = length;
830 format14->num_var_selector_records = num_records;
831 format14->offset = offset;
832
833 /* Set the pointer to the remaining record data. */
834 format14->records
835 = (struct sfnt_variation_selector_record *) (format14 + 1);
836
837 /* Read each variation selector record. */
838
839 for (i = 0; i < num_records; ++i)
840 {
841 if (read (fd, buffer, sizeof buffer) < sizeof buffer)
842 {
843 xfree (format14);
844 return NULL;
845 }
846
847 /* First, read the 24 bit variation selector. */
848 format14->records[i].var_selector
849 = sfnt_read_24 ((unsigned char *) buffer);
850
851 /* Next, read the two unaligned longs. */
852 memcpy (&format14->records[i].default_uvs_offset,
853 buffer + 3,
854 sizeof format14->records[i].default_uvs_offset);
855 memcpy (&format14->records[i].nondefault_uvs_offset,
856 buffer + 7,
857 sizeof format14->records[i].nondefault_uvs_offset);
858
859 /* And swap them. */
860 sfnt_swap32 (&format14->records[i].default_uvs_offset);
861 sfnt_swap32 (&format14->records[i].nondefault_uvs_offset);
862 }
863
864 /* Return the format 14 character mapping table. */
865 return format14;
866}
867
776/* Read the CMAP subtable data from a given file FD at TABLE_OFFSET 868/* Read the CMAP subtable data from a given file FD at TABLE_OFFSET
777 bytes from DIRECTORY_OFFSET. Return the subtable data if it is 869 bytes from DIRECTORY_OFFSET. Return the subtable data if it is
778 supported. Else, value is NULL if the format is unsupported, or -1 870 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,
791 if (lseek (fd, offset, SEEK_SET) == (off_t) -1) 883 if (lseek (fd, offset, SEEK_SET) == (off_t) -1)
792 return (struct sfnt_cmap_encoding_subtable_data *) -1; 884 return (struct sfnt_cmap_encoding_subtable_data *) -1;
793 885
794 if (read (fd, &header, sizeof header) < sizeof header) 886 if (read (fd, &header.format, sizeof header.format)
887 < sizeof header.format)
795 return (struct sfnt_cmap_encoding_subtable_data *) -1; 888 return (struct sfnt_cmap_encoding_subtable_data *) -1;
796 889
797 sfnt_swap16 (&header.format); 890 sfnt_swap16 (&header.format);
798 sfnt_swap16 (&header.length); 891
892 /* Format 14 tables are rather special: they do not have a 16-bit
893 `length' field. When these tables are encountered, leave reading
894 the rest of the header to `sfnt_read_cmap_table_14'. */
895
896 if (header.format != 14)
897 {
898 if (read (fd, &header.length, sizeof header.length)
899 < sizeof header.length)
900 return (struct sfnt_cmap_encoding_subtable_data *) -1;
901
902 sfnt_swap16 (&header.length);
903 }
904 else
905 header.length = 0;
799 906
800 switch (header.format) 907 switch (header.format)
801 { 908 {
@@ -828,6 +935,10 @@ sfnt_read_cmap_table_1 (int fd, uint32_t directory_offset,
828 return ((struct sfnt_cmap_encoding_subtable_data *) 935 return ((struct sfnt_cmap_encoding_subtable_data *)
829 sfnt_read_cmap_format_12 (fd, &header)); 936 sfnt_read_cmap_format_12 (fd, &header));
830 937
938 case 14:
939 return ((struct sfnt_cmap_encoding_subtable_data *)
940 sfnt_read_cmap_format_14 (fd, &header, offset));
941
831 default: 942 default:
832 return NULL; 943 return NULL;
833 } 944 }
@@ -909,8 +1020,7 @@ sfnt_read_cmap_table (int fd, struct sfnt_offset_subtable *subtable,
909 return cmap; 1020 return cmap;
910 1021
911 /* Second, read each encoding subtable itself. */ 1022 /* Second, read each encoding subtable itself. */
912 *data = xmalloc (cmap->num_subtables 1023 *data = xmalloc (cmap->num_subtables * sizeof *data);
913 * sizeof *data);
914 1024
915 for (i = 0; i < cmap->num_subtables; ++i) 1025 for (i = 0; i < cmap->num_subtables; ++i)
916 { 1026 {
@@ -1199,7 +1309,10 @@ sfnt_lookup_glyph_12 (sfnt_char character,
1199 1309
1200/* Look up the glyph index corresponding to the character CHARACTER, 1310/* Look up the glyph index corresponding to the character CHARACTER,
1201 which must be in the correct encoding for the cmap table pointed to 1311 which must be in the correct encoding for the cmap table pointed to
1202 by DATA. */ 1312 by DATA.
1313
1314 DATA must be either a format 0, 2, 4, 6, 8 or 12 cmap table, else
1315 behavior is undefined. */
1203 1316
1204TEST_STATIC sfnt_glyph 1317TEST_STATIC sfnt_glyph
1205sfnt_lookup_glyph (sfnt_char character, 1318sfnt_lookup_glyph (sfnt_char character,
@@ -11775,6 +11888,551 @@ sfnt_interpret_compound_glyph (struct sfnt_glyph *glyph,
11775 11888
11776 11889
11777 11890
11891/* Unicode Variation Sequence (UVS) support.
11892
11893 Unicode defines a mechanism by which a two-codepoint sequence
11894 consisting of a ``base character'' and ``variation selector'' is
11895 able to produce a glyph that is a variant of the glyph that would
11896 conventionally have been mapped to the ``base character''.
11897
11898 TrueType describes variation selector sequences through a type of
11899 character mapping table that is given the format 14. The character
11900 mapping table consists of an array of variation selectors, each of
11901 which have a corresponding ``default UVS table'', which describes
11902 ranges of ``base characters'' having no special variant glyphs, and
11903 a ``non-default UVS table'', which is a map of ``base characters''
11904 to their corresponding variant glyphs. */
11905
11906/* Read a default UVS table from the font file FD, at the specified
11907 OFFSET. Value is the default UVS table upon success, else
11908 NULL. */
11909
11910static struct sfnt_default_uvs_table *
11911sfnt_read_default_uvs_table (int fd, off_t offset)
11912{
11913 struct sfnt_default_uvs_table *uvs;
11914 uint32_t num_ranges, i, j;
11915 size_t size, temp;
11916 char data[512];
11917
11918 /* First, seek to the given offset. */
11919
11920 if (lseek (fd, offset, SEEK_SET) != offset)
11921 return NULL;
11922
11923 /* Next, read the number of ranges present. */
11924
11925 if (read (fd, &num_ranges, sizeof num_ranges) != sizeof num_ranges)
11926 return NULL;
11927
11928 /* Swap the number of ranges present. */
11929 sfnt_swap32 (&num_ranges);
11930
11931 /* Now, allocate enough to hold the UVS table. */
11932
11933 size = sizeof *uvs;
11934 if (INT_MULTIPLY_WRAPV (sizeof *uvs->ranges, num_ranges,
11935 &temp)
11936 || INT_ADD_WRAPV (temp, size, &size))
11937 return NULL;
11938
11939 uvs = xmalloc (size);
11940
11941 /* Fill in the data which was already read. */
11942 uvs->num_unicode_value_ranges = num_ranges;
11943
11944 /* Fill in the pointer to the ranges. */
11945 uvs->ranges = (struct sfnt_unicode_value_range *) (uvs + 1);
11946 i = 0;
11947
11948 /* Read each default UVS range in multiples of 512 bytes. Then,
11949 fill in uvs->ranges. */
11950
11951 while (num_ranges)
11952 {
11953 size = (num_ranges > 128 ? 512 : num_ranges * 4);
11954
11955 if (read (fd, data, size) != size)
11956 {
11957 xfree (uvs);
11958 return NULL;
11959 }
11960
11961 for (j = 0; j < size / 4; ++j)
11962 {
11963 uvs->ranges[i + j].start_unicode_value
11964 = sfnt_read_24 ((unsigned char *) data + j * 4);
11965 uvs->ranges[i + j].additional_count = data[j * 4 + 1];
11966 }
11967
11968 i += j;
11969 num_ranges -= size / 4;
11970 }
11971
11972 /* Return the resulting default UVS table. */
11973 return uvs;
11974}
11975
11976/* Read a non-default UVS table from the font file FD, at the
11977 specified OFFSET. Value is the non-default UVS table upon success,
11978 else NULL. */
11979
11980static struct sfnt_nondefault_uvs_table *
11981sfnt_read_nondefault_uvs_table (int fd, off_t offset)
11982{
11983 struct sfnt_nondefault_uvs_table *uvs;
11984 uint32_t num_mappings, i, j;
11985 size_t size, temp;
11986 char data[500];
11987
11988 /* First, seek to the given offset. */
11989
11990 if (lseek (fd, offset, SEEK_SET) != offset)
11991 return NULL;
11992
11993 /* Next, read the number of mappings present. */
11994
11995 if (read (fd, &num_mappings, sizeof num_mappings)
11996 != sizeof num_mappings)
11997 return NULL;
11998
11999 /* Swap the number of mappings present. */
12000 sfnt_swap32 (&num_mappings);
12001
12002 /* Now, allocate enough to hold the UVS table. */
12003
12004 size = sizeof *uvs;
12005 if (INT_MULTIPLY_WRAPV (sizeof *uvs->mappings, num_mappings,
12006 &temp)
12007 || INT_ADD_WRAPV (temp, size, &size))
12008 return NULL;
12009
12010 uvs = xmalloc (size);
12011
12012 /* Fill in the data which was already read. */
12013 uvs->num_uvs_mappings = num_mappings;
12014
12015 /* Fill in the pointer to the mappings. */
12016 uvs->mappings = (struct sfnt_uvs_mapping *) (uvs + 1);
12017
12018 i = 0;
12019
12020 /* Read each nondefault UVS mapping in multiples of 500 bytes.
12021 Then, fill in uvs->ranges. */
12022
12023 while (num_mappings)
12024 {
12025 size = (num_mappings > 100 ? 500 : num_mappings * 5);
12026
12027 if (read (fd, data, size) != size)
12028 {
12029 xfree (uvs);
12030 return NULL;
12031 }
12032
12033 for (j = 0; j < size / 5; ++j)
12034 {
12035 uvs->mappings[i + j].unicode_value
12036 = sfnt_read_24 ((unsigned char *) data + j * 5);
12037 memcpy (&uvs->mappings[i + j].base_character_value,
12038 data + j * 5 + 3,
12039 sizeof uvs->mappings[i + j].base_character_value);
12040 sfnt_swap16 (&uvs->mappings[i + j].base_character_value);
12041 }
12042
12043 i += j;
12044 num_mappings -= size / 5;
12045 }
12046
12047 /* Return the nondefault UVS table. */
12048 return uvs;
12049}
12050
12051/* Perform comparison of A and B, two table offsets. */
12052
12053static int
12054sfnt_compare_table_offsets (const void *a, const void *b)
12055{
12056 const struct sfnt_table_offset_rec *rec_a, *rec_b;
12057
12058 rec_a = a;
12059 rec_b = b;
12060
12061 if (rec_a->offset < rec_b->offset)
12062 return -1;
12063 else if (rec_a->offset > rec_b->offset)
12064 return 1;
12065
12066 return 0;
12067}
12068
12069/* Create a variation selection context based on the format 14 cmap
12070 subtable CMAP.
12071
12072 FD is the font file to which the table belongs.
12073
12074 Value is the variation selection context upon success, else NULL.
12075 The context contains each variation selector record and their
12076 associated default and nondefault UVS tables. Free the context
12077 with `sfnt_free_uvs_context'. */
12078
12079TEST_STATIC struct sfnt_uvs_context *
12080sfnt_create_uvs_context (struct sfnt_cmap_format_14 *cmap, int fd)
12081{
12082 struct sfnt_table_offset_rec *table_offsets, *rec, template;
12083 size_t size, i, nmemb, j;
12084 off_t offset;
12085 struct sfnt_uvs_context *context;
12086
12087 if (INT_MULTIPLY_WRAPV (cmap->num_var_selector_records,
12088 sizeof *table_offsets, &size)
12089 || INT_MULTIPLY_WRAPV (size, 2, &size))
12090 return NULL;
12091
12092 context = NULL;
12093
12094 /* First, record and sort the UVS and nondefault UVS table offsets
12095 in ascending order. */
12096
12097 table_offsets = xmalloc (size);
12098 memset (table_offsets, 0, size);
12099 nmemb = cmap->num_var_selector_records * 2;
12100 j = 0;
12101
12102 for (i = 0; i < cmap->num_var_selector_records; ++i)
12103 {
12104 /* Note that either offset may be 0, meaning there is no such
12105 table. */
12106
12107 if (cmap->records[i].default_uvs_offset)
12108 {
12109 if (INT_ADD_WRAPV (cmap->offset,
12110 cmap->records[i].default_uvs_offset,
12111 &table_offsets[j].offset))
12112 goto bail;
12113
12114 table_offsets[j++].is_nondefault_table = false;
12115 }
12116
12117 if (cmap->records[i].nondefault_uvs_offset)
12118 {
12119 if (INT_ADD_WRAPV (cmap->offset,
12120 cmap->records[i].nondefault_uvs_offset,
12121 &table_offsets[j].offset))
12122 goto bail;
12123
12124 table_offsets[j++].is_nondefault_table = true;
12125 }
12126 }
12127
12128 /* Make nmemb the number of offsets actually looked up. */
12129 nmemb = j;
12130
12131 qsort (table_offsets, nmemb, sizeof *table_offsets,
12132 sfnt_compare_table_offsets);
12133
12134 /* Now go through table_offsets, and read everything. nmemb is the
12135 number of elements in table_offsets[i]; it is kept up to date
12136 when duplicate members are removed. */
12137 offset = -1;
12138
12139 for (i = 0; i < nmemb; ++i)
12140 {
12141 /* Skip past duplicate tables. */
12142
12143 while (table_offsets[i].offset == offset && i < nmemb)
12144 {
12145 nmemb--;
12146 table_offsets[i] = table_offsets[i + 1];
12147 }
12148
12149 /* If the last element of the array is a duplicate, break out of
12150 the loop. */
12151
12152 if (i == nmemb)
12153 break;
12154
12155 /* Read the correct type of table depending on
12156 table_offsets[i].is_nondefault_table. Then skip past
12157 duplicate tables. Don't handle the case where two different
12158 kind of tables share the same offset, because that is not
12159 possible in a valid variation selector record. */
12160
12161 offset = table_offsets[i].offset;
12162
12163 if (table_offsets[i].is_nondefault_table)
12164 table_offsets[i].table
12165 = sfnt_read_nondefault_uvs_table (fd, offset);
12166 else
12167 table_offsets[i].table
12168 = sfnt_read_default_uvs_table (fd, offset);
12169 }
12170
12171 /* Now make the context. */
12172 context = xmalloc (sizeof *context);
12173 context->num_records = cmap->num_var_selector_records;
12174 context->nmemb = nmemb;
12175 context->records = xmalloc (sizeof *context->records
12176 * cmap->num_var_selector_records);
12177
12178 for (i = 0; i < cmap->num_var_selector_records; ++i)
12179 {
12180 context->records[i].selector = cmap->records[i].var_selector;
12181
12182 /* Either offset may be 0, meaning no such table exists. Also,
12183 the code below will lose if more than one kind of table
12184 shares the same offset, because that is impossible. */
12185
12186 if (cmap->records[i].default_uvs_offset)
12187 {
12188 /* Resolve the default table. */
12189 template.offset = (cmap->records[i].default_uvs_offset
12190 + cmap->offset);
12191 rec = bsearch (&template, table_offsets,
12192 nmemb, sizeof *table_offsets,
12193 sfnt_compare_table_offsets);
12194
12195 /* Make sure this record is the right type. */
12196 if (!rec || rec->is_nondefault_table || !rec->table)
12197 goto bail;
12198
12199 context->records[i].default_uvs = rec->table;
12200 }
12201 else
12202 context->records[i].default_uvs = NULL;
12203
12204 if (cmap->records[i].nondefault_uvs_offset)
12205 {
12206 /* Resolve the nondefault table. */
12207 template.offset = (cmap->records[i].nondefault_uvs_offset
12208 + cmap->offset);
12209 rec = bsearch (&template, table_offsets,
12210 nmemb, sizeof *table_offsets,
12211 sfnt_compare_table_offsets);
12212
12213 if (!rec)
12214 goto bail;
12215
12216 /* Make sure this record is the right type. */
12217 if (!rec || !rec->is_nondefault_table || !rec->table)
12218 goto bail;
12219
12220 context->records[i].nondefault_uvs = rec->table;
12221 }
12222 else
12223 context->records[i].nondefault_uvs = NULL;
12224 }
12225
12226 context->tables = table_offsets;
12227 return context;
12228
12229 bail:
12230
12231 if (context)
12232 {
12233 xfree (context->records);
12234 xfree (context);
12235 }
12236
12237 /* Loop through and free any tables that might have been read
12238 already. */
12239
12240 for (i = 0; i < nmemb; ++i)
12241 xfree (table_offsets[i].table);
12242
12243 xfree (table_offsets);
12244 return NULL;
12245}
12246
12247/* Free the specified variation selection context C. */
12248
12249TEST_STATIC void
12250sfnt_free_uvs_context (struct sfnt_uvs_context *c)
12251{
12252 size_t i;
12253
12254 xfree (c->records);
12255
12256 for (i = 0; i < c->nmemb; ++i)
12257 xfree (c->tables[i].table);
12258
12259 xfree (c->tables);
12260 xfree (c);
12261}
12262
12263/* Compare *(sfnt_char *) K to ((struct sfnt_uvs_mapping *)
12264 V)->unicode_value appropriately for bsearch. */
12265
12266static int
12267sfnt_compare_uvs_mapping (const void *k, const void *v)
12268{
12269 const sfnt_char *key;
12270 const struct sfnt_uvs_mapping *value;
12271
12272 key = k;
12273 value = v;
12274
12275 if (*key < value->unicode_value)
12276 return -1;
12277 else if (*key == value->unicode_value)
12278 return 0;
12279
12280 return 1;
12281}
12282
12283/* Return the ID of a variation glyph for the character C in the
12284 nondefault UVS mapping table UVS.
12285
12286 Value is the glyph ID upon success, or 0 if there is no variation
12287 glyph for the base character C. */
12288
12289TEST_STATIC sfnt_glyph
12290sfnt_variation_glyph_for_char (struct sfnt_nondefault_uvs_table *uvs,
12291 sfnt_char c)
12292{
12293 struct sfnt_uvs_mapping *mapping;
12294
12295 mapping = bsearch (&c, uvs->mappings, uvs->num_uvs_mappings,
12296 sizeof *uvs->mappings,
12297 sfnt_compare_uvs_mapping);
12298
12299 return mapping ? mapping->base_character_value : 0;
12300}
12301
12302
12303
12304#if defined HAVE_MMAP && !defined TEST
12305
12306/* Memory mapping support.
12307 It useful to map OpenType layout tables prior to using them in
12308 an external shaping engine such as HarfBuzz. */
12309
12310/* Map a table identified by TAG into the structure *TABLE.
12311 TAG is swapped into host byte order.
12312
12313 Use the table directory SUBTABLE, which corresponds to the font
12314 file FD.
12315
12316 Return 0 upon success, and set TABLE->data to the table data,
12317 TABLE->mapping to the start of the mapped area, TABLE->length to
12318 the length of the table contents, and TABLE->size to the size of
12319 the mapping.
12320
12321 Return 1 upon failure. */
12322
12323int
12324sfnt_map_table (int fd, struct sfnt_offset_subtable *subtable,
12325 uint32_t tag, struct sfnt_mapped_table *table)
12326{
12327 struct sfnt_table_directory *directory;
12328 size_t offset, page, map_offset;
12329 void *data;
12330 int i;
12331
12332 /* Find the table in the directory. */
12333
12334 for (i = 0; i < subtable->num_tables; ++i)
12335 {
12336 if (subtable->subtables[i].tag == tag)
12337 {
12338 directory = &subtable->subtables[i];
12339 break;
12340 }
12341 }
12342
12343 if (i == subtable->num_tables)
12344 return 1;
12345
12346 /* Now try to map the glyph data. Make sure offset is a multiple of
12347 the page size. */
12348
12349 page = getpagesize ();
12350 offset = directory->offset & ~(page - 1);
12351
12352 /* Figure out how much larger the mapping should be. */
12353 map_offset = directory->offset - offset;
12354
12355 /* Do the mmap. */
12356 data = mmap (NULL, directory->length + map_offset,
12357 PROT_READ, MAP_PRIVATE, fd, offset);
12358
12359 if (data == MAP_FAILED)
12360 return 1;
12361
12362 /* Fill in *TABLE. */
12363 table->data = (unsigned char *) data + map_offset;
12364 table->mapping = data;
12365 table->length = directory->length;
12366 table->size = directory->length + map_offset;
12367 return 0;
12368}
12369
12370/* Unmap the table inside *TABLE.
12371 Value is 0 upon success, 1 otherwise. */
12372
12373int
12374sfnt_unmap_table (struct sfnt_mapped_table *table)
12375{
12376 return munmap (table->mapping, table->size) != 0;
12377}
12378
12379#endif /* HAVE_MMAP && !TEST */
12380
12381
12382
12383#ifndef TEST
12384
12385/* Reading table contents. */
12386
12387/* Read the table with the specified TAG from the font file FD.
12388 Return its length in *LENGTH, and its data upon success, else
12389 NULL. */
12390
12391void *
12392sfnt_read_table (int fd, struct sfnt_offset_subtable *subtable,
12393 uint32_t tag, size_t *length)
12394{
12395 struct sfnt_table_directory *directory;
12396 void *data;
12397 int i;
12398
12399 /* Find the table in the directory. */
12400
12401 for (i = 0; i < subtable->num_tables; ++i)
12402 {
12403 if (subtable->subtables[i].tag == tag)
12404 {
12405 directory = &subtable->subtables[i];
12406 break;
12407 }
12408 }
12409
12410 if (i == subtable->num_tables)
12411 return NULL;
12412
12413 /* Seek to the table. */
12414
12415 if (lseek (fd, directory->offset, SEEK_SET) != directory->offset)
12416 return NULL;
12417
12418 /* Now allocate enough to hold the data and read into it. */
12419
12420 data = xmalloc (directory->length);
12421 if (read (fd, data, directory->length) != directory->length)
12422 {
12423 xfree (data);
12424 return NULL;
12425 }
12426
12427 /* Return the length and table data. */
12428 *length = directory->length;
12429 return data;
12430}
12431
12432#endif /* !TEST */
12433
12434
12435
11778#ifdef TEST 12436#ifdef TEST
11779 12437
11780struct sfnt_test_dcontext 12438struct sfnt_test_dcontext
@@ -15494,6 +16152,52 @@ sfnt_pop_hook (struct sfnt_interpreter *interpreter,
15494 16152
15495 16153
15496 16154
16155static void
16156sfnt_test_uvs (int fd, struct sfnt_cmap_format_14 *format14)
16157{
16158 struct sfnt_uvs_context *context;
16159 size_t i, j;
16160 sfnt_glyph glyph;
16161 sfnt_char c;
16162 struct sfnt_nondefault_uvs_table *uvs;
16163
16164 context = sfnt_create_uvs_context (format14, fd);
16165
16166 /* Print each variation selector and its associated ranges. */
16167
16168 if (!context)
16169 fprintf (stderr, "failed to read uvs data\n");
16170 else
16171 {
16172 fprintf (stderr, "UVS context with %zu records and %zu tables\n",
16173 context->num_records, context->nmemb);
16174
16175 for (i = 0; i < context->num_records; ++i)
16176 {
16177 if (!context->records[i].nondefault_uvs)
16178 continue;
16179
16180 uvs = context->records[i].nondefault_uvs;
16181
16182 for (j = 0; j < uvs->num_uvs_mappings; ++j)
16183 {
16184 c = uvs->mappings[j].unicode_value;
16185 glyph = sfnt_variation_glyph_for_char (uvs, c);
16186
16187 if (glyph != uvs->mappings[j].base_character_value)
16188 abort ();
16189
16190 fprintf (stderr, " UVS: %"PRIx32" (%"PRIx32") -> %"PRIu32"\n",
16191 c, context->records[i].selector, glyph);
16192 }
16193 }
16194
16195 sfnt_free_uvs_context (context);
16196 }
16197}
16198
16199
16200
15497/* Main entry point. */ 16201/* Main entry point. */
15498 16202
15499/* Simple tests that were used while developing this file. By the 16203/* Simple tests that were used while developing this file. By the
@@ -15564,7 +16268,7 @@ main (int argc, char **argv)
15564 struct sfnt_raster **rasters; 16268 struct sfnt_raster **rasters;
15565 size_t length; 16269 size_t length;
15566 16270
15567 if (argc != 2) 16271 if (argc < 2)
15568 return 1; 16272 return 1;
15569 16273
15570 if (!strcmp (argv[1], "--check-interpreter")) 16274 if (!strcmp (argv[1], "--check-interpreter"))
@@ -15654,8 +16358,25 @@ main (int argc, char **argv)
15654 data[i]->format); 16358 data[i]->format);
15655 } 16359 }
15656 16360
15657#define FANCY_PPEM 12 16361 if (argc >= 3 && !strcmp (argv[2], "--check-variation-selectors"))
15658#define EASY_PPEM 12 16362 {
16363 /* Look for a format 14 cmap table. */
16364
16365 for (i = 0; i < table->num_subtables; ++i)
16366 {
16367 if (data[i]->format == 14)
16368 {
16369 fprintf (stderr, "format 14 subtable found\n");
16370 sfnt_test_uvs (fd, (struct sfnt_cmap_format_14 *) data[i]);
16371 return 0;
16372 }
16373 }
16374
16375 return 1;
16376 }
16377
16378#define FANCY_PPEM 25
16379#define EASY_PPEM 25
15659 16380
15660 interpreter = NULL; 16381 interpreter = NULL;
15661 head = sfnt_read_head_table (fd, font); 16382 head = sfnt_read_head_table (fd, font);
diff --git a/src/sfnt.h b/src/sfnt.h
index 4bf46b62397..83d34bfb757 100644
--- a/src/sfnt.h
+++ b/src/sfnt.h
@@ -25,6 +25,8 @@ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
25#include <stddef.h> 25#include <stddef.h>
26#include <setjmp.h> 26#include <setjmp.h>
27 27
28#include <sys/types.h>
29
28#if defined emacs || defined TEST 30#if defined emacs || defined TEST
29#define SFNT_ENABLE_HINTING 31#define SFNT_ENABLE_HINTING
30#endif 32#endif
@@ -422,7 +424,7 @@ struct sfnt_cmap_format_8
422 struct sfnt_cmap_format_8_or_12_group *groups; 424 struct sfnt_cmap_format_8_or_12_group *groups;
423}; 425};
424 426
425/* cmap formats 10, 13 and 14 unsupported. */ 427/* cmap formats 10, 13 unsupported. */
426 428
427struct sfnt_cmap_format_12 429struct sfnt_cmap_format_12
428{ 430{
@@ -445,6 +447,36 @@ struct sfnt_cmap_format_12
445 struct sfnt_cmap_format_8_or_12_group *groups; 447 struct sfnt_cmap_format_8_or_12_group *groups;
446}; 448};
447 449
450struct sfnt_cmap_format_14
451{
452 /* Format, set to 14. */
453 uint16_t format;
454
455 /* The length of the table in bytes. */
456 uint32_t length;
457
458 /* Number of variation selector records. */
459 uint16_t num_var_selector_records;
460
461 /* The offset of this table in the font file. */
462 off_t offset;
463
464 /* Variable length data. */
465 struct sfnt_variation_selector_record *records;
466};
467
468struct sfnt_variation_selector_record
469{
470 /* 24-bit unsigned variation selector. */
471 unsigned int var_selector;
472
473 /* Offset to default UVS table. */
474 uint32_t default_uvs_offset;
475
476 /* Offset to non-default UVS table. */
477 uint32_t nondefault_uvs_offset;
478};
479
448struct sfnt_maxp_table 480struct sfnt_maxp_table
449{ 481{
450 /* Table version. */ 482 /* Table version. */
@@ -1437,6 +1469,106 @@ struct sfnt_instructed_outline
1437 1469
1438 1470
1439 1471
1472/* Unicode Variation Sequence (UVS) support. */
1473
1474struct sfnt_default_uvs_table
1475{
1476 /* Number of ranges that follow. */
1477 uint32_t num_unicode_value_ranges;
1478
1479 /* Variable length data. */
1480 struct sfnt_unicode_value_range *ranges;
1481};
1482
1483struct sfnt_unicode_value_range
1484{
1485 /* First value in this range. */
1486 unsigned int start_unicode_value;
1487
1488 /* Number of additional values in this range. */
1489 unsigned char additional_count;
1490};
1491
1492struct sfnt_nondefault_uvs_table
1493{
1494 /* Number of UVS mappings which follow. */
1495 uint32_t num_uvs_mappings;
1496
1497 /* Variable length data. */
1498 struct sfnt_uvs_mapping *mappings;
1499};
1500
1501struct sfnt_uvs_mapping
1502{
1503 /* Base character value. */
1504 unsigned int unicode_value;
1505
1506 /* Glyph ID of the base character value. */
1507 uint16_t base_character_value;
1508};
1509
1510struct sfnt_mapped_variation_selector_record
1511{
1512 /* The variation selector. */
1513 unsigned int selector;
1514
1515 /* Its default UVS table. */
1516 struct sfnt_default_uvs_table *default_uvs;
1517
1518 /* Its nondefault UVS table. */
1519 struct sfnt_nondefault_uvs_table *nondefault_uvs;
1520};
1521
1522/* Structure describing a single offset to load into a variation
1523 selection context. */
1524
1525struct sfnt_table_offset_rec
1526{
1527 /* The offset from the start of the font file. */
1528 off_t offset;
1529
1530 /* Whether or not the offset points to a non-default UVS table. */
1531 bool is_nondefault_table;
1532
1533 /* Pointer to the UVS table. */
1534 void *table;
1535};
1536
1537struct sfnt_uvs_context
1538{
1539 /* Number of records and tables. */
1540 size_t num_records, nmemb;
1541
1542 /* Array of UVS tables. */
1543 struct sfnt_table_offset_rec *tables;
1544
1545 /* Array of variation selector records mapped to
1546 their corresponding tables. */
1547 struct sfnt_mapped_variation_selector_record *records;
1548};
1549
1550
1551
1552#if defined HAVE_MMAP && !defined TEST
1553
1554/* Memory mapping support. */
1555
1556struct sfnt_mapped_table
1557{
1558 /* Pointer to table data. */
1559 void *data;
1560
1561 /* Pointer to table mapping. */
1562 void *mapping;
1563
1564 /* Size of mapped data and size of mapping. */
1565 size_t length, size;
1566};
1567
1568#endif /* HAVE_MMAP && !TEST */
1569
1570
1571
1440/* Functions used to read tables used by the TrueType interpreter. */ 1572/* Functions used to read tables used by the TrueType interpreter. */
1441 1573
1442#ifndef TEST 1574#ifndef TEST
@@ -1509,6 +1641,37 @@ extern const char *sfnt_interpret_compound_glyph (PROTOTYPE);
1509 1641
1510#undef PROTOTYPE 1642#undef PROTOTYPE
1511 1643
1644
1645
1646#define PROTOTYPE struct sfnt_cmap_format_14 *, int
1647
1648extern struct sfnt_uvs_context *sfnt_create_uvs_context (PROTOTYPE);
1649
1650#undef PROTOTYPE
1651
1652extern void sfnt_free_uvs_context (struct sfnt_uvs_context *);
1653
1654#define PROTOTYPE struct sfnt_nondefault_uvs_table *, sfnt_char
1655
1656extern sfnt_glyph sfnt_variation_glyph_for_char (PROTOTYPE);
1657
1658#undef PROTOTYPE
1659
1660
1661
1662#ifdef HAVE_MMAP
1663
1664extern int sfnt_map_table (int, struct sfnt_offset_subtable *,
1665 uint32_t, struct sfnt_mapped_table *);
1666extern int sfnt_unmap_table (struct sfnt_mapped_table *);
1667
1668#endif /* HAVE_MMAP */
1669
1670
1671
1672extern void *sfnt_read_table (int, struct sfnt_offset_subtable *,
1673 uint32_t, size_t *);
1674
1512#endif /* TEST */ 1675#endif /* TEST */
1513 1676
1514 1677
diff --git a/src/sfntfont-android.c b/src/sfntfont-android.c
index 8324185cc6f..37f43465097 100644
--- a/src/sfntfont-android.c
+++ b/src/sfntfont-android.c
@@ -657,8 +657,16 @@ const struct font_driver android_sfntfont_driver =
657 .encode_char = sfntfont_encode_char, 657 .encode_char = sfntfont_encode_char,
658 .text_extents = sfntfont_text_extents, 658 .text_extents = sfntfont_text_extents,
659 .list_family = sfntfont_list_family, 659 .list_family = sfntfont_list_family,
660 660 .get_variation_glyphs = sfntfont_get_variation_glyphs,
661 /* TODO: list_family, shaping. */ 661
662#ifdef HAVE_HARFBUZZ
663 /* HarfBuzz support is enabled transparently on Android without
664 using a separate font driver. */
665 .begin_hb_font = sfntfont_begin_hb_font,
666 .combining_capability = hbfont_combining_capability,
667 .shape = hbfont_shape,
668 .otf_capability = hbfont_otf_capability,
669#endif /* HAVE_HARFBUZZ */
662 }; 670 };
663 671
664 672
diff --git a/src/sfntfont.c b/src/sfntfont.c
index b8ffce27062..500256d6fb4 100644
--- a/src/sfntfont.c
+++ b/src/sfntfont.c
@@ -34,6 +34,11 @@ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
34#include "sfnt.h" 34#include "sfnt.h"
35#include "sfntfont.h" 35#include "sfntfont.h"
36 36
37#ifdef HAVE_HARFBUZZ
38#include <hb.h>
39#include <hb-ot.h>
40#endif /* HAVE_HARFBUZZ */
41
37/* For FRAME_FONT. */ 42/* For FRAME_FONT. */
38#include TERM_HEADER 43#include TERM_HEADER
39 44
@@ -1038,15 +1043,20 @@ sfntfont_charset_for_cmap (struct sfnt_cmap_encoding_subtable subtable)
1038 1043
1039/* Pick the best character map in the cmap table CMAP. Use the 1044/* Pick the best character map in the cmap table CMAP. Use the
1040 subtables in SUBTABLES and DATA. Return the subtable data and the 1045 subtables in SUBTABLES and DATA. Return the subtable data and the
1041 subtable in *SUBTABLE upon success, NULL otherwise. */ 1046 subtable in *SUBTABLE upon success, NULL otherwise.
1047
1048 If FORMAT14 is non-NULL, return any associated format 14 variation
1049 selection context in *FORMAT14 should the selected charcter map be
1050 a Unicode character map. */
1042 1051
1043static struct sfnt_cmap_encoding_subtable_data * 1052static struct sfnt_cmap_encoding_subtable_data *
1044sfntfont_select_cmap (struct sfnt_cmap_table *cmap, 1053sfntfont_select_cmap (struct sfnt_cmap_table *cmap,
1045 struct sfnt_cmap_encoding_subtable *subtables, 1054 struct sfnt_cmap_encoding_subtable *subtables,
1046 struct sfnt_cmap_encoding_subtable_data **data, 1055 struct sfnt_cmap_encoding_subtable_data **data,
1047 struct sfnt_cmap_encoding_subtable *subtable) 1056 struct sfnt_cmap_encoding_subtable *subtable,
1057 struct sfnt_cmap_format_14 **format14)
1048{ 1058{
1049 int i; 1059 int i, j;
1050 1060
1051 /* First look for a non-BMP Unicode cmap. */ 1061 /* First look for a non-BMP Unicode cmap. */
1052 1062
@@ -1055,6 +1065,24 @@ sfntfont_select_cmap (struct sfnt_cmap_table *cmap,
1055 if (data[i] && sfntfont_identify_cmap (subtables[i]) == 2) 1065 if (data[i] && sfntfont_identify_cmap (subtables[i]) == 2)
1056 { 1066 {
1057 *subtable = subtables[i]; 1067 *subtable = subtables[i];
1068
1069 if (!format14)
1070 return data[i];
1071
1072 /* Search for a correspoinding format 14 character map.
1073 This is used in conjunction with the selected character
1074 map to map variation sequences. */
1075
1076 for (j = 0; j < cmap->num_subtables; ++j)
1077 {
1078 if (data[j]
1079 && subtables[j].platform_id == SFNT_PLATFORM_UNICODE
1080 && (subtables[j].platform_specific_id
1081 == SFNT_UNICODE_VARIATION_SEQUENCES)
1082 && data[j]->format == 14)
1083 *format14 = (struct sfnt_cmap_format_14 *) data[j];
1084 }
1085
1058 return data[i]; 1086 return data[i];
1059 } 1087 }
1060 } 1088 }
@@ -1066,6 +1094,24 @@ sfntfont_select_cmap (struct sfnt_cmap_table *cmap,
1066 if (data[i] && sfntfont_identify_cmap (subtables[i]) == 1) 1094 if (data[i] && sfntfont_identify_cmap (subtables[i]) == 1)
1067 { 1095 {
1068 *subtable = subtables[i]; 1096 *subtable = subtables[i];
1097
1098 if (!format14)
1099 return data[i];
1100
1101 /* Search for a correspoinding format 14 character map.
1102 This is used in conjunction with the selected character
1103 map to map variation sequences. */
1104
1105 for (j = 0; j < cmap->num_subtables; ++j)
1106 {
1107 if (data[j]
1108 && subtables[j].platform_id == SFNT_PLATFORM_UNICODE
1109 && (subtables[j].platform_specific_id
1110 == SFNT_UNICODE_VARIATION_SEQUENCES)
1111 && data[j]->format == 14)
1112 *format14 = (struct sfnt_cmap_format_14 *) data[j];
1113 }
1114
1069 return data[i]; 1115 return data[i];
1070 } 1116 }
1071 } 1117 }
@@ -1128,7 +1174,7 @@ sfntfont_read_cmap (struct sfnt_font_desc *desc,
1128 /* Now pick the best character map. */ 1174 /* Now pick the best character map. */
1129 1175
1130 *cmap = sfntfont_select_cmap (table, subtables, data, 1176 *cmap = sfntfont_select_cmap (table, subtables, data,
1131 subtable); 1177 subtable, NULL);
1132 1178
1133 /* Free the cmap data. */ 1179 /* Free the cmap data. */
1134 1180
@@ -1960,6 +2006,9 @@ struct sfnt_font_info
1960 /* Data identifying that character map. */ 2006 /* Data identifying that character map. */
1961 struct sfnt_cmap_encoding_subtable cmap_subtable; 2007 struct sfnt_cmap_encoding_subtable cmap_subtable;
1962 2008
2009 /* The UVS context. */
2010 struct sfnt_uvs_context *uvs;
2011
1963 /* Outline cache. */ 2012 /* Outline cache. */
1964 struct sfnt_outline_cache outline_cache; 2013 struct sfnt_outline_cache outline_cache;
1965 2014
@@ -1983,6 +2032,17 @@ struct sfnt_font_info
1983 /* Whether or not the glyph table has been mmapped. */ 2032 /* Whether or not the glyph table has been mmapped. */
1984 bool glyf_table_mapped; 2033 bool glyf_table_mapped;
1985#endif /* HAVE_MMAP */ 2034#endif /* HAVE_MMAP */
2035
2036#ifdef HAVE_HARFBUZZ
2037 /* HarfBuzz font object. */
2038 hb_font_t *hb_font;
2039
2040 /* File descriptor associated with this font. */
2041 int fd;
2042
2043 /* The table directory of the font file. */
2044 struct sfnt_offset_subtable *directory;
2045#endif /* HAVE_HARFBUZZ */
1986}; 2046};
1987 2047
1988#ifdef HAVE_MMAP 2048#ifdef HAVE_MMAP
@@ -2198,6 +2258,7 @@ sfntfont_open (struct frame *f, Lisp_Object font_entity,
2198 struct charset *charset; 2258 struct charset *charset;
2199 int point_size; 2259 int point_size;
2200 Display_Info *dpyinfo; 2260 Display_Info *dpyinfo;
2261 struct sfnt_cmap_format_14 *format14;
2201 2262
2202 if (XFIXNUM (AREF (font_entity, FONT_SIZE_INDEX)) != 0) 2263 if (XFIXNUM (AREF (font_entity, FONT_SIZE_INDEX)) != 0)
2203 pixel_size = XFIXNUM (AREF (font_entity, FONT_SIZE_INDEX)); 2264 pixel_size = XFIXNUM (AREF (font_entity, FONT_SIZE_INDEX));
@@ -2240,6 +2301,7 @@ sfntfont_open (struct frame *f, Lisp_Object font_entity,
2240 font_info->prep = NULL; 2301 font_info->prep = NULL;
2241 font_info->fpgm = NULL; 2302 font_info->fpgm = NULL;
2242 font_info->cvt = NULL; 2303 font_info->cvt = NULL;
2304 font_info->uvs = NULL;
2243 2305
2244 font_info->outline_cache.next = &font_info->outline_cache; 2306 font_info->outline_cache.next = &font_info->outline_cache;
2245 font_info->outline_cache.last = &font_info->outline_cache; 2307 font_info->outline_cache.last = &font_info->outline_cache;
@@ -2251,6 +2313,11 @@ sfntfont_open (struct frame *f, Lisp_Object font_entity,
2251#ifdef HAVE_MMAP 2313#ifdef HAVE_MMAP
2252 font_info->glyf_table_mapped = false; 2314 font_info->glyf_table_mapped = false;
2253#endif /* HAVE_MMAP */ 2315#endif /* HAVE_MMAP */
2316#ifdef HAVE_HARFBUZZ
2317 font_info->hb_font = NULL;
2318 font_info->fd = -1;
2319 font_info->directory = NULL;
2320#endif /* HAVE_HARFBUZZ */
2254 2321
2255 /* Open the font. */ 2322 /* Open the font. */
2256 fd = emacs_open (desc->path, O_RDONLY, 0); 2323 fd = emacs_open (desc->path, O_RDONLY, 0);
@@ -2280,14 +2347,29 @@ sfntfont_open (struct frame *f, Lisp_Object font_entity,
2280 if (!font_info->cmap) 2347 if (!font_info->cmap)
2281 goto bail2; 2348 goto bail2;
2282 2349
2350 format14 = NULL;
2283 font_info->cmap_data 2351 font_info->cmap_data
2284 = sfntfont_select_cmap (font_info->cmap, 2352 = sfntfont_select_cmap (font_info->cmap,
2285 subtables, data, 2353 subtables, data,
2286 &font_info->cmap_subtable); 2354 &font_info->cmap_subtable,
2355 &format14);
2356
2357 if (format14)
2358 {
2359 /* Build a UVS context from this format 14 mapping table. A UVS
2360 context contains each variation selector supported by the
2361 font, and a list of ``non-default'' mappings between base
2362 characters and variation glyph IDs. */
2363
2364 font_info->uvs = sfnt_create_uvs_context (format14, fd);
2365 xfree (format14);
2366 }
2287 2367
2288 for (i = 0; i < font_info->cmap->num_subtables; ++i) 2368 for (i = 0; i < font_info->cmap->num_subtables; ++i)
2289 { 2369 {
2290 if (data[i] != font_info->cmap_data) 2370 if (data[i] != font_info->cmap_data
2371 /* format14 has already been freed. */
2372 && data[i] != (struct sfnt_cmap_encoding_subtable_data *) format14)
2291 xfree (data[i]); 2373 xfree (data[i]);
2292 } 2374 }
2293 2375
@@ -2432,11 +2514,19 @@ sfntfont_open (struct frame *f, Lisp_Object font_entity,
2432 sfntfont_setup_interpreter (fd, font_info, subtable, 2514 sfntfont_setup_interpreter (fd, font_info, subtable,
2433 point_size); 2515 point_size);
2434 2516
2517#ifndef HAVE_HARFBUZZ
2435 /* Close the font file descriptor. */ 2518 /* Close the font file descriptor. */
2436 emacs_close (fd); 2519 emacs_close (fd);
2437 2520
2438 /* Free the offset subtable. */ 2521 /* Free the offset subtable. */
2439 xfree (subtable); 2522 xfree (subtable);
2523#else /* HAVE_HARFBUZZ */
2524 /* HarfBuzz will potentially read font tables after the font has
2525 been opened by Emacs. Keep the font open, and record its offset
2526 subtable. */
2527 font_info->fd = fd;
2528 font_info->directory = subtable;
2529#endif /* !HAVE_HARFBUZZ */
2440 2530
2441#ifdef HAVE_MMAP 2531#ifdef HAVE_MMAP
2442 /* Link the font onto the font table. */ 2532 /* Link the font onto the font table. */
@@ -2483,6 +2573,10 @@ sfntfont_open (struct frame *f, Lisp_Object font_entity,
2483 xfree (font_info->cmap_data); 2573 xfree (font_info->cmap_data);
2484 font_info->cmap_data = NULL; 2574 font_info->cmap_data = NULL;
2485 bail3: 2575 bail3:
2576
2577 if (font_info->uvs)
2578 sfnt_free_uvs_context (font_info->uvs);
2579
2486 xfree (font_info->cmap); 2580 xfree (font_info->cmap);
2487 font_info->cmap = NULL; 2581 font_info->cmap = NULL;
2488 bail2: 2582 bail2:
@@ -2677,8 +2771,7 @@ sfntfont_close (struct font *font)
2677 xfree (info->hmtx); 2771 xfree (info->hmtx);
2678 2772
2679#ifdef HAVE_MMAP 2773#ifdef HAVE_MMAP
2680 if (info->glyf_table_mapped 2774 if (info->glyf_table_mapped && info->glyf)
2681 && info->glyf)
2682 { 2775 {
2683 rc = sfnt_unmap_glyf_table (info->glyf); 2776 rc = sfnt_unmap_glyf_table (info->glyf);
2684 2777
@@ -2697,6 +2790,12 @@ sfntfont_close (struct font *font)
2697 xfree (info->cvt); 2790 xfree (info->cvt);
2698 xfree (info->interpreter); 2791 xfree (info->interpreter);
2699 2792
2793 /* Deallocate any UVS context allocated to look up font variation
2794 sequences. */
2795
2796 if (info->uvs)
2797 sfnt_free_uvs_context (info->uvs);
2798
2700 /* Clear these fields. It seems that close can be called twice, 2799 /* Clear these fields. It seems that close can be called twice,
2701 once during font driver destruction, and once during GC. */ 2800 once during font driver destruction, and once during GC. */
2702 2801
@@ -2713,6 +2812,7 @@ sfntfont_close (struct font *font)
2713 info->fpgm = NULL; 2812 info->fpgm = NULL;
2714 info->cvt = NULL; 2813 info->cvt = NULL;
2715 info->interpreter = NULL; 2814 info->interpreter = NULL;
2815 info->uvs = NULL;
2716 2816
2717#ifdef HAVE_MMAP 2817#ifdef HAVE_MMAP
2718 2818
@@ -2728,6 +2828,28 @@ sfntfont_close (struct font *font)
2728 2828
2729#endif /* HAVE_MMAP */ 2829#endif /* HAVE_MMAP */
2730 2830
2831#ifdef HAVE_HARFBUZZ
2832 /* Close the font file. */
2833
2834 if (info->fd != -1)
2835 {
2836 emacs_close (info->fd);
2837 info->fd = -1;
2838 }
2839
2840 /* Free its table directory. */
2841 xfree (info->directory);
2842 info->directory = NULL;
2843
2844 /* Free any hb_font created. */
2845
2846 if (info->hb_font)
2847 {
2848 hb_font_destroy (info->hb_font);
2849 info->hb_font = NULL;
2850 }
2851#endif
2852
2731 sfntfont_free_outline_cache (&info->outline_cache); 2853 sfntfont_free_outline_cache (&info->outline_cache);
2732 sfntfont_free_raster_cache (&info->raster_cache); 2854 sfntfont_free_raster_cache (&info->raster_cache);
2733} 2855}
@@ -2821,7 +2943,11 @@ sfntfont_draw (struct glyph_string *s, int from, int to,
2821 2943
2822 /* Now work out where to put the outline. */ 2944 /* Now work out where to put the outline. */
2823 x_coords[i - from] = current_x; 2945 x_coords[i - from] = current_x;
2824 current_x += SFNT_CEIL_FIXED (metrics.advance) >> 16; 2946
2947 if (s->padding_p)
2948 current_x += 1;
2949 else
2950 current_x += SFNT_CEIL_FIXED (metrics.advance) >> 16;
2825 } 2951 }
2826 2952
2827 /* Call the window system function to put the glyphs to the 2953 /* Call the window system function to put the glyphs to the
@@ -2865,6 +2991,126 @@ sfntfont_list_family (struct frame *f)
2865 2991
2866 2992
2867 2993
2994/* Unicode Variation Selector (UVS) support. This is typically
2995 required for Harfbuzz. */
2996
2997/* Given a FONT object, a character C, and VARIATIONS, return the
2998 number of non-default variation glyphs, and their glyph ids in
2999 VARIATIONS.
3000
3001 For each variation selector character K with a non-default glyph in
3002 the variation selector range 0xFE00 to 0xFE0F, set variations[K -
3003 0xFE0] to its ID.
3004
3005 For each variation selector character K with a non-default glyph in
3006 the variation selector range 0xE0100 to 0xE01EF, set variations[K -
3007 0xE0100 + 16] to its ID.
3008
3009 If value is more than 0, set all other members of VARIATIONS to 0.
3010 Else, the contents of VARIATIONS are undefined. */
3011
3012int
3013sfntfont_get_variation_glyphs (struct font *font, int c,
3014 unsigned variations[256])
3015{
3016 struct sfnt_font_info *info;
3017 size_t i;
3018 int n;
3019 struct sfnt_mapped_variation_selector_record *record;
3020
3021 info = (struct sfnt_font_info *) font;
3022 n = 0;
3023
3024 /* Return 0 if there is no UVS mapping table. */
3025
3026 if (!info->uvs)
3027 return 0;
3028
3029 /* Clear the variations array. */
3030
3031 memset (variations, 0, sizeof *variations * 256);
3032
3033 /* Find the first 0xFExx selector. */
3034
3035 i = 0;
3036 while (i < info->uvs->num_records
3037 && info->uvs->records[i].selector < 0xfe00)
3038 ++i;
3039
3040 /* Fill in selectors 0 to 15. */
3041
3042 while (i < info->uvs->num_records
3043 && info->uvs->records[i].selector <= 0xfe0f)
3044 {
3045 record = &info->uvs->records[i];
3046
3047 /* If record has no non-default mappings, continue on to the
3048 next selector. */
3049
3050 if (!record->nondefault_uvs)
3051 goto next_selector;
3052
3053 /* Handle invalid unsorted tables. */
3054
3055 if (record->selector < 0xfe00)
3056 return 0;
3057
3058 /* Find the glyph ID associated with C and put it in
3059 VARIATIONS. */
3060
3061 variations[info->uvs->records[i].selector - 0xfe00]
3062 = sfnt_variation_glyph_for_char (record->nondefault_uvs, c);
3063
3064 if (variations[info->uvs->records[i].selector - 0xfe00])
3065 ++n;
3066
3067 next_selector:
3068 ++i;
3069 }
3070
3071 /* Find the first 0xE0100 selector. */
3072
3073 i = 0;
3074 while (i < info->uvs->num_records
3075 && info->uvs->records[i].selector < 0xe0100)
3076 ++i;
3077
3078 /* Fill in selectors 16 to 255. */
3079
3080 while (i < info->uvs->num_records
3081 && info->uvs->records[i].selector <= 0xe01ef)
3082 {
3083 record = &info->uvs->records[i];
3084
3085 /* If record has no non-default mappings, continue on to the
3086 next selector. */
3087
3088 if (!record->nondefault_uvs)
3089 goto next_selector_1;
3090
3091 /* Handle invalid unsorted tables. */
3092
3093 if (record->selector < 0xe0100)
3094 return 0;
3095
3096 /* Find the glyph ID associated with C and put it in
3097 VARIATIONS. */
3098
3099 variations[info->uvs->records[i].selector - 0xe0100 + 16]
3100 = sfnt_variation_glyph_for_char (record->nondefault_uvs, c);
3101
3102 if (variations[info->uvs->records[i].selector - 0xe0100 + 16])
3103 ++n;
3104
3105 next_selector_1:
3106 ++i;
3107 }
3108
3109 return n;
3110}
3111
3112
3113
2868/* mmap specific stuff. */ 3114/* mmap specific stuff. */
2869 3115
2870#ifdef HAVE_MMAP 3116#ifdef HAVE_MMAP
@@ -2893,6 +3139,126 @@ sfntfont_detect_sigbus (void *addr)
2893 3139
2894 3140
2895 3141
3142/* Harfbuzz font support. */
3143
3144#ifdef HAVE_HARFBUZZ
3145
3146#ifdef HAVE_MMAP
3147
3148/* Unmap the specified table. */
3149
3150static void
3151sfntfont_unmap_blob (void *ptr)
3152{
3153 if (sfnt_unmap_table (ptr))
3154 emacs_abort ();
3155
3156 xfree (ptr);
3157}
3158
3159#endif /* HAVE_MMAP */
3160
3161/* Given a font DATA and a tag TAG, return the data of the
3162 corresponding font table as a HarfBuzz blob. */
3163
3164static hb_blob_t *
3165sfntfont_get_font_table (hb_face_t *face, hb_tag_t tag, void *data)
3166{
3167 size_t size;
3168 struct sfnt_font_info *info;
3169#ifdef HAVE_MMAP
3170 struct sfnt_mapped_table *table;
3171 hb_blob_t *blob;
3172
3173 info = data;
3174 table = xmalloc (sizeof *table);
3175
3176 if (!sfnt_map_table (info->fd, info->directory, tag,
3177 table))
3178 {
3179 /* Create an hb_blob_t and return it.
3180 TODO: record this mapping properly so that SIGBUS can
3181 be handled. */
3182
3183 blob = hb_blob_create (table->data, table->length,
3184 HB_MEMORY_MODE_READONLY,
3185 table, sfntfont_unmap_blob);
3186
3187 /* Note that sfntfont_unmap_blob will be called if the empty
3188 blob is returned. */
3189 return blob;
3190 }
3191
3192 xfree (table);
3193#else /* !HAVE_MMAP */
3194
3195 /* Try to read the table conventionally. */
3196 info = data;
3197#endif /* HAVE_MMAP */
3198
3199 data = sfnt_read_table (info->fd, info->directory, tag,
3200 &size);
3201
3202 if (!data)
3203 return NULL;
3204
3205 return hb_blob_create (data, size, HB_MEMORY_MODE_WRITABLE,
3206 data, xfree);
3207}
3208
3209/* Create or return a HarfBuzz font object corresponding to the
3210 specified FONT. Return the scale to convert between fwords and
3211 pixels in POSITION_UNIT. */
3212
3213hb_font_t *
3214sfntfont_begin_hb_font (struct font *font, double *position_unit)
3215{
3216 struct sfnt_font_info *info;
3217 hb_face_t *face;
3218 int factor;
3219
3220 info = (struct sfnt_font_info *) font;
3221
3222 if (info->hb_font)
3223 {
3224 /* Calculate the scale factor. */
3225 *position_unit = 1.0 / 64.0;
3226 return info->hb_font;
3227 }
3228
3229 /* Create a face and then a font. */
3230 face = hb_face_create_for_tables (sfntfont_get_font_table, font,
3231 NULL);
3232
3233 if (hb_face_get_glyph_count (face) > 0)
3234 {
3235 info->hb_font = hb_font_create (face);
3236 if (!info->hb_font)
3237 goto bail;
3238
3239 factor = font->pixel_size;
3240
3241 /* Set the scale and PPEM values. */
3242 hb_font_set_scale (info->hb_font, factor * 64, factor * 64);
3243 hb_font_set_ppem (info->hb_font, factor, factor);
3244
3245 /* This is needed for HarfBuzz before 2.0.0; it is the default
3246 in later versions. */
3247 hb_ot_font_set_funcs (info->hb_font);
3248 }
3249
3250 bail:
3251 hb_face_destroy (face);
3252
3253 /* Calculate the scale factor. */
3254 *position_unit = 1.0 / 64.0;
3255 return info->hb_font;
3256}
3257
3258#endif /* HAVE_HARFBUZZ */
3259
3260
3261
2896void 3262void
2897syms_of_sfntfont (void) 3263syms_of_sfntfont (void)
2898{ 3264{
diff --git a/src/sfntfont.h b/src/sfntfont.h
index dc37883b4a9..df387512d0d 100644
--- a/src/sfntfont.h
+++ b/src/sfntfont.h
@@ -42,6 +42,7 @@ extern void sfntfont_close (struct font *);
42extern int sfntfont_draw (struct glyph_string *, int, int, 42extern int sfntfont_draw (struct glyph_string *, int, int,
43 int, int, bool); 43 int, int, bool);
44extern Lisp_Object sfntfont_list_family (struct frame *); 44extern Lisp_Object sfntfont_list_family (struct frame *);
45extern int sfntfont_get_variation_glyphs (struct font *, int, unsigned[256]);
45 46
46 47
47/* Initialization functions. */ 48/* Initialization functions. */
@@ -65,4 +66,14 @@ extern bool sfntfont_detect_sigbus (void *);
65 66
66#endif /* HAVE_MMAP */ 67#endif /* HAVE_MMAP */
67 68
69
70
71/* HarfBuzz specific functions. */
72
73#ifdef HAVE_HARFBUZZ
74
75extern hb_font_t *sfntfont_begin_hb_font (struct font *, double *);
76
77#endif /* HAVE_HARFBUZZ */
78
68#endif /* _SFNTFONT_H_ */ 79#endif /* _SFNTFONT_H_ */
diff --git a/src/textconv.c b/src/textconv.c
index a4e3116fb68..4fa92f43ecd 100644
--- a/src/textconv.c
+++ b/src/textconv.c
@@ -1723,12 +1723,12 @@ DEFUN ("set-text-conversion-style", Fset_text_conversion_style,
1723 Sset_text_conversion_style, 1, 1, 0, 1723 Sset_text_conversion_style, 1, 1, 0,
1724 doc: /* Set the text conversion style in the current buffer. 1724 doc: /* Set the text conversion style in the current buffer.
1725 1725
1726Set `text-conversion-mode' to VALUE, then force any input method 1726Set `text-conversion-style' to VALUE, then force any input method
1727editing frame displaying this buffer to stop itself. 1727editing frame displaying this buffer to stop itself.
1728 1728
1729This can lead to a significant amount of time being taken by the input 1729This can lead to a significant amount of time being taken by the input
1730method resetting itself, so you should not use this function lightly; 1730method resetting itself, so you should not use this function lightly;
1731instead, set `text-conversion-mode' before your buffer is displayed, 1731instead, set `text-conversion-style' before your buffer is displayed,
1732and let redisplay manage the input method appropriately. */) 1732and let redisplay manage the input method appropriately. */)
1733 (Lisp_Object value) 1733 (Lisp_Object value)
1734{ 1734{