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