summaryrefslogtreecommitdiffstats
path: root/content/common/mac
diff options
context:
space:
mode:
authoravi@chromium.org <avi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-09 23:05:34 +0000
committeravi@chromium.org <avi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-09 23:05:34 +0000
commit81fc9f01241ed5d635d35328fa226a682c7a81d2 (patch)
tree74b83b41373f3e6223461fb3bec44f43c799d599 /content/common/mac
parent8fdf9f5214e385b650c1a708a5c7e015b8fbde5e (diff)
downloadchromium_src-81fc9f01241ed5d635d35328fa226a682c7a81d2.zip
chromium_src-81fc9f01241ed5d635d35328fa226a682c7a81d2.tar.gz
chromium_src-81fc9f01241ed5d635d35328fa226a682c7a81d2.tar.bz2
Move AttributedStringCoder from chrome to content.
Also, move a few Mac-only files to the new content/commmon/mac. BUG=95573 TEST=no change Review URL: http://codereview.chromium.org/7867016 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@100526 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/common/mac')
-rw-r--r--content/common/mac/attributed_string_coder.h119
-rw-r--r--content/common/mac/attributed_string_coder.mm171
-rw-r--r--content/common/mac/attributed_string_coder_unittest.mm135
-rw-r--r--content/common/mac/font_descriptor.h34
-rw-r--r--content/common/mac/font_descriptor.mm25
-rw-r--r--content/common/mac/font_descriptor_unittest.mm114
-rw-r--r--content/common/mac/font_loader.h63
-rw-r--r--content/common/mac/font_loader.mm194
8 files changed, 855 insertions, 0 deletions
diff --git a/content/common/mac/attributed_string_coder.h b/content/common/mac/attributed_string_coder.h
new file mode 100644
index 0000000..054cb45
--- /dev/null
+++ b/content/common/mac/attributed_string_coder.h
@@ -0,0 +1,119 @@
+// Copyright (c) 2011 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.
+
+#ifndef CONTENT_COMMON_MAC_ATTRIBUTED_STRING_CODER_H_
+#define CONTENT_COMMON_MAC_ATTRIBUTED_STRING_CODER_H_
+#pragma once
+
+#include <set>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/string16.h"
+#include "content/common/mac/font_descriptor.h"
+#include "ipc/ipc_message_utils.h"
+#include "ui/base/range/range.h"
+
+#if __OBJC__
+@class NSAttributedString;
+@class NSDictionary;
+#else
+class NSAttributedString;
+class NSDictionary;
+#endif
+
+namespace mac {
+
+// This class will serialize the font information of an NSAttributedString so
+// that it can be sent over IPC. This class only stores the information of the
+// NSFontAttributeName. The motive is that of security: using NSArchiver and
+// friends to send objects from the renderer to the browser could lead to
+// deserialization of arbitrary objects. This class restricts serialization to
+// a specific object class and specific attributes of that object.
+class AttributedStringCoder {
+ public:
+ // A C++ IPC-friendly representation of the NSFontAttributeName attribute
+ // set.
+ class FontAttribute {
+ public:
+ FontAttribute(NSDictionary* ns_attributes, ui::Range effective_range);
+ FontAttribute(FontDescriptor font, ui::Range range);
+ FontAttribute();
+ ~FontAttribute();
+
+ // Creates an autoreleased NSDictionary that can be attached to an
+ // NSAttributedString.
+ NSDictionary* ToAttributesDictionary() const;
+
+ // Whether or not the attribute should be placed in the EncodedString. This
+ // can return false, e.g. if the Cocoa-based constructor can't find any
+ // information to encode.
+ bool ShouldEncode() const;
+
+ // Accessors:
+ FontDescriptor font_descriptor() const { return font_descriptor_; }
+ ui::Range effective_range() const { return effective_range_; }
+
+ private:
+ FontDescriptor font_descriptor_;
+ ui::Range effective_range_;
+ };
+
+ // A class that contains the pertinent information from an NSAttributedString,
+ // which can be serialized over IPC.
+ class EncodedString {
+ public:
+ explicit EncodedString(string16 string);
+ EncodedString();
+ ~EncodedString();
+
+ // Accessors:
+ string16 string() const { return string_; }
+ const std::vector<FontAttribute>& attributes() const {
+ return attributes_;
+ }
+ std::vector<FontAttribute>* attributes() { return &attributes_; }
+
+ private:
+ // The plain-text string.
+ string16 string_;
+ // The set of attributes that style |string_|.
+ std::vector<FontAttribute> attributes_;
+ };
+
+ // Takes an NSAttributedString, extracts the pertinent attributes, and returns
+ // an object that represents it. Caller owns the result.
+ static const EncodedString* Encode(NSAttributedString* str);
+
+ // Returns an autoreleased NSAttributedString from an encoded representation.
+ static NSAttributedString* Decode(const EncodedString* str);
+
+ private:
+ AttributedStringCoder();
+};
+
+} // namespace mac
+
+// IPC ParamTraits specialization //////////////////////////////////////////////
+
+namespace IPC {
+
+template <>
+struct ParamTraits<mac::AttributedStringCoder::EncodedString> {
+ typedef mac::AttributedStringCoder::EncodedString param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct ParamTraits<mac::AttributedStringCoder::FontAttribute> {
+ typedef mac::AttributedStringCoder::FontAttribute param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+} // namespace IPC
+
+#endif // CONTENT_COMMON_MAC_ATTRIBUTED_STRING_CODER_H_
diff --git a/content/common/mac/attributed_string_coder.mm b/content/common/mac/attributed_string_coder.mm
new file mode 100644
index 0000000..ca4847d
--- /dev/null
+++ b/content/common/mac/attributed_string_coder.mm
@@ -0,0 +1,171 @@
+// Copyright (c) 2011 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/common/mac/attributed_string_coder.h"
+
+#include <AppKit/AppKit.h>
+
+#include "base/logging.h"
+#include "base/memory/scoped_nsobject.h"
+#include "base/sys_string_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "content/common/common_param_traits.h"
+#include "content/common/view_messages.h"
+#include "ipc/ipc_message_utils.h"
+
+namespace mac {
+
+// static
+const AttributedStringCoder::EncodedString* AttributedStringCoder::Encode(
+ NSAttributedString* str) {
+ // Create the return value.
+ EncodedString* encoded_string =
+ new EncodedString(base::SysNSStringToUTF16([str string]));
+ // Iterate over all the attributes in the string.
+ NSUInteger length = [str length];
+ for (NSUInteger i = 0; i < length; ) {
+ NSRange effective_range;
+ NSDictionary* ns_attributes = [str attributesAtIndex:i
+ effectiveRange:&effective_range];
+ // Convert the attributes to IPC-friendly types.
+ FontAttribute attrs(ns_attributes, ui::Range(effective_range));
+ // Only encode the attributes if the filtered set contains font information.
+ if (attrs.ShouldEncode()) {
+ encoded_string->attributes()->push_back(attrs);
+ }
+ // Advance the iterator to the position outside of the effective range.
+ i = NSMaxRange(effective_range);
+ }
+ return encoded_string;
+}
+
+// static
+NSAttributedString* AttributedStringCoder::Decode(
+ const AttributedStringCoder::EncodedString* str) {
+ // Create the return value.
+ NSString* plain_text = base::SysUTF16ToNSString(str->string());
+ scoped_nsobject<NSMutableAttributedString> decoded_string(
+ [[NSMutableAttributedString alloc] initWithString:plain_text]);
+ // Iterate over all the encoded attributes, attaching each to the string.
+ const std::vector<FontAttribute> attributes = str->attributes();
+ for (std::vector<FontAttribute>::const_iterator it = attributes.begin();
+ it != attributes.end(); ++it) {
+ // Protect against ranges that are outside the range of the string.
+ const ui::Range& range = it->effective_range();
+ if (range.GetMin() > [plain_text length] ||
+ range.GetMax() > [plain_text length]) {
+ continue;
+ }
+ [decoded_string addAttributes:it->ToAttributesDictionary()
+ range:range.ToNSRange()];
+ }
+ return [decoded_string.release() autorelease];
+}
+
+// Data Types //////////////////////////////////////////////////////////////////
+
+AttributedStringCoder::EncodedString::EncodedString(string16 string)
+ : string_(string) {
+}
+
+AttributedStringCoder::EncodedString::EncodedString()
+ : string_() {
+}
+
+AttributedStringCoder::EncodedString::~EncodedString() {
+}
+
+AttributedStringCoder::FontAttribute::FontAttribute(NSDictionary* dict,
+ ui::Range effective_range)
+ : font_descriptor_(),
+ effective_range_(effective_range) {
+ NSFont* font = [dict objectForKey:NSFontAttributeName];
+ if (font) {
+ font_descriptor_ = FontDescriptor(font);
+ }
+}
+
+AttributedStringCoder::FontAttribute::FontAttribute(FontDescriptor font,
+ ui::Range range)
+ : font_descriptor_(font),
+ effective_range_(range) {
+}
+
+AttributedStringCoder::FontAttribute::FontAttribute()
+ : font_descriptor_(),
+ effective_range_() {
+}
+
+AttributedStringCoder::FontAttribute::~FontAttribute() {
+}
+
+NSDictionary* AttributedStringCoder::FontAttribute::ToAttributesDictionary(
+ void) const {
+ DCHECK(ShouldEncode());
+ NSFont* font = font_descriptor_.ToNSFont();
+ return [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName];
+}
+
+bool AttributedStringCoder::FontAttribute::ShouldEncode() const {
+ return !font_descriptor_.font_name.empty();
+}
+
+} // namespace mac
+
+// IPC ParamTraits specialization //////////////////////////////////////////////
+
+namespace IPC {
+
+using mac::AttributedStringCoder;
+
+void ParamTraits<AttributedStringCoder::EncodedString>::Write(
+ Message* m, const param_type& p) {
+ WriteParam(m, p.string());
+ WriteParam(m, p.attributes());
+}
+
+bool ParamTraits<AttributedStringCoder::EncodedString>::Read(
+ const Message* m, void** iter, param_type* p) {
+ bool success = true;
+
+ string16 result;
+ success &= ReadParam(m, iter, &result);
+ *p = AttributedStringCoder::EncodedString(result);
+
+ success &= ReadParam(m, iter, p->attributes());
+ return success;
+}
+
+void ParamTraits<AttributedStringCoder::EncodedString>::Log(
+ const param_type& p, std::string* l) {
+ l->append(UTF16ToUTF8(p.string()));
+}
+
+void ParamTraits<AttributedStringCoder::FontAttribute>::Write(
+ Message* m, const param_type& p) {
+ WriteParam(m, p.font_descriptor());
+ WriteParam(m, p.effective_range());
+}
+
+bool ParamTraits<AttributedStringCoder::FontAttribute>::Read(
+ const Message* m, void** iter, param_type* p) {
+ bool success = true;
+
+ FontDescriptor font;
+ success &= ReadParam(m, iter, &font);
+
+ ui::Range range;
+ success &= ReadParam(m, iter, &range);
+
+ if (success) {
+ *p = AttributedStringCoder::FontAttribute(font, range);
+ }
+ return success;
+}
+
+void ParamTraits<AttributedStringCoder::FontAttribute>::Log(
+ const param_type& p, std::string* l) {
+}
+
+} // namespace IPC
diff --git a/content/common/mac/attributed_string_coder_unittest.mm b/content/common/mac/attributed_string_coder_unittest.mm
new file mode 100644
index 0000000..993c842
--- /dev/null
+++ b/content/common/mac/attributed_string_coder_unittest.mm
@@ -0,0 +1,135 @@
+// Copyright (c) 2011 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 <AppKit/AppKit.h>
+
+#include "base/memory/scoped_nsobject.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/utf_string_conversions.h"
+#import "content/common/mac/attributed_string_coder.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gtest_mac.h"
+
+using mac::AttributedStringCoder;
+
+class AttributedStringCoderTest : public testing::Test {
+ public:
+ NSMutableAttributedString* NewAttrString() {
+ NSString* str = @"The quick brown fox jumped over the lazy dog.";
+ return [[NSMutableAttributedString alloc] initWithString:str];
+ }
+
+ NSDictionary* FontAttribute(NSString* name, CGFloat size) {
+ NSFont* font = [NSFont fontWithName:name size:size];
+ return [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName];
+ }
+
+ NSAttributedString* EncodeAndDecode(NSAttributedString* str) {
+ scoped_ptr<const AttributedStringCoder::EncodedString> encoded_str(
+ AttributedStringCoder::Encode(str));
+ return AttributedStringCoder::Decode(encoded_str.get());
+ }
+};
+
+TEST_F(AttributedStringCoderTest, SimpleString) {
+ scoped_nsobject<NSMutableAttributedString> attr_str(NewAttrString());
+ [attr_str addAttributes:FontAttribute(@"Helvetica", 12.5)
+ range:NSMakeRange(0, [attr_str length])];
+
+ NSAttributedString* decoded = EncodeAndDecode(attr_str.get());
+ EXPECT_NSEQ(attr_str.get(), decoded);
+}
+
+TEST_F(AttributedStringCoderTest, NoAttributes) {
+ scoped_nsobject<NSAttributedString> attr_str(NewAttrString());
+ NSAttributedString* decoded = EncodeAndDecode(attr_str.get());
+ EXPECT_NSEQ(attr_str.get(), decoded);
+}
+
+TEST_F(AttributedStringCoderTest, StripColor) {
+ scoped_nsobject<NSMutableAttributedString> attr_str(NewAttrString());
+ const NSUInteger kStringLength = [attr_str length];
+ [attr_str addAttribute:NSFontAttributeName
+ value:[NSFont systemFontOfSize:26]
+ range:NSMakeRange(0, kStringLength)];
+ [attr_str addAttribute:NSForegroundColorAttributeName
+ value:[NSColor redColor]
+ range:NSMakeRange(0, kStringLength)];
+
+ NSAttributedString* decoded = EncodeAndDecode(attr_str.get());
+
+ NSRange range;
+ NSDictionary* attrs = [decoded attributesAtIndex:0 effectiveRange:&range];
+ EXPECT_TRUE(NSEqualRanges(NSMakeRange(0, kStringLength), range));
+ EXPECT_NSEQ([NSFont systemFontOfSize:26],
+ [attrs objectForKey:NSFontAttributeName]);
+ EXPECT_FALSE([attrs objectForKey:NSForegroundColorAttributeName]);
+}
+
+TEST_F(AttributedStringCoderTest, MultipleFonts) {
+ scoped_nsobject<NSMutableAttributedString> attr_str(NewAttrString());
+ [attr_str setAttributes:FontAttribute(@"Courier", 12)
+ range:NSMakeRange(0, 10)];
+ [attr_str addAttributes:FontAttribute(@"Helvetica", 16)
+ range:NSMakeRange(12, 6)];
+ [attr_str addAttributes:FontAttribute(@"Helvetica", 14)
+ range:NSMakeRange(15, 5)];
+
+ NSAttributedString* decoded = EncodeAndDecode(attr_str);
+
+ EXPECT_NSEQ(attr_str.get(), decoded);
+}
+
+TEST_F(AttributedStringCoderTest, NoPertinentAttributes) {
+ scoped_nsobject<NSMutableAttributedString> attr_str(NewAttrString());
+ [attr_str addAttribute:NSForegroundColorAttributeName
+ value:[NSColor blueColor]
+ range:NSMakeRange(0, 10)];
+ [attr_str addAttribute:NSBackgroundColorAttributeName
+ value:[NSColor blueColor]
+ range:NSMakeRange(15, 5)];
+ [attr_str addAttribute:NSKernAttributeName
+ value:[NSNumber numberWithFloat:2.6]
+ range:NSMakeRange(11, 3)];
+
+ NSAttributedString* decoded = EncodeAndDecode(attr_str.get());
+
+ scoped_nsobject<NSAttributedString> expected(NewAttrString());
+ EXPECT_NSEQ(expected.get(), decoded);
+}
+
+TEST_F(AttributedStringCoderTest, NilString) {
+ NSAttributedString* decoded = EncodeAndDecode(nil);
+ EXPECT_TRUE(decoded);
+ EXPECT_EQ(0U, [decoded length]);
+}
+
+TEST_F(AttributedStringCoderTest, OutOfRange) {
+ AttributedStringCoder::EncodedString encoded(ASCIIToUTF16("Hello World"));
+ encoded.attributes()->push_back(
+ AttributedStringCoder::FontAttribute(
+ FontDescriptor([NSFont systemFontOfSize:12]),
+ ui::Range(0, 5)));
+ encoded.attributes()->push_back(
+ AttributedStringCoder::FontAttribute(
+ FontDescriptor([NSFont systemFontOfSize:14]),
+ ui::Range(5, 100)));
+ encoded.attributes()->push_back(
+ AttributedStringCoder::FontAttribute(
+ FontDescriptor([NSFont systemFontOfSize:16]),
+ ui::Range(100, 5)));
+
+ NSAttributedString* decoded = AttributedStringCoder::Decode(&encoded);
+ EXPECT_TRUE(decoded);
+
+ NSRange range;
+ NSDictionary* attrs = [decoded attributesAtIndex:0 effectiveRange:&range];
+ EXPECT_NSEQ([NSFont systemFontOfSize:12],
+ [attrs objectForKey:NSFontAttributeName]);
+ EXPECT_TRUE(NSEqualRanges(range, NSMakeRange(0, 5)));
+
+ attrs = [decoded attributesAtIndex:5 effectiveRange:&range];
+ EXPECT_FALSE([attrs objectForKey:NSFontAttributeName]);
+ EXPECT_EQ(0U, [attrs count]);
+}
diff --git a/content/common/mac/font_descriptor.h b/content/common/mac/font_descriptor.h
new file mode 100644
index 0000000..750976f
--- /dev/null
+++ b/content/common/mac/font_descriptor.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2011 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.
+
+#ifndef CONTENT_COMMON_MAC_FONT_DESCRIPTOR_H_
+#define CONTENT_COMMON_MAC_FONT_DESCRIPTOR_H_
+#pragma once
+
+#include "base/string16.h"
+
+#ifdef __OBJC__
+@class NSFont;
+#else
+class NSFont;
+#endif
+
+// Container to allow serializing an NSFont over IPC.
+struct FontDescriptor {
+ explicit FontDescriptor(NSFont* font);
+ FontDescriptor(string16 name, float size);
+
+ FontDescriptor() : font_point_size(0) {}
+
+ // Return an autoreleased NSFont corresponding to the font description.
+ NSFont* ToNSFont() const;
+
+ // Name of the font.
+ string16 font_name;
+
+ // Size in points.
+ float font_point_size;
+};
+
+#endif // CONTENT_COMMON_MAC_FONT_DESCRIPTOR_H_
diff --git a/content/common/mac/font_descriptor.mm b/content/common/mac/font_descriptor.mm
new file mode 100644
index 0000000..65ab40e
--- /dev/null
+++ b/content/common/mac/font_descriptor.mm
@@ -0,0 +1,25 @@
+// Copyright (c) 2011 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/common/mac/font_descriptor.h"
+
+#include <Cocoa/Cocoa.h>
+
+#include "base/sys_string_conversions.h"
+
+FontDescriptor::FontDescriptor(NSFont* font) {
+ font_name = base::SysNSStringToUTF16([font fontName]);
+ font_point_size = [font pointSize];
+}
+
+FontDescriptor::FontDescriptor(string16 name, float size) {
+ font_name = name;
+ font_point_size = size;
+}
+
+NSFont* FontDescriptor::ToNSFont() const {
+ NSString* font_name_ns = base::SysUTF16ToNSString(font_name);
+ NSFont* font = [NSFont fontWithName:font_name_ns size:font_point_size];
+ return font;
+}
diff --git a/content/common/mac/font_descriptor_unittest.mm b/content/common/mac/font_descriptor_unittest.mm
new file mode 100644
index 0000000..7054c22
--- /dev/null
+++ b/content/common/mac/font_descriptor_unittest.mm
@@ -0,0 +1,114 @@
+// Copyright (c) 2011 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/common/mac/font_descriptor.h"
+
+#include <Cocoa/Cocoa.h>
+
+#include "base/logging.h"
+#include "base/utf_string_conversions.h"
+#include "base/sys_string_conversions.h"
+#include "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+class FontSerializationTest : public PlatformTest {};
+
+const std::string kCourierFontName("Courier");
+
+// Compare 2 fonts, make sure they point at the same font definition and have
+// the same style. Only Bold & Italic style attributes are tested since those
+// are the only ones we care about at the moment.
+bool CompareFonts(NSFont* font1, NSFont* font2) {
+ ATSFontRef id1 = CTFontGetPlatformFont(reinterpret_cast<CTFontRef>(font1), 0);
+ ATSFontRef id2 = CTFontGetPlatformFont(reinterpret_cast<CTFontRef>(font2), 0);
+
+ if (id1 != id2) {
+ LOG(ERROR) << "ATSFontRefs for "
+ << [[font1 fontName] UTF8String]
+ << " and "
+ << [[font2 fontName] UTF8String]
+ << " are different";
+ return false;
+ }
+
+ CGFloat size1 = [font1 pointSize];
+ CGFloat size2 = [font2 pointSize];
+ if (size1 != size2) {
+ LOG(ERROR) << "font sizes for "
+ << [[font1 fontName] UTF8String] << " (" << size1 << ")"
+ << "and"
+ << [[font2 fontName] UTF8String] << " (" << size2 << ")"
+ << " are different";
+ return false;
+ }
+
+ NSFontTraitMask traits1 = [[NSFontManager sharedFontManager]
+ traitsOfFont:font1];
+ NSFontTraitMask traits2 = [[NSFontManager sharedFontManager]
+ traitsOfFont:font2];
+
+ bool is_bold1 = traits1 & NSBoldFontMask;
+ bool is_bold2 = traits2 & NSBoldFontMask;
+ bool is_italic1 = traits1 & NSItalicFontMask;
+ bool is_italic2 = traits2 & NSItalicFontMask;
+
+ if (is_bold1 != is_bold2 || is_italic1 != is_italic2) {
+ LOG(ERROR) << "Style information for "
+ << [[font1 fontName] UTF8String]
+ << " and "
+ << [[font2 fontName] UTF8String]
+ << " are different";
+ return false;
+ }
+
+ return true;
+}
+
+// Create an NSFont via a FontDescriptor object.
+NSFont* MakeNSFont(const std::string& font_name, float font_point_size) {
+ FontDescriptor desc;
+ desc.font_name = UTF8ToUTF16(font_name);
+ desc.font_point_size = font_point_size;
+ return desc.ToNSFont();
+}
+
+// Verify that serialization and deserialization of fonts with various styles
+// is performed correctly by FontDescriptor.
+TEST_F(FontSerializationTest, StyledFonts) {
+ NSFont* plain_font = [NSFont systemFontOfSize:12.0];
+ ASSERT_TRUE(plain_font != nil);
+ FontDescriptor desc_plain(plain_font);
+ EXPECT_TRUE(CompareFonts(plain_font, desc_plain.ToNSFont()));
+
+ NSFont* bold_font = [NSFont boldSystemFontOfSize:30.0];
+ ASSERT_TRUE(bold_font != nil);
+ FontDescriptor desc_bold(bold_font);
+ EXPECT_TRUE(CompareFonts(bold_font, desc_bold.ToNSFont()));
+
+ NSFont* italic_bold_font =
+ [[NSFontManager sharedFontManager]
+ fontWithFamily:base::SysUTF8ToNSString(kCourierFontName)
+ traits:(NSBoldFontMask | NSItalicFontMask)
+ weight:5
+ size:18.0];
+ ASSERT_TRUE(italic_bold_font != nil);
+ FontDescriptor desc_italic_bold(italic_bold_font);
+ EXPECT_TRUE(CompareFonts(italic_bold_font, desc_italic_bold.ToNSFont()));
+}
+
+// Test that FontDescriptor doesn't crash when used with bad parameters.
+// This is important since FontDescriptors are constructed with parameters
+// sent over IPC and bad values must not trigger unexpected behavior.
+TEST_F(FontSerializationTest, BadParameters) {
+ EXPECT_NSNE(MakeNSFont(kCourierFontName, 12), nil);
+ EXPECT_NSNE(MakeNSFont(kCourierFontName, std::numeric_limits<float>::min()),
+ nil);
+ EXPECT_NSNE(MakeNSFont(kCourierFontName, 0), nil);
+ EXPECT_NSNE(MakeNSFont(kCourierFontName, std::numeric_limits<float>::max()),
+ nil);
+}
+
+} // namespace
diff --git a/content/common/mac/font_loader.h b/content/common/mac/font_loader.h
new file mode 100644
index 0000000..7cd6682
--- /dev/null
+++ b/content/common/mac/font_loader.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2011 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.
+
+#ifndef CONTENT_COMMON_MAC_FONT_LOADER_H_
+#define CONTENT_COMMON_MAC_FONT_LOADER_H_
+#pragma once
+
+#include <ApplicationServices/ApplicationServices.h>
+
+#include "base/shared_memory.h"
+
+#ifdef __OBJC__
+@class NSFont;
+#else
+class NSFont;
+#endif
+
+// Provides functionality to transmit fonts over IPC.
+//
+// Note about font formats: .dfont (datafork suitcase) fonts are currently not
+// supported by this code since CGFontCreateWithDataProvider() can't handle them
+// directly.
+
+class FontLoader {
+ public:
+ // Load a font specified by |font_to_encode| into a shared memory buffer
+ // suitable for sending over IPC.
+ //
+ // On return:
+ // returns true on success, false on failure.
+ // |font_data| - shared memory buffer containing the raw data for the font
+ // file.
+ // |font_data_size| - size of data contained in |font_data|.
+ // |font_id| - unique identifier for the on-disk file we load for the font.
+ static bool LoadFontIntoBuffer(NSFont* font_to_encode,
+ base::SharedMemory* font_data,
+ uint32* font_data_size,
+ uint32* font_id);
+
+ // Given a shared memory buffer containing the raw data for a font file, load
+ // the font and return a CGFontRef.
+ //
+ // |data| - A shared memory handle pointing to the raw data from a font file.
+ // |data_size| - Size of |data|.
+ //
+ // On return:
+ // returns true on success, false on failure.
+ // |out| - A CGFontRef corresponding to the designated font.
+ // The caller is responsible for releasing this value via CGFontRelease()
+ // when done.
+ static bool CGFontRefFromBuffer(base::SharedMemoryHandle font_data,
+ uint32 font_data_size,
+ CGFontRef* out);
+
+
+ // TODO(jeremy): Remove once http://webk.it/66935 lands.
+ static bool ATSFontContainerFromBuffer(base::SharedMemoryHandle font_data,
+ uint32 font_data_size,
+ ATSFontContainerRef* font_container);
+};
+
+#endif // CONTENT_COMMON_MAC_FONT_LOADER_H_
diff --git a/content/common/mac/font_loader.mm b/content/common/mac/font_loader.mm
new file mode 100644
index 0000000..93eb03f
--- /dev/null
+++ b/content/common/mac/font_loader.mm
@@ -0,0 +1,194 @@
+// Copyright (c) 2011 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/common/mac/font_loader.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/mac_util.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/sys_string_conversions.h"
+
+extern "C" {
+
+// Work around http://crbug.com/93191, a really nasty memory smasher bug.
+// On Mac OS X 10.7 ("Lion"), ATS writes to memory it doesn't own.
+// SendDeactivateFontsInContainerMessage, called by ATSFontDeactivate,
+// may trash memory whenever dlsym(RTLD_DEFAULT,
+// "_CTFontManagerUnregisterFontForData") returns NULL. In that case, it tries
+// to locate that symbol in the CoreText framework, doing some extremely
+// sloppy string handling resulting in a likelihood that the string
+// "Text.framework/Versions/A/CoreText" will be written over memory that it
+// doesn't own. The kicker here is that Apple dlsym always inserts its own
+// leading underscore, so ATS actually winds up looking up a
+// __CTFontManagerUnregisterFontForData symbol, which doesn't even exist in
+// CoreText. It's only got the single-underscore variant corresponding to an
+// underscoreless extern "C" name.
+//
+// Providing a single-underscored extern "C" function by this name results in
+// a __CTFontManagerUnregisterFontForData symbol that, as long as it's public
+// (not private extern) and unstripped, ATS will find. If it finds it, it
+// avoids making amateur string mistakes that ruin everyone else's good time.
+//
+// Since ATS wouldn't normally be able to call this function anyway, it's just
+// left as a no-op here.
+//
+// This file seems as good as any other to place this function. It was chosen
+// because it already interfaces with ATS for other reasons.
+//
+// SendDeactivateFontsInContainerMessage on 10.6 ("Snow Leopard") appears to
+// share this bug but this sort of memory corruption wasn't detected until
+// 10.7. The implementation in 10.5 ("Leopard") does not have this problem.
+__attribute__((visibility("default")))
+void _CTFontManagerUnregisterFontForData(NSUInteger, int) {
+}
+
+} // extern "C"
+
+// static
+bool FontLoader::LoadFontIntoBuffer(NSFont* font_to_encode,
+ base::SharedMemory* font_data,
+ uint32* font_data_size,
+ uint32* font_id) {
+ CHECK(font_data);
+ CHECK(font_data_size);
+ CHECK(font_id);
+ *font_data_size = 0;
+ *font_id = 0;
+
+ // Used only for logging.
+ std::string font_name([[font_to_encode fontName] UTF8String]);
+
+ // Load appropriate NSFont.
+ if (!font_to_encode) {
+ LOG(ERROR) << "Failed to load font " << font_name;
+ return false;
+ }
+
+ // NSFont -> ATSFontRef.
+ ATSFontRef ats_font =
+ CTFontGetPlatformFont(reinterpret_cast<CTFontRef>(font_to_encode), NULL);
+ if (!ats_font) {
+ LOG(ERROR) << "Conversion to ATSFontRef failed for " << font_name;
+ return false;
+ }
+
+ // Retrieve the ATSFontContainerRef corresponding to the font file we want to
+ // load. This is a unique identifier that allows the caller determine if the
+ // font file in question is already loaded.
+ COMPILE_ASSERT(sizeof(ATSFontContainerRef) == sizeof(font_id),
+ uint32_cant_hold_fontcontainer_ref);
+ ATSFontContainerRef fontContainer = kATSFontContainerRefUnspecified;
+ if (ATSFontGetContainer(ats_font, 0, &fontContainer) != noErr) {
+ LOG(ERROR) << "Failed to get font container ref for " << font_name;
+ return false;
+ }
+
+ // ATSFontRef -> File path.
+ // Warning: Calling this function on a font activated from memory will result
+ // in failure with a -50 - paramErr. This may occur if
+ // CreateCGFontFromBuffer() is called in the same process as this function
+ // e.g. when writing a unit test that exercises these two functions together.
+ // If said unit test were to load a system font and activate it from memory
+ // it becomes impossible for the system to the find the original file ref
+ // since the font now lives in memory as far as it's concerned.
+ FSRef font_fsref;
+ if (ATSFontGetFileReference(ats_font, &font_fsref) != noErr) {
+ LOG(ERROR) << "Failed to find font file for " << font_name;
+ return false;
+ }
+ FilePath font_path = FilePath(base::mac::PathFromFSRef(font_fsref));
+
+ // Load file into shared memory buffer.
+ int64 font_file_size_64 = -1;
+ if (!file_util::GetFileSize(font_path, &font_file_size_64)) {
+ LOG(ERROR) << "Couldn't get font file size for " << font_path.value();
+ return false;
+ }
+
+ if (font_file_size_64 <= 0 || font_file_size_64 >= kint32max) {
+ LOG(ERROR) << "Bad size for font file " << font_path.value();
+ return false;
+ }
+
+ int32 font_file_size_32 = static_cast<int32>(font_file_size_64);
+ if (!font_data->CreateAndMapAnonymous(font_file_size_32)) {
+ LOG(ERROR) << "Failed to create shmem area for " << font_name;
+ return false;
+ }
+
+ int32 amt_read = file_util::ReadFile(font_path,
+ reinterpret_cast<char*>(font_data->memory()),
+ font_file_size_32);
+ if (amt_read != font_file_size_32) {
+ LOG(ERROR) << "Failed to read font data for " << font_path.value();
+ return false;
+ }
+
+ *font_data_size = font_file_size_32;
+ *font_id = fontContainer;
+ return true;
+}
+
+// static
+bool FontLoader::CGFontRefFromBuffer(base::SharedMemoryHandle font_data,
+ uint32 font_data_size,
+ CGFontRef* out) {
+ *out = NULL;
+
+ using base::SharedMemory;
+ DCHECK(SharedMemory::IsHandleValid(font_data));
+ DCHECK_GT(font_data_size, 0U);
+
+ SharedMemory shm(font_data, /*read_only=*/true);
+ if (!shm.Map(font_data_size))
+ return false;
+
+ NSData* data = [NSData dataWithBytes:shm.memory()
+ length:font_data_size];
+ base::mac::ScopedCFTypeRef<CGDataProviderRef> provider(
+ CGDataProviderCreateWithCFData(base::mac::NSToCFCast(data)));
+ if (!provider)
+ return false;
+
+ *out = CGFontCreateWithDataProvider(provider.get());
+
+ if (*out == NULL)
+ return false;
+
+ return true;
+}
+
+// TODO(jeremy): Remove once http://webk.it/66935 lands.
+// static
+bool FontLoader::ATSFontContainerFromBuffer(base::SharedMemoryHandle font_data,
+ uint32 font_data_size,
+ ATSFontContainerRef* font_container)
+{
+ CHECK(font_container);
+
+ using base::SharedMemory;
+ DCHECK(SharedMemory::IsHandleValid(font_data));
+ DCHECK_GT(font_data_size, 0U);
+
+ SharedMemory shm(font_data, true);
+ if (!shm.Map(font_data_size))
+ return false;
+
+ // A value of 3 means the font is private and can't be seen by anyone else.
+ // This is the value used by WebKit when activating remote fonts.
+ const ATSFontContext kFontContextPrivate = 3;
+ OSStatus err = ATSFontActivateFromMemory(shm.memory(), font_data_size,
+ kFontContextPrivate, kATSFontFormatUnspecified, NULL,
+ kATSOptionFlagsDefault, font_container);
+ if (err != noErr || !font_container)
+ return false;
+
+ return true;
+}