1 /*
2 * Copyright 2023 Google LLC
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 "tools/TestFontDataProvider.h"
9
10 #include "include/core/SkData.h"
11 #include "include/private/base/SkDebug.h"
12 #include "src/utils/SkOSPath.h"
13 #include "tools/flags/CommandLineFlags.h"
14
15 const char kTestDataJsonFilename[] = "raster_test.json";
16 const char kTestDataBasePath[] = "third_party/externals/googlefonts_testdata/data/";
17
18 std::atomic<const char*> gFontTestDataBasePath{kTestDataBasePath};
19
20 namespace skiatest {
21 static DEFINE_string(fontTestDataPath,
22 "",
23 "Path to extracted data from googlefonts_testdata CIPD file.");
24
SetFontTestDataDirectory()25 void SetFontTestDataDirectory() {
26 if (FLAGS_fontTestDataPath.isEmpty()) {
27 return;
28 }
29 if (strlen(FLAGS_fontTestDataPath[0])) {
30 gFontTestDataBasePath = FLAGS_fontTestDataPath[0];
31 }
32 }
33 } // namespace skiatest
34
35 #if defined(SK_DEBUG)
36 // Change size when rolling / changing googlefonts_testdata CIPD, see bin/fetch-fonts-testdata.
37 constexpr size_t kExpectNumFonts = 51;
38 #endif
39
40 namespace {
prefixWithTestDataPath(SkString suffix)41 SkString prefixWithTestDataPath(SkString suffix) {
42 return SkOSPath::Join(gFontTestDataBasePath, suffix.c_str());
43 }
44
prefixWithFontsPath(SkString suffix)45 SkString prefixWithFontsPath(SkString suffix) {
46 SkString fontsPath = prefixWithTestDataPath(SkString("fonts"));
47 return SkOSPath::Join(fontsPath.c_str(), suffix.c_str());
48 }
49
50 } // namespace
51
TestFontDataProvider(const std::string & fontFilterRegexp,const std::string & langFilterRegexp)52 TestFontDataProvider::TestFontDataProvider(const std::string& fontFilterRegexp,
53 const std::string& langFilterRegexp)
54 : fFontFilter(fontFilterRegexp), fLangFilter(langFilterRegexp) {
55 SkString testDataLocation = prefixWithTestDataPath(SkString(kTestDataJsonFilename));
56 sk_sp<SkData> jsonTestData = SkData::MakeFromFileName(testDataLocation.c_str());
57 SkASSERTF(jsonTestData && jsonTestData->size(),
58 "Unable to access font test metadata at location %s, check bin/fetch-fonts-testdata.",
59 testDataLocation.c_str());
60 fJsonDom = std::make_unique<skjson::DOM>(reinterpret_cast<const char*>(jsonTestData->bytes()),
61 jsonTestData->size());
62 const skjson::ObjectValue& root = fJsonDom->root().as<skjson::ObjectValue>();
63 fFonts = root["fonts"];
64 SkASSERT(fFonts);
65 SkASSERTF(fFonts->size() == kExpectNumFonts,
66 "Unable to access all %zu test fonts (only got %zu), check bin/fetch-fonts-testdata.",
67 kExpectNumFonts,
68 fFonts->size());
69 fSamples = root["samples"];
70 SkASSERT(fSamples);
71 }
72
next(TestSet * testSet)73 bool TestFontDataProvider::next(TestSet* testSet) {
74 while (testSet && fFontsIndex < fFonts->size()) {
75 const skjson::ObjectValue* fontsEntry = (*fFonts)[fFontsIndex++];
76 SkASSERT(fontsEntry);
77 const skjson::StringValue* fontName = (*fontsEntry)["name"];
78 SkASSERT(fontName);
79 std::smatch match;
80 std::string fontNameStr(fontName->str());
81 if (std::regex_match(fontNameStr, match, fFontFilter)) {
82 testSet->fontName = SkString(fontNameStr);
83 const skjson::StringValue* fontFilename = (*fontsEntry)["path"];
84 testSet->fontFilename = prefixWithFontsPath(
85 SkString(fontFilename->str().data(), fontFilename->str().size()));
86 testSet->langSamples =
87 getLanguageSamples((*fontsEntry)["languages"].as<skjson::ArrayValue>());
88 return true;
89 }
90 }
91 return false;
92 }
93
rewind()94 void TestFontDataProvider::rewind() { fFontsIndex = 0; }
95
getLanguageSamples(const skjson::ArrayValue * languages)96 std::vector<TestFontDataProvider::LangSample> TestFontDataProvider::getLanguageSamples(
97 const skjson::ArrayValue* languages) {
98 std::vector<LangSample> samples;
99 for (size_t i = 0; i < languages->size(); ++i) {
100 const skjson::StringValue* langTag = (*languages)[i];
101 std::string langTagStr(langTag->str());
102 std::smatch match;
103 if (std::regex_match(langTagStr, match, fLangFilter)) {
104 const skjson::ObjectValue* sample = (*fSamples)[langTagStr.c_str()];
105 const skjson::StringValue* shortSample = (*sample)["short_sample"];
106 const skjson::StringValue* longSample = (*sample)["long_sample"];
107 SkString sampleShort(shortSample->str().data(), shortSample->str().size());
108 SkString sampleLong(longSample->str().data(), longSample->str().size());
109 samples.push_back({SkString(langTagStr), sampleShort, sampleLong});
110 }
111 }
112 SkASSERT_RELEASE(samples.size());
113 return samples;
114 }
115