OLD | NEW |
1 /* | 1 /* |
2 * Copyright © 2009 Red Hat, Inc. | 2 * Copyright © 2009 Red Hat, Inc. |
3 * Copyright © 2011 Google, Inc. | 3 * Copyright © 2011 Google, Inc. |
4 * | 4 * |
5 * This is part of HarfBuzz, a text shaping library. | 5 * This is part of HarfBuzz, a text shaping library. |
6 * | 6 * |
7 * Permission is hereby granted, without written agreement and without | 7 * Permission is hereby granted, without written agreement and without |
8 * license or royalty fees, to use, copy, modify, and distribute this | 8 * license or royalty fees, to use, copy, modify, and distribute this |
9 * software and its documentation for any purpose, provided that the | 9 * software and its documentation for any purpose, provided that the |
10 * above copyright notice and the following two paragraphs appear in | 10 * above copyright notice and the following two paragraphs appear in |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
50 case HB_SCRIPT_YI: return HB_TAG('y','i',' ',' '); | 50 case HB_SCRIPT_YI: return HB_TAG('y','i',' ',' '); |
51 /* Unicode-5.0 additions */ | 51 /* Unicode-5.0 additions */ |
52 case HB_SCRIPT_NKO: return HB_TAG('n','k','o',' '); | 52 case HB_SCRIPT_NKO: return HB_TAG('n','k','o',' '); |
53 /* Unicode-5.1 additions */ | 53 /* Unicode-5.1 additions */ |
54 case HB_SCRIPT_VAI: return HB_TAG('v','a','i',' '); | 54 case HB_SCRIPT_VAI: return HB_TAG('v','a','i',' '); |
55 /* Unicode-5.2 additions */ | 55 /* Unicode-5.2 additions */ |
56 /* Unicode-6.0 additions */ | 56 /* Unicode-6.0 additions */ |
57 } | 57 } |
58 | 58 |
59 /* Else, just change first char to lowercase and return */ | 59 /* Else, just change first char to lowercase and return */ |
60 return ((hb_tag_t) script) | 0x20000000; | 60 return ((hb_tag_t) script) | 0x20000000u; |
61 } | 61 } |
62 | 62 |
63 static hb_script_t | 63 static hb_script_t |
64 hb_ot_old_tag_to_script (hb_tag_t tag) | 64 hb_ot_old_tag_to_script (hb_tag_t tag) |
65 { | 65 { |
66 if (unlikely (tag == HB_OT_TAG_DEFAULT_SCRIPT)) | 66 if (unlikely (tag == HB_OT_TAG_DEFAULT_SCRIPT)) |
67 return HB_SCRIPT_INVALID; | 67 return HB_SCRIPT_INVALID; |
68 | 68 |
69 /* This side of the conversion is fully algorithmic. */ | 69 /* This side of the conversion is fully algorithmic. */ |
70 | 70 |
71 /* Any spaces at the end of the tag are replaced by repeating the last | 71 /* Any spaces at the end of the tag are replaced by repeating the last |
72 * letter. Eg 'nko ' -> 'Nkoo' */ | 72 * letter. Eg 'nko ' -> 'Nkoo' */ |
73 if (unlikely ((tag & 0x0000FF00) == 0x00002000)) | 73 if (unlikely ((tag & 0x0000FF00u) == 0x00002000u)) |
74 tag |= (tag >> 8) & 0x0000FF00; /* Copy second letter to third */ | 74 tag |= (tag >> 8) & 0x0000FF00u; /* Copy second letter to third */ |
75 if (unlikely ((tag & 0x000000FF) == 0x00000020)) | 75 if (unlikely ((tag & 0x000000FFu) == 0x00000020u)) |
76 tag |= (tag >> 8) & 0x000000FF; /* Copy third letter to fourth */ | 76 tag |= (tag >> 8) & 0x000000FFu; /* Copy third letter to fourth */ |
77 | 77 |
78 /* Change first char to uppercase and return */ | 78 /* Change first char to uppercase and return */ |
79 return (hb_script_t) (tag & ~0x20000000); | 79 return (hb_script_t) (tag & ~0x20000000u); |
80 } | 80 } |
81 | 81 |
82 static hb_tag_t | 82 static hb_tag_t |
83 hb_ot_new_tag_from_script (hb_script_t script) | 83 hb_ot_new_tag_from_script (hb_script_t script) |
84 { | 84 { |
85 switch ((hb_tag_t) script) { | 85 switch ((hb_tag_t) script) { |
86 case HB_SCRIPT_BENGALI: return HB_TAG('b','n','g','2'); | 86 case HB_SCRIPT_BENGALI: return HB_TAG('b','n','g','2'); |
87 case HB_SCRIPT_DEVANAGARI: return HB_TAG('d','e','v','2'); | 87 case HB_SCRIPT_DEVANAGARI: return HB_TAG('d','e','v','2'); |
88 case HB_SCRIPT_GUJARATI: return HB_TAG('g','j','r','2'); | 88 case HB_SCRIPT_GUJARATI: return HB_TAG('g','j','r','2'); |
89 case HB_SCRIPT_GURMUKHI: return HB_TAG('g','u','r','2'); | 89 case HB_SCRIPT_GURMUKHI: return HB_TAG('g','u','r','2'); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
139 new_tag = hb_ot_new_tag_from_script (script); | 139 new_tag = hb_ot_new_tag_from_script (script); |
140 if (unlikely (new_tag != HB_OT_TAG_DEFAULT_SCRIPT)) { | 140 if (unlikely (new_tag != HB_OT_TAG_DEFAULT_SCRIPT)) { |
141 *script_tag_2 = *script_tag_1; | 141 *script_tag_2 = *script_tag_1; |
142 *script_tag_1 = new_tag; | 142 *script_tag_1 = new_tag; |
143 } | 143 } |
144 } | 144 } |
145 | 145 |
146 hb_script_t | 146 hb_script_t |
147 hb_ot_tag_to_script (hb_tag_t tag) | 147 hb_ot_tag_to_script (hb_tag_t tag) |
148 { | 148 { |
149 if (unlikely ((tag & 0x000000FF) == '2')) | 149 if (unlikely ((tag & 0x000000FFu) == '2')) |
150 return hb_ot_new_tag_to_script (tag); | 150 return hb_ot_new_tag_to_script (tag); |
151 | 151 |
152 return hb_ot_old_tag_to_script (tag); | 152 return hb_ot_old_tag_to_script (tag); |
153 } | 153 } |
154 | 154 |
155 | 155 |
156 /* hb_language_t */ | 156 /* hb_language_t */ |
157 | 157 |
158 typedef struct { | 158 typedef struct { |
159 char language[6]; | 159 char language[4]; |
160 hb_tag_t tag; | 160 hb_tag_t tag; |
161 } LangTag; | 161 } LangTag; |
162 | 162 |
163 /* | 163 /* |
164 * Complete list at: | 164 * Complete list at: |
165 * http://www.microsoft.com/typography/otspec/languagetags.htm | 165 * http://www.microsoft.com/typography/otspec/languagetags.htm |
166 * | 166 * |
167 * Generated by intersecting the OpenType language tag list from | 167 * Generated by intersecting the OpenType language tag list from |
168 * Draft OpenType 1.5 spec, with with the ISO 639-3 codes from | 168 * Draft OpenType 1.5 spec, with with the ISO 639-3 codes from |
169 * 2008-08-04, matching on name, and finally adjusted manually. | 169 * 2008-08-04, matching on name, and finally adjusted manually. |
(...skipping 586 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
756 /*{"??", HB_TAG('T','C','R',' ')},*/ /* TH-Cree */ | 756 /*{"??", HB_TAG('T','C','R',' ')},*/ /* TH-Cree */ |
757 /*{"tnz?/tog?/toi?", HB_TAG('T','N','G',' ')},*/ /* Tonga */ | 757 /*{"tnz?/tog?/toi?", HB_TAG('T','N','G',' ')},*/ /* Tonga */ |
758 /*{"enh?/yrk?", HB_TAG('T','N','E',' ')},*/ /* Tundra Nenets */ | 758 /*{"enh?/yrk?", HB_TAG('T','N','E',' ')},*/ /* Tundra Nenets */ |
759 /*{"??", HB_TAG('W','C','R',' ')},*/ /* West-Cree */ | 759 /*{"??", HB_TAG('W','C','R',' ')},*/ /* West-Cree */ |
760 /*{"cre?", HB_TAG('Y','C','R',' ')},*/ /* Y-Cree */ | 760 /*{"cre?", HB_TAG('Y','C','R',' ')},*/ /* Y-Cree */ |
761 /*{"??", HB_TAG('Y','I','C',' ')},*/ /* Yi Classic */ | 761 /*{"??", HB_TAG('Y','I','C',' ')},*/ /* Yi Classic */ |
762 /*{"ii?/Yiii?", HB_TAG('Y','I','M',' ')},*/ /* Yi Modern */ | 762 /*{"ii?/Yiii?", HB_TAG('Y','I','M',' ')},*/ /* Yi Modern */ |
763 /*{"??", HB_TAG('Z','H','P',' ')},*/ /* Chinese Phonetic */ | 763 /*{"??", HB_TAG('Z','H','P',' ')},*/ /* Chinese Phonetic */ |
764 }; | 764 }; |
765 | 765 |
766 static const LangTag ot_languages_zh[] = { | 766 typedef struct { |
| 767 char language[8]; |
| 768 hb_tag_t tag; |
| 769 } LangTagLong; |
| 770 static const LangTagLong ot_languages_zh[] = { |
767 {"zh-cn", HB_TAG('Z','H','S',' ')}, /* Chinese (China) */ | 771 {"zh-cn", HB_TAG('Z','H','S',' ')}, /* Chinese (China) */ |
768 {"zh-hk", HB_TAG('Z','H','H',' ')}, /* Chinese (Hong Kong) */ | 772 {"zh-hk", HB_TAG('Z','H','H',' ')}, /* Chinese (Hong Kong) */ |
769 {"zh-mo", HB_TAG('Z','H','T',' ')}, /* Chinese (Macao) */ | 773 {"zh-mo", HB_TAG('Z','H','T',' ')}, /* Chinese (Macao) */ |
770 {"zh-sg", HB_TAG('Z','H','S',' ')}, /* Chinese (Singapore) */ | 774 {"zh-sg", HB_TAG('Z','H','S',' ')}, /* Chinese (Singapore) */ |
771 {"zh-tw",» HB_TAG('Z','H','T',' ')} » /* Chinese (Taiwan) */ | 775 {"zh-tw",» HB_TAG('Z','H','T',' ')},» /* Chinese (Taiwan) */ |
| 776 {"zh-hans",» HB_TAG('Z','H','S',' ')},» /* Chinese (Simplified) */ |
| 777 {"zh-hant",» HB_TAG('Z','H','T',' ')},» /* Chinese (Traditional) */ |
772 }; | 778 }; |
773 | 779 |
774 static int | 780 static int |
775 lang_compare_first_component (const char *a, | 781 lang_compare_first_component (const char *a, |
776 const char *b) | 782 const char *b) |
777 { | 783 { |
778 unsigned int da, db; | 784 unsigned int da, db; |
779 const char *p; | 785 const char *p; |
780 | 786 |
781 p = strchr (a, '-'); | 787 p = strchr (a, '-'); |
(...skipping 11 matching lines...) Expand all Loading... |
793 unsigned int len = strlen (spec); | 799 unsigned int len = strlen (spec); |
794 | 800 |
795 return strncmp (lang_str, spec, len) == 0 && | 801 return strncmp (lang_str, spec, len) == 0 && |
796 (lang_str[len] == '\0' || lang_str[len] == '-'); | 802 (lang_str[len] == '\0' || lang_str[len] == '-'); |
797 } | 803 } |
798 | 804 |
799 hb_tag_t | 805 hb_tag_t |
800 hb_ot_tag_from_language (hb_language_t language) | 806 hb_ot_tag_from_language (hb_language_t language) |
801 { | 807 { |
802 const char *lang_str, *s; | 808 const char *lang_str, *s; |
803 const LangTag *lang_tag; | |
804 | 809 |
805 if (language == HB_LANGUAGE_INVALID) | 810 if (language == HB_LANGUAGE_INVALID) |
806 return HB_OT_TAG_DEFAULT_LANGUAGE; | 811 return HB_OT_TAG_DEFAULT_LANGUAGE; |
807 | 812 |
808 lang_str = hb_language_to_string (language); | 813 lang_str = hb_language_to_string (language); |
809 | 814 |
810 s = strstr (lang_str, "x-hbot"); | 815 s = strstr (lang_str, "x-hbot"); |
811 if (s) { | 816 if (s) { |
812 char tag[4]; | 817 char tag[4]; |
813 int i; | 818 int i; |
814 s += 6; | 819 s += 6; |
815 for (i = 0; i < 4 && ISALPHA (s[i]); i++) | 820 for (i = 0; i < 4 && ISALPHA (s[i]); i++) |
816 tag[i] = TOUPPER (s[i]); | 821 tag[i] = TOUPPER (s[i]); |
817 if (i) { | 822 if (i) { |
818 for (; i < 4; i++) | 823 for (; i < 4; i++) |
819 tag[i] = ' '; | 824 tag[i] = ' '; |
820 return HB_TAG_CHAR4 (tag); | 825 return HB_TAG_CHAR4 (tag); |
821 } | 826 } |
822 } | 827 } |
823 | 828 |
824 /* Find a language matching in the first component */ | 829 /* Find a language matching in the first component */ |
825 lang_tag = (LangTag *) bsearch (lang_str, ot_languages, | 830 { |
826 » » » » ARRAY_LENGTH (ot_languages), sizeof (LangTag), | 831 const LangTag *lang_tag; |
827 » » » » (hb_compare_func_t) lang_compare_first_compone
nt); | 832 lang_tag = (LangTag *) bsearch (lang_str, ot_languages, |
828 if (lang_tag) | 833 » » » » ARRAY_LENGTH (ot_languages), sizeof (LangTag
), |
829 return lang_tag->tag; | 834 » » » » (hb_compare_func_t) lang_compare_first_compo
nent); |
| 835 if (lang_tag) |
| 836 return lang_tag->tag; |
| 837 } |
830 | 838 |
831 /* Otherwise, check the Chinese ones */ | 839 /* Otherwise, check the Chinese ones */ |
832 if (0 == lang_compare_first_component (lang_str, "zh")) | 840 if (0 == lang_compare_first_component (lang_str, "zh")) |
833 { | 841 { |
834 unsigned int i; | 842 unsigned int i; |
835 | 843 |
836 for (i = 0; i < ARRAY_LENGTH (ot_languages_zh); i++) | 844 for (i = 0; i < ARRAY_LENGTH (ot_languages_zh); i++) |
837 { | 845 { |
| 846 const LangTagLong *lang_tag; |
838 lang_tag = &ot_languages_zh[i]; | 847 lang_tag = &ot_languages_zh[i]; |
839 if (lang_matches (lang_tag->language, lang_str)) | 848 if (lang_matches (lang_str, lang_tag->language)) |
840 return lang_tag->tag; | 849 return lang_tag->tag; |
841 } | 850 } |
842 | 851 |
843 /* Otherwise just return 'ZHS ' */ | 852 /* Otherwise just return 'ZHS ' */ |
844 return HB_TAG('Z','H','S',' '); | 853 return HB_TAG('Z','H','S',' '); |
845 } | 854 } |
846 | 855 |
847 s = strchr (lang_str, '-'); | 856 s = strchr (lang_str, '-'); |
848 if (!s) | 857 if (!s) |
849 s = lang_str + strlen (lang_str); | 858 s = lang_str + strlen (lang_str); |
850 if (s - lang_str == 3) { | 859 if (s - lang_str == 3) { |
851 /* Assume it's ISO-639-3 and upper-case and use it. */ | 860 /* Assume it's ISO-639-3 and upper-case and use it. */ |
852 return hb_tag_from_string (lang_str, s - lang_str) & ~0x20202000; | 861 return hb_tag_from_string (lang_str, s - lang_str) & ~0x20202000u; |
853 } | 862 } |
854 | 863 |
855 return HB_OT_TAG_DEFAULT_LANGUAGE; | 864 return HB_OT_TAG_DEFAULT_LANGUAGE; |
856 } | 865 } |
857 | 866 |
858 hb_language_t | 867 hb_language_t |
859 hb_ot_tag_to_language (hb_tag_t tag) | 868 hb_ot_tag_to_language (hb_tag_t tag) |
860 { | 869 { |
861 unsigned int i; | 870 unsigned int i; |
862 | 871 |
863 if (tag == HB_OT_TAG_DEFAULT_LANGUAGE) | 872 if (tag == HB_OT_TAG_DEFAULT_LANGUAGE) |
864 return NULL; | 873 return NULL; |
865 | 874 |
866 for (i = 0; i < ARRAY_LENGTH (ot_languages); i++) | 875 for (i = 0; i < ARRAY_LENGTH (ot_languages); i++) |
867 if (ot_languages[i].tag == tag) | 876 if (ot_languages[i].tag == tag) |
868 return hb_language_from_string (ot_languages[i].language, -1); | 877 return hb_language_from_string (ot_languages[i].language, -1); |
869 | 878 |
870 /* If tag starts with ZH, it's Chinese */ | 879 /* If tag starts with ZH, it's Chinese */ |
871 if ((tag & 0xFFFF0000) == 0x5A480000) { | 880 if ((tag & 0xFFFF0000u) == 0x5A480000u) { |
872 switch (tag) { | 881 switch (tag) { |
873 case HB_TAG('Z','H','H',' '): return hb_language_from_string ("zh-hk", -1)
; /* Hong Kong */ | 882 case HB_TAG('Z','H','H',' '): return hb_language_from_string ("zh-hk", -1)
; /* Hong Kong */ |
874 default: { | 883 case HB_TAG('Z','H','S',' '): return hb_language_from_string ("zh-Hans", -
1); /* Simplified */ |
875 /* Encode the tag... */ | 884 case HB_TAG('Z','H','T',' '): return hb_language_from_string ("zh-Hant", -
1); /* Traditional */ |
876 » unsigned char buf[14] = "zh-x-hbot"; | 885 default: break; /* Fall through */ |
877 » buf[9] = tag >> 24; | |
878 » buf[10] = (tag >> 16) & 0xFF; | |
879 » buf[11] = (tag >> 8) & 0xFF; | |
880 » buf[12] = tag & 0xFF; | |
881 » if (buf[12] == 0x20) | |
882 » buf[12] = '\0'; | |
883 » buf[13] = '\0'; | |
884 » return hb_language_from_string ((char *) buf, -1); | |
885 } | |
886 } | 886 } |
887 } | 887 } |
888 | 888 |
889 /* Else return a custom language in the form of "x-hbotABCD" */ | 889 /* Else return a custom language in the form of "x-hbotABCD" */ |
890 { | 890 { |
891 unsigned char buf[11] = "x-hbot"; | 891 unsigned char buf[11] = "x-hbot"; |
892 buf[6] = tag >> 24; | 892 buf[6] = tag >> 24; |
893 buf[7] = (tag >> 16) & 0xFF; | 893 buf[7] = (tag >> 16) & 0xFF; |
894 buf[8] = (tag >> 8) & 0xFF; | 894 buf[8] = (tag >> 8) & 0xFF; |
895 buf[9] = tag & 0xFF; | 895 buf[9] = tag & 0xFF; |
896 if (buf[9] == 0x20) | 896 if (buf[9] == 0x20) |
897 buf[9] = '\0'; | 897 buf[9] = '\0'; |
898 buf[10] = '\0'; | 898 buf[10] = '\0'; |
899 return hb_language_from_string ((char *) buf, -1); | 899 return hb_language_from_string ((char *) buf, -1); |
900 } | 900 } |
901 } | 901 } |
902 | 902 |
903 | 903 |
OLD | NEW |