FontFamilyTest.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759
  1. /*
  2. * Copyright (C) 2015 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "minikin/FontFamily.h"
  17. #include <gtest/gtest.h>
  18. #include "minikin/LocaleList.h"
  19. #include "FontTestUtils.h"
  20. #include "FreeTypeMinikinFontForTest.h"
  21. #include "LocaleListCache.h"
  22. #include "MinikinInternal.h"
  23. namespace minikin {
  24. static const LocaleList& createLocaleList(const std::string& input) {
  25. uint32_t localeListId = LocaleListCache::getId(input);
  26. return LocaleListCache::getById(localeListId);
  27. }
  28. static Locale createLocale(const std::string& input) {
  29. uint32_t localeListId = LocaleListCache::getId(input);
  30. return LocaleListCache::getById(localeListId)[0];
  31. }
  32. static Locale createLocaleWithoutICUSanitization(const std::string& input) {
  33. return Locale(input);
  34. }
  35. TEST(LocaleTest, basicTests) {
  36. Locale defaultLocale;
  37. Locale emptyLocale("");
  38. Locale english = createLocale("en");
  39. Locale french = createLocale("fr");
  40. Locale und = createLocale("und");
  41. Locale undZsye = createLocale("und-Zsye");
  42. EXPECT_EQ(english, english);
  43. EXPECT_EQ(french, french);
  44. EXPECT_TRUE(defaultLocale != defaultLocale);
  45. EXPECT_TRUE(emptyLocale != emptyLocale);
  46. EXPECT_TRUE(defaultLocale != emptyLocale);
  47. EXPECT_TRUE(defaultLocale != und);
  48. EXPECT_TRUE(emptyLocale != und);
  49. EXPECT_TRUE(english != defaultLocale);
  50. EXPECT_TRUE(english != emptyLocale);
  51. EXPECT_TRUE(english != french);
  52. EXPECT_TRUE(english != undZsye);
  53. EXPECT_TRUE(und != undZsye);
  54. EXPECT_TRUE(english != und);
  55. EXPECT_TRUE(createLocale("de-1901") != createLocale("de-1996"));
  56. EXPECT_TRUE(defaultLocale.isUnsupported());
  57. EXPECT_TRUE(emptyLocale.isUnsupported());
  58. EXPECT_FALSE(english.isUnsupported());
  59. EXPECT_FALSE(french.isUnsupported());
  60. EXPECT_FALSE(und.isUnsupported());
  61. EXPECT_FALSE(undZsye.isUnsupported());
  62. }
  63. TEST(LocaleTest, getStringTest) {
  64. EXPECT_EQ("en-Latn-US", createLocale("en").getString());
  65. EXPECT_EQ("en-Latn-US", createLocale("en-Latn").getString());
  66. // Capitalized language code or lowercased script should be normalized.
  67. EXPECT_EQ("en-Latn-US", createLocale("EN-LATN").getString());
  68. EXPECT_EQ("en-Latn-US", createLocale("EN-latn").getString());
  69. EXPECT_EQ("en-Latn-US", createLocale("en-latn").getString());
  70. // Invalid script should be kept.
  71. EXPECT_EQ("en-Xyzt-US", createLocale("en-xyzt").getString());
  72. EXPECT_EQ("en-Latn-US", createLocale("en-Latn-US").getString());
  73. EXPECT_EQ("ja-Jpan-JP", createLocale("ja").getString());
  74. EXPECT_EQ("zh-Hant-TW", createLocale("zh-TW").getString());
  75. EXPECT_EQ("zh-Hant-HK", createLocale("zh-HK").getString());
  76. EXPECT_EQ("zh-Hant-MO", createLocale("zh-MO").getString());
  77. EXPECT_EQ("zh-Hans-CN", createLocale("zh").getString());
  78. EXPECT_EQ("zh-Hans-CN", createLocale("zh-CN").getString());
  79. EXPECT_EQ("zh-Hans-SG", createLocale("zh-SG").getString());
  80. EXPECT_EQ("und", createLocale("und").getString());
  81. EXPECT_EQ("und", createLocale("UND").getString());
  82. EXPECT_EQ("und", createLocale("Und").getString());
  83. EXPECT_EQ("und-Zsye", createLocale("und-Zsye").getString());
  84. EXPECT_EQ("und-Zsye", createLocale("Und-ZSYE").getString());
  85. EXPECT_EQ("und-Zsye", createLocale("Und-zsye").getString());
  86. EXPECT_EQ("es-Latn-419", createLocale("es-Latn-419").getString());
  87. // Variant
  88. EXPECT_EQ("de-Latn-DE", createLocale("de").getString());
  89. EXPECT_EQ("de-Latn-DE-1901", createLocale("de-1901").getString());
  90. EXPECT_EQ("de-Latn-DE-1996", createLocale("de-DE-1996").getString());
  91. // Line Break subtag
  92. EXPECT_EQ("ja-Jpan-JP-u-lb-loose", createLocale("ja-JP-u-lb-loose").getString());
  93. EXPECT_EQ("ja-Jpan-JP-u-lb-normal", createLocale("ja-JP-u-lb-normal").getString());
  94. EXPECT_EQ("ja-Jpan-JP-u-lb-strict", createLocale("ja-JP-u-lb-strict").getString());
  95. EXPECT_EQ("ja-Jpan-JP-u-lb-loose", createLocale("ja-JP-u-lb-loose-em-emoji").getString());
  96. EXPECT_EQ("ja-Jpan-JP-u-lb-strict", createLocale("ja-JP-u-em-default-lb-strict").getString());
  97. EXPECT_EQ("ja-Jpan-JP", createLocale("ja-JP-u-lb-bogus").getString());
  98. // Emoji subtag is dropped from getString().
  99. EXPECT_EQ("es-Latn-419", createLocale("es-419-u-em-emoji").getString());
  100. EXPECT_EQ("es-Latn-419", createLocale("es-Latn-419-u-em-emoji").getString());
  101. // This is not a necessary desired behavior, just known behavior.
  102. EXPECT_EQ("en-Latn-US", createLocale("und-Abcdefgh").getString());
  103. }
  104. TEST(LocaleTest, invalidLanguageTagTest) { // just make sure no crash happens
  105. LocaleListCache::getId("ja-JP-u-lb-lb-strict");
  106. }
  107. TEST(LocaleTest, testReconstruction) {
  108. EXPECT_EQ("en", createLocaleWithoutICUSanitization("en").getString());
  109. EXPECT_EQ("fil", createLocaleWithoutICUSanitization("fil").getString());
  110. EXPECT_EQ("und", createLocaleWithoutICUSanitization("und").getString());
  111. EXPECT_EQ("en-Latn", createLocaleWithoutICUSanitization("en-Latn").getString());
  112. EXPECT_EQ("fil-Taga", createLocaleWithoutICUSanitization("fil-Taga").getString());
  113. EXPECT_EQ("und-Zsye", createLocaleWithoutICUSanitization("und-Zsye").getString());
  114. EXPECT_EQ("en-US", createLocaleWithoutICUSanitization("en-US").getString());
  115. EXPECT_EQ("fil-PH", createLocaleWithoutICUSanitization("fil-PH").getString());
  116. EXPECT_EQ("es-419", createLocaleWithoutICUSanitization("es-419").getString());
  117. EXPECT_EQ("en-Latn-US", createLocaleWithoutICUSanitization("en-Latn-US").getString());
  118. EXPECT_EQ("fil-Taga-PH", createLocaleWithoutICUSanitization("fil-Taga-PH").getString());
  119. EXPECT_EQ("es-Latn-419", createLocaleWithoutICUSanitization("es-Latn-419").getString());
  120. // Possible minimum/maximum values.
  121. EXPECT_EQ("aa", createLocaleWithoutICUSanitization("aa").getString());
  122. EXPECT_EQ("zz", createLocaleWithoutICUSanitization("zz").getString());
  123. EXPECT_EQ("aa-Aaaa", createLocaleWithoutICUSanitization("aa-Aaaa").getString());
  124. EXPECT_EQ("zz-Zzzz", createLocaleWithoutICUSanitization("zz-Zzzz").getString());
  125. EXPECT_EQ("aaa-Aaaa-AA", createLocaleWithoutICUSanitization("aaa-Aaaa-AA").getString());
  126. EXPECT_EQ("zzz-Zzzz-ZZ", createLocaleWithoutICUSanitization("zzz-Zzzz-ZZ").getString());
  127. EXPECT_EQ("aaa-Aaaa-000", createLocaleWithoutICUSanitization("aaa-Aaaa-000").getString());
  128. EXPECT_EQ("zzz-Zzzz-999", createLocaleWithoutICUSanitization("zzz-Zzzz-999").getString());
  129. }
  130. TEST(LocaleTest, ScriptEqualTest) {
  131. EXPECT_TRUE(createLocale("en").isEqualScript(createLocale("en")));
  132. EXPECT_TRUE(createLocale("en-Latn").isEqualScript(createLocale("en")));
  133. EXPECT_TRUE(createLocale("jp-Latn").isEqualScript(createLocale("en-Latn")));
  134. EXPECT_TRUE(createLocale("en-Jpan").isEqualScript(createLocale("en-Jpan")));
  135. EXPECT_FALSE(createLocale("en-Jpan").isEqualScript(createLocale("en-Hira")));
  136. EXPECT_FALSE(createLocale("en-Jpan").isEqualScript(createLocale("en-Hani")));
  137. }
  138. TEST(LocaleTest, ScriptMatchTest) {
  139. const bool SUPPORTED = true;
  140. const bool NOT_SUPPORTED = false;
  141. struct TestCase {
  142. const std::string baseScript;
  143. const std::string requestedScript;
  144. bool isSupported;
  145. } testCases[] = {
  146. // Same scripts
  147. {"en-Latn", "Latn", SUPPORTED},
  148. {"ja-Jpan", "Jpan", SUPPORTED},
  149. {"ja-Hira", "Hira", SUPPORTED},
  150. {"ja-Kana", "Kana", SUPPORTED},
  151. {"ja-Hrkt", "Hrkt", SUPPORTED},
  152. {"zh-Hans", "Hans", SUPPORTED},
  153. {"zh-Hant", "Hant", SUPPORTED},
  154. {"zh-Hani", "Hani", SUPPORTED},
  155. {"ko-Kore", "Kore", SUPPORTED},
  156. {"ko-Hang", "Hang", SUPPORTED},
  157. {"zh-Hanb", "Hanb", SUPPORTED},
  158. // Japanese supports Hiragana, Katakanara, etc.
  159. {"ja-Jpan", "Hira", SUPPORTED},
  160. {"ja-Jpan", "Kana", SUPPORTED},
  161. {"ja-Jpan", "Hrkt", SUPPORTED},
  162. {"ja-Hrkt", "Hira", SUPPORTED},
  163. {"ja-Hrkt", "Kana", SUPPORTED},
  164. // Chinese supports Han.
  165. {"zh-Hans", "Hani", SUPPORTED},
  166. {"zh-Hant", "Hani", SUPPORTED},
  167. {"zh-Hanb", "Hani", SUPPORTED},
  168. // Hanb supports Bopomofo.
  169. {"zh-Hanb", "Bopo", SUPPORTED},
  170. // Korean supports Hangul.
  171. {"ko-Kore", "Hang", SUPPORTED},
  172. // Different scripts
  173. {"ja-Jpan", "Latn", NOT_SUPPORTED},
  174. {"en-Latn", "Jpan", NOT_SUPPORTED},
  175. {"ja-Jpan", "Hant", NOT_SUPPORTED},
  176. {"zh-Hant", "Jpan", NOT_SUPPORTED},
  177. {"ja-Jpan", "Hans", NOT_SUPPORTED},
  178. {"zh-Hans", "Jpan", NOT_SUPPORTED},
  179. {"ja-Jpan", "Kore", NOT_SUPPORTED},
  180. {"ko-Kore", "Jpan", NOT_SUPPORTED},
  181. {"zh-Hans", "Hant", NOT_SUPPORTED},
  182. {"zh-Hant", "Hans", NOT_SUPPORTED},
  183. {"zh-Hans", "Kore", NOT_SUPPORTED},
  184. {"ko-Kore", "Hans", NOT_SUPPORTED},
  185. {"zh-Hant", "Kore", NOT_SUPPORTED},
  186. {"ko-Kore", "Hant", NOT_SUPPORTED},
  187. // Hiragana doesn't support Japanese, etc.
  188. {"ja-Hira", "Jpan", NOT_SUPPORTED},
  189. {"ja-Kana", "Jpan", NOT_SUPPORTED},
  190. {"ja-Hrkt", "Jpan", NOT_SUPPORTED},
  191. {"ja-Hani", "Jpan", NOT_SUPPORTED},
  192. {"ja-Hira", "Hrkt", NOT_SUPPORTED},
  193. {"ja-Kana", "Hrkt", NOT_SUPPORTED},
  194. {"ja-Hani", "Hrkt", NOT_SUPPORTED},
  195. {"ja-Hani", "Hira", NOT_SUPPORTED},
  196. {"ja-Hani", "Kana", NOT_SUPPORTED},
  197. // Kanji doesn't support Chinese, etc.
  198. {"zh-Hani", "Hant", NOT_SUPPORTED},
  199. {"zh-Hani", "Hans", NOT_SUPPORTED},
  200. {"zh-Hani", "Hanb", NOT_SUPPORTED},
  201. // Hangul doesn't support Korean, etc.
  202. {"ko-Hang", "Kore", NOT_SUPPORTED},
  203. {"ko-Hani", "Kore", NOT_SUPPORTED},
  204. {"ko-Hani", "Hang", NOT_SUPPORTED},
  205. {"ko-Hang", "Hani", NOT_SUPPORTED},
  206. // Han with botomofo doesn't support simplified Chinese, etc.
  207. {"zh-Hanb", "Hant", NOT_SUPPORTED},
  208. {"zh-Hanb", "Hans", NOT_SUPPORTED},
  209. {"zh-Hanb", "Jpan", NOT_SUPPORTED},
  210. {"zh-Hanb", "Kore", NOT_SUPPORTED},
  211. };
  212. for (const auto& testCase : testCases) {
  213. hb_script_t script = hb_script_from_iso15924_tag(
  214. HB_TAG(testCase.requestedScript[0], testCase.requestedScript[1],
  215. testCase.requestedScript[2], testCase.requestedScript[3]));
  216. if (testCase.isSupported) {
  217. EXPECT_TRUE(createLocale(testCase.baseScript).supportsHbScript(script))
  218. << testCase.baseScript << " should support " << testCase.requestedScript;
  219. } else {
  220. EXPECT_FALSE(createLocale(testCase.baseScript).supportsHbScript(script))
  221. << testCase.baseScript << " shouldn't support " << testCase.requestedScript;
  222. }
  223. }
  224. }
  225. TEST(LocaleListTest, basicTests) {
  226. LocaleList emptyLocales;
  227. EXPECT_EQ(0u, emptyLocales.size());
  228. Locale english = createLocale("en");
  229. const LocaleList& singletonLocales = createLocaleList("en");
  230. EXPECT_EQ(1u, singletonLocales.size());
  231. EXPECT_EQ(english, singletonLocales[0]);
  232. Locale french = createLocale("fr");
  233. const LocaleList& twoLocales = createLocaleList("en,fr");
  234. EXPECT_EQ(2u, twoLocales.size());
  235. EXPECT_EQ(english, twoLocales[0]);
  236. EXPECT_EQ(french, twoLocales[1]);
  237. }
  238. TEST(LocaleListTest, unsupportedLocaleuageTests) {
  239. const LocaleList& oneUnsupported = createLocaleList("abcd-example");
  240. EXPECT_TRUE(oneUnsupported.empty());
  241. const LocaleList& twoUnsupporteds = createLocaleList("abcd-example,abcd-example");
  242. EXPECT_TRUE(twoUnsupporteds.empty());
  243. Locale english = createLocale("en");
  244. const LocaleList& firstUnsupported = createLocaleList("abcd-example,en");
  245. EXPECT_EQ(1u, firstUnsupported.size());
  246. EXPECT_EQ(english, firstUnsupported[0]);
  247. const LocaleList& lastUnsupported = createLocaleList("en,abcd-example");
  248. EXPECT_EQ(1u, lastUnsupported.size());
  249. EXPECT_EQ(english, lastUnsupported[0]);
  250. }
  251. TEST(LocaleListTest, repeatedLocaleuageTests) {
  252. Locale english = createLocale("en");
  253. Locale french = createLocale("fr");
  254. Locale canadianFrench = createLocale("fr-CA");
  255. Locale englishInLatn = createLocale("en-Latn");
  256. ASSERT_TRUE(english == englishInLatn);
  257. const LocaleList& locales = createLocaleList("en,en-Latn");
  258. EXPECT_EQ(1u, locales.size());
  259. EXPECT_EQ(english, locales[0]);
  260. const LocaleList& fr = createLocaleList("fr,fr-FR,fr-Latn-FR");
  261. EXPECT_EQ(1u, fr.size());
  262. EXPECT_EQ(french, fr[0]);
  263. // ICU appends FR to fr. The third language is dropped which is same as the first language.
  264. const LocaleList& fr2 = createLocaleList("fr,fr-CA,fr-FR");
  265. EXPECT_EQ(2u, fr2.size());
  266. EXPECT_EQ(french, fr2[0]);
  267. EXPECT_EQ(canadianFrench, fr2[1]);
  268. // The order should be kept.
  269. const LocaleList& locales2 = createLocaleList("en,fr,en-Latn");
  270. EXPECT_EQ(2u, locales2.size());
  271. EXPECT_EQ(english, locales2[0]);
  272. EXPECT_EQ(french, locales2[1]);
  273. }
  274. TEST(LocaleListTest, identifierTest) {
  275. EXPECT_EQ(createLocale("en-Latn-US"), createLocale("en-Latn-US"));
  276. EXPECT_EQ(createLocale("zh-Hans-CN"), createLocale("zh-Hans-CN"));
  277. EXPECT_EQ(createLocale("en-Zsye-US"), createLocale("en-Zsye-US"));
  278. EXPECT_NE(createLocale("en-Latn-US"), createLocale("en-Latn-GB"));
  279. EXPECT_NE(createLocale("en-Latn-US"), createLocale("en-Zsye-US"));
  280. EXPECT_NE(createLocale("es-Latn-US"), createLocale("en-Latn-US"));
  281. EXPECT_NE(createLocale("zh-Hant-HK"), createLocale("zh-Hant-TW"));
  282. }
  283. TEST(LocaleListTest, undEmojiTests) {
  284. Locale emoji = createLocale("und-Zsye");
  285. EXPECT_EQ(EmojiStyle::EMOJI, emoji.getEmojiStyle());
  286. Locale und = createLocale("und");
  287. EXPECT_EQ(EmojiStyle::EMPTY, und.getEmojiStyle());
  288. EXPECT_FALSE(emoji == und);
  289. Locale undExample = createLocale("und-example");
  290. EXPECT_EQ(EmojiStyle::EMPTY, undExample.getEmojiStyle());
  291. EXPECT_FALSE(emoji == undExample);
  292. }
  293. TEST(LocaleListTest, subtagEmojiTest) {
  294. std::string subtagEmojiStrings[] = {
  295. // Duplicate subtag case.
  296. "und-Latn-u-em-emoji-u-em-text",
  297. // Strings that contain language.
  298. "und-u-em-emoji", "en-u-em-emoji",
  299. // Strings that contain the script.
  300. "und-Jpan-u-em-emoji", "en-Latn-u-em-emoji", "und-Zsym-u-em-emoji",
  301. "und-Zsye-u-em-emoji", "en-Zsym-u-em-emoji", "en-Zsye-u-em-emoji",
  302. // Strings that contain the country.
  303. "und-US-u-em-emoji", "en-US-u-em-emoji", "es-419-u-em-emoji", "und-Latn-US-u-em-emoji",
  304. "en-Zsym-US-u-em-emoji", "en-Zsye-US-u-em-emoji", "es-Zsye-419-u-em-emoji",
  305. // Strings that contain the variant.
  306. "de-Latn-DE-1901-u-em-emoji",
  307. };
  308. for (const auto& subtagEmojiString : subtagEmojiStrings) {
  309. SCOPED_TRACE("Test for \"" + subtagEmojiString + "\"");
  310. Locale subtagEmoji = createLocale(subtagEmojiString);
  311. EXPECT_EQ(EmojiStyle::EMOJI, subtagEmoji.getEmojiStyle());
  312. }
  313. }
  314. TEST(LocaleListTest, subtagTextTest) {
  315. std::string subtagTextStrings[] = {
  316. // Duplicate subtag case.
  317. "und-Latn-u-em-text-u-em-emoji",
  318. // Strings that contain language.
  319. "und-u-em-text", "en-u-em-text",
  320. // Strings that contain the script.
  321. "und-Latn-u-em-text", "en-Jpan-u-em-text", "und-Zsym-u-em-text", "und-Zsye-u-em-text",
  322. "en-Zsym-u-em-text", "en-Zsye-u-em-text",
  323. // Strings that contain the country.
  324. "und-US-u-em-text", "en-US-u-em-text", "es-419-u-em-text", "und-Latn-US-u-em-text",
  325. "en-Zsym-US-u-em-text", "en-Zsye-US-u-em-text", "es-Zsye-419-u-em-text",
  326. // Strings that contain the variant.
  327. "de-Latn-DE-1901-u-em-text",
  328. };
  329. for (const auto& subtagTextString : subtagTextStrings) {
  330. SCOPED_TRACE("Test for \"" + subtagTextString + "\"");
  331. Locale subtagText = createLocale(subtagTextString);
  332. EXPECT_EQ(EmojiStyle::TEXT, subtagText.getEmojiStyle());
  333. }
  334. }
  335. // TODO: add more "und" language cases whose language and script are
  336. // unexpectedly translated to en-Latn by ICU.
  337. TEST(LocaleListTest, subtagDefaultTest) {
  338. std::string subtagDefaultStrings[] = {
  339. // Duplicate subtag case.
  340. "en-Latn-u-em-default-u-em-emoji", "en-Latn-u-em-default-u-em-text",
  341. // Strings that contain language.
  342. "und-u-em-default", "en-u-em-default",
  343. // Strings that contain the script.
  344. "en-Latn-u-em-default", "en-Zsym-u-em-default", "en-Zsye-u-em-default",
  345. // Strings that contain the country.
  346. "en-US-u-em-default", "en-Latn-US-u-em-default", "es-Latn-419-u-em-default",
  347. "en-Zsym-US-u-em-default", "en-Zsye-US-u-em-default", "es-Zsye-419-u-em-default",
  348. // Strings that contain the variant.
  349. "de-Latn-DE-1901-u-em-default",
  350. };
  351. for (const auto& subtagDefaultString : subtagDefaultStrings) {
  352. SCOPED_TRACE("Test for \"" + subtagDefaultString + "\"");
  353. Locale subtagDefault = createLocale(subtagDefaultString);
  354. EXPECT_EQ(EmojiStyle::DEFAULT, subtagDefault.getEmojiStyle());
  355. }
  356. }
  357. TEST(LocaleListTest, subtagEmptyTest) {
  358. std::string subtagEmptyStrings[] = {
  359. "und",
  360. "jp",
  361. "en-US",
  362. "en-Latn",
  363. "en-Latn-US",
  364. "en-Latn-US-u-em",
  365. "en-Latn-US-u-em-defaultemoji",
  366. "de-Latn-DE-1901",
  367. };
  368. for (const auto& subtagEmptyString : subtagEmptyStrings) {
  369. SCOPED_TRACE("Test for \"" + subtagEmptyString + "\"");
  370. Locale subtagEmpty = createLocale(subtagEmptyString);
  371. EXPECT_EQ(EmojiStyle::EMPTY, subtagEmpty.getEmojiStyle());
  372. }
  373. }
  374. TEST(LocaleListTest, registerLocaleListTest) {
  375. EXPECT_EQ(0UL, registerLocaleList(""));
  376. EXPECT_NE(0UL, registerLocaleList("en"));
  377. EXPECT_NE(0UL, registerLocaleList("jp"));
  378. EXPECT_NE(0UL, registerLocaleList("en,zh-Hans"));
  379. EXPECT_EQ(registerLocaleList("en"), registerLocaleList("en"));
  380. EXPECT_NE(registerLocaleList("en"), registerLocaleList("jp"));
  381. EXPECT_NE(registerLocaleList("de"), registerLocaleList("de-1901"));
  382. EXPECT_EQ(registerLocaleList("en,zh-Hans"), registerLocaleList("en,zh-Hans"));
  383. EXPECT_NE(registerLocaleList("en,zh-Hans"), registerLocaleList("zh-Hans,en"));
  384. EXPECT_NE(registerLocaleList("en,zh-Hans"), registerLocaleList("jp"));
  385. EXPECT_NE(registerLocaleList("en,zh-Hans"), registerLocaleList("en"));
  386. EXPECT_NE(registerLocaleList("en,zh-Hans"), registerLocaleList("en,zh-Hant"));
  387. EXPECT_NE(registerLocaleList("de,de-1901"), registerLocaleList("de-1901,de"));
  388. }
  389. // The test font has following glyphs.
  390. // U+82A6
  391. // U+82A6 U+FE00 (VS1)
  392. // U+82A6 U+E0100 (VS17)
  393. // U+82A6 U+E0101 (VS18)
  394. // U+82A6 U+E0102 (VS19)
  395. // U+845B
  396. // U+845B U+FE00 (VS2)
  397. // U+845B U+E0101 (VS18)
  398. // U+845B U+E0102 (VS19)
  399. // U+845B U+E0103 (VS20)
  400. // U+537F
  401. // U+717D U+FE02 (VS3)
  402. // U+717D U+E0102 (VS19)
  403. // U+717D U+E0103 (VS20)
  404. const char kVsTestFont[] = "VariationSelectorTest-Regular.ttf";
  405. class FontFamilyTest : public testing::Test {
  406. public:
  407. virtual void SetUp() override {
  408. if (access(getTestFontPath(kVsTestFont).c_str(), R_OK) != 0) {
  409. FAIL() << "Unable to read " << kVsTestFont << ". "
  410. << "Please prepare the test data directory. "
  411. << "For more details, please see how_to_run.txt.";
  412. }
  413. }
  414. };
  415. // Asserts that the font family has glyphs for and only for specified codepoint
  416. // and variationSelector pairs.
  417. void expectVSGlyphs(FontFamily* family, uint32_t codepoint, const std::set<uint32_t>& vs) {
  418. for (uint32_t i = 0xFE00; i <= 0xE01EF; ++i) {
  419. // Move to variation selectors supplements after variation selectors.
  420. if (i == 0xFF00) {
  421. i = 0xE0100;
  422. }
  423. if (vs.find(i) == vs.end()) {
  424. EXPECT_FALSE(family->hasGlyph(codepoint, i))
  425. << "Glyph for U+" << std::hex << codepoint << " U+" << i;
  426. } else {
  427. EXPECT_TRUE(family->hasGlyph(codepoint, i))
  428. << "Glyph for U+" << std::hex << codepoint << " U+" << i;
  429. }
  430. }
  431. }
  432. TEST_F(FontFamilyTest, hasVariationSelectorTest) {
  433. std::shared_ptr<FontFamily> family = buildFontFamily(kVsTestFont);
  434. const uint32_t kVS1 = 0xFE00;
  435. const uint32_t kVS2 = 0xFE01;
  436. const uint32_t kVS3 = 0xFE02;
  437. const uint32_t kVS17 = 0xE0100;
  438. const uint32_t kVS18 = 0xE0101;
  439. const uint32_t kVS19 = 0xE0102;
  440. const uint32_t kVS20 = 0xE0103;
  441. const uint32_t kSupportedChar1 = 0x82A6;
  442. EXPECT_TRUE(family->getCoverage().get(kSupportedChar1));
  443. expectVSGlyphs(family.get(), kSupportedChar1, std::set<uint32_t>({kVS1, kVS17, kVS18, kVS19}));
  444. const uint32_t kSupportedChar2 = 0x845B;
  445. EXPECT_TRUE(family->getCoverage().get(kSupportedChar2));
  446. expectVSGlyphs(family.get(), kSupportedChar2, std::set<uint32_t>({kVS2, kVS18, kVS19, kVS20}));
  447. const uint32_t kNoVsSupportedChar = 0x537F;
  448. EXPECT_TRUE(family->getCoverage().get(kNoVsSupportedChar));
  449. expectVSGlyphs(family.get(), kNoVsSupportedChar, std::set<uint32_t>());
  450. const uint32_t kVsOnlySupportedChar = 0x717D;
  451. EXPECT_FALSE(family->getCoverage().get(kVsOnlySupportedChar));
  452. expectVSGlyphs(family.get(), kVsOnlySupportedChar, std::set<uint32_t>({kVS3, kVS19, kVS20}));
  453. const uint32_t kNotSupportedChar = 0x845C;
  454. EXPECT_FALSE(family->getCoverage().get(kNotSupportedChar));
  455. expectVSGlyphs(family.get(), kNotSupportedChar, std::set<uint32_t>());
  456. }
  457. TEST_F(FontFamilyTest, hasVSTableTest) {
  458. struct TestCase {
  459. const std::string fontPath;
  460. bool hasVSTable;
  461. } testCases[] = {
  462. {"Ja.ttf", true}, {"ZhHant.ttf", true}, {"ZhHans.ttf", true},
  463. {"Italic.ttf", false}, {"Bold.ttf", false}, {"BoldItalic.ttf", false},
  464. };
  465. for (const auto& testCase : testCases) {
  466. SCOPED_TRACE(testCase.hasVSTable ? "Font " + testCase.fontPath +
  467. " should have a variation sequence table."
  468. : "Font " + testCase.fontPath +
  469. " shouldn't have a variation sequence table.");
  470. std::shared_ptr<FontFamily> family = buildFontFamily(testCase.fontPath);
  471. EXPECT_EQ(testCase.hasVSTable, family->hasVSTable());
  472. }
  473. }
  474. TEST_F(FontFamilyTest, createFamilyWithVariationTest) {
  475. // This font has 'wdth' and 'wght' axes.
  476. const char kMultiAxisFont[] = "MultiAxis.ttf";
  477. const char kNoAxisFont[] = "Regular.ttf";
  478. std::shared_ptr<FontFamily> multiAxisFamily = buildFontFamily(kMultiAxisFont);
  479. std::shared_ptr<FontFamily> noAxisFamily = buildFontFamily(kNoAxisFont);
  480. {
  481. // Do not ceate new instance if none of variations are specified.
  482. EXPECT_EQ(nullptr,
  483. multiAxisFamily->createFamilyWithVariation(std::vector<FontVariation>()));
  484. EXPECT_EQ(nullptr, noAxisFamily->createFamilyWithVariation(std::vector<FontVariation>()));
  485. }
  486. {
  487. // New instance should be used for supported variation.
  488. std::vector<FontVariation> variations = {{MinikinFont::MakeTag('w', 'd', 't', 'h'), 1.0f}};
  489. std::shared_ptr<FontFamily> newFamily(
  490. multiAxisFamily->createFamilyWithVariation(variations));
  491. EXPECT_NE(nullptr, newFamily.get());
  492. EXPECT_NE(multiAxisFamily.get(), newFamily.get());
  493. EXPECT_EQ(nullptr, noAxisFamily->createFamilyWithVariation(variations));
  494. }
  495. {
  496. // New instance should be used for supported variation. (multiple variations case)
  497. std::vector<FontVariation> variations = {{MinikinFont::MakeTag('w', 'd', 't', 'h'), 1.0f},
  498. {MinikinFont::MakeTag('w', 'g', 'h', 't'), 1.0f}};
  499. std::shared_ptr<FontFamily> newFamily(
  500. multiAxisFamily->createFamilyWithVariation(variations));
  501. EXPECT_NE(nullptr, newFamily.get());
  502. EXPECT_NE(multiAxisFamily.get(), newFamily.get());
  503. EXPECT_EQ(nullptr, noAxisFamily->createFamilyWithVariation(variations));
  504. }
  505. {
  506. // Do not ceate new instance if none of variations are supported.
  507. std::vector<FontVariation> variations = {{MinikinFont::MakeTag('Z', 'Z', 'Z', 'Z'), 1.0f}};
  508. EXPECT_EQ(nullptr, multiAxisFamily->createFamilyWithVariation(variations));
  509. EXPECT_EQ(nullptr, noAxisFamily->createFamilyWithVariation(variations));
  510. }
  511. {
  512. // At least one axis is supported, should create new instance.
  513. std::vector<FontVariation> variations = {{MinikinFont::MakeTag('w', 'd', 't', 'h'), 1.0f},
  514. {MinikinFont::MakeTag('Z', 'Z', 'Z', 'Z'), 1.0f}};
  515. std::shared_ptr<FontFamily> newFamily(
  516. multiAxisFamily->createFamilyWithVariation(variations));
  517. EXPECT_NE(nullptr, newFamily.get());
  518. EXPECT_NE(multiAxisFamily.get(), newFamily.get());
  519. EXPECT_EQ(nullptr, noAxisFamily->createFamilyWithVariation(variations));
  520. }
  521. }
  522. TEST_F(FontFamilyTest, coverageTableSelectionTest) {
  523. // This font supports U+0061. The cmap subtable is format 4 and its platform ID is 0 and
  524. // encoding ID is 1.
  525. const char kUnicodeEncoding1Font[] = "UnicodeBMPOnly.ttf";
  526. // This font supports U+0061. The cmap subtable is format 4 and its platform ID is 0 and
  527. // encoding ID is 3.
  528. const char kUnicodeEncoding3Font[] = "UnicodeBMPOnly2.ttf";
  529. // This font has both cmap format 4 subtable which platform ID is 0 and encoding ID is 1
  530. // and cmap format 14 subtable which platform ID is 0 and encoding ID is 10.
  531. // U+0061 is listed in both subtable but U+1F926 is only listed in latter.
  532. const char kUnicodeEncoding4Font[] = "UnicodeUCS4.ttf";
  533. std::shared_ptr<FontFamily> unicodeEnc1Font = buildFontFamily(kUnicodeEncoding1Font);
  534. std::shared_ptr<FontFamily> unicodeEnc3Font = buildFontFamily(kUnicodeEncoding3Font);
  535. std::shared_ptr<FontFamily> unicodeEnc4Font = buildFontFamily(kUnicodeEncoding4Font);
  536. EXPECT_TRUE(unicodeEnc1Font->hasGlyph(0x0061, 0));
  537. EXPECT_TRUE(unicodeEnc3Font->hasGlyph(0x0061, 0));
  538. EXPECT_TRUE(unicodeEnc4Font->hasGlyph(0x0061, 0));
  539. EXPECT_TRUE(unicodeEnc4Font->hasGlyph(0x1F926, 0));
  540. }
  541. const char* slantToString(FontStyle::Slant slant) {
  542. if (slant == FontStyle::Slant::ITALIC) {
  543. return "ITALIC";
  544. } else {
  545. return "UPRIGHT";
  546. }
  547. }
  548. std::string fontStyleToString(const FontStyle& style) {
  549. char buf[64] = {};
  550. snprintf(buf, sizeof(buf), "FontStyle(weight=%d, slant=%s)", style.weight(),
  551. slantToString(style.slant()));
  552. return buf;
  553. }
  554. TEST_F(FontFamilyTest, closestMatch) {
  555. constexpr char kTestFont[] = "Ascii.ttf";
  556. constexpr FontStyle::Weight THIN = FontStyle::Weight::THIN;
  557. constexpr FontStyle::Weight LIGHT = FontStyle::Weight::LIGHT;
  558. constexpr FontStyle::Weight NORMAL = FontStyle::Weight::NORMAL;
  559. constexpr FontStyle::Weight MEDIUM = FontStyle::Weight::MEDIUM;
  560. constexpr FontStyle::Weight BOLD = FontStyle::Weight::BOLD;
  561. constexpr FontStyle::Weight BLACK = FontStyle::Weight::BLACK;
  562. constexpr FontStyle::Slant UPRIGHT = FontStyle::Slant::UPRIGHT;
  563. constexpr FontStyle::Slant ITALIC = FontStyle::Slant::ITALIC;
  564. const std::vector<FontStyle> STANDARD_SET = {
  565. FontStyle(NORMAL, UPRIGHT), // 0
  566. FontStyle(BOLD, UPRIGHT), // 1
  567. FontStyle(NORMAL, ITALIC), // 2
  568. FontStyle(BOLD, ITALIC), // 3
  569. };
  570. const std::vector<FontStyle> FULL_SET = {
  571. FontStyle(THIN, UPRIGHT), // 0
  572. FontStyle(LIGHT, UPRIGHT), // 1
  573. FontStyle(NORMAL, UPRIGHT), // 2
  574. FontStyle(MEDIUM, UPRIGHT), // 3
  575. FontStyle(BOLD, UPRIGHT), // 4
  576. FontStyle(BLACK, UPRIGHT), // 5
  577. FontStyle(THIN, ITALIC), // 6
  578. FontStyle(LIGHT, ITALIC), // 7
  579. FontStyle(NORMAL, ITALIC), // 8
  580. FontStyle(MEDIUM, ITALIC), // 9
  581. FontStyle(BOLD, ITALIC), // 10
  582. FontStyle(BLACK, ITALIC), // 11
  583. };
  584. struct TestCase {
  585. FontStyle wantedStyle;
  586. std::vector<FontStyle> familyStyles;
  587. size_t expectedIndex;
  588. } testCases[] = {
  589. {FontStyle(), {FontStyle()}, 0},
  590. // Exact matches
  591. {FontStyle(BOLD), {FontStyle(NORMAL), FontStyle(BOLD)}, 1},
  592. {FontStyle(BOLD), {FontStyle(LIGHT), FontStyle(BOLD)}, 1},
  593. {FontStyle(LIGHT), {FontStyle(NORMAL), FontStyle(LIGHT)}, 1},
  594. {FontStyle(LIGHT), {FontStyle(BOLD), FontStyle(LIGHT)}, 1},
  595. {FontStyle(NORMAL), {FontStyle(NORMAL), FontStyle(LIGHT)}, 0},
  596. {FontStyle(NORMAL), {FontStyle(NORMAL), FontStyle(BOLD)}, 0},
  597. {FontStyle(LIGHT), {FontStyle(LIGHT), FontStyle(NORMAL), FontStyle(BOLD)}, 0},
  598. {FontStyle(NORMAL), {FontStyle(LIGHT), FontStyle(NORMAL), FontStyle(BOLD)}, 1},
  599. {FontStyle(BOLD), {FontStyle(LIGHT), FontStyle(NORMAL), FontStyle(BOLD)}, 2},
  600. {FontStyle(UPRIGHT), {FontStyle(UPRIGHT), FontStyle(ITALIC)}, 0},
  601. {FontStyle(ITALIC), {FontStyle(UPRIGHT), FontStyle(ITALIC)}, 1},
  602. {FontStyle(NORMAL, UPRIGHT), STANDARD_SET, 0},
  603. {FontStyle(BOLD, UPRIGHT), STANDARD_SET, 1},
  604. {FontStyle(NORMAL, ITALIC), STANDARD_SET, 2},
  605. {FontStyle(BOLD, ITALIC), STANDARD_SET, 3},
  606. {FontStyle(NORMAL, UPRIGHT), FULL_SET, 2},
  607. {FontStyle(BOLD, UPRIGHT), FULL_SET, 4},
  608. {FontStyle(NORMAL, ITALIC), FULL_SET, 8},
  609. {FontStyle(BOLD, ITALIC), FULL_SET, 10},
  610. // TODO: Add fallback expectations. (b/68814338)
  611. };
  612. for (const TestCase& testCase : testCases) {
  613. std::vector<std::shared_ptr<MinikinFont>> dummyFonts;
  614. std::vector<Font> fonts;
  615. for (auto familyStyle : testCase.familyStyles) {
  616. std::shared_ptr<MinikinFont> dummyFont(
  617. new FreeTypeMinikinFontForTest(getTestFontPath(kTestFont)));
  618. dummyFonts.push_back(dummyFont);
  619. fonts.push_back(Font::Builder(dummyFont).setStyle(familyStyle).build());
  620. }
  621. FontFamily family(std::move(fonts));
  622. FakedFont closest = family.getClosestMatch(testCase.wantedStyle);
  623. size_t idx = dummyFonts.size();
  624. for (size_t i = 0; i < dummyFonts.size(); i++) {
  625. if (dummyFonts[i].get() == closest.font->typeface().get()) {
  626. idx = i;
  627. break;
  628. }
  629. }
  630. ASSERT_NE(idx, dummyFonts.size()) << "The selected font is unknown.";
  631. EXPECT_EQ(testCase.expectedIndex, idx)
  632. << "Input Style: " << fontStyleToString(testCase.wantedStyle) << std::endl
  633. << "Actual Families' Style: " << fontStyleToString(testCase.familyStyles[idx])
  634. << std::endl
  635. << "Expected Families' Style: "
  636. << fontStyleToString(testCase.familyStyles[testCase.expectedIndex]) << std::endl;
  637. }
  638. }
  639. } // namespace minikin