Flutter Engine
The Flutter Engine
FontHostTest.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2012 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
12#include "include/core/SkRect.h"
21#include "src/base/SkEndian.h"
23#include "tests/Test.h"
24#include "tools/Resources.h"
26
27#include <cstdint>
28#include <cstring>
29#include <memory>
30#include <string>
31
32using namespace skia_private;
33
34//#define DUMP_TABLES
35//#define DUMP_TTC_TABLES
36
37#define kFontTableTag_head SkSetFourByteTag('h', 'e', 'a', 'd')
38#define kFontTableTag_hhea SkSetFourByteTag('h', 'h', 'e', 'a')
39#define kFontTableTag_maxp SkSetFourByteTag('m', 'a', 'x', 'p')
40
41static const struct TagSize {
43 size_t fSize;
44} gKnownTableSizes[] = {
45 { kFontTableTag_head, 54 },
46 { kFontTableTag_hhea, 36 },
47};
48
49// Test that getUnitsPerEm() agrees with a direct lookup in the 'head' table
50// (if that table is available).
52 int nativeUPEM = face->getUnitsPerEm();
53
54 int tableUPEM = -1;
55 size_t size = face->getTableSize(kFontTableTag_head);
56 if (size) {
57 // unitsPerEm is at offset 18 into the 'head' table.
58 uint16_t rawUPEM;
59 face->getTableData(kFontTableTag_head, 18, sizeof(rawUPEM), &rawUPEM);
60 tableUPEM = SkEndian_SwapBE16(rawUPEM);
61 }
62
63 if (tableUPEM >= 0) {
64 REPORTER_ASSERT(reporter, tableUPEM == nativeUPEM);
65 }
66}
67
68// Test that countGlyphs() agrees with a direct lookup in the 'maxp' table
69// (if that table is available).
71 int nativeGlyphs = face->countGlyphs();
72
73 int tableGlyphs = -1;
74 size_t size = face->getTableSize(kFontTableTag_maxp);
75 if (size) {
76 // glyphs is at offset 4 into the 'maxp' table.
77 uint16_t rawGlyphs;
78 face->getTableData(kFontTableTag_maxp, 4, sizeof(rawGlyphs), &rawGlyphs);
79 tableGlyphs = SkEndian_SwapBE16(rawGlyphs);
80 }
81
82 if (tableGlyphs >= 0) {
83 REPORTER_ASSERT(reporter, tableGlyphs == nativeGlyphs);
84 }
85}
86
88 int n = SkFontStream::GetTableTags(stream, ttcIndex, nullptr);
90
91 int n2 = SkFontStream::GetTableTags(stream, ttcIndex, array.get());
92 REPORTER_ASSERT(reporter, n == n2);
93
94 for (int i = 0; i < n; ++i) {
95#ifdef DUMP_TTC_TABLES
96 SkString str;
97 SkFontTableTag t = array[i];
98 str.appendUnichar((t >> 24) & 0xFF);
99 str.appendUnichar((t >> 16) & 0xFF);
100 str.appendUnichar((t >> 8) & 0xFF);
101 str.appendUnichar((t >> 0) & 0xFF);
102 SkDebugf("[%d:%d] '%s'\n", ttcIndex, i, str.c_str());
103#endif
104 size_t size = SkFontStream::GetTableSize(stream, ttcIndex, array[i]);
105 for (size_t j = 0; j < std::size(gKnownTableSizes); ++j) {
106 if (gKnownTableSizes[j].fTag == array[i]) {
108 }
109 }
110 }
111}
112
114 std::unique_ptr<SkStreamAsset> stream(GetResourceAsStream("fonts/test.ttc"));
115 if (!stream) {
116 SkDebugf("Skipping FontHostTest::test_fontstream\n");
117 return;
118 }
119
121#ifdef DUMP_TTC_TABLES
122 SkDebugf("CountTTCEntries %d\n", count);
123#endif
124 for (int i = 0; i < count; ++i) {
126 }
127}
128
129// Exercise this rare cmap format (platform 3, encoding 0)
131 auto tf = ToolUtils::CreateTypefaceFromResource("fonts/SpiderSymbol.ttf");
132 if (tf) {
133 SkUnichar c = 0xf021;
134 uint16_t g = SkFont(tf).unicharToGlyph(c);
135 REPORTER_ASSERT(reporter, g == 3);
136 } else {
137 // not all platforms support data fonts, so we just note that failure
138 SkDebugf("Skipping FontHostTest::test_symbolfont\n");
139 }
140}
141
143 if ((false)) { // avoid bit rot, suppress warning
144 SkTypefaceID typefaceID = face->uniqueID();
145 REPORTER_ASSERT(reporter, typefaceID);
146 }
147
148 int count = face->countTables();
149
151 SkFontTableTag* tags = storage.get();
152
153 int count2 = face->getTableTags(tags);
154 REPORTER_ASSERT(reporter, count2 == count);
155
156 for (int i = 0; i < count; ++i) {
157 size_t size = face->getTableSize(tags[i]);
159
160#ifdef DUMP_TABLES
161 char name[5];
162 name[0] = (tags[i] >> 24) & 0xFF;
163 name[1] = (tags[i] >> 16) & 0xFF;
164 name[2] = (tags[i] >> 8) & 0xFF;
165 name[3] = (tags[i] >> 0) & 0xFF;
166 name[4] = 0;
167 SkDebugf("%s %d\n", name, size);
168#endif
169
170 for (size_t j = 0; j < std::size(gKnownTableSizes); ++j) {
171 if (gKnownTableSizes[j].fTag == tags[i]) {
173 }
174 }
175
176 // do we get the same size from GetTableData and GetTableSize
177 {
179 size_t size2 = face->getTableData(tags[i], 0, size, data.get());
180 REPORTER_ASSERT(reporter, size2 == size);
181 sk_sp<SkData> data2 = face->copyTableData(tags[i]);
182 REPORTER_ASSERT(reporter, size == data2->size());
183 REPORTER_ASSERT(reporter, !memcmp(data.get(), data2->data(), size));
184 }
185 }
186}
187
189 static const char* const gNames[] = {
190 nullptr, // default font
191 "Helvetica", "Arial",
192 "Times", "Times New Roman",
193 "Courier", "Courier New",
194 "Terminal", "MS Sans Serif",
195 "Hiragino Mincho ProN", "MS PGothic",
196 };
197
198 for (size_t i = 0; i < std::size(gNames); ++i) {
200 if (face) {
201#ifdef DUMP_TABLES
202 SkDebugf("%s\n", gNames[i]);
203#endif
204 test_tables(reporter, face);
207 }
208 }
209}
210
211/*
212 * Verifies that the advance values returned by various methods match.
213 */
215 static const char* const faces[] = {
216 nullptr, // default font
217 "Arial", "Times", "Times New Roman", "Helvetica", "Courier",
218 "Courier New", "Verdana", "monospace",
219 };
220
221 static const struct {
222 SkFontHinting hinting;
223 bool linear;
224 bool subpixel;
225 } settings[] = {
226 { SkFontHinting::kNone, false, false },
227 { SkFontHinting::kNone, true, false },
228 { SkFontHinting::kNone, false, true },
229 { SkFontHinting::kSlight, false, false },
230 { SkFontHinting::kSlight, true, false },
231 { SkFontHinting::kSlight, false, true },
232 { SkFontHinting::kNormal, false, false },
233 { SkFontHinting::kNormal, true, false },
234 { SkFontHinting::kNormal, false, true },
235 };
236
237 static const struct {
238 SkScalar fScaleX;
239 SkScalar fSkewX;
240 } gScaleRec[] = {
241 { SK_Scalar1, 0 },
242 { SK_Scalar1/2, 0 },
243 // these two exercise obliquing (skew)
244 { SK_Scalar1, -SK_Scalar1/4 },
245 { SK_Scalar1/2, -SK_Scalar1/4 },
246 };
247
248 SkFont font;
249 char const * const txt = "long.text.with.lots.of.dots.";
250 size_t textLen = strlen(txt);
251
252 for (size_t i = 0; i < std::size(faces); i++) {
254
255 for (size_t j = 0; j < std::size(settings); j++) {
256 font.setHinting(settings[j].hinting);
257 font.setLinearMetrics(settings[j].linear);
258 font.setSubpixel(settings[j].subpixel);
259
260 for (size_t k = 0; k < std::size(gScaleRec); ++k) {
261 font.setScaleX(gScaleRec[k].fScaleX);
262 font.setSkewX(gScaleRec[k].fSkewX);
263
265
266 SkScalar width1 = font.measureText(txt, textLen, SkTextEncoding::kUTF8);
267
268 // Requesting the bounds forces a generateMetrics call.
269 SkScalar width2 = font.measureText(txt, textLen, SkTextEncoding::kUTF8, &bounds);
270
271 REPORTER_ASSERT(reporter, width1 == width2);
272 }
273 }
274 }
275}
276
277DEF_TEST(FontHost, reporter) {
282}
283
284// need tests for SkStrSearch
const Face faces[]
Definition: 3DSlide.cpp:137
static const struct TagSize gKnownTableSizes[]
static void test_symbolfont(skiatest::Reporter *reporter)
#define kFontTableTag_hhea
DEF_TEST(FontHost, reporter)
static void test_unitsPerEm(skiatest::Reporter *reporter, const sk_sp< SkTypeface > &face)
static void test_countGlyphs(skiatest::Reporter *reporter, const sk_sp< SkTypeface > &face)
#define kFontTableTag_head
#define kFontTableTag_maxp
static void test_tables(skiatest::Reporter *reporter, const sk_sp< SkTypeface > &face)
static void test_advances(skiatest::Reporter *reporter)
static void test_fontstream(skiatest::Reporter *reporter, SkStream *stream, int ttcIndex)
reporter
Definition: FontMgrTest.cpp:39
int count
Definition: FontMgrTest.cpp:50
std::unique_ptr< SkStreamAsset > GetResourceAsStream(const char *resource, bool useFileStream)
Definition: Resources.cpp:31
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
#define SkEndian_SwapBE16(n)
Definition: SkEndian.h:135
SkFontHinting
Definition: SkFontTypes.h:18
@ kNormal
glyph outlines modified to improve constrast
@ kNone
glyph outlines unchanged
@ kSlight
minimal modification to improve constrast
@ kUTF8
uses bytes to represent UTF-8 or ASCII
#define SK_Scalar1
Definition: SkScalar.h:18
uint32_t SkFontTableTag
Definition: SkTypeface.h:41
uint32_t SkTypefaceID
Definition: SkTypeface.h:38
int32_t SkUnichar
Definition: SkTypes.h:175
#define REPORTER_ASSERT(r, cond,...)
Definition: Test.h:286
const void * data() const
Definition: SkData.h:37
size_t size() const
Definition: SkData.h:30
static int GetTableTags(SkStream *, int ttcIndex, SkFontTableTag tags[])
static size_t GetTableSize(SkStream *stream, int ttcIndex, SkFontTableTag tag)
Definition: SkFontStream.h:46
static int CountTTCEntries(SkStream *)
Definition: SkFont.h:35
SkGlyphID unicharToGlyph(SkUnichar uni) const
Definition: SkFont.cpp:173
void appendUnichar(SkUnichar uni)
Definition: SkString.h:207
const char * c_str() const
Definition: SkString.h:133
int countGlyphs() const
Definition: SkTypeface.cpp:432
sk_sp< SkData > copyTableData(SkFontTableTag tag) const
Definition: SkTypeface.cpp:318
SkTypefaceID uniqueID() const
Definition: SkTypeface.h:101
int getUnitsPerEm() const
Definition: SkTypeface.cpp:436
int getTableTags(SkFontTableTag tags[]) const
Definition: SkTypeface.cpp:305
size_t getTableSize(SkFontTableTag) const
Definition: SkTypeface.cpp:309
int countTables() const
Definition: SkTypeface.cpp:301
size_t getTableData(SkFontTableTag tag, size_t offset, size_t length, void *data) const
Definition: SkTypeface.cpp:313
float SkScalar
Definition: extension.cpp:12
Optional< SkRect > bounds
Definition: SkRecords.h:189
sk_sp< SkTypeface > CreateTypefaceFromResource(const char *resource, int ttcIndex)
sk_sp< SkTypeface > CreateTestTypeface(const char *name, SkFontStyle style)
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
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.
SkFontTableTag fTag
size_t fSize
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63
static sk_sp< SkShader > linear(sk_sp< SkShader > shader)