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 if (safe_length == 0) { 227 table_size = 0; 228 } else { 229 table_size = GetFontData(hdc, table_tag, safe_offset, 230 reinterpret_cast<uint8_t*>(&(*data)[0]), 231 safe_length); 232 if (table_size == GDI_ERROR) 233 return PP_ERROR_FAILED; 234 } 235 return static_cast<int32_t>(table_size); 236 } 237 238 } // namespace 239 240 // static 241 PepperTrueTypeFont* PepperTrueTypeFont::Create( 242 const ppapi::proxy::SerializedTrueTypeFontDesc& desc) { 243 return new PepperTrueTypeFontWin(desc); 244 } 245 246 } // namespace content 247