| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "content/browser/renderer_host/pepper/pepper_truetype_font.h" |
| |
| #include <windows.h> |
| #include <set> |
| |
| #include "base/compiler_specific.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/sys_byteorder.h" |
| #include "base/win/scoped_gdi_object.h" |
| #include "base/win/scoped_hdc.h" |
| #include "base/win/scoped_select_object.h" |
| #include "ppapi/c/dev/ppb_truetype_font_dev.h" |
| #include "ppapi/c/pp_errors.h" |
| |
| namespace content { |
| |
| namespace { |
| |
| class PepperTrueTypeFontWin : public PepperTrueTypeFont { |
| public: |
| PepperTrueTypeFontWin(); |
| |
| // PepperTrueTypeFont implementation. |
| int32_t Initialize(ppapi::proxy::SerializedTrueTypeFontDesc* desc) override; |
| int32_t GetTableTags(std::vector<uint32_t>* tags) override; |
| int32_t GetTable(uint32_t table_tag, |
| int32_t offset, |
| int32_t max_data_length, |
| std::string* data) override; |
| |
| private: |
| ~PepperTrueTypeFontWin() override; |
| |
| DWORD GetFontData(HDC hdc, |
| DWORD table, |
| DWORD offset, |
| LPVOID buffer, |
| DWORD length); |
| |
| base::win::ScopedHFONT font_; |
| |
| DISALLOW_COPY_AND_ASSIGN(PepperTrueTypeFontWin); |
| }; |
| |
| PepperTrueTypeFontWin::PepperTrueTypeFontWin() { |
| } |
| |
| PepperTrueTypeFontWin::~PepperTrueTypeFontWin() { |
| } |
| |
| int32_t PepperTrueTypeFontWin::Initialize( |
| ppapi::proxy::SerializedTrueTypeFontDesc* desc) { |
| DWORD pitch_and_family = DEFAULT_PITCH; |
| switch (desc->generic_family) { |
| case PP_TRUETYPEFONTFAMILY_SERIF: |
| pitch_and_family |= FF_ROMAN; |
| break; |
| case PP_TRUETYPEFONTFAMILY_SANSSERIF: |
| pitch_and_family |= FF_SWISS; |
| break; |
| case PP_TRUETYPEFONTFAMILY_CURSIVE: |
| pitch_and_family |= FF_SCRIPT; |
| break; |
| case PP_TRUETYPEFONTFAMILY_FANTASY: |
| pitch_and_family |= FF_DECORATIVE; |
| break; |
| case PP_TRUETYPEFONTFAMILY_MONOSPACE: |
| pitch_and_family |= FF_MODERN; |
| break; |
| } |
| // TODO(bbudge) support widths (extended, condensed). |
| |
| font_.Set(CreateFont(0 /* height */, |
| 0 /* width */, |
| 0 /* escapement */, |
| 0 /* orientation */, |
| desc->weight, // our weight enum matches Windows. |
| (desc->style & PP_TRUETYPEFONTSTYLE_ITALIC) ? 1 : 0, |
| 0 /* underline */, |
| 0 /* strikeout */, |
| desc->charset, // our charset enum matches Windows. |
| OUT_OUTLINE_PRECIS, // truetype and other outline fonts |
| CLIP_DEFAULT_PRECIS, |
| DEFAULT_QUALITY, |
| pitch_and_family, |
| base::UTF8ToUTF16(desc->family).c_str())); |
| if (!font_.Get()) |
| return PP_ERROR_FAILED; |
| |
| LOGFONT font_desc; |
| if (!::GetObject(font_.Get(), sizeof(LOGFONT), &font_desc)) |
| return PP_ERROR_FAILED; |
| |
| switch (font_desc.lfPitchAndFamily & 0xF0) { // Top 4 bits are family. |
| case FF_ROMAN: |
| desc->generic_family = PP_TRUETYPEFONTFAMILY_SERIF; |
| break; |
| case FF_SWISS: |
| desc->generic_family = PP_TRUETYPEFONTFAMILY_SANSSERIF; |
| break; |
| case FF_SCRIPT: |
| desc->generic_family = PP_TRUETYPEFONTFAMILY_CURSIVE; |
| break; |
| case FF_DECORATIVE: |
| desc->generic_family = PP_TRUETYPEFONTFAMILY_FANTASY; |
| break; |
| case FF_MODERN: |
| desc->generic_family = PP_TRUETYPEFONTFAMILY_MONOSPACE; |
| break; |
| } |
| |
| desc->style = font_desc.lfItalic ? PP_TRUETYPEFONTSTYLE_ITALIC |
| : PP_TRUETYPEFONTSTYLE_NORMAL; |
| desc->weight = static_cast<PP_TrueTypeFontWeight_Dev>(font_desc.lfWeight); |
| desc->width = PP_TRUETYPEFONTWIDTH_NORMAL; |
| desc->charset = static_cast<PP_TrueTypeFontCharset_Dev>(font_desc.lfCharSet); |
| |
| // To get the face name, select the font and query for the name. GetObject |
| // doesn't fill in the name field of the LOGFONT structure. |
| base::win::ScopedCreateDC hdc(::CreateCompatibleDC(NULL)); |
| if (hdc.IsValid()) { |
| base::win::ScopedSelectObject select_object(hdc.Get(), font_.Get()); |
| WCHAR name[LF_FACESIZE]; |
| GetTextFace(hdc.Get(), LF_FACESIZE, name); |
| desc->family = base::UTF16ToUTF8(name); |
| } |
| |
| return PP_OK; |
| } |
| |
| int32_t PepperTrueTypeFontWin::GetTableTags(std::vector<uint32_t>* tags) { |
| if (!font_.Get()) |
| return PP_ERROR_FAILED; |
| |
| base::win::ScopedCreateDC hdc(::CreateCompatibleDC(NULL)); |
| if (!hdc.IsValid()) |
| return PP_ERROR_FAILED; |
| |
| base::win::ScopedSelectObject select_object(hdc.Get(), font_.Get()); |
| |
| // Get the whole font header. |
| static const DWORD kFontHeaderSize = 12; |
| uint8_t header_buf[kFontHeaderSize]; |
| if (GetFontData(hdc.Get(), 0, 0, header_buf, kFontHeaderSize) == GDI_ERROR) |
| return PP_ERROR_FAILED; |
| |
| // The numTables follows a 4 byte scalerType tag. Font data is stored in |
| // big-endian order. |
| DWORD num_tables = (header_buf[4] << 8) | header_buf[5]; |
| |
| // The size in bytes of an entry in the table directory. |
| static const DWORD kDirectoryEntrySize = 16; |
| DWORD directory_size = num_tables * kDirectoryEntrySize; |
| scoped_ptr<uint8_t[]> directory(new uint8_t[directory_size]); |
| // Get the table directory entries after the font header. |
| if (GetFontData(hdc.Get(), 0 /* tag */, kFontHeaderSize, directory.get(), |
| directory_size) == |
| GDI_ERROR) |
| return PP_ERROR_FAILED; |
| |
| tags->resize(num_tables); |
| for (DWORD i = 0; i < num_tables; i++) { |
| const uint8_t* entry = directory.get() + i * kDirectoryEntrySize; |
| uint32_t tag = static_cast<uint32_t>(entry[0]) << 24 | |
| static_cast<uint32_t>(entry[1]) << 16 | |
| static_cast<uint32_t>(entry[2]) << 8 | |
| static_cast<uint32_t>(entry[3]); |
| (*tags)[i] = tag; |
| } |
| |
| return num_tables; |
| } |
| |
| int32_t PepperTrueTypeFontWin::GetTable(uint32_t table_tag, |
| int32_t offset, |
| int32_t max_data_length, |
| std::string* data) { |
| if (!font_.Get()) |
| return PP_ERROR_FAILED; |
| |
| base::win::ScopedCreateDC hdc(::CreateCompatibleDC(NULL)); |
| if (!hdc.IsValid()) |
| return PP_ERROR_FAILED; |
| |
| base::win::ScopedSelectObject select_object(hdc.Get(), font_.Get()); |
| |
| // Tags are byte swapped on Windows. |
| table_tag = base::ByteSwap(table_tag); |
| // Get the size of the font table first. |
| DWORD table_size = GetFontData(hdc.Get(), table_tag, 0, NULL, 0); |
| if (table_size == GDI_ERROR) |
| return PP_ERROR_FAILED; |
| |
| DWORD safe_offset = std::min(static_cast<DWORD>(offset), table_size); |
| DWORD safe_length = |
| std::min(table_size - safe_offset, static_cast<DWORD>(max_data_length)); |
| data->resize(safe_length); |
| if (safe_length == 0) { |
| table_size = 0; |
| } else { |
| table_size = GetFontData(hdc.Get(), |
| table_tag, |
| safe_offset, |
| reinterpret_cast<uint8_t*>(&(*data)[0]), |
| safe_length); |
| if (table_size == GDI_ERROR) |
| return PP_ERROR_FAILED; |
| } |
| return static_cast<int32_t>(table_size); |
| } |
| |
| DWORD PepperTrueTypeFontWin::GetFontData(HDC hdc, |
| DWORD table, |
| DWORD offset, |
| void* buffer, |
| DWORD length) { |
| // If this is a zero byte read, return a successful result. |
| if (buffer && !length) |
| return 0; |
| |
| return ::GetFontData(hdc, table, offset, buffer, length); |
| } |
| |
| } // namespace |
| |
| // static |
| PepperTrueTypeFont* PepperTrueTypeFont::Create() { |
| return new PepperTrueTypeFontWin(); |
| } |
| |
| } // namespace content |