diff options
| author | Po Lu | 2023-03-20 14:47:39 +0800 |
|---|---|---|
| committer | Po Lu | 2023-03-20 14:47:39 +0800 |
| commit | 6bd1cfa24fd04de855e53e74b46cdf4047bced4c (patch) | |
| tree | b652dff0db980c71d94fa6215138e51ede9ae174 | |
| parent | 739558c36958d9ec9f221ce168e15467b4579111 (diff) | |
| download | emacs-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.ac | 6 | ||||
| -rw-r--r-- | java/INSTALL | 16 | ||||
| -rw-r--r-- | lisp/subr.el | 16 | ||||
| -rw-r--r-- | src/sfnt.c | 741 | ||||
| -rw-r--r-- | src/sfnt.h | 165 | ||||
| -rw-r--r-- | src/sfntfont-android.c | 12 | ||||
| -rw-r--r-- | src/sfntfont.c | 384 | ||||
| -rw-r--r-- | src/sfntfont.h | 11 | ||||
| -rw-r--r-- | src/textconv.c | 4 |
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 | |||
| 4581 | fi | 4582 | fi |
| 4582 | if test "${HAVE_X11}" = "yes" && test "${HAVE_FREETYPE}" = "yes" \ | 4583 | if 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 | ||
| 269 | And other developers have ported the following dependencies to Android | 271 | And other developers have ported the following dependencies to Android |
| 270 | systems: | 272 | systems: |
| @@ -305,15 +307,23 @@ should not try to build these packages separately using any | |||
| 305 | TREE-SITTER | 307 | TREE-SITTER |
| 306 | 308 | ||
| 307 | A copy of tree-sitter modified to build with the ndk-build system can | 309 | A copy of tree-sitter modified to build with the ndk-build system can |
| 308 | also find that URL. To build Emacs with tree-sitter, you must unpack | 310 | also be found that URL. To build Emacs with tree-sitter, you must |
| 309 | the following tar archive in that site: | 311 | unpack 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 | ||
| 313 | and add the resulting folder to ``--with-ndk-build''. | 315 | and add the resulting folder to ``--with-ndk-build''. |
| 314 | 316 | ||
| 315 | 317 | ||
| 316 | IMAGEMAGICK | 318 | HARFBUZZ |
| 319 | |||
| 320 | A copy of HarfBuzz modified to build with the ndk-build system can | ||
| 321 | also be found at that URL. To build Emacs with HarfBuzz, you must | ||
| 322 | unpack the following tar archive in that site: | ||
| 323 | |||
| 324 | harfbuzz-7.1.0-emacs.tar.gz | ||
| 325 | |||
| 326 | and add the resulting folder to ``--with-ndk-build''. | ||
| 317 | 327 | ||
| 318 | There is a third party port of ImageMagick to Android. Unfortunately, | 328 | There is a third party port of ImageMagick to Android. Unfortunately, |
| 319 | the port also uses its own patched versions of libpng, libjpeg, | 329 | the 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 | |||
| 778 | static unsigned int | ||
| 779 | sfnt_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 | |||
| 791 | static struct sfnt_cmap_format_14 * | ||
| 792 | sfnt_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 | ||
| 1204 | TEST_STATIC sfnt_glyph | 1317 | TEST_STATIC sfnt_glyph |
| 1205 | sfnt_lookup_glyph (sfnt_char character, | 1318 | sfnt_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 | |||
| 11910 | static struct sfnt_default_uvs_table * | ||
| 11911 | sfnt_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 | |||
| 11980 | static struct sfnt_nondefault_uvs_table * | ||
| 11981 | sfnt_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 | |||
| 12053 | static int | ||
| 12054 | sfnt_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 | |||
| 12079 | TEST_STATIC struct sfnt_uvs_context * | ||
| 12080 | sfnt_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 | |||
| 12249 | TEST_STATIC void | ||
| 12250 | sfnt_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 | |||
| 12266 | static int | ||
| 12267 | sfnt_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 | |||
| 12289 | TEST_STATIC sfnt_glyph | ||
| 12290 | sfnt_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 | |||
| 12323 | int | ||
| 12324 | sfnt_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 | |||
| 12373 | int | ||
| 12374 | sfnt_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 | |||
| 12391 | void * | ||
| 12392 | sfnt_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 | ||
| 11780 | struct sfnt_test_dcontext | 12438 | struct sfnt_test_dcontext |
| @@ -15494,6 +16152,52 @@ sfnt_pop_hook (struct sfnt_interpreter *interpreter, | |||
| 15494 | 16152 | ||
| 15495 | 16153 | ||
| 15496 | 16154 | ||
| 16155 | static void | ||
| 16156 | sfnt_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 | ||
| 427 | struct sfnt_cmap_format_12 | 429 | struct 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 | ||
| 450 | struct 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 | |||
| 468 | struct 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 | |||
| 448 | struct sfnt_maxp_table | 480 | struct 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 | |||
| 1474 | struct 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 | |||
| 1483 | struct 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 | |||
| 1492 | struct 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 | |||
| 1501 | struct 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 | |||
| 1510 | struct 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 | |||
| 1525 | struct 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 | |||
| 1537 | struct 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 | |||
| 1556 | struct 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 | |||
| 1648 | extern struct sfnt_uvs_context *sfnt_create_uvs_context (PROTOTYPE); | ||
| 1649 | |||
| 1650 | #undef PROTOTYPE | ||
| 1651 | |||
| 1652 | extern void sfnt_free_uvs_context (struct sfnt_uvs_context *); | ||
| 1653 | |||
| 1654 | #define PROTOTYPE struct sfnt_nondefault_uvs_table *, sfnt_char | ||
| 1655 | |||
| 1656 | extern sfnt_glyph sfnt_variation_glyph_for_char (PROTOTYPE); | ||
| 1657 | |||
| 1658 | #undef PROTOTYPE | ||
| 1659 | |||
| 1660 | |||
| 1661 | |||
| 1662 | #ifdef HAVE_MMAP | ||
| 1663 | |||
| 1664 | extern int sfnt_map_table (int, struct sfnt_offset_subtable *, | ||
| 1665 | uint32_t, struct sfnt_mapped_table *); | ||
| 1666 | extern int sfnt_unmap_table (struct sfnt_mapped_table *); | ||
| 1667 | |||
| 1668 | #endif /* HAVE_MMAP */ | ||
| 1669 | |||
| 1670 | |||
| 1671 | |||
| 1672 | extern 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 | ||
| 1043 | static struct sfnt_cmap_encoding_subtable_data * | 1052 | static struct sfnt_cmap_encoding_subtable_data * |
| 1044 | sfntfont_select_cmap (struct sfnt_cmap_table *cmap, | 1053 | sfntfont_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 | |||
| 3012 | int | ||
| 3013 | sfntfont_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 | |||
| 3150 | static void | ||
| 3151 | sfntfont_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 | |||
| 3164 | static hb_blob_t * | ||
| 3165 | sfntfont_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 | |||
| 3213 | hb_font_t * | ||
| 3214 | sfntfont_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 | |||
| 2896 | void | 3262 | void |
| 2897 | syms_of_sfntfont (void) | 3263 | syms_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 *); | |||
| 42 | extern int sfntfont_draw (struct glyph_string *, int, int, | 42 | extern int sfntfont_draw (struct glyph_string *, int, int, |
| 43 | int, int, bool); | 43 | int, int, bool); |
| 44 | extern Lisp_Object sfntfont_list_family (struct frame *); | 44 | extern Lisp_Object sfntfont_list_family (struct frame *); |
| 45 | extern 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 | |||
| 75 | extern 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 | ||
| 1726 | Set `text-conversion-mode' to VALUE, then force any input method | 1726 | Set `text-conversion-style' to VALUE, then force any input method |
| 1727 | editing frame displaying this buffer to stop itself. | 1727 | editing frame displaying this buffer to stop itself. |
| 1728 | 1728 | ||
| 1729 | This can lead to a significant amount of time being taken by the input | 1729 | This can lead to a significant amount of time being taken by the input |
| 1730 | method resetting itself, so you should not use this function lightly; | 1730 | method resetting itself, so you should not use this function lightly; |
| 1731 | instead, set `text-conversion-mode' before your buffer is displayed, | 1731 | instead, set `text-conversion-style' before your buffer is displayed, |
| 1732 | and let redisplay manage the input method appropriately. */) | 1732 | and let redisplay manage the input method appropriately. */) |
| 1733 | (Lisp_Object value) | 1733 | (Lisp_Object value) |
| 1734 | { | 1734 | { |