blob: 9670b6f91eb710f71fa160554784b9f1f5efec70 [file] [log] [blame]
bungeman@google.com07a69f82013-04-02 14:12:38 +00001/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkOTTable_name.h"
9
10#include "SkEndian.h"
11#include "SkString.h"
12#include "SkTSearch.h"
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +000013#include "SkTemplates.h"
bungeman@google.com07a69f82013-04-02 14:12:38 +000014#include "SkUtils.h"
15
16static SkUnichar SkUTF16BE_NextUnichar(const uint16_t** srcPtr) {
17 SkASSERT(srcPtr && *srcPtr);
18
19 const uint16_t* src = *srcPtr;
20 SkUnichar c = SkEndian_SwapBE16(*src++);
21
22 SkASSERT(!SkUTF16_IsLowSurrogate(c));
23 if (SkUTF16_IsHighSurrogate(c)) {
24 unsigned c2 = SkEndian_SwapBE16(*src++);
25 SkASSERT(SkUTF16_IsLowSurrogate(c2));
26
27 c = (c << 10) + c2 + (0x10000 - (0xD800 << 10) - 0xDC00);
28 }
29 *srcPtr = src;
30 return c;
31}
32
33static void SkStringFromUTF16BE(const uint16_t* utf16be, size_t length, SkString& utf8) {
halcanary96fcdcc2015-08-27 07:41:13 -070034 SkASSERT(utf16be != nullptr);
bungeman@google.com07a69f82013-04-02 14:12:38 +000035
36 utf8.reset();
37 size_t numberOf16BitValues = length / 2;
38 const uint16_t* end = utf16be + numberOf16BitValues;
39 while (utf16be < end) {
40 utf8.appendUnichar(SkUTF16BE_NextUnichar(&utf16be));
41 }
42}
43
44/** UnicodeFromMacRoman[macRomanPoint - 0x80] -> unicodeCodePoint.
45 * Derived from http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/ROMAN.TXT .
46 * In MacRoman the first 128 code points match ASCII code points.
47 * This maps the second 128 MacRoman code points to unicode code points.
48 */
Bruce Dawson34194692016-12-29 14:05:39 -080049static const uint16_t UnicodeFromMacRoman[0x80] = {
bungeman@google.com07a69f82013-04-02 14:12:38 +000050 0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1,
51 0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8,
52 0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3,
53 0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC,
54 0x2020, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF,
55 0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x00C6, 0x00D8,
56 0x221E, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211,
57 0x220F, 0x03C0, 0x222B, 0x00AA, 0x00BA, 0x03A9, 0x00E6, 0x00F8,
58 0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB,
59 0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153,
60 0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA,
61 0x00FF, 0x0178, 0x2044, 0x20AC, 0x2039, 0x203A, 0xFB01, 0xFB02,
62 0x2021, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x00CA, 0x00C1,
63 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4,
64 0xF8FF, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC,
65 0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7,
66};
67
68static void SkStringFromMacRoman(const uint8_t* macRoman, size_t length, SkString& utf8) {
69 utf8.reset();
70 for (size_t i = 0; i < length; ++i) {
mtklein@google.com1e4c4fe2013-11-04 21:22:45 +000071 utf8.appendUnichar(macRoman[i] < 0x80 ? macRoman[i]
72 : UnicodeFromMacRoman[macRoman[i] - 0x80]);
bungeman@google.com07a69f82013-04-02 14:12:38 +000073 }
74}
75
Bruce Dawson34194692016-12-29 14:05:39 -080076static const struct BCP47FromLanguageId {
bungeman@google.com07a69f82013-04-02 14:12:38 +000077 uint16_t languageID;
78 const char* bcp47;
79}
80/** The Mac and Windows values do not conflict, so this is currently one single table. */
81BCP47FromLanguageID[] = {
82 /** A mapping from Mac Language Designators to BCP 47 codes.
83 * The following list was constructed more or less manually.
84 * Apple now uses BCP 47 (post OSX10.4), so there will be no new entries.
85 */
86 {0, "en"}, //English
87 {1, "fr"}, //French
88 {2, "de"}, //German
89 {3, "it"}, //Italian
90 {4, "nl"}, //Dutch
91 {5, "sv"}, //Swedish
92 {6, "es"}, //Spanish
93 {7, "da"}, //Danish
94 {8, "pt"}, //Portuguese
95 {9, "nb"}, //Norwegian
96 {10, "he"}, //Hebrew
97 {11, "ja"}, //Japanese
98 {12, "ar"}, //Arabic
99 {13, "fi"}, //Finnish
100 {14, "el"}, //Greek
101 {15, "is"}, //Icelandic
102 {16, "mt"}, //Maltese
103 {17, "tr"}, //Turkish
104 {18, "hr"}, //Croatian
105 {19, "zh-Hant"}, //Chinese (Traditional)
106 {20, "ur"}, //Urdu
107 {21, "hi"}, //Hindi
108 {22, "th"}, //Thai
109 {23, "ko"}, //Korean
110 {24, "lt"}, //Lithuanian
111 {25, "pl"}, //Polish
112 {26, "hu"}, //Hungarian
113 {27, "et"}, //Estonian
114 {28, "lv"}, //Latvian
115 {29, "se"}, //Sami
116 {30, "fo"}, //Faroese
117 {31, "fa"}, //Farsi (Persian)
118 {32, "ru"}, //Russian
119 {33, "zh-Hans"}, //Chinese (Simplified)
120 {34, "nl"}, //Dutch
121 {35, "ga"}, //Irish(Gaelic)
122 {36, "sq"}, //Albanian
123 {37, "ro"}, //Romanian
124 {38, "cs"}, //Czech
125 {39, "sk"}, //Slovak
126 {40, "sl"}, //Slovenian
127 {41, "yi"}, //Yiddish
128 {42, "sr"}, //Serbian
129 {43, "mk"}, //Macedonian
130 {44, "bg"}, //Bulgarian
131 {45, "uk"}, //Ukrainian
132 {46, "be"}, //Byelorussian
133 {47, "uz"}, //Uzbek
134 {48, "kk"}, //Kazakh
135 {49, "az-Cyrl"}, //Azerbaijani (Cyrillic)
136 {50, "az-Arab"}, //Azerbaijani (Arabic)
137 {51, "hy"}, //Armenian
138 {52, "ka"}, //Georgian
139 {53, "mo"}, //Moldavian
140 {54, "ky"}, //Kirghiz
141 {55, "tg"}, //Tajiki
142 {56, "tk"}, //Turkmen
143 {57, "mn-Mong"}, //Mongolian (Traditional)
144 {58, "mn-Cyrl"}, //Mongolian (Cyrillic)
145 {59, "ps"}, //Pashto
146 {60, "ku"}, //Kurdish
147 {61, "ks"}, //Kashmiri
148 {62, "sd"}, //Sindhi
149 {63, "bo"}, //Tibetan
150 {64, "ne"}, //Nepali
151 {65, "sa"}, //Sanskrit
152 {66, "mr"}, //Marathi
153 {67, "bn"}, //Bengali
154 {68, "as"}, //Assamese
155 {69, "gu"}, //Gujarati
156 {70, "pa"}, //Punjabi
157 {71, "or"}, //Oriya
158 {72, "ml"}, //Malayalam
159 {73, "kn"}, //Kannada
160 {74, "ta"}, //Tamil
161 {75, "te"}, //Telugu
162 {76, "si"}, //Sinhalese
163 {77, "my"}, //Burmese
164 {78, "km"}, //Khmer
165 {79, "lo"}, //Lao
166 {80, "vi"}, //Vietnamese
167 {81, "id"}, //Indonesian
168 {82, "tl"}, //Tagalog
169 {83, "ms-Latn"}, //Malay (Roman)
170 {84, "ms-Arab"}, //Malay (Arabic)
171 {85, "am"}, //Amharic
172 {86, "ti"}, //Tigrinya
173 {87, "om"}, //Oromo
174 {88, "so"}, //Somali
175 {89, "sw"}, //Swahili
176 {90, "rw"}, //Kinyarwanda/Ruanda
177 {91, "rn"}, //Rundi
178 {92, "ny"}, //Nyanja/Chewa
179 {93, "mg"}, //Malagasy
180 {94, "eo"}, //Esperanto
181 {128, "cy"}, //Welsh
182 {129, "eu"}, //Basque
183 {130, "ca"}, //Catalan
184 {131, "la"}, //Latin
185 {132, "qu"}, //Quechua
186 {133, "gn"}, //Guarani
187 {134, "ay"}, //Aymara
188 {135, "tt"}, //Tatar
189 {136, "ug"}, //Uighur
190 {137, "dz"}, //Dzongkha
191 {138, "jv-Latn"}, //Javanese (Roman)
192 {139, "su-Latn"}, //Sundanese (Roman)
193 {140, "gl"}, //Galician
194 {141, "af"}, //Afrikaans
195 {142, "br"}, //Breton
196 {143, "iu"}, //Inuktitut
197 {144, "gd"}, //Scottish (Gaelic)
198 {145, "gv"}, //Manx (Gaelic)
199 {146, "ga"}, //Irish (Gaelic with Lenition)
200 {147, "to"}, //Tongan
201 {148, "el"}, //Greek (Polytonic) Note: ISO 15924 does not have an equivalent script name.
202 {149, "kl"}, //Greenlandic
203 {150, "az-Latn"}, //Azerbaijani (Roman)
204 {151, "nn"}, //Nynorsk
205
206 /** A mapping from Windows LCID to BCP 47 codes.
207 * This list is the sorted, curated output of tools/win_lcid.cpp.
208 * Note that these are sorted by value for quick binary lookup, and not logically by lsb.
209 * The 'bare' language ids (e.g. 0x0001 for Arabic) are ommitted
210 * as they do not appear as valid language ids in the OpenType specification.
211 */
212 { 0x0401, "ar-SA" }, //Arabic
213 { 0x0402, "bg-BG" }, //Bulgarian
214 { 0x0403, "ca-ES" }, //Catalan
215 { 0x0404, "zh-TW" }, //Chinese (Traditional)
216 { 0x0405, "cs-CZ" }, //Czech
217 { 0x0406, "da-DK" }, //Danish
218 { 0x0407, "de-DE" }, //German
219 { 0x0408, "el-GR" }, //Greek
220 { 0x0409, "en-US" }, //English
221 { 0x040a, "es-ES_tradnl" }, //Spanish
222 { 0x040b, "fi-FI" }, //Finnish
223 { 0x040c, "fr-FR" }, //French
224 { 0x040d, "he-IL" }, //Hebrew
225 { 0x040d, "he" }, //Hebrew
226 { 0x040e, "hu-HU" }, //Hungarian
227 { 0x040e, "hu" }, //Hungarian
228 { 0x040f, "is-IS" }, //Icelandic
229 { 0x0410, "it-IT" }, //Italian
230 { 0x0411, "ja-JP" }, //Japanese
231 { 0x0412, "ko-KR" }, //Korean
232 { 0x0413, "nl-NL" }, //Dutch
Ben Wagner4bcb4c72016-07-19 15:55:16 -0400233 { 0x0414, "nb-NO" }, //Norwegian (Bokmål)
bungeman@google.com07a69f82013-04-02 14:12:38 +0000234 { 0x0415, "pl-PL" }, //Polish
235 { 0x0416, "pt-BR" }, //Portuguese
236 { 0x0417, "rm-CH" }, //Romansh
237 { 0x0418, "ro-RO" }, //Romanian
238 { 0x0419, "ru-RU" }, //Russian
239 { 0x041a, "hr-HR" }, //Croatian
240 { 0x041b, "sk-SK" }, //Slovak
241 { 0x041c, "sq-AL" }, //Albanian
242 { 0x041d, "sv-SE" }, //Swedish
243 { 0x041e, "th-TH" }, //Thai
244 { 0x041f, "tr-TR" }, //Turkish
245 { 0x0420, "ur-PK" }, //Urdu
246 { 0x0421, "id-ID" }, //Indonesian
247 { 0x0422, "uk-UA" }, //Ukrainian
248 { 0x0423, "be-BY" }, //Belarusian
249 { 0x0424, "sl-SI" }, //Slovenian
250 { 0x0425, "et-EE" }, //Estonian
251 { 0x0426, "lv-LV" }, //Latvian
252 { 0x0427, "lt-LT" }, //Lithuanian
253 { 0x0428, "tg-Cyrl-TJ" }, //Tajik (Cyrillic)
254 { 0x0429, "fa-IR" }, //Persian
255 { 0x042a, "vi-VN" }, //Vietnamese
256 { 0x042b, "hy-AM" }, //Armenian
257 { 0x042c, "az-Latn-AZ" }, //Azeri (Latin)
258 { 0x042d, "eu-ES" }, //Basque
259 { 0x042e, "hsb-DE" }, //Upper Sorbian
260 { 0x042f, "mk-MK" }, //Macedonian (FYROM)
261 { 0x0432, "tn-ZA" }, //Setswana
262 { 0x0434, "xh-ZA" }, //isiXhosa
263 { 0x0435, "zu-ZA" }, //isiZulu
264 { 0x0436, "af-ZA" }, //Afrikaans
265 { 0x0437, "ka-GE" }, //Georgian
266 { 0x0438, "fo-FO" }, //Faroese
267 { 0x0439, "hi-IN" }, //Hindi
268 { 0x043a, "mt-MT" }, //Maltese
269 { 0x043b, "se-NO" }, //Sami (Northern)
270 { 0x043e, "ms-MY" }, //Malay
271 { 0x043f, "kk-KZ" }, //Kazakh
272 { 0x0440, "ky-KG" }, //Kyrgyz
273 { 0x0441, "sw-KE" }, //Kiswahili
274 { 0x0442, "tk-TM" }, //Turkmen
275 { 0x0443, "uz-Latn-UZ" }, //Uzbek (Latin)
276 { 0x0443, "uz" }, //Uzbek
277 { 0x0444, "tt-RU" }, //Tatar
278 { 0x0445, "bn-IN" }, //Bengali
279 { 0x0446, "pa-IN" }, //Punjabi
280 { 0x0447, "gu-IN" }, //Gujarati
281 { 0x0448, "or-IN" }, //Oriya
282 { 0x0449, "ta-IN" }, //Tamil
283 { 0x044a, "te-IN" }, //Telugu
284 { 0x044b, "kn-IN" }, //Kannada
285 { 0x044c, "ml-IN" }, //Malayalam
286 { 0x044d, "as-IN" }, //Assamese
287 { 0x044e, "mr-IN" }, //Marathi
288 { 0x044f, "sa-IN" }, //Sanskrit
289 { 0x0450, "mn-Cyrl" }, //Mongolian (Cyrillic)
290 { 0x0451, "bo-CN" }, //Tibetan
291 { 0x0452, "cy-GB" }, //Welsh
292 { 0x0453, "km-KH" }, //Khmer
293 { 0x0454, "lo-LA" }, //Lao
294 { 0x0456, "gl-ES" }, //Galician
295 { 0x0457, "kok-IN" }, //Konkani
296 { 0x045a, "syr-SY" }, //Syriac
297 { 0x045b, "si-LK" }, //Sinhala
298 { 0x045d, "iu-Cans-CA" }, //Inuktitut (Syllabics)
299 { 0x045e, "am-ET" }, //Amharic
300 { 0x0461, "ne-NP" }, //Nepali
301 { 0x0462, "fy-NL" }, //Frisian
302 { 0x0463, "ps-AF" }, //Pashto
303 { 0x0464, "fil-PH" }, //Filipino
304 { 0x0465, "dv-MV" }, //Divehi
305 { 0x0468, "ha-Latn-NG" }, //Hausa (Latin)
306 { 0x046a, "yo-NG" }, //Yoruba
307 { 0x046b, "quz-BO" }, //Quechua
308 { 0x046c, "nso-ZA" }, //Sesotho sa Leboa
309 { 0x046d, "ba-RU" }, //Bashkir
310 { 0x046e, "lb-LU" }, //Luxembourgish
311 { 0x046f, "kl-GL" }, //Greenlandic
312 { 0x0470, "ig-NG" }, //Igbo
313 { 0x0478, "ii-CN" }, //Yi
314 { 0x047a, "arn-CL" }, //Mapudungun
315 { 0x047c, "moh-CA" }, //Mohawk
316 { 0x047e, "br-FR" }, //Breton
317 { 0x0480, "ug-CN" }, //Uyghur
318 { 0x0481, "mi-NZ" }, //Maori
319 { 0x0482, "oc-FR" }, //Occitan
320 { 0x0483, "co-FR" }, //Corsican
321 { 0x0484, "gsw-FR" }, //Alsatian
322 { 0x0485, "sah-RU" }, //Yakut
323 { 0x0486, "qut-GT" }, //K'iche
324 { 0x0487, "rw-RW" }, //Kinyarwanda
325 { 0x0488, "wo-SN" }, //Wolof
326 { 0x048c, "prs-AF" }, //Dari
327 { 0x0491, "gd-GB" }, //Scottish Gaelic
328 { 0x0801, "ar-IQ" }, //Arabic
329 { 0x0804, "zh-Hans" }, //Chinese (Simplified)
330 { 0x0807, "de-CH" }, //German
331 { 0x0809, "en-GB" }, //English
332 { 0x080a, "es-MX" }, //Spanish
333 { 0x080c, "fr-BE" }, //French
334 { 0x0810, "it-CH" }, //Italian
335 { 0x0813, "nl-BE" }, //Dutch
336 { 0x0814, "nn-NO" }, //Norwegian (Nynorsk)
337 { 0x0816, "pt-PT" }, //Portuguese
338 { 0x081a, "sr-Latn-CS" }, //Serbian (Latin)
339 { 0x081d, "sv-FI" }, //Swedish
340 { 0x082c, "az-Cyrl-AZ" }, //Azeri (Cyrillic)
341 { 0x082e, "dsb-DE" }, //Lower Sorbian
342 { 0x082e, "dsb" }, //Lower Sorbian
343 { 0x083b, "se-SE" }, //Sami (Northern)
344 { 0x083c, "ga-IE" }, //Irish
345 { 0x083e, "ms-BN" }, //Malay
346 { 0x0843, "uz-Cyrl-UZ" }, //Uzbek (Cyrillic)
347 { 0x0845, "bn-BD" }, //Bengali
348 { 0x0850, "mn-Mong-CN" }, //Mongolian (Traditional Mongolian)
349 { 0x085d, "iu-Latn-CA" }, //Inuktitut (Latin)
350 { 0x085f, "tzm-Latn-DZ" }, //Tamazight (Latin)
351 { 0x086b, "quz-EC" }, //Quechua
352 { 0x0c01, "ar-EG" }, //Arabic
353 { 0x0c04, "zh-Hant" }, //Chinese (Traditional)
354 { 0x0c07, "de-AT" }, //German
355 { 0x0c09, "en-AU" }, //English
356 { 0x0c0a, "es-ES" }, //Spanish
357 { 0x0c0c, "fr-CA" }, //French
358 { 0x0c1a, "sr-Cyrl-CS" }, //Serbian (Cyrillic)
359 { 0x0c3b, "se-FI" }, //Sami (Northern)
360 { 0x0c6b, "quz-PE" }, //Quechua
361 { 0x1001, "ar-LY" }, //Arabic
362 { 0x1004, "zh-SG" }, //Chinese (Simplified)
363 { 0x1007, "de-LU" }, //German
364 { 0x1009, "en-CA" }, //English
365 { 0x100a, "es-GT" }, //Spanish
366 { 0x100c, "fr-CH" }, //French
367 { 0x101a, "hr-BA" }, //Croatian (Latin)
368 { 0x103b, "smj-NO" }, //Sami (Lule)
369 { 0x1401, "ar-DZ" }, //Arabic
370 { 0x1404, "zh-MO" }, //Chinese (Traditional)
371 { 0x1407, "de-LI" }, //German
372 { 0x1409, "en-NZ" }, //English
373 { 0x140a, "es-CR" }, //Spanish
374 { 0x140c, "fr-LU" }, //French
375 { 0x141a, "bs-Latn-BA" }, //Bosnian (Latin)
376 { 0x141a, "bs" }, //Bosnian
377 { 0x143b, "smj-SE" }, //Sami (Lule)
378 { 0x143b, "smj" }, //Sami (Lule)
379 { 0x1801, "ar-MA" }, //Arabic
380 { 0x1809, "en-IE" }, //English
381 { 0x180a, "es-PA" }, //Spanish
382 { 0x180c, "fr-MC" }, //French
383 { 0x181a, "sr-Latn-BA" }, //Serbian (Latin)
384 { 0x183b, "sma-NO" }, //Sami (Southern)
385 { 0x1c01, "ar-TN" }, //Arabic
386 { 0x1c09, "en-ZA" }, //English
387 { 0x1c0a, "es-DO" }, //Spanish
388 { 0x1c1a, "sr-Cyrl-BA" }, //Serbian (Cyrillic)
389 { 0x1c3b, "sma-SE" }, //Sami (Southern)
390 { 0x1c3b, "sma" }, //Sami (Southern)
391 { 0x2001, "ar-OM" }, //Arabic
392 { 0x2009, "en-JM" }, //English
393 { 0x200a, "es-VE" }, //Spanish
394 { 0x201a, "bs-Cyrl-BA" }, //Bosnian (Cyrillic)
395 { 0x201a, "bs-Cyrl" }, //Bosnian (Cyrillic)
396 { 0x203b, "sms-FI" }, //Sami (Skolt)
397 { 0x203b, "sms" }, //Sami (Skolt)
398 { 0x2401, "ar-YE" }, //Arabic
399 { 0x2409, "en-029" }, //English
400 { 0x240a, "es-CO" }, //Spanish
401 { 0x241a, "sr-Latn-RS" }, //Serbian (Latin)
402 { 0x243b, "smn-FI" }, //Sami (Inari)
403 { 0x2801, "ar-SY" }, //Arabic
404 { 0x2809, "en-BZ" }, //English
405 { 0x280a, "es-PE" }, //Spanish
406 { 0x281a, "sr-Cyrl-RS" }, //Serbian (Cyrillic)
407 { 0x2c01, "ar-JO" }, //Arabic
408 { 0x2c09, "en-TT" }, //English
409 { 0x2c0a, "es-AR" }, //Spanish
410 { 0x2c1a, "sr-Latn-ME" }, //Serbian (Latin)
411 { 0x3001, "ar-LB" }, //Arabic
412 { 0x3009, "en-ZW" }, //English
413 { 0x300a, "es-EC" }, //Spanish
414 { 0x301a, "sr-Cyrl-ME" }, //Serbian (Cyrillic)
415 { 0x3401, "ar-KW" }, //Arabic
416 { 0x3409, "en-PH" }, //English
417 { 0x340a, "es-CL" }, //Spanish
418 { 0x3801, "ar-AE" }, //Arabic
419 { 0x380a, "es-UY" }, //Spanish
420 { 0x3c01, "ar-BH" }, //Arabic
421 { 0x3c0a, "es-PY" }, //Spanish
422 { 0x4001, "ar-QA" }, //Arabic
423 { 0x4009, "en-IN" }, //English
424 { 0x400a, "es-BO" }, //Spanish
425 { 0x4409, "en-MY" }, //English
426 { 0x440a, "es-SV" }, //Spanish
427 { 0x4809, "en-SG" }, //English
428 { 0x480a, "es-HN" }, //Spanish
429 { 0x4c0a, "es-NI" }, //Spanish
430 { 0x500a, "es-PR" }, //Spanish
431 { 0x540a, "es-US" }, //Spanish
432};
433
bungeman@google.com5df74342013-04-02 14:40:44 +0000434namespace {
bsalomon@google.com20f7f172013-05-17 19:05:03 +0000435bool BCP47FromLanguageIdLess(const BCP47FromLanguageId& a, const BCP47FromLanguageId& b) {
436 return a.languageID < b.languageID;
bungeman@google.com07a69f82013-04-02 14:12:38 +0000437}
bungeman@google.com5df74342013-04-02 14:40:44 +0000438}
bungeman@google.com07a69f82013-04-02 14:12:38 +0000439
bungeman@google.com07a69f82013-04-02 14:12:38 +0000440bool SkOTTableName::Iterator::next(SkOTTableName::Iterator::Record& record) {
441 const size_t nameRecordsCount = SkEndian_SwapBE16(fName.count);
442 const SkOTTableName::Record* nameRecords = SkTAfter<const SkOTTableName::Record>(&fName);
443 const SkOTTableName::Record* nameRecord;
444
445 // Find the next record which matches the requested type.
446 do {
447 if (fIndex >= nameRecordsCount) {
448 return false;
449 }
450
451 nameRecord = &nameRecords[fIndex];
452 ++fIndex;
453 } while (fType != -1 && nameRecord->nameID.fontSpecific != fType);
454
bungeman@google.coma9802692013-08-07 02:45:25 +0000455 record.type = nameRecord->nameID.fontSpecific;
456
bungeman@google.com07a69f82013-04-02 14:12:38 +0000457 const uint16_t stringTableOffset = SkEndian_SwapBE16(fName.stringOffset);
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000458 const char* stringTable = SkTAddOffset<const char>(&fName, stringTableOffset);
bungeman@google.com07a69f82013-04-02 14:12:38 +0000459
460 // Decode the name into UTF-8.
461 const uint16_t nameOffset = SkEndian_SwapBE16(nameRecord->offset);
462 const uint16_t nameLength = SkEndian_SwapBE16(nameRecord->length);
commit-bot@chromium.orgb5e34e22013-05-07 15:28:15 +0000463 const char* nameString = SkTAddOffset<const char>(stringTable, nameOffset);
bungeman@google.com07a69f82013-04-02 14:12:38 +0000464 switch (nameRecord->platformID.value) {
465 case SkOTTableName::Record::PlatformID::Windows:
bungeman@google.coma9802692013-08-07 02:45:25 +0000466 if (SkOTTableName::Record::EncodingID::Windows::UnicodeBMPUCS2
467 != nameRecord->encodingID.windows.value
468 && SkOTTableName::Record::EncodingID::Windows::UnicodeUCS4
469 != nameRecord->encodingID.windows.value
470 && SkOTTableName::Record::EncodingID::Windows::Symbol
471 != nameRecord->encodingID.windows.value)
472 {
473 record.name.reset();
474 break;
475 }
bungeman@google.com07a69f82013-04-02 14:12:38 +0000476 case SkOTTableName::Record::PlatformID::Unicode:
477 case SkOTTableName::Record::PlatformID::ISO:
478 SkStringFromUTF16BE((const uint16_t*)nameString, nameLength, record.name);
479 break;
480
481 case SkOTTableName::Record::PlatformID::Macintosh:
bungeman@google.coma9802692013-08-07 02:45:25 +0000482 // TODO: need better decoding, especially on Mac.
483 if (SkOTTableName::Record::EncodingID::Macintosh::Roman
484 != nameRecord->encodingID.macintosh.value)
485 {
486 record.name.reset();
487 break;
488 }
bungeman@google.com07a69f82013-04-02 14:12:38 +0000489 SkStringFromMacRoman((const uint8_t*)nameString, nameLength, record.name);
490 break;
491
492 case SkOTTableName::Record::PlatformID::Custom:
493 // These should never appear in a 'name' table.
494 default:
495 SkASSERT(false);
496 record.name.reset();
497 break;
498 }
499
500 // Determine the language.
501 const uint16_t languageID = SkEndian_SwapBE16(nameRecord->languageID.languageTagID);
502
503 // Handle format 1 languages.
504 if (SkOTTableName::format_1 == fName.format && languageID >= 0x8000) {
505 const uint16_t languageTagRecordIndex = languageID - 0x8000;
506
507 const SkOTTableName::Format1Ext* format1ext =
508 SkTAfter<const SkOTTableName::Format1Ext>(nameRecords, nameRecordsCount);
509
bungeman@google.coma3aaf162013-07-29 22:25:02 +0000510 if (languageTagRecordIndex < SkEndian_SwapBE16(format1ext->langTagCount)) {
bungeman@google.com07a69f82013-04-02 14:12:38 +0000511 const SkOTTableName::Format1Ext::LangTagRecord* languageTagRecord =
512 SkTAfter<const SkOTTableName::Format1Ext::LangTagRecord>(format1ext);
513
514 uint16_t offset = SkEndian_SwapBE16(languageTagRecord[languageTagRecordIndex].offset);
515 uint16_t length = SkEndian_SwapBE16(languageTagRecord[languageTagRecordIndex].length);
516 const uint16_t* string = SkTAddOffset<const uint16_t>(stringTable, offset);
517 SkStringFromUTF16BE(string, length, record.language);
518 return true;
519 }
520 }
521
522 // Handle format 0 languages, translating them into BCP 47.
523 const BCP47FromLanguageId target = { languageID, "" };
bsalomon@google.com20f7f172013-05-17 19:05:03 +0000524 int languageIndex = SkTSearch<BCP47FromLanguageId, BCP47FromLanguageIdLess>(
bungeman@google.com07a69f82013-04-02 14:12:38 +0000525 BCP47FromLanguageID, SK_ARRAY_COUNT(BCP47FromLanguageID), target, sizeof(target));
526 if (languageIndex >= 0) {
527 record.language = BCP47FromLanguageID[languageIndex].bcp47;
528 return true;
529 }
530
531 // Unknown language, return the BCP 47 code 'und' for 'undetermined'.
bungeman@google.com07a69f82013-04-02 14:12:38 +0000532 record.language = "und";
533 return true;
534}