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