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 "content/browser/renderer_host/pepper/pepper_truetype_font.h"
6
7#include <windows.h>
8#include <set>
9
10#include "base/compiler_specific.h"
11#include "base/memory/scoped_ptr.h"
12#include "base/strings/utf_string_conversions.h"
13#include "base/sys_byteorder.h"
14#include "base/win/scoped_gdi_object.h"
15#include "base/win/scoped_hdc.h"
16#include "base/win/scoped_select_object.h"
17#include "ppapi/c/dev/ppb_truetype_font_dev.h"
18#include "ppapi/c/pp_errors.h"
19
20namespace content {
21
22namespace {
23
24class PepperTrueTypeFontWin : public PepperTrueTypeFont {
25 public:
26  PepperTrueTypeFontWin();
27
28  // PepperTrueTypeFont implementation.
29  virtual int32_t Initialize(
30      ppapi::proxy::SerializedTrueTypeFontDesc* desc) OVERRIDE;
31  virtual int32_t GetTableTags(std::vector<uint32_t>* tags) OVERRIDE;
32  virtual int32_t GetTable(uint32_t table_tag,
33                           int32_t offset,
34                           int32_t max_data_length,
35                           std::string* data) OVERRIDE;
36
37 private:
38  virtual ~PepperTrueTypeFontWin();
39
40  DWORD GetFontData(HDC hdc,
41                    DWORD table,
42                    DWORD offset,
43                    LPVOID buffer,
44                    DWORD length);
45
46  base::win::ScopedHFONT font_;
47
48  DISALLOW_COPY_AND_ASSIGN(PepperTrueTypeFontWin);
49};
50
51PepperTrueTypeFontWin::PepperTrueTypeFontWin() {
52}
53
54PepperTrueTypeFontWin::~PepperTrueTypeFontWin() {
55}
56
57int32_t PepperTrueTypeFontWin::Initialize(
58    ppapi::proxy::SerializedTrueTypeFontDesc* desc) {
59  DWORD pitch_and_family = DEFAULT_PITCH;
60  switch (desc->generic_family) {
61    case PP_TRUETYPEFONTFAMILY_SERIF:
62      pitch_and_family |= FF_ROMAN;
63      break;
64    case PP_TRUETYPEFONTFAMILY_SANSSERIF:
65      pitch_and_family |= FF_SWISS;
66      break;
67    case PP_TRUETYPEFONTFAMILY_CURSIVE:
68      pitch_and_family |= FF_SCRIPT;
69      break;
70    case PP_TRUETYPEFONTFAMILY_FANTASY:
71      pitch_and_family |= FF_DECORATIVE;
72      break;
73    case PP_TRUETYPEFONTFAMILY_MONOSPACE:
74      pitch_and_family |= FF_MODERN;
75      break;
76  }
77  // TODO(bbudge) support widths (extended, condensed).
78
79  font_.Set(CreateFont(0 /* height */,
80                       0 /* width */,
81                       0 /* escapement */,
82                       0 /* orientation */,
83                       desc->weight,  // our weight enum matches Windows.
84                       (desc->style & PP_TRUETYPEFONTSTYLE_ITALIC) ? 1 : 0,
85                       0 /* underline */,
86                       0 /* strikeout */,
87                       desc->charset,       // our charset enum matches Windows.
88                       OUT_OUTLINE_PRECIS,  // truetype and other outline fonts
89                       CLIP_DEFAULT_PRECIS,
90                       DEFAULT_QUALITY,
91                       pitch_and_family,
92                       base::UTF8ToUTF16(desc->family).c_str()));
93  if (!font_.Get())
94    return PP_ERROR_FAILED;
95
96  LOGFONT font_desc;
97  if (!::GetObject(font_.Get(), sizeof(LOGFONT), &font_desc))
98    return PP_ERROR_FAILED;
99
100  switch (font_desc.lfPitchAndFamily & 0xF0) {  // Top 4 bits are family.
101    case FF_ROMAN:
102      desc->generic_family = PP_TRUETYPEFONTFAMILY_SERIF;
103      break;
104    case FF_SWISS:
105      desc->generic_family = PP_TRUETYPEFONTFAMILY_SANSSERIF;
106      break;
107    case FF_SCRIPT:
108      desc->generic_family = PP_TRUETYPEFONTFAMILY_CURSIVE;
109      break;
110    case FF_DECORATIVE:
111      desc->generic_family = PP_TRUETYPEFONTFAMILY_FANTASY;
112      break;
113    case FF_MODERN:
114      desc->generic_family = PP_TRUETYPEFONTFAMILY_MONOSPACE;
115      break;
116  }
117
118  desc->style = font_desc.lfItalic ? PP_TRUETYPEFONTSTYLE_ITALIC
119                                   : PP_TRUETYPEFONTSTYLE_NORMAL;
120  desc->weight = static_cast<PP_TrueTypeFontWeight_Dev>(font_desc.lfWeight);
121  desc->width = PP_TRUETYPEFONTWIDTH_NORMAL;
122  desc->charset = static_cast<PP_TrueTypeFontCharset_Dev>(font_desc.lfCharSet);
123
124  // To get the face name, select the font and query for the name. GetObject
125  // doesn't fill in the name field of the LOGFONT structure.
126  base::win::ScopedCreateDC hdc(::CreateCompatibleDC(NULL));
127  if (hdc.IsValid()) {
128    base::win::ScopedSelectObject select_object(hdc.Get(), font_.Get());
129    WCHAR name[LF_FACESIZE];
130    GetTextFace(hdc.Get(), LF_FACESIZE, name);
131    desc->family = base::UTF16ToUTF8(name);
132  }
133
134  return PP_OK;
135}
136
137int32_t PepperTrueTypeFontWin::GetTableTags(std::vector<uint32_t>* tags) {
138  if (!font_.Get())
139    return PP_ERROR_FAILED;
140
141  base::win::ScopedCreateDC hdc(::CreateCompatibleDC(NULL));
142  if (!hdc.IsValid())
143    return PP_ERROR_FAILED;
144
145  base::win::ScopedSelectObject select_object(hdc.Get(), font_.Get());
146
147  // Get the whole font header.
148  static const DWORD kFontHeaderSize = 12;
149  uint8_t header_buf[kFontHeaderSize];
150  if (GetFontData(hdc.Get(), 0, 0, header_buf, kFontHeaderSize) == GDI_ERROR)
151    return PP_ERROR_FAILED;
152
153  // The numTables follows a 4 byte scalerType tag. Font data is stored in
154  // big-endian order.
155  DWORD num_tables = (header_buf[4] << 8) | header_buf[5];
156
157  // The size in bytes of an entry in the table directory.
158  static const DWORD kDirectoryEntrySize = 16;
159  DWORD directory_size = num_tables * kDirectoryEntrySize;
160  scoped_ptr<uint8_t[]> directory(new uint8_t[directory_size]);
161  // Get the table directory entries after the font header.
162  if (GetFontData(hdc.Get(), 0 /* tag */, kFontHeaderSize, directory.get(),
163                  directory_size) ==
164      GDI_ERROR)
165    return PP_ERROR_FAILED;
166
167  tags->resize(num_tables);
168  for (DWORD i = 0; i < num_tables; i++) {
169    const uint8_t* entry = directory.get() + i * kDirectoryEntrySize;
170    uint32_t tag = static_cast<uint32_t>(entry[0]) << 24 |
171                   static_cast<uint32_t>(entry[1]) << 16 |
172                   static_cast<uint32_t>(entry[2]) << 8 |
173                   static_cast<uint32_t>(entry[3]);
174    (*tags)[i] = tag;
175  }
176
177  return num_tables;
178}
179
180int32_t PepperTrueTypeFontWin::GetTable(uint32_t table_tag,
181                                        int32_t offset,
182                                        int32_t max_data_length,
183                                        std::string* data) {
184  if (!font_.Get())
185    return PP_ERROR_FAILED;
186
187  base::win::ScopedCreateDC hdc(::CreateCompatibleDC(NULL));
188  if (!hdc.IsValid())
189    return PP_ERROR_FAILED;
190
191  base::win::ScopedSelectObject select_object(hdc.Get(), font_.Get());
192
193  // Tags are byte swapped on Windows.
194  table_tag = base::ByteSwap(table_tag);
195  // Get the size of the font table first.
196  DWORD table_size = GetFontData(hdc.Get(), table_tag, 0, NULL, 0);
197  if (table_size == GDI_ERROR)
198    return PP_ERROR_FAILED;
199
200  DWORD safe_offset = std::min(static_cast<DWORD>(offset), table_size);
201  DWORD safe_length =
202      std::min(table_size - safe_offset, static_cast<DWORD>(max_data_length));
203  data->resize(safe_length);
204  if (safe_length == 0) {
205    table_size = 0;
206  } else {
207    table_size = GetFontData(hdc.Get(),
208                             table_tag,
209                             safe_offset,
210                             reinterpret_cast<uint8_t*>(&(*data)[0]),
211                             safe_length);
212    if (table_size == GDI_ERROR)
213      return PP_ERROR_FAILED;
214  }
215  return static_cast<int32_t>(table_size);
216}
217
218DWORD PepperTrueTypeFontWin::GetFontData(HDC hdc,
219                                         DWORD table,
220                                         DWORD offset,
221                                         void* buffer,
222                                         DWORD length) {
223  // If this is a zero byte read, return a successful result.
224  if (buffer && !length)
225    return 0;
226
227  return ::GetFontData(hdc, table, offset, buffer, length);
228}
229
230}  // namespace
231
232// static
233PepperTrueTypeFont* PepperTrueTypeFont::Create() {
234  return new PepperTrueTypeFontWin();
235}
236
237}  // namespace content
238