Make certificate viewer a tab-modal dialog.
[chromium-blink-merge.git] / ppapi / tests / test_truetype_font.cc
blob67587a08a6a3d4e126103348bbc68dc5b619507f
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 //
5 // Tests PPB_TrueTypeFont interface.
7 #include "ppapi/tests/test_truetype_font.h"
9 #include <string.h>
10 #include <algorithm>
11 #include <limits>
13 #include "ppapi/c/dev/ppb_testing_dev.h"
14 #include "ppapi/cpp/completion_callback.h"
15 #include "ppapi/cpp/dev/truetype_font_dev.h"
16 #include "ppapi/cpp/instance.h"
17 #include "ppapi/cpp/var.h"
18 #include "ppapi/tests/test_utils.h"
19 #include "ppapi/tests/testing_instance.h"
21 REGISTER_TEST_CASE(TrueTypeFont);
23 #define MAKE_TABLE_TAG(a, b, c, d) ((a) << 24) + ((b) << 16) + ((c) << 8) + (d)
25 namespace {
27 const PP_Resource kInvalidResource = 0;
28 const PP_Instance kInvalidInstance = 0;
30 // TrueType font header and table entry structs. See
31 // https://developer.apple.com/fonts/TTRefMan/RM06/Chap6.html
32 struct FontHeader {
33 int32_t font_type;
34 uint16_t num_tables;
35 uint16_t search_range;
36 uint16_t entry_selector;
37 uint16_t range_shift;
40 struct FontDirectoryEntry {
41 uint32_t tag;
42 uint32_t checksum;
43 uint32_t offset;
44 uint32_t logical_length;
47 uint32_t ReadBigEndian32(const void* ptr) {
48 const uint8_t* data = reinterpret_cast<const uint8_t*>(ptr);
49 return (data[3] << 0) | (data[2] << 8) | (data[1] << 16) | (data[0] << 24);
52 uint16_t ReadBigEndian16(const void* ptr) {
53 const uint8_t* data = reinterpret_cast<const uint8_t*>(ptr);
54 return (data[1] << 0) | (data[0] << 8);
59 TestTrueTypeFont::TestTrueTypeFont(TestingInstance* instance)
60 : TestCase(instance),
61 ppb_truetype_font_interface_(NULL),
62 ppb_core_interface_(NULL),
63 ppb_var_interface_(NULL) {
66 bool TestTrueTypeFont::Init() {
67 ppb_truetype_font_interface_ = static_cast<const PPB_TrueTypeFont_Dev*>(
68 pp::Module::Get()->GetBrowserInterface(PPB_TRUETYPEFONT_DEV_INTERFACE));
69 ppb_core_interface_ = static_cast<const PPB_Core*>(
70 pp::Module::Get()->GetBrowserInterface(PPB_CORE_INTERFACE));
71 ppb_var_interface_ = static_cast<const PPB_Var*>(
72 pp::Module::Get()->GetBrowserInterface(PPB_VAR_INTERFACE));
73 if (!ppb_truetype_font_interface_)
74 instance_->AppendError("PPB_TrueTypeFont_Dev interface not available");
75 if (!ppb_core_interface_)
76 instance_->AppendError("PPB_Core interface not available");
77 if (!ppb_var_interface_)
78 instance_->AppendError("PPB_Var interface not available");
80 return true;
83 TestTrueTypeFont::~TestTrueTypeFont() {
86 void TestTrueTypeFont::RunTests(const std::string& filter) {
87 RUN_TEST(GetFontFamilies, filter);
88 RUN_TEST(GetFontsInFamily, filter);
89 RUN_TEST(Create, filter);
90 RUN_TEST(Describe, filter);
91 RUN_TEST(GetTableTags, filter);
92 RUN_TEST(GetTable, filter);
95 std::string TestTrueTypeFont::TestGetFontFamilies() {
97 // A valid instance should be able to enumerate fonts.
98 TestCompletionCallbackWithOutput< std::vector<pp::Var> > cc(
99 instance_->pp_instance(), false);
100 cc.WaitForResult(pp::TrueTypeFont_Dev::GetFontFamilies(instance_,
101 cc.GetCallback()));
102 const std::vector<pp::Var> font_families = cc.output();
103 // We should get some font families on any platform.
104 ASSERT_NE(0, font_families.size());
105 ASSERT_EQ(static_cast<int32_t>(font_families.size()), cc.result());
106 // Make sure at least one family is a non-empty string.
107 ASSERT_NE(0, font_families[0].AsString().size());
110 // Using an invalid instance should fail.
111 TestCompletionCallbackWithOutput< std::vector<pp::Var> > cc(
112 instance_->pp_instance(), false);
113 cc.WaitForResult(
114 ppb_truetype_font_interface_->GetFontFamilies(
115 kInvalidInstance,
116 cc.GetCallback().output(),
117 cc.GetCallback().pp_completion_callback()));
118 ASSERT_TRUE(cc.result() == PP_ERROR_FAILED ||
119 cc.result() == PP_ERROR_BADARGUMENT);
120 ASSERT_EQ(0, cc.output().size());
123 PASS();
126 std::string TestTrueTypeFont::TestGetFontsInFamily() {
128 // Get the list of all font families.
129 TestCompletionCallbackWithOutput< std::vector<pp::Var> > cc(
130 instance_->pp_instance(), false);
131 cc.WaitForResult(pp::TrueTypeFont_Dev::GetFontFamilies(instance_,
132 cc.GetCallback()));
133 // Try to use a common family that is likely to have multiple variations.
134 const std::vector<pp::Var> families = cc.output();
135 pp::Var family("Arial");
136 if (std::find(families.begin(), families.end(), family) == families.end()) {
137 family = pp::Var("Times");
138 if (std::find(families.begin(), families.end(), family) == families.end())
139 family = families[0]; // Just use the first family.
142 // GetFontsInFamily: A valid instance should be able to enumerate fonts
143 // in a given family.
144 TestCompletionCallbackWithOutput< std::vector<pp::TrueTypeFontDesc_Dev> >
145 cc2(instance_->pp_instance(), false);
146 cc2.WaitForResult(pp::TrueTypeFont_Dev::GetFontsInFamily(
147 instance_,
148 family,
149 cc2.GetCallback()));
150 std::vector<pp::TrueTypeFontDesc_Dev> fonts_in_family = cc2.output();
151 ASSERT_NE(0, fonts_in_family.size());
152 ASSERT_EQ(static_cast<int32_t>(fonts_in_family.size()), cc2.result());
154 // We should be able to create any of the returned fonts without fallback.
155 for (size_t i = 0; i < fonts_in_family.size(); ++i) {
156 pp::TrueTypeFontDesc_Dev& font_in_family = fonts_in_family[i];
157 pp::TrueTypeFont_Dev font(instance_, font_in_family);
158 TestCompletionCallbackWithOutput<pp::TrueTypeFontDesc_Dev> cc(
159 instance_->pp_instance(), false);
160 cc.WaitForResult(font.Describe(cc.GetCallback()));
161 const pp::TrueTypeFontDesc_Dev desc = cc.output();
163 ASSERT_EQ(family, desc.family());
164 ASSERT_EQ(font_in_family.style(), desc.style());
165 ASSERT_EQ(font_in_family.weight(), desc.weight());
169 // Using an invalid instance should fail.
170 TestCompletionCallbackWithOutput< std::vector<pp::TrueTypeFontDesc_Dev> >
171 cc(instance_->pp_instance(), false);
172 pp::Var family("Times");
173 cc.WaitForResult(
174 ppb_truetype_font_interface_->GetFontsInFamily(
175 kInvalidInstance,
176 family.pp_var(),
177 cc.GetCallback().output(),
178 cc.GetCallback().pp_completion_callback()));
179 ASSERT_TRUE(cc.result() == PP_ERROR_FAILED ||
180 cc.result() == PP_ERROR_BADARGUMENT);
181 ASSERT_EQ(0, cc.output().size());
184 PASS();
187 std::string TestTrueTypeFont::TestCreate() {
188 PP_Resource font;
189 PP_TrueTypeFontDesc_Dev desc = {
190 PP_MakeUndefined(),
191 PP_TRUETYPEFONTFAMILY_SERIF,
192 PP_TRUETYPEFONTSTYLE_NORMAL,
193 PP_TRUETYPEFONTWEIGHT_NORMAL,
194 PP_TRUETYPEFONTWIDTH_NORMAL,
195 PP_TRUETYPEFONTCHARSET_DEFAULT
197 // Creating a font from an invalid instance returns an invalid resource.
198 font = ppb_truetype_font_interface_->Create(kInvalidInstance, &desc);
199 ASSERT_EQ(kInvalidResource, font);
200 ASSERT_NE(PP_TRUE, ppb_truetype_font_interface_->IsTrueTypeFont(font));
202 // Creating a font from a valid instance returns a font resource.
203 font = ppb_truetype_font_interface_->Create(instance_->pp_instance(), &desc);
204 ASSERT_NE(kInvalidResource, font);
205 ASSERT_EQ(PP_TRUE, ppb_truetype_font_interface_->IsTrueTypeFont(font));
207 ppb_core_interface_->ReleaseResource(font);
208 // Once released, the resource shouldn't be a font.
209 ASSERT_NE(PP_TRUE, ppb_truetype_font_interface_->IsTrueTypeFont(font));
211 PASS();
214 std::string TestTrueTypeFont::TestDescribe() {
215 pp::TrueTypeFontDesc_Dev create_desc;
216 create_desc.set_generic_family(PP_TRUETYPEFONTFAMILY_SERIF);
217 create_desc.set_style(PP_TRUETYPEFONTSTYLE_NORMAL);
218 create_desc.set_weight(PP_TRUETYPEFONTWEIGHT_NORMAL);
219 pp::TrueTypeFont_Dev font(instance_, create_desc);
220 // Describe: See what font-matching did with a generic font. We should always
221 // be able to Create a generic Serif font.
222 TestCompletionCallbackWithOutput<pp::TrueTypeFontDesc_Dev> cc(
223 instance_->pp_instance(), false);
224 cc.WaitForResult(font.Describe(cc.GetCallback()));
225 const pp::TrueTypeFontDesc_Dev desc = cc.output();
226 ASSERT_NE(0, desc.family().AsString().size());
227 ASSERT_EQ(PP_TRUETYPEFONTFAMILY_SERIF, desc.generic_family());
228 ASSERT_EQ(PP_TRUETYPEFONTSTYLE_NORMAL, desc.style());
229 ASSERT_EQ(PP_TRUETYPEFONTWEIGHT_NORMAL, desc.weight());
231 // Describe an invalid resource should fail.
232 PP_TrueTypeFontDesc_Dev fail_desc;
233 memset(&fail_desc, 0, sizeof(fail_desc));
234 fail_desc.family = PP_MakeUndefined();
235 // Create a shallow copy to check that no data is changed.
236 PP_TrueTypeFontDesc_Dev fail_desc_copy;
237 memcpy(&fail_desc_copy, &fail_desc, sizeof(fail_desc));
239 cc.WaitForResult(
240 ppb_truetype_font_interface_->Describe(
241 kInvalidResource,
242 &fail_desc,
243 cc.GetCallback().pp_completion_callback()));
244 ASSERT_EQ(PP_ERROR_BADRESOURCE, cc.result());
245 ASSERT_EQ(PP_VARTYPE_UNDEFINED, fail_desc.family.type);
246 ASSERT_EQ(0, memcmp(&fail_desc, &fail_desc_copy, sizeof(fail_desc)));
248 PASS();
251 std::string TestTrueTypeFont::TestGetTableTags() {
252 pp::TrueTypeFontDesc_Dev desc;
253 pp::TrueTypeFont_Dev font(instance_, desc);
255 TestCompletionCallbackWithOutput< std::vector<uint32_t> > cc(
256 instance_->pp_instance(), false);
257 cc.WaitForResult(font.GetTableTags(cc.GetCallback()));
258 std::vector<uint32_t> tags = cc.output();
259 ASSERT_NE(0, tags.size());
260 ASSERT_EQ(static_cast<int32_t>(tags.size()), cc.result());
261 // Tags will vary depending on the actual font that the host platform
262 // chooses. Check that all required TrueType tags are present.
263 const int required_tag_count = 9;
264 uint32_t required_tags[required_tag_count] = {
265 // Note: these must be sorted for std::includes below.
266 MAKE_TABLE_TAG('c', 'm', 'a', 'p'),
267 MAKE_TABLE_TAG('g', 'l', 'y', 'f'),
268 MAKE_TABLE_TAG('h', 'e', 'a', 'd'),
269 MAKE_TABLE_TAG('h', 'h', 'e', 'a'),
270 MAKE_TABLE_TAG('h', 'm', 't', 'x'),
271 MAKE_TABLE_TAG('l', 'o', 'c', 'a'),
272 MAKE_TABLE_TAG('m', 'a', 'x', 'p'),
273 MAKE_TABLE_TAG('n', 'a', 'm', 'e'),
274 MAKE_TABLE_TAG('p', 'o', 's', 't')
276 std::sort(tags.begin(), tags.end());
277 ASSERT_TRUE(std::includes(tags.begin(),
278 tags.end(),
279 required_tags,
280 required_tags + required_tag_count));
283 // Invalid resource should fail and write no data.
284 TestCompletionCallbackWithOutput< std::vector<uint32_t> > cc(
285 instance_->pp_instance(), false);
286 cc.WaitForResult(
287 ppb_truetype_font_interface_->GetTableTags(
288 kInvalidResource,
289 cc.GetCallback().output(),
290 cc.GetCallback().pp_completion_callback()));
291 ASSERT_EQ(PP_ERROR_BADRESOURCE, cc.result());
292 ASSERT_EQ(0, cc.output().size());
295 PASS();
298 std::string TestTrueTypeFont::TestGetTable() {
299 pp::TrueTypeFontDesc_Dev desc;
300 pp::TrueTypeFont_Dev font(instance_, desc);
303 // Getting a required table from a valid font should succeed.
304 TestCompletionCallbackWithOutput< std::vector<char> > cc1(
305 instance_->pp_instance(), false);
306 cc1.WaitForResult(font.GetTable(MAKE_TABLE_TAG('c', 'm', 'a', 'p'),
307 0, std::numeric_limits<int32_t>::max(),
308 cc1.GetCallback()));
309 const std::vector<char> cmap_data = cc1.output();
310 ASSERT_NE(0, cmap_data.size());
311 ASSERT_EQ(static_cast<int32_t>(cmap_data.size()), cc1.result());
313 // Passing 0 for the table tag should return the entire font.
314 TestCompletionCallbackWithOutput< std::vector<char> > cc2(
315 instance_->pp_instance(), false);
316 cc2.WaitForResult(font.GetTable(0 /* table_tag */,
317 0, std::numeric_limits<int32_t>::max(),
318 cc2.GetCallback()));
319 const std::vector<char> entire_font = cc2.output();
320 ASSERT_NE(0, entire_font.size());
321 ASSERT_EQ(static_cast<int32_t>(entire_font.size()), cc2.result());
323 // Verify that the CMAP table is in entire_font, and that it's identical
324 // to the one we retrieved above. Note that since the font header and table
325 // directory are in file (big-endian) order, we need to byte swap tags and
326 // numbers.
327 const size_t kHeaderSize = sizeof(FontHeader);
328 const size_t kEntrySize = sizeof(FontDirectoryEntry);
329 ASSERT_TRUE(kHeaderSize < entire_font.size());
330 FontHeader header;
331 memcpy(&header, &entire_font[0], kHeaderSize);
332 uint16_t num_tables = ReadBigEndian16(&header.num_tables);
333 std::vector<FontDirectoryEntry> directory(num_tables);
334 size_t directory_size = kEntrySize * num_tables;
335 ASSERT_TRUE(kHeaderSize + directory_size < entire_font.size());
336 memcpy(&directory[0], &entire_font[kHeaderSize], directory_size);
337 const FontDirectoryEntry* cmap_entry = NULL;
338 for (uint16_t i = 0; i < num_tables; i++) {
339 if (ReadBigEndian32(&directory[i].tag) ==
340 MAKE_TABLE_TAG('c', 'm', 'a', 'p')) {
341 cmap_entry = &directory[i];
342 break;
345 ASSERT_NE(NULL, cmap_entry);
347 uint32_t logical_length = ReadBigEndian32(&cmap_entry->logical_length);
348 uint32_t table_offset = ReadBigEndian32(&cmap_entry->offset);
349 ASSERT_EQ(static_cast<size_t>(logical_length), cmap_data.size());
350 ASSERT_TRUE(static_cast<size_t>(table_offset + logical_length) <
351 entire_font.size());
352 const char* cmap_table = &entire_font[0] + table_offset;
353 ASSERT_EQ(0, memcmp(cmap_table, &cmap_data[0], cmap_data.size()));
355 // Use offset and max_data_length to restrict the data. Read a part of
356 // the 'CMAP' table.
357 TestCompletionCallbackWithOutput< std::vector<char> > cc3(
358 instance_->pp_instance(), false);
359 const int32_t kOffset = 4;
360 int32_t partial_cmap_size = static_cast<int32_t>(cmap_data.size() - 64);
361 cc3.WaitForResult(font.GetTable(MAKE_TABLE_TAG('c', 'm', 'a', 'p'),
362 kOffset,
363 partial_cmap_size,
364 cc3.GetCallback()));
365 const std::vector<char> partial_cmap_data = cc3.output();
366 ASSERT_EQ(partial_cmap_data.size(), static_cast<size_t>(cc3.result()));
367 ASSERT_EQ(partial_cmap_data.size(), static_cast<size_t>(partial_cmap_size));
368 ASSERT_EQ(0, memcmp(cmap_table + kOffset, &partial_cmap_data[0],
369 partial_cmap_size));
372 // Getting an invalid table should fail ('zzzz' should be safely invalid).
373 TestCompletionCallbackWithOutput< std::vector<char> > cc(
374 instance_->pp_instance(), false);
375 cc.WaitForResult(font.GetTable(MAKE_TABLE_TAG('z', 'z', 'z', 'z'),
376 0, std::numeric_limits<int32_t>::max(),
377 cc.GetCallback()));
378 ASSERT_EQ(0, cc.output().size());
379 ASSERT_EQ(PP_ERROR_FAILED, cc.result());
382 // GetTable on an invalid resource should fail with a bad resource error
383 // and write no data.
384 TestCompletionCallbackWithOutput< std::vector<char> > cc(
385 instance_->pp_instance(), false);
386 cc.WaitForResult(
387 ppb_truetype_font_interface_->GetTable(
388 kInvalidResource,
389 MAKE_TABLE_TAG('c', 'm', 'a', 'p'),
390 0, std::numeric_limits<int32_t>::max(),
391 cc.GetCallback().output(),
392 cc.GetCallback().pp_completion_callback()));
393 ASSERT_EQ(PP_ERROR_BADRESOURCE, cc.result());
394 ASSERT_EQ(0, cc.output().size());
397 // Negative offset should fail with a bad argument error and write no data.
398 TestCompletionCallbackWithOutput< std::vector<char> > cc(
399 instance_->pp_instance(), false);
400 cc.WaitForResult(font.GetTable(MAKE_TABLE_TAG('c', 'm', 'a', 'p'),
401 -100, 0,
402 cc.GetCallback()));
403 ASSERT_EQ(PP_ERROR_BADARGUMENT, cc.result());
404 ASSERT_EQ(0, cc.output().size());
407 // Offset larger than file size succeeds but returns no data.
408 TestCompletionCallbackWithOutput< std::vector<char> > cc(
409 instance_->pp_instance(), false);
410 cc.WaitForResult(font.GetTable(MAKE_TABLE_TAG('c', 'm', 'a', 'p'),
411 1 << 28, 0,
412 cc.GetCallback()));
413 ASSERT_EQ(PP_OK, cc.result());
414 ASSERT_EQ(0, cc.output().size());
417 // Negative max_data_length should fail with a bad argument error and write
418 // no data.
419 TestCompletionCallbackWithOutput< std::vector<char> > cc(
420 instance_->pp_instance(), false);
421 cc.WaitForResult(font.GetTable(MAKE_TABLE_TAG('c', 'm', 'a', 'p'),
422 0, -100,
423 cc.GetCallback()));
424 ASSERT_EQ(PP_ERROR_BADARGUMENT, cc.result());
425 ASSERT_EQ(0, cc.output().size());
428 PASS();