1// Copyright 2014 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#include "base/compiler_specific.h"
6#include "base/files/scoped_file.h"
7#include "base/memory/scoped_ptr.h"
8#include "base/numerics/safe_conversions.h"
9#include "base/sys_byteorder.h"
10#include "content/browser/renderer_host/font_utils_linux.h"
11#include "content/browser/renderer_host/pepper/pepper_truetype_font.h"
12#include "content/public/common/child_process_sandbox_support_linux.h"
13#include "ppapi/c/dev/ppb_truetype_font_dev.h"
14#include "ppapi/c/pp_errors.h"
15
16namespace content {
17
18namespace {
19
20class PepperTrueTypeFontLinux : public PepperTrueTypeFont {
21 public:
22  PepperTrueTypeFontLinux();
23
24  // PepperTrueTypeFont implementation.
25  virtual int32_t Initialize(
26      ppapi::proxy::SerializedTrueTypeFontDesc* desc) OVERRIDE;
27  virtual int32_t GetTableTags(std::vector<uint32_t>* tags) OVERRIDE;
28  virtual int32_t GetTable(uint32_t table_tag,
29                           int32_t offset,
30                           int32_t max_data_length,
31                           std::string* data) OVERRIDE;
32
33 private:
34  virtual ~PepperTrueTypeFontLinux() OVERRIDE;
35
36  base::ScopedFD fd_;
37
38  DISALLOW_COPY_AND_ASSIGN(PepperTrueTypeFontLinux);
39};
40
41PepperTrueTypeFontLinux::PepperTrueTypeFontLinux() {
42}
43
44PepperTrueTypeFontLinux::~PepperTrueTypeFontLinux() {
45}
46
47int32_t PepperTrueTypeFontLinux::Initialize(
48    ppapi::proxy::SerializedTrueTypeFontDesc* desc) {
49  // If no face is provided, convert family to the platform defaults. These
50  // names should be mapped by FontConfig to an appropriate default font.
51  if (desc->family.empty()) {
52    switch (desc->generic_family) {
53      case PP_TRUETYPEFONTFAMILY_SERIF:
54        desc->family = "serif";
55        break;
56      case PP_TRUETYPEFONTFAMILY_SANSSERIF:
57        desc->family = "sans-serif";
58        break;
59      case PP_TRUETYPEFONTFAMILY_CURSIVE:
60        desc->family = "cursive";
61        break;
62      case PP_TRUETYPEFONTFAMILY_FANTASY:
63        desc->family = "fantasy";
64        break;
65      case PP_TRUETYPEFONTFAMILY_MONOSPACE:
66        desc->family = "monospace";
67        break;
68    }
69  }
70
71  fd_.reset(
72      MatchFontFaceWithFallback(desc->family,
73                                desc->weight >= PP_TRUETYPEFONTWEIGHT_BOLD,
74                                desc->style & PP_TRUETYPEFONTSTYLE_ITALIC,
75                                desc->charset,
76                                PP_BROWSERFONT_TRUSTED_FAMILY_DEFAULT));
77  // TODO(bbudge) Modify content API to return results of font matching and
78  // fallback, so we can update |desc| to reflect that.
79  return fd_.is_valid() ? PP_OK : PP_ERROR_FAILED;
80}
81
82int32_t PepperTrueTypeFontLinux::GetTableTags(std::vector<uint32_t>* tags) {
83  if (!fd_.is_valid())
84    return PP_ERROR_FAILED;
85  // Get the 2 byte numTables field at an offset of 4 in the font.
86  uint8_t num_tables_buf[2];
87  size_t output_length = sizeof(num_tables_buf);
88  if (!GetFontTable(fd_.get(),
89                    0 /* tag */,
90                    4 /* offset */,
91                    reinterpret_cast<uint8_t*>(&num_tables_buf),
92                    &output_length))
93    return PP_ERROR_FAILED;
94  DCHECK(output_length == sizeof(num_tables_buf));
95  // Font data is stored in big-endian order.
96  uint16_t num_tables = (num_tables_buf[0] << 8) | num_tables_buf[1];
97
98  // The font has a header, followed by n table entries in its directory.
99  static const size_t kFontHeaderSize = 12;
100  static const size_t kTableEntrySize = 16;
101  output_length = num_tables * kTableEntrySize;
102  scoped_ptr<uint8_t[]> table_entries(new uint8_t[output_length]);
103  // Get the table directory entries, which follow the font header.
104  if (!GetFontTable(fd_.get(),
105                    0 /* tag */,
106                    kFontHeaderSize /* offset */,
107                    table_entries.get(),
108                    &output_length))
109    return PP_ERROR_FAILED;
110  DCHECK(output_length == num_tables * kTableEntrySize);
111
112  tags->resize(num_tables);
113  for (uint16_t i = 0; i < num_tables; i++) {
114    uint8_t* entry = table_entries.get() + i * kTableEntrySize;
115    uint32_t tag = static_cast<uint32_t>(entry[0]) << 24 |
116                   static_cast<uint32_t>(entry[1]) << 16 |
117                   static_cast<uint32_t>(entry[2]) << 8 |
118                   static_cast<uint32_t>(entry[3]);
119    (*tags)[i] = tag;
120  }
121
122  return num_tables;
123}
124
125int32_t PepperTrueTypeFontLinux::GetTable(uint32_t table_tag,
126                                          int32_t offset,
127                                          int32_t max_data_length,
128                                          std::string* data) {
129  if (!fd_.is_valid())
130    return PP_ERROR_FAILED;
131  // Get the size of the font data first.
132  size_t table_size = 0;
133  // Tags are byte swapped on Linux.
134  table_tag = base::ByteSwap(table_tag);
135  if (!GetFontTable(fd_.get(), table_tag, offset, NULL, &table_size))
136    return PP_ERROR_FAILED;
137  // Only retrieve as much as the caller requested.
138  table_size = std::min(table_size, static_cast<size_t>(max_data_length));
139  data->resize(table_size);
140  if (!GetFontTable(fd_.get(),
141                    table_tag,
142                    offset,
143                    reinterpret_cast<uint8_t*>(&(*data)[0]),
144                    &table_size))
145    return PP_ERROR_FAILED;
146
147  return base::checked_cast<int32_t>(table_size);
148}
149
150}  // namespace
151
152// static
153PepperTrueTypeFont* PepperTrueTypeFont::Create() {
154  return new PepperTrueTypeFontLinux();
155}
156
157}  // namespace content
158