diff options
| author | Eli Zaretskii | 2015-08-19 18:04:22 +0300 |
|---|---|---|
| committer | Eli Zaretskii | 2015-08-19 18:04:22 +0300 |
| commit | ae7cfd0baf24fda984ff4c0631bcaa477ea11b7f (patch) | |
| tree | 9a3dae67498d68e75afbc92b6c7e2586b8ead738 | |
| parent | 7eed7399358faecd719febae4dc720ef2be41155 (diff) | |
| download | emacs-ae7cfd0baf24fda984ff4c0631bcaa477ea11b7f.tar.gz emacs-ae7cfd0baf24fda984ff4c0631bcaa477ea11b7f.zip | |
Improve and future-proof OTF fonts support in w32uniscribe.c
* src/w32uniscribe.c (uniscribe_otf_capability): Add commentary
about the expected results and why the new Uniscribe APIs are not
used in this function.
(ScriptGetFontScriptTags_Proc, ScriptGetFontLanguageTags_Proc)
(ScriptGetFontFeatureTags_Proc): New function typedefs.
(uniscribe_new_apis): New static variable.
(uniscribe_check_features): New function, implements OTF features
verification while correctly accounting for features in the list
after the nil member, if any.
(uniscribe_check_otf_1): New function, retrieves the features
supported by the font for the requested script and language using
the Uniscribe APIs available from Windows Vista onwards.
(uniscribe_check_otf): If the new Uniscribe APIs are available,
use them in preference to reading the font data directly. Call
uniscribe_check_features to verify that the requested features are
supported, replacing the original incomplete code.
(syms_of_w32uniscribe): Initialize function pointers for the new
Uniscribe APIs. (Bug#21260)
(otf_features): Scan the script, langsys, and feature arrays back
to front, so that the result we return has them in alphabetical
order, like ftfont.c does.
* src/w32fns.c (syms_of_w32fns) <w32-disable-new-uniscribe-apis>:
New variable for debugging w32uniscribe.c code.
| -rw-r--r-- | src/w32fns.c | 10 | ||||
| -rw-r--r-- | src/w32uniscribe.c | 284 |
2 files changed, 253 insertions, 41 deletions
diff --git a/src/w32fns.c b/src/w32fns.c index 189a27c62f1..e91097ba20e 100644 --- a/src/w32fns.c +++ b/src/w32fns.c | |||
| @@ -9242,6 +9242,16 @@ Default is nil. | |||
| 9242 | This variable has effect only on NT family of systems, not on Windows 9X. */); | 9242 | This variable has effect only on NT family of systems, not on Windows 9X. */); |
| 9243 | w32_use_fallback_wm_chars_method = 0; | 9243 | w32_use_fallback_wm_chars_method = 0; |
| 9244 | 9244 | ||
| 9245 | DEFVAR_BOOL ("w32-disable-new-uniscribe-apis", | ||
| 9246 | w32_disable_new_uniscribe_apis, | ||
| 9247 | doc: /* Non-nil means don't use new Uniscribe APIs. | ||
| 9248 | The new APIs are used to access OTF features supported by fonts. | ||
| 9249 | This is intended only for debugging of the new Uniscribe-related code. | ||
| 9250 | Default is nil. | ||
| 9251 | |||
| 9252 | This variable has effect only on Windows Vista and later. */); | ||
| 9253 | w32_disable_new_uniscribe_apis = 0; | ||
| 9254 | |||
| 9245 | #if 0 /* TODO: Port to W32 */ | 9255 | #if 0 /* TODO: Port to W32 */ |
| 9246 | defsubr (&Sx_change_window_property); | 9256 | defsubr (&Sx_change_window_property); |
| 9247 | defsubr (&Sx_delete_window_property); | 9257 | defsubr (&Sx_delete_window_property); |
diff --git a/src/w32uniscribe.c b/src/w32uniscribe.c index 73c0410c7b7..b1056bc104e 100644 --- a/src/w32uniscribe.c +++ b/src/w32uniscribe.c | |||
| @@ -141,7 +141,26 @@ uniscribe_close (struct font *font) | |||
| 141 | } | 141 | } |
| 142 | 142 | ||
| 143 | /* Return a list describing which scripts/languages FONT supports by | 143 | /* Return a list describing which scripts/languages FONT supports by |
| 144 | which GSUB/GPOS features of OpenType tables. */ | 144 | which GSUB/GPOS features of OpenType tables. |
| 145 | |||
| 146 | Implementation note: otf_features called by this function uses | ||
| 147 | GetFontData to access the font tables directly, instead of using | ||
| 148 | ScriptGetFontScriptTags etc. APIs even if those are available. The | ||
| 149 | reason is that font-get, which uses the result of this function, | ||
| 150 | expects a cons cell (GSUB . GPOS) where the features are reported | ||
| 151 | separately for these 2 OTF tables, while the Uniscribe APIs report | ||
| 152 | the features as a single list. There doesn't seem to be a reason | ||
| 153 | for returning the features in 2 separate parts, except for | ||
| 154 | compatibility with libotf; the features are disjoint (each can | ||
| 155 | appear only in one of the 2 slots), and no client of this data | ||
| 156 | discerns between the two slots: the few that request this data all | ||
| 157 | look in both slots. If use of the Uniscribe APIs ever becomes | ||
| 158 | necessary here, and the 2 separate slots are still required, it | ||
| 159 | should be possible to split the feature list the APIs return into 2 | ||
| 160 | because each sub-list is alphabetically sorted, so the place where | ||
| 161 | the sorting order breaks is where the GSUB features end and GPOS | ||
| 162 | features begin. But for now, this is not necessary, so we leave | ||
| 163 | the original code in place. */ | ||
| 145 | static Lisp_Object | 164 | static Lisp_Object |
| 146 | uniscribe_otf_capability (struct font *font) | 165 | uniscribe_otf_capability (struct font *font) |
| 147 | { | 166 | { |
| @@ -643,7 +662,7 @@ add_opentype_font_name_to_list (ENUMLOGFONTEX *logical_font, | |||
| 643 | 662 | ||
| 644 | /* :otf property handling. | 663 | /* :otf property handling. |
| 645 | Since the necessary Uniscribe APIs for getting font tag information | 664 | Since the necessary Uniscribe APIs for getting font tag information |
| 646 | are only available in Vista, we need to parse the font data directly | 665 | are only available in Vista, we may need to parse the font data directly |
| 647 | according to the OpenType Specification. */ | 666 | according to the OpenType Specification. */ |
| 648 | 667 | ||
| 649 | /* Push into DWORD backwards to cope with endianness. */ | 668 | /* Push into DWORD backwards to cope with endianness. */ |
| @@ -674,7 +693,171 @@ add_opentype_font_name_to_list (ENUMLOGFONTEX *logical_font, | |||
| 674 | STR[4] = '\0'; \ | 693 | STR[4] = '\0'; \ |
| 675 | } while (0) | 694 | } while (0) |
| 676 | 695 | ||
| 677 | #define SNAME(VAL) SDATA (SYMBOL_NAME (VAL)) | 696 | #define SNAME(VAL) SSDATA (SYMBOL_NAME (VAL)) |
| 697 | |||
| 698 | /* Uniscribe APIs available only since Windows Vista. */ | ||
| 699 | typedef HRESULT (WINAPI *ScriptGetFontScriptTags_Proc) | ||
| 700 | (HDC, SCRIPT_CACHE *, SCRIPT_ANALYSIS *, int, OPENTYPE_TAG *, int *); | ||
| 701 | |||
| 702 | typedef HRESULT (WINAPI *ScriptGetFontLanguageTags_Proc) | ||
| 703 | (HDC, SCRIPT_CACHE *, SCRIPT_ANALYSIS *, OPENTYPE_TAG, int, OPENTYPE_TAG *, int *); | ||
| 704 | |||
| 705 | typedef HRESULT (WINAPI *ScriptGetFontFeatureTags_Proc) | ||
| 706 | (HDC, SCRIPT_CACHE *, SCRIPT_ANALYSIS *, OPENTYPE_TAG, OPENTYPE_TAG, int, OPENTYPE_TAG *, int *); | ||
| 707 | |||
| 708 | ScriptGetFontScriptTags_Proc script_get_font_scripts_fn; | ||
| 709 | ScriptGetFontLanguageTags_Proc script_get_font_languages_fn; | ||
| 710 | ScriptGetFontFeatureTags_Proc script_get_font_features_fn; | ||
| 711 | |||
| 712 | static bool uniscribe_new_apis; | ||
| 713 | |||
| 714 | /* Verify that all the required features in FEATURES, each of whose | ||
| 715 | elements is a list or nil, can be found among the N feature tags in | ||
| 716 | FTAGS. Return 'true' if the required features are supported, | ||
| 717 | 'false' if not. Each list in FEATURES can include an element of | ||
| 718 | nil, which means all the elements after it must not be in FTAGS. */ | ||
| 719 | static bool | ||
| 720 | uniscribe_check_features (Lisp_Object features[2], OPENTYPE_TAG *ftags, int n) | ||
| 721 | { | ||
| 722 | int j; | ||
| 723 | |||
| 724 | for (j = 0; j < 2; j++) | ||
| 725 | { | ||
| 726 | bool negative = false; | ||
| 727 | Lisp_Object rest; | ||
| 728 | |||
| 729 | for (rest = features[j]; CONSP (rest); rest = XCDR (rest)) | ||
| 730 | { | ||
| 731 | Lisp_Object feature = XCAR (rest); | ||
| 732 | |||
| 733 | /* The font must NOT have any of the features after nil. | ||
| 734 | See the doc string of 'font-spec', under ':otf'. */ | ||
| 735 | if (NILP (feature)) | ||
| 736 | negative = true; | ||
| 737 | else | ||
| 738 | { | ||
| 739 | OPENTYPE_TAG feature_tag = OTF_TAG (SNAME (feature)); | ||
| 740 | int i; | ||
| 741 | |||
| 742 | for (i = 0; i < n; i++) | ||
| 743 | { | ||
| 744 | if (ftags[i] == feature_tag) | ||
| 745 | { | ||
| 746 | /* Test fails if we find a feature that the font | ||
| 747 | must NOT have. */ | ||
| 748 | if (negative) | ||
| 749 | return false; | ||
| 750 | break; | ||
| 751 | } | ||
| 752 | } | ||
| 753 | |||
| 754 | /* Test fails if we do NOT find a feature that the font | ||
| 755 | should have. */ | ||
| 756 | if (i >= n && !negative) | ||
| 757 | return false; | ||
| 758 | } | ||
| 759 | } | ||
| 760 | } | ||
| 761 | |||
| 762 | return true; | ||
| 763 | } | ||
| 764 | |||
| 765 | /* Check if font supports the required OTF script/language/features | ||
| 766 | using the Unsicribe APIs available since Windows Vista. We prefer | ||
| 767 | these APIs as a kind of future-proofing Emacs: they seem to | ||
| 768 | retrieve script tags that the old code (and also libotf) doesn't | ||
| 769 | seem to be able to get, e.g., some fonts that claim support for | ||
| 770 | "dev2" script don't show "deva", but the new APIs do report it. */ | ||
| 771 | static int | ||
| 772 | uniscribe_check_otf_1 (HDC context, Lisp_Object script, Lisp_Object lang, | ||
| 773 | Lisp_Object features[2], int *retval) | ||
| 774 | { | ||
| 775 | SCRIPT_CACHE cache = NULL; | ||
| 776 | OPENTYPE_TAG tags[32], script_tag, lang_tag; | ||
| 777 | int max_tags = ARRAYELTS (tags); | ||
| 778 | int ntags, i, ret = 0; | ||
| 779 | HRESULT rslt; | ||
| 780 | Lisp_Object rest; | ||
| 781 | |||
| 782 | *retval = 0; | ||
| 783 | |||
| 784 | rslt = script_get_font_scripts_fn (context, &cache, NULL, max_tags, | ||
| 785 | tags, &ntags); | ||
| 786 | if (FAILED (rslt)) | ||
| 787 | { | ||
| 788 | DebPrint (("ScriptGetFontScriptTags failed with 0x%x\n", rslt)); | ||
| 789 | ret = -1; | ||
| 790 | goto no_support; | ||
| 791 | } | ||
| 792 | if (NILP (script)) | ||
| 793 | script_tag = OTF_TAG ("DFLT"); | ||
| 794 | else | ||
| 795 | script_tag = OTF_TAG (SNAME (script)); | ||
| 796 | for (i = 0; i < ntags; i++) | ||
| 797 | if (tags[i] == script_tag) | ||
| 798 | break; | ||
| 799 | |||
| 800 | if (i >= ntags) | ||
| 801 | goto no_support; | ||
| 802 | |||
| 803 | if (NILP (lang)) | ||
| 804 | lang_tag = OTF_TAG ("dflt"); | ||
| 805 | else | ||
| 806 | { | ||
| 807 | rslt = script_get_font_languages_fn (context, &cache, NULL, script_tag, | ||
| 808 | max_tags, tags, &ntags); | ||
| 809 | if (FAILED (rslt)) | ||
| 810 | { | ||
| 811 | DebPrint (("ScriptGetFontLanguageTags failed with 0x%x\n", rslt)); | ||
| 812 | ret = -1; | ||
| 813 | goto no_support; | ||
| 814 | } | ||
| 815 | if (ntags == 0) | ||
| 816 | lang_tag = OTF_TAG ("dflt"); | ||
| 817 | else | ||
| 818 | { | ||
| 819 | lang_tag = OTF_TAG (SNAME (lang)); | ||
| 820 | for (i = 0; i < ntags; i++) | ||
| 821 | if (tags[i] == lang_tag) | ||
| 822 | break; | ||
| 823 | |||
| 824 | if (i >= ntags) | ||
| 825 | goto no_support; | ||
| 826 | } | ||
| 827 | } | ||
| 828 | |||
| 829 | if (!NILP (features[0])) | ||
| 830 | { | ||
| 831 | /* Are the 2 feature lists valid? */ | ||
| 832 | if (!CONSP (features[0]) | ||
| 833 | || (!NILP (features[1]) && !CONSP (features[1]))) | ||
| 834 | goto no_support; | ||
| 835 | rslt = script_get_font_features_fn (context, &cache, NULL, | ||
| 836 | script_tag, lang_tag, | ||
| 837 | max_tags, tags, &ntags); | ||
| 838 | if (FAILED (rslt)) | ||
| 839 | { | ||
| 840 | DebPrint (("ScriptGetFontFeatureTags failed with 0x%x\n", rslt)); | ||
| 841 | ret = -1; | ||
| 842 | goto no_support; | ||
| 843 | } | ||
| 844 | |||
| 845 | /* ScriptGetFontFeatureTags doesn't let us query features | ||
| 846 | separately for GSUB and GPOS, so we check them all together. | ||
| 847 | It doesn't really matter, since the features in GSUB and GPOS | ||
| 848 | are disjoint, i.e. no feature can appear in both tables. */ | ||
| 849 | if (!uniscribe_check_features (features, tags, ntags)) | ||
| 850 | goto no_support; | ||
| 851 | } | ||
| 852 | |||
| 853 | ret = 1; | ||
| 854 | *retval = 1; | ||
| 855 | |||
| 856 | no_support: | ||
| 857 | if (cache) | ||
| 858 | ScriptFreeCache (&cache); | ||
| 859 | return ret; | ||
| 860 | } | ||
| 678 | 861 | ||
| 679 | /* Check if font supports the otf script/language/features specified. | 862 | /* Check if font supports the otf script/language/features specified. |
| 680 | OTF_SPEC is in the format | 863 | OTF_SPEC is in the format |
| @@ -710,6 +893,18 @@ uniscribe_check_otf (LOGFONT *font, Lisp_Object otf_spec) | |||
| 710 | else | 893 | else |
| 711 | features[1] = XCAR (rest); | 894 | features[1] = XCAR (rest); |
| 712 | 895 | ||
| 896 | /* Set up graphics context so we can use the font. */ | ||
| 897 | f = XFRAME (selected_frame); | ||
| 898 | context = get_frame_dc (f); | ||
| 899 | check_font = CreateFontIndirect (font); | ||
| 900 | old_font = SelectObject (context, check_font); | ||
| 901 | |||
| 902 | /* If we are on Vista or later, use the new APIs. */ | ||
| 903 | if (uniscribe_new_apis | ||
| 904 | && !w32_disable_new_uniscribe_apis | ||
| 905 | && uniscribe_check_otf_1 (context, script, lang, features, &retval) != -1) | ||
| 906 | goto done; | ||
| 907 | |||
| 713 | /* Set up tags we will use in the search. */ | 908 | /* Set up tags we will use in the search. */ |
| 714 | feature_tables[0] = OTF_TAG ("GSUB"); | 909 | feature_tables[0] = OTF_TAG ("GSUB"); |
| 715 | feature_tables[1] = OTF_TAG ("GPOS"); | 910 | feature_tables[1] = OTF_TAG ("GPOS"); |
| @@ -721,12 +916,6 @@ uniscribe_check_otf (LOGFONT *font, Lisp_Object otf_spec) | |||
| 721 | if (!NILP (lang)) | 916 | if (!NILP (lang)) |
| 722 | lang_tag = OTF_TAG (SNAME (lang)); | 917 | lang_tag = OTF_TAG (SNAME (lang)); |
| 723 | 918 | ||
| 724 | /* Set up graphics context so we can use the font. */ | ||
| 725 | f = XFRAME (selected_frame); | ||
| 726 | context = get_frame_dc (f); | ||
| 727 | check_font = CreateFontIndirect (font); | ||
| 728 | old_font = SelectObject (context, check_font); | ||
| 729 | |||
| 730 | /* Everything else is contained within otf_spec so should get | 919 | /* Everything else is contained within otf_spec so should get |
| 731 | marked along with it. */ | 920 | marked along with it. */ |
| 732 | GCPRO1 (otf_spec); | 921 | GCPRO1 (otf_spec); |
| @@ -739,6 +928,8 @@ uniscribe_check_otf (LOGFONT *font, Lisp_Object otf_spec) | |||
| 739 | unsigned short script_table, langsys_table, n_langs; | 928 | unsigned short script_table, langsys_table, n_langs; |
| 740 | unsigned short feature_index, n_features; | 929 | unsigned short feature_index, n_features; |
| 741 | DWORD tbl = feature_tables[i]; | 930 | DWORD tbl = feature_tables[i]; |
| 931 | DWORD feature_id, *ftags; | ||
| 932 | Lisp_Object farray[2]; | ||
| 742 | 933 | ||
| 743 | /* Skip if no features requested from this table. */ | 934 | /* Skip if no features requested from this table. */ |
| 744 | if (NILP (features[i])) | 935 | if (NILP (features[i])) |
| @@ -805,51 +996,49 @@ uniscribe_check_otf (LOGFONT *font, Lisp_Object otf_spec) | |||
| 805 | /* Offset is from beginning of script table. */ | 996 | /* Offset is from beginning of script table. */ |
| 806 | langsys_table += script_table; | 997 | langsys_table += script_table; |
| 807 | 998 | ||
| 808 | /* Check the features. Features may contain nil according to | ||
| 809 | documentation in font_prop_validate_otf, so count them. */ | ||
| 810 | n_match_features = 0; | ||
| 811 | for (rest = features[i]; CONSP (rest); rest = XCDR (rest)) | ||
| 812 | { | ||
| 813 | Lisp_Object feature = XCAR (rest); | ||
| 814 | if (!NILP (feature)) | ||
| 815 | n_match_features++; | ||
| 816 | } | ||
| 817 | |||
| 818 | /* If there are no features to check, skip checking. */ | 999 | /* If there are no features to check, skip checking. */ |
| 819 | if (!n_match_features) | 1000 | if (NILP (features[i])) |
| 820 | continue; | 1001 | continue; |
| 1002 | if (!CONSP (features[i])) | ||
| 1003 | goto no_support; | ||
| 1004 | |||
| 1005 | n_match_features = 0; | ||
| 821 | 1006 | ||
| 822 | /* First check required feature (if any). */ | 1007 | /* First get required feature (if any). */ |
| 823 | OTF_INT16_VAL (tbl, langsys_table + 2, &feature_index); | 1008 | OTF_INT16_VAL (tbl, langsys_table + 2, &feature_index); |
| 824 | if (feature_index != 0xFFFF) | 1009 | if (feature_index != 0xFFFF) |
| 1010 | n_match_features = 1; | ||
| 1011 | OTF_INT16_VAL (tbl, langsys_table + 4, &n_features); | ||
| 1012 | n_match_features += n_features; | ||
| 1013 | USE_SAFE_ALLOCA; | ||
| 1014 | SAFE_NALLOCA (ftags, 1, n_match_features); | ||
| 1015 | int k = 0; | ||
| 1016 | if (feature_index != 0xFFFF) | ||
| 825 | { | 1017 | { |
| 826 | char feature_id[5]; | 1018 | OTF_DWORDTAG_VAL (tbl, feature_table + 2 + feature_index * 6, |
| 827 | OTF_TAG_VAL (tbl, feature_table + 2 + feature_index * 6, feature_id); | 1019 | &feature_id); |
| 828 | OTF_TAG_VAL (tbl, feature_table + 2 + feature_index * 6, feature_id); | 1020 | ftags[k++] = feature_id; |
| 829 | /* Assume no duplicates in the font table. This allows us to mark | ||
| 830 | the features off by simply decrementing a counter. */ | ||
| 831 | if (!NILP (Fmemq (intern (feature_id), features[i]))) | ||
| 832 | n_match_features--; | ||
| 833 | } | 1021 | } |
| 834 | /* Now check all the other features. */ | 1022 | /* Now get all the other features. */ |
| 835 | OTF_INT16_VAL (tbl, langsys_table + 4, &n_features); | ||
| 836 | for (j = 0; j < n_features; j++) | 1023 | for (j = 0; j < n_features; j++) |
| 837 | { | 1024 | { |
| 838 | char feature_id[5]; | ||
| 839 | OTF_INT16_VAL (tbl, langsys_table + 6 + j * 2, &feature_index); | 1025 | OTF_INT16_VAL (tbl, langsys_table + 6 + j * 2, &feature_index); |
| 840 | OTF_TAG_VAL (tbl, feature_table + 2 + feature_index * 6, feature_id); | 1026 | OTF_DWORDTAG_VAL (tbl, feature_table + 2 + feature_index * 6, |
| 841 | /* Assume no duplicates in the font table. This allows us to mark | 1027 | &feature_id); |
| 842 | the features off by simply decrementing a counter. */ | 1028 | ftags[k++] = feature_id; |
| 843 | if (!NILP (Fmemq (intern (feature_id), features[i]))) | ||
| 844 | n_match_features--; | ||
| 845 | } | 1029 | } |
| 846 | 1030 | ||
| 847 | if (n_match_features > 0) | 1031 | /* Check the features for this table. */ |
| 1032 | farray[0] = features[i]; | ||
| 1033 | farray[1] = Qnil; | ||
| 1034 | if (!uniscribe_check_features (farray, ftags, n_match_features)) | ||
| 848 | goto no_support; | 1035 | goto no_support; |
| 1036 | SAFE_FREE (); | ||
| 849 | } | 1037 | } |
| 850 | 1038 | ||
| 851 | retval = 1; | 1039 | retval = 1; |
| 852 | 1040 | ||
| 1041 | done: | ||
| 853 | no_support: | 1042 | no_support: |
| 854 | font_table_error: | 1043 | font_table_error: |
| 855 | /* restore graphics context. */ | 1044 | /* restore graphics context. */ |
| @@ -873,7 +1062,7 @@ otf_features (HDC context, char *table) | |||
| 873 | OTF_INT16_VAL (tbl, 6, &feature_table); | 1062 | OTF_INT16_VAL (tbl, 6, &feature_table); |
| 874 | OTF_INT16_VAL (tbl, scriptlist_table, &n_scripts); | 1063 | OTF_INT16_VAL (tbl, scriptlist_table, &n_scripts); |
| 875 | 1064 | ||
| 876 | for (i = 0; i < n_scripts; i++) | 1065 | for (i = n_scripts - 1; i >= 0; i--) |
| 877 | { | 1066 | { |
| 878 | char script[5], lang[5]; | 1067 | char script[5], lang[5]; |
| 879 | unsigned short script_table, lang_count, langsys_table, feature_count; | 1068 | unsigned short script_table, lang_count, langsys_table, feature_count; |
| @@ -898,7 +1087,7 @@ otf_features (HDC context, char *table) | |||
| 898 | langsys_tag = Qnil; | 1087 | langsys_tag = Qnil; |
| 899 | feature_list = Qnil; | 1088 | feature_list = Qnil; |
| 900 | OTF_INT16_VAL (tbl, langsys_table + 4, &feature_count); | 1089 | OTF_INT16_VAL (tbl, langsys_table + 4, &feature_count); |
| 901 | for (k = 0; k < feature_count; k++) | 1090 | for (k = feature_count - 1; k >= 0; k--) |
| 902 | { | 1091 | { |
| 903 | char feature[5]; | 1092 | char feature[5]; |
| 904 | unsigned short index; | 1093 | unsigned short index; |
| @@ -913,7 +1102,7 @@ otf_features (HDC context, char *table) | |||
| 913 | /* List of supported languages. */ | 1102 | /* List of supported languages. */ |
| 914 | OTF_INT16_VAL (tbl, script_table + 2, &lang_count); | 1103 | OTF_INT16_VAL (tbl, script_table + 2, &lang_count); |
| 915 | 1104 | ||
| 916 | for (j = 0; j < lang_count; j++) | 1105 | for (j = lang_count - 1; j >= 0; j--) |
| 917 | { | 1106 | { |
| 918 | record_offset = script_table + 4 + j * 6; | 1107 | record_offset = script_table + 4 + j * 6; |
| 919 | OTF_TAG_VAL (tbl, record_offset, lang); | 1108 | OTF_TAG_VAL (tbl, record_offset, lang); |
| @@ -925,7 +1114,7 @@ otf_features (HDC context, char *table) | |||
| 925 | langsys_tag = intern (lang); | 1114 | langsys_tag = intern (lang); |
| 926 | feature_list = Qnil; | 1115 | feature_list = Qnil; |
| 927 | OTF_INT16_VAL (tbl, langsys_table + 4, &feature_count); | 1116 | OTF_INT16_VAL (tbl, langsys_table + 4, &feature_count); |
| 928 | for (k = 0; k < feature_count; k++) | 1117 | for (k = feature_count - 1; k >= 0; k--) |
| 929 | { | 1118 | { |
| 930 | char feature[5]; | 1119 | char feature[5]; |
| 931 | unsigned short index; | 1120 | unsigned short index; |
| @@ -1003,4 +1192,17 @@ syms_of_w32uniscribe (void) | |||
| 1003 | uniscribe_available = 1; | 1192 | uniscribe_available = 1; |
| 1004 | 1193 | ||
| 1005 | register_font_driver (&uniscribe_font_driver, NULL); | 1194 | register_font_driver (&uniscribe_font_driver, NULL); |
| 1195 | |||
| 1196 | script_get_font_scripts_fn = (ScriptGetFontScriptTags_Proc) | ||
| 1197 | GetProcAddress (uniscribe, "ScriptGetFontScriptTags"); | ||
| 1198 | script_get_font_languages_fn = (ScriptGetFontLanguageTags_Proc) | ||
| 1199 | GetProcAddress (uniscribe, "ScriptGetFontLanguageTags"); | ||
| 1200 | script_get_font_features_fn = (ScriptGetFontFeatureTags_Proc) | ||
| 1201 | GetProcAddress (uniscribe, "ScriptGetFontFeatureTags"); | ||
| 1202 | if (script_get_font_scripts_fn | ||
| 1203 | && script_get_font_languages_fn | ||
| 1204 | && script_get_font_features_fn) | ||
| 1205 | uniscribe_new_apis = true; | ||
| 1206 | else | ||
| 1207 | uniscribe_new_apis = false; | ||
| 1006 | } | 1208 | } |