Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
ShaperTest.cpp
Go to the documentation of this file.
1// Copyright 2019 Google LLC.
2// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
3
4#include "tests/Test.h"
5
10#include "include/core/SkSpan.h"
19#include "src/base/SkZip.h"
20#include "tools/Resources.h"
22
23#include <cinttypes>
24#include <cstdint>
25#include <memory>
26
27#if defined(SK_UNICODE_ICU_IMPLEMENTATION)
29#endif
30
31#if defined(SK_UNICODE_LIBGRAPHEME_IMPLEMENTATION)
33#endif
34
35#if defined(SK_UNICODE_ICU4X_IMPLEMENTATION)
37#endif
38
39namespace {
40
42#if defined(SK_UNICODE_ICU_IMPLEMENTATION)
43 if (auto unicode = SkUnicodes::ICU::Make()) {
44 return unicode;
45 }
46#endif // defined(SK_UNICODE_ICU_IMPLEMENTATION)
47#if defined(SK_UNICODE_LIBGRAPHEME_IMPLEMENTATION)
48 if (auto unicode = SkUnicodes::Libgrapheme::Make()) {
49 return unicode;
50 }
51#endif
52#if defined(SK_UNICODE_ICU4X_IMPLEMENTATION)
53 if (auto unicode = SkUnicodes::ICU4X::Make()) {
54 return unicode;
55 }
56#endif
57 return nullptr;
58}
59
60struct RunHandler final : public SkShaper::RunHandler {
61 const char* fResource;
62 skiatest::Reporter* fReporter;
63 const char* fUtf8;
64 size_t fUtf8Size;
65 std::unique_ptr<SkGlyphID[]> fGlyphs;
66 std::unique_ptr<SkPoint[]> fPositions;
67 std::unique_ptr<uint32_t[]> fClusters;
69 unsigned fGlyphCount = 0;
70
71 bool fBeginLine = false;
72 bool fCommitRunInfo = false;
73 bool fCommitLine = false;
74
75 RunHandler(const char* resource, skiatest::Reporter* reporter, const char* utf8,size_t utf8Size)
76 : fResource(resource), fReporter(reporter), fUtf8(utf8), fUtf8Size(utf8Size) {}
77
78 void beginLine() override { fBeginLine = true;}
79 void runInfo(const SkShaper::RunHandler::RunInfo& info) override {}
80 void commitRunInfo() override { fCommitRunInfo = true; }
82 fGlyphCount = SkToUInt(info.glyphCount);
83 fRange = info.utf8Range;
84 fGlyphs = std::make_unique<SkGlyphID[]>(info.glyphCount);
85 fPositions = std::make_unique<SkPoint[]>(info.glyphCount);
86 fClusters = std::make_unique<uint32_t[]>(info.glyphCount);
87 return SkShaper::RunHandler::Buffer{fGlyphs.get(),
88 fPositions.get(),
89 nullptr,
90 fClusters.get(),
91 {0, 0}};
92 }
93 void commitRunBuffer(const RunInfo& info) override {
94 REPORTER_ASSERT(fReporter, fGlyphCount == info.glyphCount, "%s", fResource);
95 REPORTER_ASSERT(fReporter, fRange.begin() == info.utf8Range.begin(), "%s", fResource);
96 REPORTER_ASSERT(fReporter, fRange.size() == info.utf8Range.size(), "%s", fResource);
97 if (!(fRange.begin() + fRange.size() <= fUtf8Size)) {
98 REPORTER_ASSERT(fReporter, fRange.begin() + fRange.size() <= fUtf8Size, "%s",fResource);
99 return;
100 }
101
102 if ((false)) {
103 SkString familyName;
104 SkString postscriptName;
105 SkTypeface* typeface = info.fFont.getTypeface();
106 int ttcIndex = 0;
107 size_t fontSize = 0;
108 if (typeface) {
109 typeface->getFamilyName(&familyName);
110 typeface->getPostScriptName(&postscriptName);
111 std::unique_ptr<SkStreamAsset> stream = typeface->openStream(&ttcIndex);
112 if (stream) {
113 fontSize = stream->getLength();
114 }
115 }
117 for (auto&& [glyph, cluster] : SkZip(info.glyphCount, fGlyphs.get(), fClusters.get())) {
118 glyphs.appendU32(glyph);
119 glyphs.append(":");
120 glyphs.appendU32(cluster);
121 glyphs.append(" ");
122 }
123 SkString chars;
124 for (const char c : SkSpan(fUtf8 + fRange.begin(), fRange.size())) {
125 chars.appendHex((unsigned char)c, 2);
126 chars.append(" ");
127 }
128 SkDebugf(
129 "%s range: %zu-%zu(%zu) glyphCount:%u font: \"%s\" \"%s\" #%d %zuB\n"
130 "rangeText: \"%.*s\"\n"
131 "rangeBytes: %s\n"
132 "glyphs:%s\n\n",
133 fResource, fRange.begin(), fRange.end(), fRange.size(), fGlyphCount,
134 familyName.c_str(), postscriptName.c_str(), ttcIndex, fontSize,
135 (int)fRange.size(), fUtf8 + fRange.begin(),
136 chars.c_str(),
137 glyphs.c_str());
138 }
139
140 for (unsigned i = 0; i < fGlyphCount; ++i) {
141 REPORTER_ASSERT(fReporter, fClusters[i] >= fRange.begin(),
142 "%" PRIu32 " >= %zu %s i:%u glyphCount:%u",
143 fClusters[i], fRange.begin(), fResource, i, fGlyphCount);
144 REPORTER_ASSERT(fReporter, fClusters[i] < fRange.end(),
145 "%" PRIu32 " < %zu %s i:%u glyphCount:%u",
146 fClusters[i], fRange.end(), fResource, i, fGlyphCount);
147 }
148 }
149 void commitLine() override { fCommitLine = true; }
150};
151
152#if defined(SK_SHAPER_HARFBUZZ_AVAILABLE) && defined(SK_SHAPER_UNICODE_AVAILABLE)
153void shaper_test(skiatest::Reporter* reporter, const char* name, SkData* data) {
155 auto unicode = get_unicode();
156 if (!unicode) {
157 ERRORF(reporter, "Could not create unicode.");
158 return;
159 }
160
161 auto shaper = SkShapers::HB::ShaperDrivenWrapper(unicode,
162 SkFontMgr::RefEmpty()); // no fallback
163 if (!shaper) {
164 ERRORF(reporter, "Could not create shaper.");
165 return;
166 }
167 if (!unicode) {
168 ERRORF(reporter, "Could not create unicode.");
169 return;
170 }
171 constexpr float kWidth = 400;
173 const char* utf8 = (const char*)data->data();
174 size_t utf8Bytes = data->size();
175
176 RunHandler rh(name, reporter, utf8, utf8Bytes);
177
178 const SkBidiIterator::Level defaultLevel = SkBidiIterator::kLTR;
179 std::unique_ptr<SkShaper::BiDiRunIterator> bidi =
180 SkShapers::unicode::BidiRunIterator(unicode, utf8, utf8Bytes, defaultLevel);
181 SkASSERT(bidi);
182
183 std::unique_ptr<SkShaper::LanguageRunIterator> language =
185 SkASSERT(language);
186
187 std::unique_ptr<SkShaper::ScriptRunIterator> script =
188 SkShapers::HB::ScriptRunIterator(utf8, utf8Bytes);
189 SkASSERT(script);
190
191 std::unique_ptr<SkShaper::FontRunIterator> fontRuns =
193 SkASSERT(fontRuns);
194 shaper->shape(utf8, utf8Bytes, *fontRuns, *bidi, *script, *language, nullptr, 0, kWidth, &rh);
195
196 // Even on empty input, expect that the line is started, that the zero run infos are committed,
197 // and the empty line is committed. This allows the user to properly handle empty runs.
198 REPORTER_ASSERT(reporter, rh.fBeginLine);
199 REPORTER_ASSERT(reporter, rh.fCommitRunInfo);
200 REPORTER_ASSERT(reporter, rh.fCommitLine);
201
202 constexpr SkFourByteTag latn = SkSetFourByteTag('l','a','t','n');
203 auto fontIterator = SkShaper::TrivialFontRunIterator(font, data->size());
204 auto bidiIterator = SkShaper::TrivialBiDiRunIterator(0, data->size());
205 auto scriptIterator = SkShaper::TrivialScriptRunIterator(latn, data->size());
206 auto languageIterator = SkShaper::TrivialLanguageRunIterator("en-US", data->size());
207 shaper->shape((const char*)data->data(),
208 data->size(),
209 fontIterator,
210 bidiIterator,
211 scriptIterator,
212 languageIterator,
213 nullptr,
214 0,
215 kWidth,
216 &rh);
217}
218
219void cluster_test(skiatest::Reporter* reporter, const char* resource) {
220 auto data = GetResourceAsData(resource);
221 if (!data) {
222 ERRORF(reporter, "Could not get resource %s.", resource);
223 return;
224 }
225
226 shaper_test(reporter, resource, data.get());
227}
228
229#endif // defined(SK_SHAPER_HARFBUZZ_AVAILABLE) && defined(SK_SHAPER_UNICODE_AVAILABLE)
230
231} // namespace
232
233#if defined(SK_SHAPER_HARFBUZZ_AVAILABLE) && defined(SK_SHAPER_UNICODE_AVAILABLE)
234
235DEF_TEST(Shaper_cluster_empty, r) { shaper_test(r, "empty", SkData::MakeEmpty().get()); }
236
237#define SHAPER_TEST(X) DEF_TEST(Shaper_cluster_ ## X, r) { cluster_test(r, "text/" #X ".txt"); }
238SHAPER_TEST(arabic)
239SHAPER_TEST(armenian)
240SHAPER_TEST(balinese)
241SHAPER_TEST(buginese)
242SHAPER_TEST(cherokee)
243SHAPER_TEST(cyrillic)
244SHAPER_TEST(emoji)
245SHAPER_TEST(english)
246SHAPER_TEST(ethiopic)
247SHAPER_TEST(greek)
248SHAPER_TEST(hangul)
249SHAPER_TEST(han_simplified)
250SHAPER_TEST(han_traditional)
251SHAPER_TEST(hebrew)
252SHAPER_TEST(javanese)
253SHAPER_TEST(kana)
254SHAPER_TEST(lao)
255SHAPER_TEST(mandaic)
256SHAPER_TEST(newtailue)
257SHAPER_TEST(nko)
258SHAPER_TEST(sinhala)
259SHAPER_TEST(sundanese)
260SHAPER_TEST(syriac)
261SHAPER_TEST(thaana)
262SHAPER_TEST(thai)
263SHAPER_TEST(tibetan)
264SHAPER_TEST(tifnagh)
265SHAPER_TEST(vai)
266SHAPER_TEST(bengali)
267SHAPER_TEST(devanagari)
268SHAPER_TEST(khmer)
269SHAPER_TEST(myanmar)
270SHAPER_TEST(taitham)
271SHAPER_TEST(tamil)
272#undef SHAPER_TEST
273
274#endif // #if defined(SK_SHAPER_HARFBUZZ_AVAILABLE) && defined(SK_SHAPER_UNICODE_AVAILABLE)
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
reporter
uint16_t glyphs[5]
sk_sp< SkData > GetResourceAsData(const char *resource)
Definition Resources.cpp:42
#define SkASSERT(cond)
Definition SkAssert.h:116
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
constexpr unsigned SkToUInt(S x)
Definition SkTo.h:30
uint32_t SkFourByteTag
Definition SkTypes.h:166
static constexpr SkFourByteTag SkSetFourByteTag(char a, char b, char c, char d)
Definition SkTypes.h:167
#define DEF_TEST(name, reporter)
Definition Test.h:312
#define REPORTER_ASSERT(r, cond,...)
Definition Test.h:286
#define ERRORF(r,...)
Definition Test.h:293
uint8_t Level
Definition SkUnicode.h:46
static sk_sp< SkData > MakeEmpty()
Definition SkData.cpp:94
static sk_sp< SkFontMgr > RefEmpty()
virtual void commitLine()=0
Definition shape.cpp:201
virtual void commitRunBuffer(const RunInfo &)=0
Definition shape.cpp:176
virtual void commitRunInfo()=0
Definition shape.cpp:150
virtual void runInfo(const RunInfo &)=0
Definition shape.cpp:142
virtual void beginLine()=0
Definition shape.cpp:135
virtual Buffer runBuffer(const RunInfo &)=0
Definition shape.cpp:154
static std::unique_ptr< FontRunIterator > MakeFontMgrRunIterator(const char *utf8, size_t utf8Bytes, const SkFont &font, sk_sp< SkFontMgr > fallback)
Definition SkShaper.cpp:187
static std::unique_ptr< LanguageRunIterator > MakeStdLanguageRunIterator(const char *utf8, size_t utf8Bytes)
Definition SkShaper.cpp:204
void append(const char text[])
Definition SkString.h:203
void appendHex(uint32_t value, int minDigits=0)
Definition SkString.h:212
void appendU32(uint32_t value)
Definition SkString.h:210
const char * c_str() const
Definition SkString.h:133
void getFamilyName(SkString *name) const
bool getPostScriptName(SkString *name) const
std::unique_ptr< SkStreamAsset > openStream(int *ttcIndex) const
Definition SkZip.h:25
static const char * begin(const StringSlice &s)
Definition editor.cpp:252
const char * name
Definition fuchsia.cc:50
SKSHAPER_API std::unique_ptr< SkShaper > ShaperDrivenWrapper(sk_sp< SkUnicode > unicode, sk_sp< SkFontMgr > fallback)
SKSHAPER_API std::unique_ptr< SkShaper::ScriptRunIterator > ScriptRunIterator(const char *utf8, size_t utf8Bytes)
SKSHAPER_API std::unique_ptr< SkShaper::BiDiRunIterator > BidiRunIterator(sk_sp< SkUnicode > unicode, const char *utf8, size_t utf8Bytes, uint8_t bidiLevel)
SKUNICODE_API sk_sp< SkUnicode > Make()
SKUNICODE_API sk_sp< SkUnicode > Make()
SKUNICODE_API sk_sp< SkUnicode > Make()
SkFont DefaultFont()
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition switches.h:41
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition switches.h:259
font
Font Metadata and Metrics.
const myers::Point & get(const myers::Segment &)
static sk_sp< SkUnicode > get_unicode()
constexpr size_t size() const
Definition SkShaper.h:200
constexpr size_t begin() const
Definition SkShaper.h:198
constexpr size_t end() const
Definition SkShaper.h:199
constexpr size_t kWidth