summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjeremy@chromium.org <jeremy@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-06-17 03:29:26 +0000
committerjeremy@chromium.org <jeremy@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-06-17 03:29:26 +0000
commit2019966658e19a873744641668e134b92123f1d5 (patch)
tree853ac0828cc46bec543851b7c57c70a3bb1fc06e
parentf7d992aa311c3cec1fc95ce06338b129f4b34cbe (diff)
downloadchromium_src-2019966658e19a873744641668e134b92123f1d5.zip
chromium_src-2019966658e19a873744641668e134b92123f1d5.tar.gz
chromium_src-2019966658e19a873744641668e134b92123f1d5.tar.bz2
Mac: More pluming for OOP font loading
* Add font_descriptor and corresponding pluming to send an NSFont over IPC. * Rejigger font_loader to accept an NSFont as input and output an ATSFontContainerRef. The reasoning behind this is that WebKit ultimately controls the font lifetime and we can only deactivate the font container once the font is no longer in use. BUG=29729 Test=Unit tests should pass. Review URL: http://codereview.chromium.org/2804001 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@50076 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/chrome_common.gypi2
-rwxr-xr-xchrome/chrome_tests.gypi1
-rw-r--r--chrome/common/font_descriptor_mac.h32
-rw-r--r--chrome/common/font_descriptor_mac.mm20
-rw-r--r--chrome/common/font_descriptor_mac_unittest.mm91
-rw-r--r--chrome/common/font_loader_mac.h26
-rw-r--r--chrome/common/font_loader_mac.mm55
-rw-r--r--chrome/common/render_messages.h19
-rwxr-xr-xchrome/common/render_messages_internal.h10
-rw-r--r--chrome/common/sandbox_mac_fontloading_unittest.mm61
-rw-r--r--ipc/ipc_message_utils.h39
11 files changed, 293 insertions, 63 deletions
diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi
index 7be94dd..b491315 100644
--- a/chrome/chrome_common.gypi
+++ b/chrome/chrome_common.gypi
@@ -47,6 +47,8 @@
'common/debug_flags.h',
'common/devtools_messages.h',
'common/devtools_messages_internal.h',
+ 'common/font_descriptor_mac.h',
+ 'common/font_descriptor_mac.mm',
'common/geoposition.cc',
'common/geoposition.h',
'common/gpu_messages.h',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 31f31a5..19dc485 100755
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1000,6 +1000,7 @@
'common/extensions/update_manifest_unittest.cc',
'common/extensions/url_pattern_unittest.cc',
'common/extensions/user_script_unittest.cc',
+ 'common/font_descriptor_mac_unittest.mm',
'common/important_file_writer_unittest.cc',
'common/json_pref_store_unittest.cc',
'common/json_value_serializer_unittest.cc',
diff --git a/chrome/common/font_descriptor_mac.h b/chrome/common/font_descriptor_mac.h
new file mode 100644
index 0000000..25ae9db
--- /dev/null
+++ b/chrome/common/font_descriptor_mac.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2010 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 CHROME_COMMON_FONT_DESCRIPTOR_MAC_H_
+#define CHROME_COMMON_FONT_DESCRIPTOR_MAC_H_
+
+#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() : font_point_size(0) {}
+
+ // Return an autoreleased NSFont corresponding to the font description.
+ NSFont* nsFont() const;
+
+ // Name of the font.
+ string16 font_name;
+
+ // Size in points.
+ float font_point_size;
+};
+
+#endif // CHROME_COMMON_FONT_DESCRIPTOR_MAC_H_
diff --git a/chrome/common/font_descriptor_mac.mm b/chrome/common/font_descriptor_mac.mm
new file mode 100644
index 0000000..485c215
--- /dev/null
+++ b/chrome/common/font_descriptor_mac.mm
@@ -0,0 +1,20 @@
+// Copyright (c) 2010 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 "chrome/common/font_descriptor_mac.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];
+}
+
+NSFont* FontDescriptor::nsFont() 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/chrome/common/font_descriptor_mac_unittest.mm b/chrome/common/font_descriptor_mac_unittest.mm
new file mode 100644
index 0000000..442e8e2
--- /dev/null
+++ b/chrome/common/font_descriptor_mac_unittest.mm
@@ -0,0 +1,91 @@
+// Copyright (c) 2010 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 "chrome/common/font_descriptor_mac.h"
+
+#include <Cocoa/Cocoa.h>
+
+#include "base/logging.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace {
+
+class FontSerializationTest : public PlatformTest {};
+
+
+// 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;
+}
+
+// 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.nsFont()));
+
+ NSFont* bold_font = [NSFont boldSystemFontOfSize:30.0];
+ ASSERT_TRUE(bold_font != nil);
+ FontDescriptor desc_bold(bold_font);
+ EXPECT_TRUE(CompareFonts(bold_font, desc_bold.nsFont()));
+
+ NSFont* italic_bold_font =
+ [[NSFontManager sharedFontManager]
+ fontWithFamily:@"Courier"
+ 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.nsFont()));
+}
+
+} // namsepace
diff --git a/chrome/common/font_loader_mac.h b/chrome/common/font_loader_mac.h
index 8d2467f..2ec42bce 100644
--- a/chrome/common/font_loader_mac.h
+++ b/chrome/common/font_loader_mac.h
@@ -10,6 +10,12 @@
#include "base/shared_memory.h"
#include "base/string16.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
@@ -18,32 +24,32 @@
class FontLoader {
public:
- // Load a font specified by |font_name| and |font_point_size| into a shared
- // memory buffer suitable for sending over IPC.
+ // 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|.
- static bool LoadFontIntoBuffer(const string16& font_name,
- float font_point_size,
+ static bool LoadFontIntoBuffer(NSFont* font_to_encode,
base::SharedMemory* font_data,
uint32* font_data_size);
// Given a shared memory buffer containing the raw data for a font file, load
- // the font into a CGFontRef.
+ // the font and return a container ref.
//
// |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.
- // |font| - A CGFontRef containing the designated font, the caller is
- // responsible for releasing this value.
- static bool CreateCGFontFromBuffer(base::SharedMemoryHandle font_data,
- uint32 font_data_size,
- CGFontRef* font);
+ // |font_container| - A font container corresponding to the designated font.
+ // The caller is responsible for releasing this value via ATSFontDeactivate()
+ // when done
+ static bool ATSFontContainerFromBuffer(base::SharedMemoryHandle font_data,
+ uint32 font_data_size,
+ ATSFontContainerRef* font_container);
};
#endif // CHROME_COMMON_FONT_LOADER_MAC_H_
diff --git a/chrome/common/font_loader_mac.mm b/chrome/common/font_loader_mac.mm
index a6b9c25..849ae87 100644
--- a/chrome/common/font_loader_mac.mm
+++ b/chrome/common/font_loader_mac.mm
@@ -15,17 +15,16 @@
#include "base/sys_string_conversions.h"
// static
-bool FontLoader::LoadFontIntoBuffer(const string16& font_name,
- float font_point_size,
+bool FontLoader::LoadFontIntoBuffer(NSFont* font_to_encode,
base::SharedMemory* font_data,
uint32* font_data_size) {
CHECK(font_data && font_data_size);
*font_data_size = 0;
+ // Used only for logging.
+ std::string font_name([[font_to_encode fontName] UTF8String]);
+
// Load appropriate NSFont.
- NSString* font_name_ns = base::SysUTF16ToNSString(font_name);
- NSFont* font_to_encode =
- [NSFont fontWithName:font_name_ns size:font_point_size];
if (!font_to_encode) {
LOG(ERROR) << "Failed to load font " << font_name;
return false;
@@ -90,9 +89,12 @@ bool FontLoader::LoadFontIntoBuffer(const string16& font_name,
}
// static
-bool FontLoader::CreateCGFontFromBuffer(base::SharedMemoryHandle font_data,
- uint32 font_data_size,
- CGFontRef *font) {
+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);
@@ -101,41 +103,14 @@ bool FontLoader::CreateCGFontFromBuffer(base::SharedMemoryHandle font_data,
if (!shm.Map(font_data_size))
return false;
- ATSFontContainerRef font_container = 0;
+ // 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,
- kATSFontContextLocal, kATSFontFormatUnspecified,
- NULL, kATSOptionFlagsDefault, &font_container );
+ kFontContextPrivate, kATSFontFormatUnspecified, NULL,
+ kATSOptionFlagsDefault, font_container);
if (err != noErr || !font_container)
return false;
- // Count the number of fonts that were loaded.
- ItemCount fontCount = 0;
- err = ATSFontFindFromContainer(font_container, kATSOptionFlagsDefault, 0,
- NULL, &fontCount);
-
- if (err != noErr || fontCount < 1) {
- ATSFontDeactivate(font_container, NULL, kATSOptionFlagsDefault);
- return false;
- }
-
- // Load font from container.
- ATSFontRef font_ref_ats = 0;
- ATSFontFindFromContainer(font_container, kATSOptionFlagsDefault, 1,
- &font_ref_ats, NULL);
-
- if (!font_ref_ats) {
- ATSFontDeactivate(font_container, NULL, kATSOptionFlagsDefault);
- return false;
- }
-
- // Convert to cgFont.
- CGFontRef font_ref_cg = CGFontCreateWithPlatformFont(&font_ref_ats);
-
- if (!font_ref_cg) {
- ATSFontDeactivate(font_container, NULL, kATSOptionFlagsDefault);
- return false;
- }
-
- *font = font_ref_cg;
return true;
}
diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h
index e501a8b9..f5a3376 100644
--- a/chrome/common/render_messages.h
+++ b/chrome/common/render_messages.h
@@ -22,6 +22,7 @@
#include "chrome/common/edit_command.h"
#include "chrome/common/extensions/extension_extent.h"
#include "chrome/common/extensions/url_pattern.h"
+#include "chrome/common/font_descriptor_mac.h"
#include "chrome/common/navigation_gesture.h"
#include "chrome/common/page_transition_types.h"
#include "chrome/common/renderer_preferences.h"
@@ -914,6 +915,24 @@ struct ParamTraits<webkit_glue::FormField> {
}
};
+// Traits for FontDescriptor structure to pack/unpack.
+template <>
+struct ParamTraits<FontDescriptor> {
+ typedef FontDescriptor param_type;
+ static void Write(Message* m, const param_type& p) {
+ WriteParam(m, p.font_name);
+ WriteParam(m, p.font_point_size);
+ }
+ static bool Read(const Message* m, void** iter, param_type* p) {
+ return(
+ ReadParam(m, iter, &p->font_name) &&
+ ReadParam(m, iter, &p->font_point_size));
+ }
+ static void Log(const param_type& p, std::wstring* l) {
+ l->append(L"<FontDescriptor>");
+ }
+};
+
// Traits for ViewHostMsg_FrameNavigate_Params structure to pack/unpack.
template <>
struct ParamTraits<ViewHostMsg_FrameNavigate_Params> {
diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h
index 4596986..7d38c3a 100755
--- a/chrome/common/render_messages_internal.h
+++ b/chrome/common/render_messages_internal.h
@@ -39,6 +39,10 @@
#include "base/file_descriptor_posix.h"
#endif
+#if defined(OS_MACOSX)
+#include "chrome/common/font_descriptor_mac.h"
+#endif
+
// TODO(mpcomplete): rename ViewMsg and ViewHostMsg to something that makes
// more sense with our current design.
@@ -1433,6 +1437,12 @@ IPC_BEGIN_MESSAGES(ViewHost)
#if defined(OS_MACOSX)
IPC_MESSAGE_CONTROL1(ViewHostMsg_ClipboardFindPboardWriteStringAsync,
string16 /* text */)
+
+ // Request that the browser load a font into shared memory for us.
+ IPC_SYNC_MESSAGE_CONTROL1_2(ViewHostMsg_LoadFont,
+ FontDescriptor /* font to load */,
+ uint32 /* buffer size */,
+ base::SharedMemoryHandle /* font data */)
#endif
#if defined(OS_WIN)
diff --git a/chrome/common/sandbox_mac_fontloading_unittest.mm b/chrome/common/sandbox_mac_fontloading_unittest.mm
index 9eadf0d..a20d263 100644
--- a/chrome/common/sandbox_mac_fontloading_unittest.mm
+++ b/chrome/common/sandbox_mac_fontloading_unittest.mm
@@ -17,6 +17,48 @@ namespace {
using sandboxtest::MacSandboxTest;
+bool CGFontFromFontContainer(ATSFontContainerRef container, CGFontRef* out) {
+ // Count the number of fonts that were loaded.
+ ItemCount fontCount = 0;
+ OSStatus err = ATSFontFindFromContainer(container, kATSOptionFlagsDefault, 0,
+ NULL, &fontCount);
+
+ if (err != noErr || fontCount < 1) {
+ return false;
+ }
+
+ // Load font from container.
+ ATSFontRef font_ref_ats = 0;
+ ATSFontFindFromContainer(container, kATSOptionFlagsDefault, 1,
+ &font_ref_ats, NULL);
+
+ if (!font_ref_ats) {
+ return false;
+ }
+
+ // Convert to cgFont.
+ CGFontRef font_ref_cg = CGFontCreateWithPlatformFont(&font_ref_ats);
+
+ if (!font_ref_cg) {
+ return false;
+ }
+
+ *out = font_ref_cg;
+ return true;
+}
+
+class ScopedFontContainer {
+ public:
+ explicit ScopedFontContainer(ATSFontContainerRef ref)
+ : container_ref(ref) {}
+
+ ~ScopedFontContainer() {
+ ATSFontDeactivate(container_ref, NULL, kATSOptionFlagsDefault);
+ }
+
+ ATSFontContainerRef container_ref;
+};
+
class FontLoadingTestCase : public sandboxtest::MacSandboxTestCase {
public:
FontLoadingTestCase() : font_data_length_(-1) {}
@@ -74,19 +116,27 @@ bool FontLoadingTestCase::SandboxedTest() {
return false;
}
- CGFontRef font_ref;
- if (!FontLoader::CreateCGFontFromBuffer(shmem_handle, font_data_length_,
- &font_ref)) {
+ ATSFontContainerRef font_container;
+ if (!FontLoader::ATSFontContainerFromBuffer(shmem_handle, font_data_length_,
+ &font_container)) {
LOG(ERROR) << "Call to CreateCGFontFromBuffer() failed";
return false;
}
- scoped_cftyperef<CGFontRef> cgfont;
+ // Unload the font container when done.
+ ScopedFontContainer scoped_unloader(font_container);
+
+ CGFontRef font_ref;
+ if (!CGFontFromFontContainer(font_container, &font_ref)) {
+ LOG(ERROR) << "CGFontFromFontContainer failed";
+ return false;
+ }
if (!font_ref) {
LOG(ERROR) << "Got NULL CGFontRef";
return false;
}
+ scoped_cftyperef<CGFontRef> cgfont;
cgfont.reset(font_ref);
const NSFont* nsfont = reinterpret_cast<const NSFont*>(
@@ -116,7 +166,8 @@ TEST_F(MacSandboxTest, FontLoadingTest) {
base::SharedMemory font_data;
uint32 font_data_size;
- EXPECT_TRUE(FontLoader::LoadFontIntoBuffer(ASCIIToUTF16("Geeza Pro"), 16.0,
+ NSFont* srcFont = [NSFont fontWithName:@"Geeza Pro" size:16.0];
+ EXPECT_TRUE(FontLoader::LoadFontIntoBuffer(srcFont,
&font_data, &font_data_size));
EXPECT_GT(font_data_size, 0U);
diff --git a/ipc/ipc_message_utils.h b/ipc/ipc_message_utils.h
index df2c6c7..46c7298 100644
--- a/ipc/ipc_message_utils.h
+++ b/ipc/ipc_message_utils.h
@@ -226,6 +226,31 @@ struct ParamTraits<unsigned long long> {
}
};
+// Note that the IPC layer doesn't sanitize NaNs and +/- INF values. Clients
+// should be sure to check the sanity of these values after receiving them over
+// IPC.
+template <>
+struct ParamTraits<float> {
+ typedef float param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteData(reinterpret_cast<const char*>(&p), sizeof(param_type));
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ const char *data;
+ int data_size;
+ if (!m->ReadData(iter, &data, &data_size) ||
+ data_size != sizeof(param_type)) {
+ NOTREACHED();
+ return false;
+ }
+ memcpy(r, data, sizeof(param_type));
+ return true;
+ }
+ static void Log(const param_type& p, std::wstring* l) {
+ l->append(StringPrintf(L"e", p));
+ }
+};
+
template <>
struct ParamTraits<double> {
typedef double param_type;
@@ -234,16 +259,14 @@ struct ParamTraits<double> {
}
static bool Read(const Message* m, void** iter, param_type* r) {
const char *data;
- int data_size = 0;
- bool result = m->ReadData(iter, &data, &data_size);
- if (result && data_size == sizeof(param_type)) {
- memcpy(r, data, sizeof(param_type));
- } else {
- result = false;
+ int data_size;
+ if (!m->ReadData(iter, &data, &data_size) ||
+ data_size != sizeof(param_type)) {
NOTREACHED();
+ return false;
}
-
- return result;
+ memcpy(r, data, sizeof(param_type));
+ return true;
}
static void Log(const param_type& p, std::wstring* l) {
l->append(StringPrintf(L"e", p));