Home | History | Annotate | Download | only in pepper
      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 
     20 namespace content {
     21 
     22 namespace {
     23 
     24 class 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 
     51 PepperTrueTypeFontWin::PepperTrueTypeFontWin() {
     52 }
     53 
     54 PepperTrueTypeFontWin::~PepperTrueTypeFontWin() {
     55 }
     56 
     57 int32_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 
    137 int32_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 
    180 int32_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 
    218 DWORD 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
    233 PepperTrueTypeFont* PepperTrueTypeFont::Create() {
    234   return new PepperTrueTypeFontWin();
    235 }
    236 
    237 }  // namespace content
    238