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