Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / content / browser / renderer_host / pepper / pepper_truetype_font_mac.mm
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 #import <ApplicationServices/ApplicationServices.h>
8
9 #include <stdio.h>
10
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/numerics/safe_conversions.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"
20
21 namespace content {
22
23 namespace {
24
25 static bool FindFloat(CFDictionaryRef dict, CFStringRef name, float* value) {
26   CFNumberRef num;
27   return CFDictionaryGetValueIfPresent(
28              dict, name, reinterpret_cast<const void**>(&num)) &&
29          CFNumberIsFloatType(num) &&
30          CFNumberGetValue(num, kCFNumberFloatType, value);
31 }
32
33 float GetMacWeight(PP_TrueTypeFontWeight_Dev weight) {
34   // Map values from NORMAL (400) to HEAVY (900) to the range [0 .. 1], and
35   // values below NORMAL to the range [-0.6 .. 0]. NORMAL should map to 0.
36   float normal = PP_TRUETYPEFONTWEIGHT_NORMAL;
37   float heavy = PP_TRUETYPEFONTWEIGHT_HEAVY;
38   return (weight - normal) / (heavy - normal);
39 }
40
41 PP_TrueTypeFontWeight_Dev GetPepperWeight(float weight) {
42   // Perform the inverse mapping of GetMacWeight.
43   return static_cast<PP_TrueTypeFontWeight_Dev>(
44       weight * (PP_TRUETYPEFONTWEIGHT_HEAVY - PP_TRUETYPEFONTWEIGHT_NORMAL) +
45       PP_TRUETYPEFONTWEIGHT_NORMAL);
46 }
47
48 float GetMacWidth(PP_TrueTypeFontWidth_Dev width) {
49   // Map values from NORMAL (4) to ULTRA_EXPANDED (8) to the range [0 .. 1],
50   // and values below NORMAL to the range [-1 .. 0]. Normal should map to 0.
51   float normal = PP_TRUETYPEFONTWIDTH_NORMAL;
52   float ultra_expanded = PP_TRUETYPEFONTWIDTH_ULTRAEXPANDED;
53   return (width - normal) / (ultra_expanded - normal);
54 }
55
56 PP_TrueTypeFontWidth_Dev GetPepperWidth(float width) {
57   // Perform the inverse mapping of GetMacWeight.
58   return static_cast<PP_TrueTypeFontWidth_Dev>(
59       width *
60           (PP_TRUETYPEFONTWIDTH_ULTRAEXPANDED - PP_TRUETYPEFONTWIDTH_NORMAL) +
61       PP_TRUETYPEFONTWIDTH_NORMAL);
62 }
63
64 #define MAKE_TABLE_TAG(a, b, c, d) ((a) << 24) + ((b) << 16) + ((c) << 8) + (d)
65
66 // TrueType font header and table entry structs. See
67 // https://developer.apple.com/fonts/TTRefMan/RM06/Chap6.html
68 struct FontHeader {
69   int32_t font_type;
70   uint16_t num_tables;
71   uint16_t search_range;
72   uint16_t entry_selector;
73   uint16_t range_shift;
74 };
75 static_assert(sizeof(FontHeader) == 12, "FontHeader wrong size");
76
77 struct FontDirectoryEntry {
78   uint32_t tag;
79   uint32_t checksum;
80   uint32_t offset;
81   uint32_t logical_length;
82 };
83 static_assert(sizeof(FontDirectoryEntry) == 16,
84               "FontDirectoryEntry wrong size");
85
86 uint32_t CalculateChecksum(char* table, int32_t table_length) {
87   uint32_t sum = 0;
88   uint32_t* current = reinterpret_cast<uint32_t*>(table);
89   uint32_t length = (table_length + 3) / 4;
90   // Raw font data is big-endian.
91   while (length-- > 0)
92     sum += base::NetToHost32(*current++);
93   return sum;
94 }
95
96 class PepperTrueTypeFontMac : public PepperTrueTypeFont {
97  public:
98   PepperTrueTypeFontMac();
99
100   // PepperTrueTypeFont implementation.
101   int32_t Initialize(ppapi::proxy::SerializedTrueTypeFontDesc* desc) override;
102   int32_t GetTableTags(std::vector<uint32_t>* tags) override;
103   int32_t GetTable(uint32_t table_tag,
104                    int32_t offset,
105                    int32_t max_data_length,
106                    std::string* data) override;
107
108  private:
109   ~PepperTrueTypeFontMac() override;
110
111   virtual int32_t GetEntireFont(int32_t offset,
112                                 int32_t max_data_length,
113                                 std::string* data);
114
115   base::ScopedCFTypeRef<CTFontRef> font_ref_;
116
117   DISALLOW_COPY_AND_ASSIGN(PepperTrueTypeFontMac);
118 };
119
120 PepperTrueTypeFontMac::PepperTrueTypeFontMac() {
121 }
122
123 PepperTrueTypeFontMac::~PepperTrueTypeFontMac() {
124 }
125
126 int32_t PepperTrueTypeFontMac::Initialize(
127     ppapi::proxy::SerializedTrueTypeFontDesc* desc) {
128   // Create the font in a nested scope, so we can use the same variable names
129   // when we get the actual font characteristics.
130   {
131     // Create attributes and traits dictionaries.
132     base::ScopedCFTypeRef<CFMutableDictionaryRef> attributes_ref(
133         CFDictionaryCreateMutable(kCFAllocatorDefault,
134                                   0,
135                                   &kCFTypeDictionaryKeyCallBacks,
136                                   &kCFTypeDictionaryValueCallBacks));
137
138     base::ScopedCFTypeRef<CFMutableDictionaryRef> traits_ref(
139         CFDictionaryCreateMutable(kCFAllocatorDefault,
140                                   0,
141                                   &kCFTypeDictionaryKeyCallBacks,
142                                   &kCFTypeDictionaryValueCallBacks));
143     if (!attributes_ref || !traits_ref)
144       return PP_ERROR_FAILED;
145
146     CFDictionaryAddValue(attributes_ref, kCTFontTraitsAttribute, traits_ref);
147
148     // Use symbolic traits to specify traits when possible.
149     CTFontSymbolicTraits symbolic_traits = 0;
150     if (desc->style & PP_TRUETYPEFONTSTYLE_ITALIC)
151       symbolic_traits |= kCTFontItalicTrait;
152     if (desc->weight == PP_TRUETYPEFONTWEIGHT_BOLD)
153       symbolic_traits |= kCTFontBoldTrait;
154     if (desc->width == PP_TRUETYPEFONTWIDTH_CONDENSED)
155       symbolic_traits |= kCTFontCondensedTrait;
156     else if (desc->width == PP_TRUETYPEFONTWIDTH_EXPANDED)
157       symbolic_traits |= kCTFontExpandedTrait;
158
159     base::ScopedCFTypeRef<CFNumberRef> symbolic_traits_ref(CFNumberCreate(
160         kCFAllocatorDefault, kCFNumberSInt32Type, &symbolic_traits));
161     if (!symbolic_traits_ref)
162       return PP_ERROR_FAILED;
163     CFDictionaryAddValue(traits_ref, kCTFontSymbolicTrait, symbolic_traits_ref);
164
165     // Font family matching doesn't work using family classes in symbolic
166     // traits. Instead, map generic_family to font families that are always
167     // available.
168     std::string family(desc->family);
169     if (family.empty()) {
170       switch (desc->generic_family) {
171         case PP_TRUETYPEFONTFAMILY_SERIF:
172           family = "Times";
173           break;
174         case PP_TRUETYPEFONTFAMILY_SANSSERIF:
175           family = "Helvetica";
176           break;
177         case PP_TRUETYPEFONTFAMILY_CURSIVE:
178           family = "Apple Chancery";
179           break;
180         case PP_TRUETYPEFONTFAMILY_FANTASY:
181           family = "Papyrus";
182           break;
183         case PP_TRUETYPEFONTFAMILY_MONOSPACE:
184           family = "Courier";
185           break;
186       }
187     }
188
189     base::ScopedCFTypeRef<CFStringRef> name_ref(
190         base::SysUTF8ToCFStringRef(family));
191     if (name_ref)
192       CFDictionaryAddValue(
193           attributes_ref, kCTFontFamilyNameAttribute, name_ref);
194
195     if (desc->weight != PP_TRUETYPEFONTWEIGHT_NORMAL &&
196         desc->weight != PP_TRUETYPEFONTWEIGHT_BOLD) {
197       float weight = GetMacWeight(desc->weight);
198       base::ScopedCFTypeRef<CFNumberRef> weight_trait_ref(
199           CFNumberCreate(kCFAllocatorDefault, kCFNumberFloat32Type, &weight));
200       if (weight_trait_ref)
201         CFDictionaryAddValue(traits_ref, kCTFontWeightTrait, weight_trait_ref);
202     }
203
204     if (desc->width != PP_TRUETYPEFONTWIDTH_NORMAL &&
205         desc->width != PP_TRUETYPEFONTWIDTH_CONDENSED &&
206         desc->width != PP_TRUETYPEFONTWIDTH_EXPANDED) {
207       float width = GetMacWidth(desc->width);
208       base::ScopedCFTypeRef<CFNumberRef> width_trait_ref(
209           CFNumberCreate(kCFAllocatorDefault, kCFNumberFloat32Type, &width));
210       if (width_trait_ref)
211         CFDictionaryAddValue(traits_ref, kCTFontWidthTrait, width_trait_ref);
212     }
213
214     base::ScopedCFTypeRef<CTFontDescriptorRef> desc_ref(
215         CTFontDescriptorCreateWithAttributes(attributes_ref));
216
217     if (desc_ref)
218       font_ref_.reset(CTFontCreateWithFontDescriptor(desc_ref, 0, NULL));
219
220     if (!font_ref_.get())
221       return PP_ERROR_FAILED;
222   }
223
224   // Now query to get the actual font characteristics.
225   base::ScopedCFTypeRef<CTFontDescriptorRef> desc_ref(
226       CTFontCopyFontDescriptor(font_ref_));
227
228   base::ScopedCFTypeRef<CFStringRef> family_name_ref(
229       base::mac::CFCast<CFStringRef>(
230           CTFontDescriptorCopyAttribute(desc_ref, kCTFontFamilyNameAttribute)));
231   desc->family = base::SysCFStringRefToUTF8(family_name_ref);
232
233   base::ScopedCFTypeRef<CFDictionaryRef> traits_ref(
234       base::mac::CFCast<CFDictionaryRef>(
235           CTFontDescriptorCopyAttribute(desc_ref, kCTFontTraitsAttribute)));
236
237   desc->style = PP_TRUETYPEFONTSTYLE_NORMAL;
238   CTFontSymbolicTraits symbolic_traits(CTFontGetSymbolicTraits(font_ref_));
239   if (symbolic_traits & kCTFontItalicTrait)
240     desc->style = static_cast<PP_TrueTypeFontStyle_Dev>(
241         desc->style | PP_TRUETYPEFONTSTYLE_ITALIC);
242   if (symbolic_traits & kCTFontBoldTrait) {
243     desc->weight = PP_TRUETYPEFONTWEIGHT_BOLD;
244   } else {
245     float weight;
246     if (FindFloat(traits_ref, kCTFontWeightTrait, &weight))
247       desc->weight = GetPepperWeight(weight);
248   }
249   if (symbolic_traits & kCTFontCondensedTrait) {
250     desc->width = PP_TRUETYPEFONTWIDTH_CONDENSED;
251   } else if (symbolic_traits & kCTFontExpandedTrait) {
252     desc->width = PP_TRUETYPEFONTWIDTH_EXPANDED;
253   } else {
254     float width;
255     if (FindFloat(traits_ref, kCTFontWidthTrait, &width))
256       desc->width = GetPepperWidth(width);
257   }
258
259   // Character set isn't supported on Mac.
260   desc->charset = PP_TRUETYPEFONTCHARSET_DEFAULT;
261   return PP_OK;
262 }
263
264 int32_t PepperTrueTypeFontMac::GetTableTags(std::vector<uint32_t>* tags) {
265   if (!font_ref_.get())
266     return PP_ERROR_FAILED;
267   base::ScopedCFTypeRef<CFArrayRef> tag_array(
268       CTFontCopyAvailableTables(font_ref_, kCTFontTableOptionNoOptions));
269   if (!tag_array)
270     return PP_ERROR_FAILED;
271
272   // Items returned by CTFontCopyAvailableTables are not boxed. Whose bright
273   // idea was this?
274   CFIndex length = CFArrayGetCount(tag_array);
275   tags->resize(length);
276   for (CFIndex i = 0; i < length; ++i) {
277     (*tags)[i] =
278         reinterpret_cast<uintptr_t>(CFArrayGetValueAtIndex(tag_array, i));
279   }
280   return length;
281 }
282
283 int32_t PepperTrueTypeFontMac::GetTable(uint32_t table_tag,
284                                         int32_t offset,
285                                         int32_t max_data_length,
286                                         std::string* data) {
287   if (!font_ref_.get())
288     return PP_ERROR_FAILED;
289
290   if (!table_tag)
291     return GetEntireFont(offset, max_data_length, data);
292
293   base::ScopedCFTypeRef<CFDataRef> table_ref(
294       CTFontCopyTable(font_ref_,
295                       static_cast<CTFontTableTag>(table_tag),
296                       kCTFontTableOptionNoOptions));
297   if (!table_ref)
298     return PP_ERROR_FAILED;
299
300   CFIndex table_size = CFDataGetLength(table_ref);
301   CFIndex safe_offset =
302       std::min(base::checked_cast<CFIndex>(offset), table_size);
303   CFIndex safe_length = std::min(table_size - safe_offset,
304                                  base::checked_cast<CFIndex>(max_data_length));
305   data->resize(safe_length);
306   CFDataGetBytes(table_ref,
307                  CFRangeMake(safe_offset, safe_length),
308                  reinterpret_cast<UInt8*>(&(*data)[0]));
309
310   return safe_length;
311 }
312
313 int32_t PepperTrueTypeFontMac::GetEntireFont(int32_t offset,
314                                              int32_t max_data_length,
315                                              std::string* data) {
316   // Reconstruct the font header, table directory, and tables.
317   std::vector<uint32_t> table_tags;
318   int32_t table_count = GetTableTags(&table_tags);
319   if (table_count < 0)
320     return table_count;  // PPAPI error code.
321
322   // Allocate enough room for the header and the table directory entries.
323   std::string font(
324       sizeof(FontHeader) + sizeof(FontDirectoryEntry) * table_count, 0);
325   // Map the OS X font type value to a TrueType scalar type.
326   base::ScopedCFTypeRef<CFNumberRef> font_type_ref(
327       base::mac::CFCast<CFNumberRef>(
328           CTFontCopyAttribute(font_ref_, kCTFontFormatAttribute)));
329   int32_t font_type;
330   CFNumberGetValue(font_type_ref, kCFNumberSInt32Type, &font_type);
331   switch (font_type) {
332     case kCTFontFormatOpenTypePostScript:
333       font_type = MAKE_TABLE_TAG('O', 'T', 'T', 'O');
334       break;
335     case kCTFontFormatTrueType:
336     case kCTFontFormatBitmap:
337       font_type = MAKE_TABLE_TAG('t', 'r', 'u', 'e');
338       break;
339     case kCTFontFormatPostScript:
340       font_type = MAKE_TABLE_TAG('t', 'y', 'p', '1');
341       break;
342     case kCTFontFormatOpenTypeTrueType:
343     case kCTFontFormatUnrecognized:
344     default:
345       font_type = MAKE_TABLE_TAG(0, 1, 0, 0);
346       break;
347   }
348
349   // Calculate the rest of the header values.
350   uint16_t num_tables = base::checked_cast<uint16_t>(table_count);
351   uint16_t entry_selector = 0;
352   uint16_t search_range = 1;
353   while (search_range < (num_tables >> 1)) {
354     entry_selector++;
355     search_range <<= 1;
356   }
357   search_range <<= 4;
358   uint16_t range_shift = (num_tables << 4) - search_range;
359
360   // Write the header, with values in big-endian order.
361   FontHeader* font_header = reinterpret_cast<FontHeader*>(&font[0]);
362   font_header->font_type = base::HostToNet32(font_type);
363   font_header->num_tables = base::HostToNet16(num_tables);
364   font_header->search_range = base::HostToNet16(search_range);
365   font_header->entry_selector = base::HostToNet16(entry_selector);
366   font_header->range_shift = base::HostToNet16(range_shift);
367
368   for (int32_t i = 0; i < table_count; i++) {
369     // Get the table data.
370     std::string table;
371     int32_t table_size =
372         GetTable(table_tags[i], 0, std::numeric_limits<int32_t>::max(), &table);
373     if (table_size < 0)
374       return table_size;  // PPAPI error code.
375
376     // Append it to the font data so far, and zero pad so tables stay aligned.
377     size_t table_offset = font.size();
378     font.append(table);
379     size_t padding = font.size() & 0x3;
380     font.append(padding, 0);
381
382     // Fill in the directory entry for this table.
383     FontDirectoryEntry* entry = reinterpret_cast<FontDirectoryEntry*>(
384         &font[0] + sizeof(FontHeader) + i * sizeof(FontDirectoryEntry));
385     entry->tag = base::HostToNet32(table_tags[i]);
386     entry->checksum =
387         base::HostToNet32(CalculateChecksum(&font[table_offset], table_size));
388     entry->offset = base::HostToNet32(table_offset);
389     entry->logical_length = base::HostToNet32(table_size);
390     // TODO(bbudge) set the 'head' table checksumAdjustment.
391   }
392
393   // Extract a substring if the caller specified an offset or max data length.
394   int32_t font_size = base::checked_cast<int32_t>(font.size());
395   int32_t safe_offset = std::min(offset, font_size);
396   int32_t safe_length = std::min(font_size - safe_offset, max_data_length);
397   if (safe_offset || safe_length != font_size)
398     font = font.substr(safe_offset, safe_length);
399
400   data->clear();
401   data->swap(font);
402   return safe_length;
403 }
404
405 }  // namespace
406
407 // static
408 PepperTrueTypeFont* PepperTrueTypeFont::Create() {
409   return new PepperTrueTypeFontMac();
410 }
411
412 }  // namespace content