OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2015 The Chromium Authors. All rights reserved. | |
scottmg
2015/09/17 23:24:25
no (c)
| |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "content/common/font_warmup_win.h" | |
6 | |
7 #include <vector> | |
8 | |
9 #include "base/files/file_path.h" | |
10 #include "base/logging.h" | |
11 #include "base/memory/scoped_ptr.h" | |
12 #include "base/win/windows_version.h" | |
13 #include "skia/ext/refptr.h" | |
14 #include "testing/gtest/include/gtest/gtest.h" | |
15 #include "third_party/skia/include/core/SkString.h" | |
16 #include "third_party/skia/include/core/SkTypeface.h" | |
17 #include "third_party/skia/include/ports/SkFontMgr.h" | |
18 | |
19 class TestSkTypeface : public SkTypeface { | |
scottmg
2015/09/17 23:24:25
all in namespace content {
forshaw
2015/09/18 00:00:28
Acknowledged.
| |
20 public: | |
21 TestSkTypeface(const SkFontStyle& style, | |
22 const char* familyName, | |
23 SkFontTableTag tag, | |
24 const char* data, | |
25 size_t dataLength) | |
26 : SkTypeface(style, 0), | |
27 familyName_(familyName), | |
28 tag_(tag), | |
29 data_(data, data + dataLength) {} | |
30 | |
31 protected: | |
32 SkScalerContext* onCreateScalerContext(const SkDescriptor*) const override { | |
33 ADD_FAILURE(); | |
34 return nullptr; | |
35 } | |
36 void onFilterRec(SkScalerContextRec*) const override { ADD_FAILURE(); } | |
37 SkAdvancedTypefaceMetrics* onGetAdvancedTypefaceMetrics( | |
38 PerGlyphInfo, | |
39 const uint32_t* glyphIDs, | |
40 uint32_t glyphIDsCount) const override { | |
41 ADD_FAILURE(); | |
42 return nullptr; | |
43 } | |
44 | |
45 SkStreamAsset* onOpenStream(int* ttcIndex) const override { | |
46 ADD_FAILURE(); | |
47 return nullptr; | |
48 } | |
49 | |
50 SkFontData* onCreateFontData() const override { | |
51 ADD_FAILURE(); | |
52 return nullptr; | |
53 } | |
54 | |
55 void onGetFontDescriptor(SkFontDescriptor*, bool* isLocal) const override { | |
56 ADD_FAILURE(); | |
57 } | |
58 | |
59 int onCharsToGlyphs(const void* chars, | |
60 Encoding, | |
61 uint16_t glyphs[], | |
62 int glyphCount) const override { | |
63 ADD_FAILURE(); | |
64 return 0; | |
65 } | |
66 | |
67 int onCountGlyphs() const override { | |
68 ADD_FAILURE(); | |
69 return 0; | |
70 } | |
71 | |
72 int onGetUPEM() const override { | |
73 ADD_FAILURE(); | |
74 return 0; | |
75 } | |
76 bool onGetKerningPairAdjustments(const uint16_t glyphs[], | |
77 int count, | |
78 int32_t adjustments[]) const override { | |
79 ADD_FAILURE(); | |
80 return false; | |
81 } | |
82 | |
83 /** Returns the family name of the typeface as known by its font manager. | |
scottmg
2015/09/17 23:24:25
no /** or /* comments unless in .c files.
forshaw
2015/09/18 00:00:28
Okay, this was just C&P from the skia headers, wil
| |
84 * This name may or may not be produced by the family name iterator. | |
85 */ | |
86 void onGetFamilyName(SkString* familyName) const override { | |
87 *familyName = familyName_; | |
88 } | |
89 | |
90 /** Returns an iterator over the family names in the font. */ | |
91 LocalizedStrings* onCreateFamilyNameIterator() const override { | |
92 ADD_FAILURE(); | |
93 return nullptr; | |
94 } | |
95 | |
96 int onGetTableTags(SkFontTableTag tags[]) const override { | |
97 ADD_FAILURE(); | |
98 return 0; | |
99 } | |
100 | |
101 size_t onGetTableData(SkFontTableTag tag, | |
102 size_t offset, | |
103 size_t length, | |
104 void* data) const override { | |
105 size_t retsize = 0; | |
106 if (tag == tag_) { | |
107 retsize = length > data_.size() ? data_.size() : length; | |
108 if (data) | |
109 memcpy(data, &data_[0], retsize); | |
110 } | |
111 return retsize; | |
112 } | |
113 | |
114 bool onComputeBounds(SkRect*) const override { | |
115 ADD_FAILURE(); | |
116 return false; | |
117 } | |
118 | |
119 private: | |
120 SkString familyName_; | |
121 SkFontTableTag tag_; | |
122 std::vector<char> data_; | |
123 }; | |
124 | |
125 const char* kTestFontFamily = "GDITest"; | |
126 const wchar_t* kTestFontFamilyW = L"GDITest"; | |
127 const SkFontTableTag kTestFontTableTag = 0x11223344; | |
128 const char* kTestFontData = "GDITestGDITest"; | |
129 const wchar_t* kTestFontFamilyInvalid = L"InvalidFont"; | |
130 | |
131 static inline DWORD SwapEndian(DWORD dwTable) { | |
scottmg
2015/09/17 23:24:25
replace with base/sys_byteorder.h
forshaw
2015/09/18 00:00:28
Acknowledged.
| |
132 return ((dwTable & 0xFF) << 24) | ((dwTable & 0xFF00) << 8) | | |
133 ((dwTable & 0xFF0000) >> 8) | (dwTable >> 24); | |
134 } | |
135 | |
136 class TestSkFontMgr : public SkFontMgr { | |
137 public: | |
138 TestSkFontMgr() { content::SetPreSandboxWarmupFontMgr(this); } | |
139 | |
140 ~TestSkFontMgr() { content::SetPreSandboxWarmupFontMgr(nullptr); } | |
141 | |
142 protected: | |
143 // Implement the virtual methods | |
144 int onCountFamilies() const override { return 1; } | |
145 | |
146 void onGetFamilyName(int index, SkString* familyName) const override { | |
147 if (index == 0) | |
148 *familyName = kTestFontFamily; | |
149 } | |
150 | |
151 SkFontStyleSet* onCreateStyleSet(int index) const override { | |
152 ADD_FAILURE(); | |
153 return nullptr; | |
154 } | |
155 | |
156 /** May return nullptr if the name is not found. */ | |
157 SkFontStyleSet* onMatchFamily(const char familyName[]) const override { | |
158 ADD_FAILURE(); | |
159 return nullptr; | |
160 } | |
161 | |
162 SkTypeface* onMatchFamilyStyle(const char familyName[], | |
163 const SkFontStyle&) const override { | |
164 if (strcmp(familyName, kTestFontFamily) == 0) { | |
165 return createTypeface(); | |
166 } | |
167 return nullptr; | |
168 } | |
169 | |
170 SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], | |
171 const SkFontStyle&, | |
172 const char* bcp47[], | |
173 int bcp47Count, | |
174 SkUnichar character) const override { | |
175 ADD_FAILURE(); | |
176 return nullptr; | |
177 } | |
178 | |
179 SkTypeface* onMatchFaceStyle(const SkTypeface*, | |
180 const SkFontStyle&) const override { | |
181 ADD_FAILURE(); | |
182 return nullptr; | |
183 } | |
184 | |
185 SkTypeface* onCreateFromData(SkData*, int ttcIndex) const override { | |
186 ADD_FAILURE(); | |
187 return nullptr; | |
188 } | |
189 | |
190 SkTypeface* onCreateFromStream(SkStreamAsset*, int ttcIndex) const override { | |
191 ADD_FAILURE(); | |
192 return nullptr; | |
193 } | |
194 | |
195 SkTypeface* onCreateFromFontData(SkFontData*) const override { | |
196 ADD_FAILURE(); | |
197 return nullptr; | |
198 } | |
199 | |
200 SkTypeface* onCreateFromFile(const char path[], int ttcIndex) const override { | |
201 ADD_FAILURE(); | |
202 return nullptr; | |
203 } | |
204 | |
205 SkTypeface* onLegacyCreateTypeface(const char familyName[], | |
206 unsigned styleBits) const override { | |
207 ADD_FAILURE(); | |
208 return nullptr; | |
209 } | |
210 | |
211 private: | |
212 SkTypeface* createTypeface() const { | |
213 SkFontStyle style(400, 100, SkFontStyle::kUpright_Slant); | |
214 | |
215 return new TestSkTypeface(style, kTestFontFamily, | |
216 SwapEndian(kTestFontTableTag), kTestFontData, | |
217 strlen(kTestFontData)); | |
218 } | |
219 }; | |
220 | |
221 static void InitLogFont(LOGFONTW* logfont, const wchar_t* fontname) { | |
222 memcpy(logfont->lfFaceName, fontname, | |
scottmg
2015/09/17 23:24:25
probably better to use the (small) target buffer s
forshaw
2015/09/18 00:00:28
Acknowledged.
| |
223 (wcslen(fontname) + 1) * sizeof(wchar_t)); | |
224 } | |
225 | |
226 static content::GdiFontPatchData* SetupTest() { | |
227 HMODULE module_handle; | |
228 if (GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, | |
229 reinterpret_cast<LPCWSTR>(SetupTest), | |
230 &module_handle)) { | |
231 WCHAR module_path[MAX_PATH]; | |
232 | |
233 if (GetModuleFileNameW(module_handle, module_path, MAX_PATH) > 0) { | |
234 base::FilePath path(module_path); | |
235 return content::PatchGdiFontEnumeration(path); | |
236 } | |
237 } | |
238 return nullptr; | |
239 } | |
240 | |
241 static int CALLBACK EnumFontCallbackTest(const LOGFONT* lpelfe, | |
242 const TEXTMETRIC* lpntme, | |
243 DWORD FontType, | |
244 LPARAM lParam) { | |
245 const NEWTEXTMETRICEX* m = reinterpret_cast<const NEWTEXTMETRICEX*>(lpntme); | |
246 | |
247 return !(FontType & TRUETYPE_FONTTYPE) && | |
248 !(m->ntmTm.ntmFlags & NTM_PS_OPENTYPE); | |
249 } | |
250 | |
251 TEST(GDIFontEmulationTest, CreateDeleteDCSuccess) { | |
252 if (base::win::GetVersion() < base::win::VERSION_WIN8) | |
253 return; | |
254 TestSkFontMgr fontmgr; | |
255 scoped_ptr<content::GdiFontPatchData> patch_data(SetupTest()); | |
256 EXPECT_FALSE(!patch_data); | |
257 | |
258 HDC hdc = CreateCompatibleDC(0); | |
259 EXPECT_TRUE(hdc != nullptr); | |
scottmg
2015/09/17 23:24:25
EXPECT_NE(nullptr, hdc) and similar below
forshaw
2015/09/18 00:00:28
Acknowledged.
| |
260 EXPECT_TRUE(DeleteDC(hdc)); | |
261 } | |
262 | |
263 TEST(GDIFontEmulationTest, CreateUniqueDCSuccess) { | |
264 if (base::win::GetVersion() < base::win::VERSION_WIN8) | |
265 return; | |
266 TestSkFontMgr fontmgr; | |
267 scoped_ptr<content::GdiFontPatchData> patch_data(SetupTest()); | |
268 EXPECT_FALSE(!patch_data); | |
scottmg
2015/09/17 23:24:25
does EXPECT_TRUE() not compile?
forshaw
2015/09/18 00:00:28
Acknowledged.
| |
269 | |
270 HDC hdc1 = CreateCompatibleDC(0); | |
271 EXPECT_TRUE(hdc1 != nullptr); | |
272 HDC hdc2 = CreateCompatibleDC(0); | |
273 EXPECT_TRUE(hdc2 != nullptr); | |
274 EXPECT_NE(hdc1, hdc2); | |
275 EXPECT_TRUE(DeleteDC(hdc2)); | |
276 EXPECT_TRUE(DeleteDC(hdc1)); | |
277 } | |
278 | |
279 TEST(GDIFontEmulationTest, CreateFontSuccess) { | |
280 if (base::win::GetVersion() < base::win::VERSION_WIN8) | |
281 return; | |
282 TestSkFontMgr fontmgr; | |
283 scoped_ptr<content::GdiFontPatchData> patch_data(SetupTest()); | |
284 EXPECT_FALSE(!patch_data); | |
285 LOGFONTW logfont = {0}; | |
286 InitLogFont(&logfont, kTestFontFamilyW); | |
287 HFONT font = CreateFontIndirectW(&logfont); | |
288 EXPECT_TRUE(font != nullptr); | |
289 EXPECT_TRUE(DeleteObject(font)); | |
290 } | |
291 | |
292 TEST(GDIFontEmulationTest, CreateFontFailure) { | |
293 if (base::win::GetVersion() < base::win::VERSION_WIN8) | |
294 return; | |
295 TestSkFontMgr fontmgr; | |
296 scoped_ptr<content::GdiFontPatchData> patch_data(SetupTest()); | |
297 EXPECT_FALSE(!patch_data); | |
298 LOGFONTW logfont = {0}; | |
299 InitLogFont(&logfont, kTestFontFamilyInvalid); | |
300 HFONT font = CreateFontIndirectW(&logfont); | |
301 EXPECT_TRUE(font == nullptr); | |
302 } | |
303 | |
304 TEST(GDIFontEmulationTest, EnumFontFamilySuccess) { | |
305 if (base::win::GetVersion() < base::win::VERSION_WIN8) | |
306 return; | |
307 TestSkFontMgr fontmgr; | |
308 scoped_ptr<content::GdiFontPatchData> patch_data(SetupTest()); | |
309 EXPECT_FALSE(!patch_data); | |
310 HDC hdc = CreateCompatibleDC(0); | |
311 EXPECT_TRUE(hdc != nullptr); | |
312 LOGFONTW logfont = {0}; | |
313 InitLogFont(&logfont, kTestFontFamilyW); | |
314 int res = EnumFontFamiliesExW(hdc, &logfont, EnumFontCallbackTest, 0, 0); | |
315 EXPECT_FALSE(res); | |
316 EXPECT_TRUE(DeleteDC(hdc)); | |
317 } | |
318 | |
319 TEST(GDIFontEmulationTest, EnumFontFamilyFailure) { | |
320 if (base::win::GetVersion() < base::win::VERSION_WIN8) | |
321 return; | |
322 TestSkFontMgr fontmgr; | |
323 scoped_ptr<content::GdiFontPatchData> patch_data(SetupTest()); | |
324 EXPECT_FALSE(!patch_data); | |
325 HDC hdc = CreateCompatibleDC(0); | |
326 EXPECT_TRUE(hdc != nullptr); | |
327 LOGFONTW logfont = {0}; | |
328 InitLogFont(&logfont, kTestFontFamilyInvalid); | |
329 int res = EnumFontFamiliesExW(hdc, &logfont, EnumFontCallbackTest, 0, 0); | |
330 EXPECT_TRUE(res); | |
331 EXPECT_TRUE(DeleteDC(hdc)); | |
332 } | |
333 | |
334 TEST(GDIFontEmulationTest, DeleteDCFailure) { | |
335 if (base::win::GetVersion() < base::win::VERSION_WIN8) | |
336 return; | |
337 TestSkFontMgr fontmgr; | |
338 scoped_ptr<content::GdiFontPatchData> patch_data(SetupTest()); | |
339 EXPECT_FALSE(!patch_data); | |
340 HDC hdc = reinterpret_cast<HDC>(0x11223344); | |
scottmg
2015/09/17 23:24:25
maybe use something other than 11223344 unless you
forshaw
2015/09/18 00:00:28
Acknowledged.
| |
341 EXPECT_FALSE(DeleteDC(hdc)); | |
342 } | |
343 | |
344 TEST(GDIFontEmulationTest, DeleteObjectFailure) { | |
345 if (base::win::GetVersion() < base::win::VERSION_WIN8) | |
346 return; | |
347 TestSkFontMgr fontmgr; | |
348 scoped_ptr<content::GdiFontPatchData> patch_data(SetupTest()); | |
349 EXPECT_FALSE(!patch_data); | |
350 HFONT font = reinterpret_cast<HFONT>(0x11223344); | |
351 EXPECT_FALSE(DeleteObject(font)); | |
352 } | |
353 | |
354 TEST(GDIFontEmulationTest, GetFontDataSizeSuccess) { | |
355 if (base::win::GetVersion() < base::win::VERSION_WIN8) | |
356 return; | |
357 TestSkFontMgr fontmgr; | |
358 scoped_ptr<content::GdiFontPatchData> patch_data(SetupTest()); | |
359 EXPECT_FALSE(!patch_data); | |
360 HDC hdc = CreateCompatibleDC(0); | |
361 EXPECT_TRUE(hdc != nullptr); | |
362 LOGFONTW logfont = {0}; | |
363 InitLogFont(&logfont, kTestFontFamilyW); | |
364 HFONT font = CreateFontIndirectW(&logfont); | |
365 EXPECT_TRUE(font != nullptr); | |
366 EXPECT_TRUE(SelectObject(hdc, font) == nullptr); | |
367 DWORD size = GetFontData(hdc, kTestFontTableTag, 0, nullptr, 0); | |
368 DWORD data_size = static_cast<DWORD>(strlen(kTestFontData)); | |
369 EXPECT_EQ(size, data_size); | |
370 EXPECT_TRUE(DeleteObject(font)); | |
371 EXPECT_TRUE(DeleteDC(hdc)); | |
372 } | |
373 | |
374 TEST(GDIFontEmulationTest, GetFontDataInvalidTagSuccess) { | |
375 if (base::win::GetVersion() < base::win::VERSION_WIN8) | |
376 return; | |
377 TestSkFontMgr fontmgr; | |
378 scoped_ptr<content::GdiFontPatchData> patch_data(SetupTest()); | |
379 EXPECT_FALSE(!patch_data); | |
380 HDC hdc = CreateCompatibleDC(0); | |
381 EXPECT_TRUE(hdc != nullptr); | |
382 LOGFONTW logfont = {0}; | |
383 InitLogFont(&logfont, kTestFontFamilyW); | |
384 HFONT font = CreateFontIndirectW(&logfont); | |
385 EXPECT_TRUE(font != nullptr); | |
386 EXPECT_TRUE(SelectObject(hdc, font) == nullptr); | |
387 DWORD size = GetFontData(hdc, kTestFontTableTag + 1, 0, nullptr, 0); | |
388 EXPECT_EQ(size, GDI_ERROR); | |
389 EXPECT_TRUE(DeleteObject(font)); | |
390 EXPECT_TRUE(DeleteDC(hdc)); | |
391 } | |
392 | |
393 TEST(GDIFontEmulationTest, GetFontDataInvalidFontSuccess) { | |
394 if (base::win::GetVersion() < base::win::VERSION_WIN8) | |
395 return; | |
396 TestSkFontMgr fontmgr; | |
397 scoped_ptr<content::GdiFontPatchData> patch_data(SetupTest()); | |
398 EXPECT_FALSE(!patch_data); | |
399 HDC hdc = CreateCompatibleDC(0); | |
400 EXPECT_TRUE(hdc != nullptr); | |
401 DWORD size = GetFontData(hdc, kTestFontTableTag, 0, nullptr, 0); | |
402 EXPECT_EQ(size, GDI_ERROR); | |
403 EXPECT_TRUE(DeleteDC(hdc)); | |
404 } | |
405 | |
406 TEST(GDIFontEmulationTest, GetFontDataDataSuccess) { | |
407 if (base::win::GetVersion() < base::win::VERSION_WIN8) | |
408 return; | |
409 TestSkFontMgr fontmgr; | |
410 scoped_ptr<content::GdiFontPatchData> patch_data(SetupTest()); | |
411 EXPECT_FALSE(!patch_data); | |
412 HDC hdc = CreateCompatibleDC(0); | |
413 EXPECT_TRUE(hdc != nullptr); | |
414 LOGFONTW logfont = {0}; | |
415 InitLogFont(&logfont, kTestFontFamilyW); | |
416 HFONT font = CreateFontIndirectW(&logfont); | |
417 EXPECT_TRUE(font != nullptr); | |
418 EXPECT_TRUE(SelectObject(hdc, font) == nullptr); | |
419 DWORD data_size = static_cast<DWORD>(strlen(kTestFontData)); | |
420 std::vector<char> data(data_size); | |
421 DWORD size = GetFontData(hdc, kTestFontTableTag, 0, &data[0], data.size()); | |
422 EXPECT_EQ(size, data_size); | |
423 EXPECT_EQ(memcmp(&data[0], kTestFontData, data.size()), 0); | |
424 EXPECT_TRUE(DeleteObject(font)); | |
425 EXPECT_TRUE(DeleteDC(hdc)); | |
scottmg
2015/09/17 23:24:25
is it worth verifying the globals are empty in som
forshaw
2015/09/18 00:00:28
As in the global state of handles? Yeah probably,
| |
426 } | |
OLD | NEW |