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