• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 "include/core/SkFontMgr.h"
9 #include "include/core/SkTypeface.h"
10 #include "src/sfnt/SkOTTable_name.h"
11 #include "tests/Test.h"
12 #include "tools/flags/CommandLineFlags.h"
13 
14 #include <stddef.h>
15 
16 namespace {
17 
18 template <size_t R, size_t D> struct Format0NameTable {
19     SkOTTableName header;
20     SkOTTableName::Record nameRecord[R];
21     char data[D];
22 };
23 
24 template <size_t R, size_t L, size_t D> struct Format1NameTable {
25     SkOTTableName header;
26     SkOTTableName::Record nameRecord[R];
27     struct {
28         SkOTTableName::Format1Ext header;
29         SkOTTableName::Format1Ext::LangTagRecord langTagRecord[L];
30     } format1ext;
31     char data[D];
32 };
33 
34 typedef Format0NameTable<1, 9> SimpleFormat0NameTable;
35 constexpr SimpleFormat0NameTable simpleFormat0NameTable = {
36     /*header*/ {
37         /*format*/ SkOTTableName::format_0,
38         /*count*/ SkTEndianSwap16<1>::value,
39         /*stringOffset*/ SkTEndianSwap16<offsetof(SimpleFormat0NameTable, data)>::value,
40     },
41     /*nameRecord[]*/ {
42         /*Record*/ {
43             /*platformID*/ { SkOTTableName::Record::PlatformID::Windows },
44             /*encodingID*/ { SkOTTableName::Record::EncodingID::Windows::UnicodeBMPUCS2 },
45             /*languageID*/ { SkOTTableName::Record::LanguageID::Windows::English_UnitedStates },
46             /*nameID*/ { SkOTTableName::Record::NameID::Predefined::FontFamilyName },
47             /*length*/ SkTEndianSwap16<8>::value,
48             /*offset*/ SkTEndianSwap16<0>::value,
49         }
50     },
51     /*data*/ "\x0" "T" "\x0" "e" "\x0" "s" "\x0" "t",
52 };
53 
54 typedef Format1NameTable<1, 1, 19> SimpleFormat1NameTable;
55 constexpr SimpleFormat1NameTable simpleFormat1NameTable = {
56     /*header*/ {
57         /*format*/ SkOTTableName::format_1,
58         /*count*/ SkTEndianSwap16<1>::value,
59         /*stringOffset*/ SkTEndianSwap16<offsetof(SimpleFormat1NameTable, data)>::value,
60     },
61     /*nameRecord[]*/ {
62         /*Record*/ {
63             /*platformID*/ { SkOTTableName::Record::PlatformID::Windows },
64             /*encodingID*/ { SkOTTableName::Record::EncodingID::Windows::UnicodeBMPUCS2 },
65             /*languageID*/ { SkTEndianSwap16<0x8000 + 0>::value },
66             /*nameID*/ { SkOTTableName::Record::NameID::Predefined::FontFamilyName },
67             /*length*/ SkTEndianSwap16<8>::value,
68             /*offset*/ SkTEndianSwap16<0>::value,
69         }
70     },
71     /*format1ext*/ {
72         /*header*/ {
73             /*langTagCount*/ SkTEndianSwap16<1>::value,
74         },
75         /*langTagRecord[]*/ {
76             /*LangTagRecord*/ {
77                 /*length*/ SkTEndianSwap16<10>::value,
78                 /*offset*/ SkTEndianSwap16<8>::value,
79             },
80         },
81     },
82     /*data*/ "\x0" "T" "\x0" "e" "\x0" "s" "\x0" "t"
83              "\x0" "e" "\x0" "n" "\x0" "-" "\x0" "U" "\x0" "S",
84 };
85 
86 struct FontNamesTest {
87     const uint8_t* data;
88     size_t size;
89     SkOTTableName::Record::NameID nameID;
90     size_t nameCount;
91     struct {
92         const char* name;
93         const char* language;
94     } names[10];
95 
96 } tests[] = {
97     {
98         reinterpret_cast<const uint8_t*>(&simpleFormat0NameTable),
99         sizeof(simpleFormat0NameTable),
100         { SkOTTableName::Record::NameID::Predefined::FontFamilyName },
101         1,
102         {
103             { "Test", "en-US" },
104         },
105     },
106     {
107         reinterpret_cast<const uint8_t*>(&simpleFormat1NameTable),
108         sizeof(simpleFormat1NameTable),
109         { SkOTTableName::Record::NameID::Predefined::FontFamilyName },
110         1,
111         {
112             { "Test", "en-US" },
113         },
114     },
115 };
116 
test_synthetic(skiatest::Reporter * reporter,bool verbose)117 static void test_synthetic(skiatest::Reporter* reporter, bool verbose) {
118     for (const auto& test : tests) {
119         SkOTTableName::Iterator iter(test.data, test.size, test.nameID.predefined.value);
120         SkOTTableName::Iterator::Record record;
121         size_t nameIndex = 0;
122         while (nameIndex < test.nameCount && iter.next(record)) {
123             REPORTER_ASSERT(reporter,
124                             strcmp(test.names[nameIndex].name, record.name.c_str()) == 0,
125                             "Name did not match.");
126 
127             REPORTER_ASSERT(reporter,
128                             strcmp(test.names[nameIndex].language, record.language.c_str()) == 0,
129                             "Language did not match.");
130 
131             if (verbose) {
132                 SkDebugf("%s <%s>\n", record.name.c_str(), record.language.c_str());
133             }
134 
135             ++nameIndex;
136         }
137 
138         REPORTER_ASSERT(reporter, nameIndex == test.nameCount, "Fewer names than expected.");
139 
140         REPORTER_ASSERT(reporter, !iter.next(record), "More names than expected.");
141     }
142 }
143 
144 #define MAX_FAMILIES 1000
test_systemfonts(skiatest::Reporter * reporter,bool verbose)145 static void test_systemfonts(skiatest::Reporter* reporter, bool verbose) {
146     static const SkFontTableTag nameTag = SkSetFourByteTag('n','a','m','e');
147 
148     sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
149     int count = std::min(fm->countFamilies(), MAX_FAMILIES);
150     for (int i = 0; i < count; ++i) {
151         sk_sp<SkFontStyleSet> set(fm->createStyleSet(i));
152         for (int j = 0; j < set->count(); ++j) {
153             SkString sname;
154             SkFontStyle fs;
155             set->getStyle(j, &fs, &sname);
156 
157             sk_sp<SkTypeface> typeface(set->createTypeface(j));
158 
159             SkString familyName;
160             typeface->getFamilyName(&familyName);
161             if (verbose) {
162                 SkDebugf("[%s]\n", familyName.c_str());
163             }
164 
165             sk_sp<SkTypeface::LocalizedStrings> familyNamesIter(
166                 typeface->createFamilyNameIterator());
167             SkTypeface::LocalizedString familyNameLocalized;
168             while (familyNamesIter->next(&familyNameLocalized)) {
169                 if (verbose) {
170                     SkDebugf("(%s) <%s>\n", familyNameLocalized.fString.c_str(),
171                                             familyNameLocalized.fLanguage.c_str());
172                 }
173             }
174 
175             size_t nameTableSize = typeface->getTableSize(nameTag);
176             if (0 == nameTableSize) {
177                 continue;
178             }
179             SkAutoTMalloc<uint8_t> nameTableData(nameTableSize);
180             size_t copied = typeface->getTableData(nameTag, 0, nameTableSize, nameTableData.get());
181             if (copied != nameTableSize) {
182                 continue;
183             }
184 
185             SkOTTableName::Iterator::Record record;
186             SkOTTableName::Iterator familyNameIter(nameTableData.get(), nameTableSize,
187                 SkOTTableName::Record::NameID::Predefined::FontFamilyName);
188             while (familyNameIter.next(record)) {
189                 REPORTER_ASSERT(
190                         reporter,
191                         SkOTTableName::Record::NameID::Predefined::FontFamilyName == record.type,
192                         "Requested family name, got something else.");
193                 if (verbose) {
194                     SkDebugf("{%s} <%s>\n", record.name.c_str(), record.language.c_str());
195                 }
196             }
197 
198             SkOTTableName::Iterator styleNameIter(nameTableData.get(), nameTableSize,
199                 SkOTTableName::Record::NameID::Predefined::FontSubfamilyName);
200             while (styleNameIter.next(record)) {
201                 REPORTER_ASSERT(
202                         reporter,
203                         SkOTTableName::Record::NameID::Predefined::FontSubfamilyName == record.type,
204                         "Requested subfamily name, got something else.");
205                 if (verbose) {
206                     SkDebugf("{{%s}} <%s>\n", record.name.c_str(), record.language.c_str());
207                 }
208             }
209 
210             if (verbose) {
211                 SkDebugf("\n");
212             }
213         }
214     }
215 }
216 
217 } // namespace
218 
219 static DEFINE_bool(verboseFontNames, false, "verbose FontNames test.");
220 
DEF_TEST(FontNames,reporter)221 DEF_TEST(FontNames, reporter) {
222     test_synthetic(reporter, FLAGS_verboseFontNames);
223     test_systemfonts(reporter, FLAGS_verboseFontNames);
224 }
225