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.
5 #include "content/renderer/pepper/pepper_truetype_font.h"
7 #import <ApplicationServices/ApplicationServices.h>
11 #include "base/compiler_specific.h"
12 #include "base/mac/foundation_util.h"
13 #include "base/mac/scoped_cftyperef.h"
14 #include "base/mac/scoped_nsautorelease_pool.h"
15 #include "base/safe_numerics.h"
16 #include "base/strings/sys_string_conversions.h"
17 #include "base/sys_byteorder.h"
18 #include "ppapi/c/dev/ppb_truetype_font_dev.h"
19 #include "ppapi/c/pp_errors.h"
25 static bool FindFloat(CFDictionaryRef dict, CFStringRef name, float* value) {
28 CFDictionaryGetValueIfPresent(dict, name,
29 reinterpret_cast<const void**>(&num)) &&
30 CFNumberIsFloatType(num) &&
31 CFNumberGetValue(num, kCFNumberFloatType, value);
34 float GetMacWeight(PP_TrueTypeFontWeight_Dev weight) {
35 // Map values from NORMAL (400) to HEAVY (900) to the range [0 .. 1], and
36 // values below NORMAL to the range [-0.6 .. 0]. NORMAL should map to 0.
37 float normal = PP_TRUETYPEFONTWEIGHT_NORMAL;
38 float heavy = PP_TRUETYPEFONTWEIGHT_HEAVY;
39 return (weight - normal) / (heavy - normal);
42 PP_TrueTypeFontWeight_Dev GetPepperWeight(float weight) {
43 // Perform the inverse mapping of GetMacWeight.
44 return static_cast<PP_TrueTypeFontWeight_Dev>(
45 weight * (PP_TRUETYPEFONTWEIGHT_HEAVY - PP_TRUETYPEFONTWEIGHT_NORMAL) +
46 PP_TRUETYPEFONTWEIGHT_NORMAL);
49 float GetMacWidth(PP_TrueTypeFontWidth_Dev width) {
50 // Map values from NORMAL (4) to ULTRA_EXPANDED (8) to the range [0 .. 1],
51 // and values below NORMAL to the range [-1 .. 0]. Normal should map to 0.
52 float normal = PP_TRUETYPEFONTWIDTH_NORMAL;
53 float ultra_expanded = PP_TRUETYPEFONTWIDTH_ULTRAEXPANDED;
54 return (width - normal) / (ultra_expanded - normal);
57 PP_TrueTypeFontWidth_Dev GetPepperWidth(float width) {
58 // Perform the inverse mapping of GetMacWeight.
59 return static_cast<PP_TrueTypeFontWidth_Dev>(
61 (PP_TRUETYPEFONTWIDTH_ULTRAEXPANDED - PP_TRUETYPEFONTWIDTH_NORMAL) +
62 PP_TRUETYPEFONTWIDTH_NORMAL);
65 #define MAKE_TABLE_TAG(a, b, c, d) ((a) << 24) + ((b) << 16) + ((c) << 8) + (d)
67 // TrueType font header and table entry structs. See
68 // https://developer.apple.com/fonts/TTRefMan/RM06/Chap6.html
72 uint16_t search_range;
73 uint16_t entry_selector;
76 static_assert(sizeof(FontHeader) == 12, "FontHeader wrong size");
78 struct FontDirectoryEntry {
82 uint32_t logical_length;
84 static_assert(sizeof(FontDirectoryEntry) == 16,
85 "FontDirectoryEntry wrong size");
87 uint32_t CalculateChecksum(char* table, int32_t table_length) {
89 uint32_t* current = reinterpret_cast<uint32_t*>(table);
90 uint32_t length = (table_length + 3) / 4;
91 // Raw font data is big-endian.
93 sum += base::NetToHost32(*current++);
97 class PepperTrueTypeFontMac : public PepperTrueTypeFont {
99 explicit PepperTrueTypeFontMac(
100 const ppapi::proxy::SerializedTrueTypeFontDesc& desc);
101 virtual ~PepperTrueTypeFontMac() OVERRIDE;
103 // PepperTrueTypeFont overrides.
104 virtual bool IsValid() OVERRIDE;
105 virtual int32_t Describe(
106 ppapi::proxy::SerializedTrueTypeFontDesc* desc) OVERRIDE;
107 virtual int32_t GetTableTags(std::vector<uint32_t>* tags) OVERRIDE;
108 virtual int32_t GetTable(uint32_t table_tag,
110 int32_t max_data_length,
111 std::string* data) OVERRIDE;
113 virtual int32_t GetEntireFont(int32_t offset,
114 int32_t max_data_length,
117 base::ScopedCFTypeRef<CTFontRef> font_ref_;
119 DISALLOW_COPY_AND_ASSIGN(PepperTrueTypeFontMac);
122 PepperTrueTypeFontMac::PepperTrueTypeFontMac(
123 const ppapi::proxy::SerializedTrueTypeFontDesc& desc) {
124 // Create attributes and traits dictionaries.
125 base::ScopedCFTypeRef<CFMutableDictionaryRef> attributes_ref(
126 CFDictionaryCreateMutable(kCFAllocatorDefault,
128 &kCFTypeDictionaryKeyCallBacks,
129 &kCFTypeDictionaryValueCallBacks));
131 base::ScopedCFTypeRef<CFMutableDictionaryRef> traits_ref(
132 CFDictionaryCreateMutable(kCFAllocatorDefault,
134 &kCFTypeDictionaryKeyCallBacks,
135 &kCFTypeDictionaryValueCallBacks));
136 if (!attributes_ref || !traits_ref)
139 CFDictionaryAddValue(attributes_ref, kCTFontTraitsAttribute, traits_ref);
141 // Use symbolic traits to specify traits when possible.
142 CTFontSymbolicTraits symbolic_traits = 0;
143 if (desc.style & PP_TRUETYPEFONTSTYLE_ITALIC)
144 symbolic_traits |= kCTFontItalicTrait;
145 if (desc.weight == PP_TRUETYPEFONTWEIGHT_BOLD)
146 symbolic_traits |= kCTFontBoldTrait;
147 if (desc.width == PP_TRUETYPEFONTWIDTH_CONDENSED)
148 symbolic_traits |= kCTFontCondensedTrait;
149 else if (desc.width == PP_TRUETYPEFONTWIDTH_EXPANDED)
150 symbolic_traits |= kCTFontExpandedTrait;
152 base::ScopedCFTypeRef<CFNumberRef> symbolic_traits_ref(CFNumberCreate(
153 kCFAllocatorDefault, kCFNumberSInt32Type, &symbolic_traits));
154 if (!symbolic_traits_ref)
156 CFDictionaryAddValue(traits_ref, kCTFontSymbolicTrait, symbolic_traits_ref);
158 // Font family matching doesn't work using family classes in symbolic traits.
159 // Instead, map generic_family to font families that are always available.
160 std::string family(desc.family);
161 if (family.empty()) {
162 switch (desc.generic_family) {
163 case PP_TRUETYPEFONTFAMILY_SERIF:
166 case PP_TRUETYPEFONTFAMILY_SANSSERIF:
167 family = "Helvetica";
169 case PP_TRUETYPEFONTFAMILY_CURSIVE:
170 family = "Apple Chancery";
172 case PP_TRUETYPEFONTFAMILY_FANTASY:
175 case PP_TRUETYPEFONTFAMILY_MONOSPACE:
181 base::ScopedCFTypeRef<CFStringRef> name_ref(
182 base::SysUTF8ToCFStringRef(family));
184 CFDictionaryAddValue(attributes_ref, kCTFontFamilyNameAttribute, name_ref);
186 if (desc.weight != PP_TRUETYPEFONTWEIGHT_NORMAL &&
187 desc.weight != PP_TRUETYPEFONTWEIGHT_BOLD) {
188 float weight = GetMacWeight(desc.weight);
189 base::ScopedCFTypeRef<CFNumberRef> weight_trait_ref(
190 CFNumberCreate(kCFAllocatorDefault, kCFNumberFloat32Type, &weight));
191 if (weight_trait_ref)
192 CFDictionaryAddValue(traits_ref, kCTFontWeightTrait, weight_trait_ref);
195 if (desc.width != PP_TRUETYPEFONTWIDTH_NORMAL &&
196 desc.width != PP_TRUETYPEFONTWIDTH_CONDENSED &&
197 desc.width != PP_TRUETYPEFONTWIDTH_EXPANDED) {
198 float width = GetMacWidth(desc.width);
199 base::ScopedCFTypeRef<CFNumberRef> width_trait_ref(
200 CFNumberCreate(kCFAllocatorDefault, kCFNumberFloat32Type, &width));
202 CFDictionaryAddValue(traits_ref, kCTFontWidthTrait, width_trait_ref);
205 base::ScopedCFTypeRef<CTFontDescriptorRef> desc_ref(
206 CTFontDescriptorCreateWithAttributes(attributes_ref));
209 font_ref_.reset(CTFontCreateWithFontDescriptor(desc_ref, 0, NULL));
212 PepperTrueTypeFontMac::~PepperTrueTypeFontMac() {
215 bool PepperTrueTypeFontMac::IsValid() {
216 return font_ref_.get() != NULL;
219 int32_t PepperTrueTypeFontMac::Describe(
220 ppapi::proxy::SerializedTrueTypeFontDesc* desc) {
222 return PP_ERROR_FAILED;
224 base::ScopedCFTypeRef<CTFontDescriptorRef> desc_ref(
225 CTFontCopyFontDescriptor(font_ref_));
227 base::ScopedCFTypeRef<CFStringRef> family_name_ref(
228 base::mac::CFCast<CFStringRef>(
229 CTFontDescriptorCopyAttribute(desc_ref, kCTFontFamilyNameAttribute)));
230 desc->family = base::SysCFStringRefToUTF8(family_name_ref);
232 base::ScopedCFTypeRef<CFDictionaryRef> traits_ref(
233 base::mac::CFCast<CFDictionaryRef>(
234 CTFontDescriptorCopyAttribute(desc_ref, kCTFontTraitsAttribute)));
236 desc->style = PP_TRUETYPEFONTSTYLE_NORMAL;
237 CTFontSymbolicTraits symbolic_traits(CTFontGetSymbolicTraits(font_ref_));
238 if (symbolic_traits & kCTFontItalicTrait)
239 desc->style = static_cast<PP_TrueTypeFontStyle_Dev>(
240 desc->style | PP_TRUETYPEFONTSTYLE_ITALIC);
241 if (symbolic_traits & kCTFontBoldTrait) {
242 desc->weight = PP_TRUETYPEFONTWEIGHT_BOLD;
245 if (FindFloat(traits_ref, kCTFontWeightTrait, &weight))
246 desc->weight = GetPepperWeight(weight);
248 if (symbolic_traits & kCTFontCondensedTrait) {
249 desc->width = PP_TRUETYPEFONTWIDTH_CONDENSED;
250 } else if (symbolic_traits & kCTFontExpandedTrait) {
251 desc->width = PP_TRUETYPEFONTWIDTH_EXPANDED;
254 if (FindFloat(traits_ref, kCTFontWidthTrait, &width))
255 desc->width = GetPepperWidth(width);
258 // Character set isn't supported on Mac.
259 desc->charset = PP_TRUETYPEFONTCHARSET_DEFAULT;
263 int32_t PepperTrueTypeFontMac::GetTableTags(std::vector<uint32_t>* tags) {
264 base::ScopedCFTypeRef<CFArrayRef> tag_array(
265 CTFontCopyAvailableTables(font_ref_, kCTFontTableOptionNoOptions));
267 return PP_ERROR_FAILED;
269 // Items returned by CTFontCopyAvailableTables are not boxed. Whose bright
271 CFIndex length = CFArrayGetCount(tag_array);
272 tags->resize(length);
273 for (CFIndex i = 0; i < length; ++i) {
275 reinterpret_cast<uintptr_t>(CFArrayGetValueAtIndex(tag_array, i));
280 int32_t PepperTrueTypeFontMac::GetTable(uint32_t table_tag,
282 int32_t max_data_length,
285 return GetEntireFont(offset, max_data_length, data);
287 base::ScopedCFTypeRef<CFDataRef> table_ref(
288 CTFontCopyTable(font_ref_,
289 static_cast<CTFontTableTag>(table_tag),
290 kCTFontTableOptionNoOptions));
292 return PP_ERROR_FAILED;
294 CFIndex table_size = CFDataGetLength(table_ref);
295 CFIndex safe_offset =
296 std::min(base::checked_numeric_cast<CFIndex>(offset), table_size);
297 CFIndex safe_length =
298 std::min(table_size - safe_offset,
299 base::checked_numeric_cast<CFIndex>(max_data_length));
300 data->resize(safe_length);
301 CFDataGetBytes(table_ref, CFRangeMake(safe_offset, safe_length),
302 reinterpret_cast<UInt8*>(&(*data)[0]));
307 int32_t PepperTrueTypeFontMac::GetEntireFont(int32_t offset,
308 int32_t max_data_length,
310 // Reconstruct the font header, table directory, and tables.
311 std::vector<uint32_t> table_tags;
312 int32_t table_count = GetTableTags(&table_tags);
314 return table_count; // PPAPI error code.
316 // Allocate enough room for the header and the table directory entries.
317 std::string font(sizeof(FontHeader) +
318 sizeof(FontDirectoryEntry) * table_count, 0);
319 // Map the OS X font type value to a TrueType scalar type.
320 base::ScopedCFTypeRef<CFNumberRef> font_type_ref(
321 base::mac::CFCast<CFNumberRef>(
322 CTFontCopyAttribute(font_ref_, kCTFontFormatAttribute)));
324 CFNumberGetValue(font_type_ref, kCFNumberSInt32Type, &font_type);
326 case kCTFontFormatOpenTypePostScript:
327 font_type = MAKE_TABLE_TAG('O', 'T', 'T', 'O');
329 case kCTFontFormatTrueType:
330 case kCTFontFormatBitmap:
331 font_type = MAKE_TABLE_TAG('t', 'r', 'u', 'e');
333 case kCTFontFormatPostScript:
334 font_type = MAKE_TABLE_TAG('t', 'y', 'p', '1');
336 case kCTFontFormatOpenTypeTrueType:
337 case kCTFontFormatUnrecognized:
339 font_type = MAKE_TABLE_TAG(0, 1, 0, 0);
343 // Calculate the rest of the header values.
344 uint16_t num_tables = base::checked_numeric_cast<uint16_t>(table_count);
345 uint16_t entry_selector = 0;
346 uint16_t search_range = 1;
347 while (search_range < num_tables >> 1) {
352 uint16_t range_shift = (num_tables << 4) - search_range;
354 // Write the header, with values in big-endian order.
355 FontHeader* font_header = reinterpret_cast<FontHeader*>(&font[0]);
356 font_header->font_type = base::HostToNet32(font_type);
357 font_header->num_tables = base::HostToNet16(num_tables);
358 font_header->search_range = base::HostToNet16(search_range);
359 font_header->entry_selector = base::HostToNet16(entry_selector);
360 font_header->range_shift = base::HostToNet16(range_shift);
362 for (int32_t i = 0; i < table_count; i++) {
363 // Get the table data.
365 int32_t table_size = GetTable(table_tags[i],
366 0, std::numeric_limits<int32_t>::max(),
369 return table_size; // PPAPI error code.
371 // Append it to the font data so far, and zero pad so tables stay aligned.
372 size_t table_offset = font.size();
374 size_t padding = font.size() & 0x3;
375 font.append(padding, 0);
377 // Fill in the directory entry for this table.
378 FontDirectoryEntry* entry = reinterpret_cast<FontDirectoryEntry*>(
379 &font[0] + sizeof(FontHeader) + i * sizeof(FontDirectoryEntry));
380 entry->tag = base::HostToNet32(table_tags[i]);
381 entry->checksum = base::HostToNet32(
382 CalculateChecksum(&font[table_offset], table_size));
383 entry->offset = base::HostToNet32(table_offset);
384 entry->logical_length = base::HostToNet32(table_size);
385 // TODO(bbudge) set the 'head' table checksumAdjustment.
388 // Extract a substring if the caller specified an offset or max data length.
389 int32_t font_size = base::checked_numeric_cast<int32_t>(font.size());
390 int32_t safe_offset = std::min(offset, font_size);
391 int32_t safe_length = std::min(font_size - safe_offset, max_data_length);
392 if (safe_offset || safe_length != font_size)
393 font = font.substr(safe_offset, safe_length);
403 PepperTrueTypeFont* PepperTrueTypeFont::Create(
404 const ppapi::proxy::SerializedTrueTypeFontDesc& desc) {
405 return new PepperTrueTypeFontMac(desc);
408 } // namespace content