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
16template <size_t R, size_t D> struct Format0NameTable {
17    SkOTTableName header;
18    SkOTTableName::Record nameRecord[R];
19    char data[D];
20};
21
22template <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
32typedef Format0NameTable<1, 9> SimpleFormat0NameTable;
33SimpleFormat0NameTable 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
52typedef Format1NameTable<1, 1, 19> SimpleFormat1NameTable;
53SimpleFormat1NameTable 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
84struct 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
112static 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
142static 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
156            SkString familyName;
157            typeface->getFamilyName(&familyName);
158            if (verbose) {
159                SkDebugf("[%s]\n", familyName.c_str());
160            }
161
162            SkAutoTUnref<SkTypeface::LocalizedStrings> familyNamesIter(
163                typeface->createFamilyNameIterator());
164            SkTypeface::LocalizedString familyNameLocalized;
165            while (familyNamesIter->next(&familyNameLocalized)) {
166                if (verbose) {
167                    SkDebugf("(%s) <%s>\n", familyNameLocalized.fString.c_str(),
168                                            familyNameLocalized.fLanguage.c_str());
169                }
170            }
171
172            size_t nameTableSize = typeface->getTableSize(nameTag);
173            if (0 == nameTableSize) {
174                continue;
175            }
176            SkAutoTMalloc<uint8_t> nameTableData(nameTableSize);
177            size_t copied = typeface->getTableData(nameTag, 0, nameTableSize, nameTableData.get());
178            if (copied != nameTableSize) {
179                continue;
180            }
181
182            SkOTTableName::Iterator::Record record;
183            SkOTTableName::Iterator familyNameIter(*((SkOTTableName*)nameTableData.get()),
184                SkOTTableName::Record::NameID::Predefined::FontFamilyName);
185            while (familyNameIter.next(record)) {
186                REPORTER_ASSERT_MESSAGE(reporter,
187                    SkOTTableName::Record::NameID::Predefined::FontFamilyName == record.type,
188                    "Requested family name, got something else."
189                );
190                if (verbose) {
191                    SkDebugf("{%s} <%s>\n", record.name.c_str(), record.language.c_str());
192                }
193            }
194
195            SkOTTableName::Iterator styleNameIter(*((SkOTTableName*)nameTableData.get()),
196                SkOTTableName::Record::NameID::Predefined::FontSubfamilyName);
197            while (styleNameIter.next(record)) {
198                REPORTER_ASSERT_MESSAGE(reporter,
199                    SkOTTableName::Record::NameID::Predefined::FontSubfamilyName == record.type,
200                    "Requested subfamily name, got something else."
201                );
202                if (verbose) {
203                    SkDebugf("{{%s}} <%s>\n", record.name.c_str(), record.language.c_str());
204                }
205            }
206
207            if (verbose) {
208                SkDebugf("\n");
209            }
210        }
211    }
212}
213
214DEFINE_bool(verboseFontNames, false, "verbose FontNames test.");
215
216DEF_TEST(FontNames, reporter) {
217    test_synthetic(reporter, FLAGS_verboseFontNames);
218    test_systemfonts(reporter, FLAGS_verboseFontNames);
219}
220