diff options
-rw-r--r-- | chrome/chrome_common.gypi | 2 | ||||
-rwxr-xr-x | chrome/chrome_tests.gypi | 1 | ||||
-rw-r--r-- | chrome/common/font_descriptor_mac.h | 32 | ||||
-rw-r--r-- | chrome/common/font_descriptor_mac.mm | 20 | ||||
-rw-r--r-- | chrome/common/font_descriptor_mac_unittest.mm | 91 | ||||
-rw-r--r-- | chrome/common/font_loader_mac.h | 26 | ||||
-rw-r--r-- | chrome/common/font_loader_mac.mm | 55 | ||||
-rw-r--r-- | chrome/common/render_messages.h | 19 | ||||
-rwxr-xr-x | chrome/common/render_messages_internal.h | 10 | ||||
-rw-r--r-- | chrome/common/sandbox_mac_fontloading_unittest.mm | 61 | ||||
-rw-r--r-- | ipc/ipc_message_utils.h | 39 |
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)); |