root/content/renderer/pepper/pepper_truetype_font_win.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. IsValid
  2. Describe
  3. GetFontData
  4. GetTableTags
  5. GetTable
  6. Create

// Copyright (c) 2013 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/renderer/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_hdc.h"
#include "base/win/scoped_select_object.h"
#include "content/public/renderer/render_thread.h"
#include "ppapi/c/dev/ppb_truetype_font_dev.h"
#include "ppapi/c/pp_errors.h"

namespace content {

namespace {

class PepperTrueTypeFontWin : public PepperTrueTypeFont {
 public:
  explicit PepperTrueTypeFontWin(
      const ppapi::proxy::SerializedTrueTypeFontDesc& desc);
  virtual ~PepperTrueTypeFontWin();

  // PepperTrueTypeFont overrides.
  virtual bool IsValid() OVERRIDE;
  virtual int32_t Describe(
      ppapi::proxy::SerializedTrueTypeFontDesc* desc) OVERRIDE;
  virtual int32_t GetTableTags(std::vector<uint32_t>* tags) OVERRIDE;
  virtual int32_t GetTable(uint32_t table_tag,
                           int32_t offset,
                           int32_t max_data_length,
                           std::string* data) OVERRIDE;
 private:
  DWORD GetFontData(HDC hdc,
                    DWORD table,
                    DWORD offset,
                    LPVOID buffer,
                    DWORD length);

  HFONT font_;

  DISALLOW_COPY_AND_ASSIGN(PepperTrueTypeFontWin);
};

PepperTrueTypeFontWin::PepperTrueTypeFontWin(
    const 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_ = 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());
}

PepperTrueTypeFontWin::~PepperTrueTypeFontWin() {
}

bool PepperTrueTypeFontWin::IsValid() {
  return font_ != NULL;
}

int32_t PepperTrueTypeFontWin::Describe(
      ppapi::proxy::SerializedTrueTypeFontDesc* desc) {
  LOGFONT font_desc;
  if (!::GetObject(font_, 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) {
    base::win::ScopedSelectObject select_object(hdc, font_);
    WCHAR name[LF_FACESIZE];
    GetTextFace(hdc, LF_FACESIZE, name);
    desc->family = base::UTF16ToUTF8(name);
  }
  return PP_OK;
}

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;

  DWORD result = ::GetFontData(hdc, table, offset, buffer, length);
  if (result == GDI_ERROR) {
    // The font may not be cached by the OS, causing an attempt to read it in
    // the renderer process to fail. Attempt to pre-cache it.
    LOGFONTW logfont;
    if (!::GetObject(font_, sizeof(LOGFONTW), &logfont))
      return GDI_ERROR;
    RenderThread* render_thread = RenderThread::Get();
    if (!render_thread)
      return GDI_ERROR;
    render_thread->PreCacheFont(logfont);

    result = ::GetFontData(hdc, table, offset, buffer, length);
  }
  return result;
}

int32_t PepperTrueTypeFontWin::GetTableTags(std::vector<uint32_t>* tags) {
  base::win::ScopedCreateDC hdc(::CreateCompatibleDC(NULL));
  if (!hdc)
    return PP_ERROR_FAILED;

  base::win::ScopedSelectObject select_object(hdc, font_);

  // Get the whole font header.
  static const DWORD kFontHeaderSize = 12;
  uint8_t header_buf[kFontHeaderSize];
  if (GetFontData(hdc, 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, 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) {
  base::win::ScopedCreateDC hdc(::CreateCompatibleDC(NULL));
  if (!hdc)
    return PP_ERROR_FAILED;

  base::win::ScopedSelectObject select_object(hdc, font_);

  // 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, 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, 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);
}

}  // namespace

// static
PepperTrueTypeFont* PepperTrueTypeFont::Create(
    const ppapi::proxy::SerializedTrueTypeFontDesc& desc) {
  return new PepperTrueTypeFontWin(desc);
}

}  // namespace content

/* [<][>][^][v][top][bottom][index][help] */