blob: 64b7f0417e4a43d7b364862f84e817b1e0d53f7a [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/core/SkFontMgr.h"
Kevin Lubick8c73a592022-10-17 15:25:35 -04009#include "include/core/SkFontStyle.h"
10#include "include/core/SkRefCnt.h"
11#include "include/core/SkString.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "include/core/SkTypeface.h"
Kevin Lubick8c73a592022-10-17 15:25:35 -040013#include "include/core/SkTypes.h"
Kevin Lubick86f7b2d2023-02-01 08:36:05 -050014#include "include/private/base/SkDebug.h"
Brian Osmana8c24d42023-02-27 11:23:54 -050015#include "include/private/base/SkTemplates.h"
Kevin Lubick171ecb32023-03-22 13:55:55 -040016#include "src/base/SkEndian.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050017#include "src/sfnt/SkOTTable_name.h"
18#include "tests/Test.h"
19#include "tools/flags/CommandLineFlags.h"
bungeman@google.com07a69f82013-04-02 14:12:38 +000020
Kevin Lubick8c73a592022-10-17 15:25:35 -040021#include <algorithm>
22#include <cstddef>
23#include <cstdint>
24#include <cstring>
bungeman@google.com07a69f82013-04-02 14:12:38 +000025
Herb Derbyf7e2ca22022-11-30 10:10:49 -050026using namespace skia_private;
27
Ben Wagnerad031f52018-08-20 13:45:57 -040028namespace {
29
bungeman@google.com07a69f82013-04-02 14:12:38 +000030template <size_t R, size_t D> struct Format0NameTable {
31 SkOTTableName header;
32 SkOTTableName::Record nameRecord[R];
33 char data[D];
34};
35
36template <size_t R, size_t L, size_t D> struct Format1NameTable {
37 SkOTTableName header;
38 SkOTTableName::Record nameRecord[R];
39 struct {
40 SkOTTableName::Format1Ext header;
41 SkOTTableName::Format1Ext::LangTagRecord langTagRecord[L];
42 } format1ext;
43 char data[D];
44};
45
46typedef Format0NameTable<1, 9> SimpleFormat0NameTable;
Ben Wagnerad031f52018-08-20 13:45:57 -040047constexpr SimpleFormat0NameTable simpleFormat0NameTable = {
bungeman@google.com07a69f82013-04-02 14:12:38 +000048 /*header*/ {
49 /*format*/ SkOTTableName::format_0,
50 /*count*/ SkTEndianSwap16<1>::value,
51 /*stringOffset*/ SkTEndianSwap16<offsetof(SimpleFormat0NameTable, data)>::value,
52 },
53 /*nameRecord[]*/ {
54 /*Record*/ {
55 /*platformID*/ { SkOTTableName::Record::PlatformID::Windows },
56 /*encodingID*/ { SkOTTableName::Record::EncodingID::Windows::UnicodeBMPUCS2 },
57 /*languageID*/ { SkOTTableName::Record::LanguageID::Windows::English_UnitedStates },
58 /*nameID*/ { SkOTTableName::Record::NameID::Predefined::FontFamilyName },
59 /*length*/ SkTEndianSwap16<8>::value,
60 /*offset*/ SkTEndianSwap16<0>::value,
61 }
62 },
63 /*data*/ "\x0" "T" "\x0" "e" "\x0" "s" "\x0" "t",
64};
65
66typedef Format1NameTable<1, 1, 19> SimpleFormat1NameTable;
Ben Wagnerad031f52018-08-20 13:45:57 -040067constexpr SimpleFormat1NameTable simpleFormat1NameTable = {
bungeman@google.com07a69f82013-04-02 14:12:38 +000068 /*header*/ {
69 /*format*/ SkOTTableName::format_1,
70 /*count*/ SkTEndianSwap16<1>::value,
71 /*stringOffset*/ SkTEndianSwap16<offsetof(SimpleFormat1NameTable, data)>::value,
72 },
73 /*nameRecord[]*/ {
74 /*Record*/ {
75 /*platformID*/ { SkOTTableName::Record::PlatformID::Windows },
76 /*encodingID*/ { SkOTTableName::Record::EncodingID::Windows::UnicodeBMPUCS2 },
77 /*languageID*/ { SkTEndianSwap16<0x8000 + 0>::value },
78 /*nameID*/ { SkOTTableName::Record::NameID::Predefined::FontFamilyName },
79 /*length*/ SkTEndianSwap16<8>::value,
80 /*offset*/ SkTEndianSwap16<0>::value,
81 }
82 },
83 /*format1ext*/ {
84 /*header*/ {
85 /*langTagCount*/ SkTEndianSwap16<1>::value,
86 },
87 /*langTagRecord[]*/ {
88 /*LangTagRecord*/ {
89 /*length*/ SkTEndianSwap16<10>::value,
90 /*offset*/ SkTEndianSwap16<8>::value,
91 },
92 },
93 },
94 /*data*/ "\x0" "T" "\x0" "e" "\x0" "s" "\x0" "t"
95 "\x0" "e" "\x0" "n" "\x0" "-" "\x0" "U" "\x0" "S",
96};
97
98struct FontNamesTest {
Ben Wagnerad031f52018-08-20 13:45:57 -040099 const uint8_t* data;
100 size_t size;
bungeman@google.com07a69f82013-04-02 14:12:38 +0000101 SkOTTableName::Record::NameID nameID;
102 size_t nameCount;
103 struct {
104 const char* name;
105 const char* language;
106 } names[10];
107
Ben Wagnerad031f52018-08-20 13:45:57 -0400108} tests[] = {
bungeman@google.com07a69f82013-04-02 14:12:38 +0000109 {
Ben Wagnerad031f52018-08-20 13:45:57 -0400110 reinterpret_cast<const uint8_t*>(&simpleFormat0NameTable),
111 sizeof(simpleFormat0NameTable),
bungeman@google.com07a69f82013-04-02 14:12:38 +0000112 { SkOTTableName::Record::NameID::Predefined::FontFamilyName },
113 1,
114 {
115 { "Test", "en-US" },
116 },
117 },
118 {
Ben Wagnerad031f52018-08-20 13:45:57 -0400119 reinterpret_cast<const uint8_t*>(&simpleFormat1NameTable),
120 sizeof(simpleFormat1NameTable),
bungeman@google.com07a69f82013-04-02 14:12:38 +0000121 { SkOTTableName::Record::NameID::Predefined::FontFamilyName },
122 1,
123 {
124 { "Test", "en-US" },
125 },
126 },
127};
128
bungeman@google.coma9802692013-08-07 02:45:25 +0000129static void test_synthetic(skiatest::Reporter* reporter, bool verbose) {
Ben Wagnerad031f52018-08-20 13:45:57 -0400130 for (const auto& test : tests) {
131 SkOTTableName::Iterator iter(test.data, test.size, test.nameID.predefined.value);
bungeman@google.com07a69f82013-04-02 14:12:38 +0000132 SkOTTableName::Iterator::Record record;
133 size_t nameIndex = 0;
Ben Wagnerad031f52018-08-20 13:45:57 -0400134 while (nameIndex < test.nameCount && iter.next(record)) {
Brian Salomon1c80e992018-01-29 09:50:47 -0500135 REPORTER_ASSERT(reporter,
Ben Wagnerad031f52018-08-20 13:45:57 -0400136 strcmp(test.names[nameIndex].name, record.name.c_str()) == 0,
Brian Salomon1c80e992018-01-29 09:50:47 -0500137 "Name did not match.");
bungeman@google.com07a69f82013-04-02 14:12:38 +0000138
Brian Salomon1c80e992018-01-29 09:50:47 -0500139 REPORTER_ASSERT(reporter,
Ben Wagnerad031f52018-08-20 13:45:57 -0400140 strcmp(test.names[nameIndex].language, record.language.c_str()) == 0,
Brian Salomon1c80e992018-01-29 09:50:47 -0500141 "Language did not match.");
bungeman@google.com07a69f82013-04-02 14:12:38 +0000142
Ben Wagnerad031f52018-08-20 13:45:57 -0400143 if (verbose) {
144 SkDebugf("%s <%s>\n", record.name.c_str(), record.language.c_str());
145 }
bungeman@google.com07a69f82013-04-02 14:12:38 +0000146
147 ++nameIndex;
148 }
149
Ben Wagnerad031f52018-08-20 13:45:57 -0400150 REPORTER_ASSERT(reporter, nameIndex == test.nameCount, "Fewer names than expected.");
bungeman@google.com07a69f82013-04-02 14:12:38 +0000151
Brian Salomon1c80e992018-01-29 09:50:47 -0500152 REPORTER_ASSERT(reporter, !iter.next(record), "More names than expected.");
bungeman@google.com07a69f82013-04-02 14:12:38 +0000153 }
154}
155
bungeman@google.coma9802692013-08-07 02:45:25 +0000156#define MAX_FAMILIES 1000
157static void test_systemfonts(skiatest::Reporter* reporter, bool verbose) {
158 static const SkFontTableTag nameTag = SkSetFourByteTag('n','a','m','e');
159
Hal Canary342b7ac2016-11-04 11:49:42 -0400160 sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
Brian Osman7f364052020-02-06 11:25:43 -0500161 int count = std::min(fm->countFamilies(), MAX_FAMILIES);
bungeman@google.coma9802692013-08-07 02:45:25 +0000162 for (int i = 0; i < count; ++i) {
Hal Canary342b7ac2016-11-04 11:49:42 -0400163 sk_sp<SkFontStyleSet> set(fm->createStyleSet(i));
bungeman@google.coma9802692013-08-07 02:45:25 +0000164 for (int j = 0; j < set->count(); ++j) {
165 SkString sname;
166 SkFontStyle fs;
167 set->getStyle(j, &fs, &sname);
168
Hal Canary342b7ac2016-11-04 11:49:42 -0400169 sk_sp<SkTypeface> typeface(set->createTypeface(j));
bungeman@google.coma9802692013-08-07 02:45:25 +0000170
171 SkString familyName;
172 typeface->getFamilyName(&familyName);
173 if (verbose) {
bungeman@google.comfab44db2013-10-11 18:50:45 +0000174 SkDebugf("[%s]\n", familyName.c_str());
bungeman@google.coma9802692013-08-07 02:45:25 +0000175 }
176
Hal Canary342b7ac2016-11-04 11:49:42 -0400177 sk_sp<SkTypeface::LocalizedStrings> familyNamesIter(
bungeman@google.com839702b2013-08-07 17:09:22 +0000178 typeface->createFamilyNameIterator());
bungeman@google.coma9802692013-08-07 02:45:25 +0000179 SkTypeface::LocalizedString familyNameLocalized;
180 while (familyNamesIter->next(&familyNameLocalized)) {
181 if (verbose) {
bungeman@google.comfab44db2013-10-11 18:50:45 +0000182 SkDebugf("(%s) <%s>\n", familyNameLocalized.fString.c_str(),
bungemana6785cc2014-08-25 12:00:49 -0700183 familyNameLocalized.fLanguage.c_str());
bungeman@google.coma9802692013-08-07 02:45:25 +0000184 }
185 }
186
187 size_t nameTableSize = typeface->getTableSize(nameTag);
188 if (0 == nameTableSize) {
189 continue;
190 }
Herb Derbyf7e2ca22022-11-30 10:10:49 -0500191 AutoTMalloc<uint8_t> nameTableData(nameTableSize);
bungeman@google.coma9802692013-08-07 02:45:25 +0000192 size_t copied = typeface->getTableData(nameTag, 0, nameTableSize, nameTableData.get());
193 if (copied != nameTableSize) {
194 continue;
195 }
196
197 SkOTTableName::Iterator::Record record;
Ben Wagnerad031f52018-08-20 13:45:57 -0400198 SkOTTableName::Iterator familyNameIter(nameTableData.get(), nameTableSize,
bungeman@google.coma9802692013-08-07 02:45:25 +0000199 SkOTTableName::Record::NameID::Predefined::FontFamilyName);
200 while (familyNameIter.next(record)) {
Brian Salomon1c80e992018-01-29 09:50:47 -0500201 REPORTER_ASSERT(
202 reporter,
203 SkOTTableName::Record::NameID::Predefined::FontFamilyName == record.type,
204 "Requested family name, got something else.");
bungeman@google.coma9802692013-08-07 02:45:25 +0000205 if (verbose) {
bungeman@google.comfab44db2013-10-11 18:50:45 +0000206 SkDebugf("{%s} <%s>\n", record.name.c_str(), record.language.c_str());
bungeman@google.coma9802692013-08-07 02:45:25 +0000207 }
208 }
209
Ben Wagnerad031f52018-08-20 13:45:57 -0400210 SkOTTableName::Iterator styleNameIter(nameTableData.get(), nameTableSize,
bungeman@google.coma9802692013-08-07 02:45:25 +0000211 SkOTTableName::Record::NameID::Predefined::FontSubfamilyName);
212 while (styleNameIter.next(record)) {
Brian Salomon1c80e992018-01-29 09:50:47 -0500213 REPORTER_ASSERT(
214 reporter,
215 SkOTTableName::Record::NameID::Predefined::FontSubfamilyName == record.type,
216 "Requested subfamily name, got something else.");
bungeman@google.coma9802692013-08-07 02:45:25 +0000217 if (verbose) {
bungeman@google.comfab44db2013-10-11 18:50:45 +0000218 SkDebugf("{{%s}} <%s>\n", record.name.c_str(), record.language.c_str());
bungeman@google.coma9802692013-08-07 02:45:25 +0000219 }
220 }
221
222 if (verbose) {
bungeman@google.comfab44db2013-10-11 18:50:45 +0000223 SkDebugf("\n");
bungeman@google.coma9802692013-08-07 02:45:25 +0000224 }
225 }
226 }
227}
228
Ben Wagnerad031f52018-08-20 13:45:57 -0400229} // namespace
230
Mike Klein84836b72019-03-21 11:31:36 -0500231static DEFINE_bool(verboseFontNames, false, "verbose FontNames test.");
bungeman@google.coma9802692013-08-07 02:45:25 +0000232
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +0000233DEF_TEST(FontNames, reporter) {
bungeman@google.coma9802692013-08-07 02:45:25 +0000234 test_synthetic(reporter, FLAGS_verboseFontNames);
235 test_systemfonts(reporter, FLAGS_verboseFontNames);
236}