summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/file_util.h4
-rw-r--r--chrome/chrome_common.gypi2
-rw-r--r--chrome/chrome_tests.gypi3
-rw-r--r--chrome/common/font_loader_mac.h49
-rw-r--r--chrome/common/font_loader_mac.mm141
-rw-r--r--chrome/common/sandbox_mac_diraccess_unittest.mm (renamed from chrome/common/sandbox_mac_unittest.mm)6
-rw-r--r--chrome/common/sandbox_mac_fontloading_unittest.mm132
-rw-r--r--chrome/common/sandbox_mac_unittest_helper.h13
-rw-r--r--chrome/common/sandbox_mac_unittest_helper.mm12
9 files changed, 353 insertions, 9 deletions
diff --git a/base/file_util.h b/base/file_util.h
index e62b30e..16f18f1 100644
--- a/base/file_util.h
+++ b/base/file_util.h
@@ -239,8 +239,8 @@ FilePath GetHomeDir();
bool CreateTemporaryFile(FilePath* path);
// Create and open a temporary file. File is opened for read/write.
-// The full path is placed in |path|, and the function returns true if
-// was successful in creating and opening the file.
+// The full path is placed in |path|.
+// Returns a handle to the opened file or NULL if an error occured.
FILE* CreateAndOpenTemporaryFile(FilePath* path);
// Like above but for shmem files. Only useful for POSIX.
FILE* CreateAndOpenTemporaryShmemFile(FilePath* path);
diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi
index d226b5d..3f69a97 100644
--- a/chrome/chrome_common.gypi
+++ b/chrome/chrome_common.gypi
@@ -195,6 +195,8 @@
'common/dom_storage_common.h',
'common/deprecated/event_sys-inl.h',
'common/deprecated/event_sys.h',
+ 'common/font_loader_mac.h',
+ 'common/font_loader_mac.mm',
'common/gears_api.h',
'common/gpu_plugin.cc',
'common/gpu_plugin.h',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index e5b4d4e..a0f8bd2 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -999,7 +999,8 @@
'common/property_bag_unittest.cc',
'common/render_messages_unittest.cc',
'common/resource_dispatcher_unittest.cc',
- 'common/sandbox_mac_unittest.mm',
+ 'common/sandbox_mac_diraccess_unittest.mm',
+ 'common/sandbox_mac_fontloading_unittest.mm',
'common/sandbox_mac_unittest_helper.h',
'common/sandbox_mac_unittest_helper.mm',
'common/sandbox_mac_system_access_unittest.mm',
diff --git a/chrome/common/font_loader_mac.h b/chrome/common/font_loader_mac.h
new file mode 100644
index 0000000..8d2467f
--- /dev/null
+++ b/chrome/common/font_loader_mac.h
@@ -0,0 +1,49 @@
+// 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_LOADER_MAC_H_
+#define CHROME_COMMON_FONT_LOADER_MAC_H_
+
+#include <ApplicationServices/ApplicationServices.h>
+
+#include "base/shared_memory.h"
+#include "base/string16.h"
+
+// Provides functionality to transmit fonts over IPC.
+//
+// Note about font formats: .dfont (datafork suitcase) fonts are currently not
+// supported by this code since ATSFontActivateFromMemory() can't handle them
+// directly.
+
+class FontLoader {
+ public:
+ // Load a font specified by |font_name| and |font_point_size| 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,
+ 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.
+ //
+ // |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);
+};
+
+#endif // CHROME_COMMON_FONT_LOADER_MAC_H_
diff --git a/chrome/common/font_loader_mac.mm b/chrome/common/font_loader_mac.mm
new file mode 100644
index 0000000..a6b9c25
--- /dev/null
+++ b/chrome/common/font_loader_mac.mm
@@ -0,0 +1,141 @@
+// 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_loader_mac.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_util.h"
+#include "base/scoped_cftyperef.h"
+#include "base/sys_string_conversions.h"
+
+// static
+bool FontLoader::LoadFontIntoBuffer(const string16& font_name,
+ float font_point_size,
+ base::SharedMemory* font_data,
+ uint32* font_data_size) {
+ CHECK(font_data && font_data_size);
+ *font_data_size = 0;
+
+ // 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;
+ }
+
+ // 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;
+ }
+
+ // 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(mac_util::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->Create(L"", false, false, font_file_size_32)) {
+ LOG(ERROR) << "Failed to create shmem area for " << font_name;
+ return false;
+ }
+
+ if (!font_data->Map(font_file_size_32)) {
+ LOG(ERROR) << "Failed to map 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;
+ return true;
+}
+
+// static
+bool FontLoader::CreateCGFontFromBuffer(base::SharedMemoryHandle font_data,
+ uint32 font_data_size,
+ CGFontRef *font) {
+ 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;
+
+ ATSFontContainerRef font_container = 0;
+ OSStatus err = ATSFontActivateFromMemory(shm.memory(), font_data_size,
+ kATSFontContextLocal, 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/sandbox_mac_unittest.mm b/chrome/common/sandbox_mac_diraccess_unittest.mm
index dcd9814..71eff73 100644
--- a/chrome/common/sandbox_mac_unittest.mm
+++ b/chrome/common/sandbox_mac_diraccess_unittest.mm
@@ -17,6 +17,8 @@ extern "C" {
#include "chrome/common/sandbox_mac.h"
#include "testing/gtest/include/gtest/gtest.h"
+// Tests to exercise directory-access-related restrictions of Mac sandbox.
+
namespace sandbox {
bool QuotePlainString(const std::string& str_utf8, std::string* dst);
@@ -24,6 +26,8 @@ bool QuoteStringForRegex(const std::string& str_utf8, std::string* dst);
} // namespace sandbox
+namespace {
+
static const char* kSandboxAccessPathKey = "sandbox_dir";
class MacDirAccessSandboxTest : public MultiProcessTest {
@@ -242,3 +246,5 @@ MULTIPROCESS_TEST_MAIN(mac_sandbox_path_access) {
return 0;
}
+
+} // namespace
diff --git a/chrome/common/sandbox_mac_fontloading_unittest.mm b/chrome/common/sandbox_mac_fontloading_unittest.mm
new file mode 100644
index 0000000..9eadf0d
--- /dev/null
+++ b/chrome/common/sandbox_mac_fontloading_unittest.mm
@@ -0,0 +1,132 @@
+// 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.
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/scoped_cftyperef.h"
+#include "base/scoped_ptr.h"
+#include "base/shared_memory.h"
+#include "chrome/common/font_loader_mac.h"
+#include "chrome/common/sandbox_mac_unittest_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+using sandboxtest::MacSandboxTest;
+
+class FontLoadingTestCase : public sandboxtest::MacSandboxTestCase {
+ public:
+ FontLoadingTestCase() : font_data_length_(-1) {}
+ virtual bool BeforeSandboxInit();
+ virtual bool SandboxedTest();
+ private:
+ scoped_ptr<base::SharedMemory> font_shmem_;
+ size_t font_data_length_;
+};
+REGISTER_SANDBOX_TEST_CASE(FontLoadingTestCase);
+
+
+// Load raw font data into shared memory object.
+bool FontLoadingTestCase::BeforeSandboxInit() {
+ std::string font_data;
+ if (!file_util::ReadFileToString(FilePath(test_data_.c_str()), &font_data)) {
+ LOG(ERROR) << "Failed to read font data from file (" << test_data_ << ")";
+ return false;
+ }
+
+ font_data_length_ = font_data.length();
+ if (font_data_length_ <= 0) {
+ LOG(ERROR) << "No font data: " << font_data_length_;
+ return false;
+ }
+
+ font_shmem_.reset(new base::SharedMemory);
+ if (!font_shmem_.get()) {
+ LOG(ERROR) << "Failed to create shared memory object.";
+ return false;
+ }
+
+ if (!font_shmem_->Create(L"", false, false, font_data_length_)) {
+ LOG(ERROR) << "SharedMemory::Create failed";
+ return false;
+ }
+
+ if (!font_shmem_->Map(font_data_length_)) {
+ LOG(ERROR) << "SharedMemory::Map failed";
+ return false;
+ }
+
+ memcpy(font_shmem_->memory(), font_data.c_str(), font_data_length_);
+ if (!font_shmem_->Unmap()) {
+ LOG(ERROR) << "SharedMemory::Unmap failed";
+ return false;
+ }
+ return true;
+}
+
+bool FontLoadingTestCase::SandboxedTest() {
+ base::SharedMemoryHandle shmem_handle;
+ if (!font_shmem_->ShareToProcess(NULL, &shmem_handle)) {
+ LOG(ERROR) << "SharedMemory::ShareToProcess failed";
+ return false;
+ }
+
+ CGFontRef font_ref;
+ if (!FontLoader::CreateCGFontFromBuffer(shmem_handle, font_data_length_,
+ &font_ref)) {
+ LOG(ERROR) << "Call to CreateCGFontFromBuffer() failed";
+ return false;
+ }
+
+ scoped_cftyperef<CGFontRef> cgfont;
+
+ if (!font_ref) {
+ LOG(ERROR) << "Got NULL CGFontRef";
+ return false;
+ }
+ cgfont.reset(font_ref);
+
+ const NSFont* nsfont = reinterpret_cast<const NSFont*>(
+ CTFontCreateWithGraphicsFont(cgfont.get(), 16.0,
+ NULL, NULL));
+ if (!nsfont) {
+ LOG(ERROR) << "CTFontCreateWithGraphicsFont() failed";
+ return false;
+ }
+
+ // Do something with the font to make sure it's loaded.
+ CGFloat cap_height = [nsfont capHeight];
+
+ if (cap_height <= 0.0) {
+ LOG(ERROR) << "Got bad value for [NSFont capHeight] " << cap_height;
+ return false;
+ }
+
+ return true;
+}
+
+TEST_F(MacSandboxTest, FontLoadingTest) {
+ FilePath temp_file_path;
+ FILE* temp_file = file_util::CreateAndOpenTemporaryFile(&temp_file_path);
+ ASSERT_TRUE(temp_file);
+ file_util::ScopedFILE temp_file_closer(temp_file);
+
+ base::SharedMemory font_data;
+ uint32 font_data_size;
+ EXPECT_TRUE(FontLoader::LoadFontIntoBuffer(ASCIIToUTF16("Geeza Pro"), 16.0,
+ &font_data, &font_data_size));
+ EXPECT_GT(font_data_size, 0U);
+
+ file_util::WriteFileDescriptor(fileno(temp_file),
+ static_cast<const char *>(font_data.memory()), font_data_size);
+
+ ASSERT_TRUE(RunTestInSandbox(sandbox::SANDBOX_TYPE_RENDERER,
+ "FontLoadingTestCase", temp_file_path.value().c_str()));
+ temp_file_closer.reset();
+ ASSERT_TRUE(file_util::Delete(temp_file_path, false));
+}
+
+} // namespace
diff --git a/chrome/common/sandbox_mac_unittest_helper.h b/chrome/common/sandbox_mac_unittest_helper.h
index 533b132..24a8b4c 100644
--- a/chrome/common/sandbox_mac_unittest_helper.h
+++ b/chrome/common/sandbox_mac_unittest_helper.h
@@ -81,22 +81,23 @@ class MacSandboxTestCase {
// The data that's passed in the |user_data| parameter of
// RunTest[s]InSandbox() is passed to this function.
- virtual void SetTestData(const char* test_data) {}
+ virtual void SetTestData(const char* test_data) { test_data_ = test_data; }
+
+ protected:
+ std::string test_data_;
};
// Plumbing to support the REGISTER_SANDBOX_TEST_CASE macro.
namespace internal {
-typedef std::map<std::string,MacSandboxTestCase*> SandboxTestMap;
-
-// A function that returns a common map from string -> test case class.
-SandboxTestMap& GetSandboxTestMap();
+// Register a test case with a given name.
+void AddSandboxTestCase(const char* test_name, MacSandboxTestCase* test_class);
// Construction of this class causes a new entry to be placed in a global
// map.
template <class T> struct RegisterSandboxTest {
RegisterSandboxTest(const char* test_name) {
- GetSandboxTestMap()[test_name] = new T;
+ AddSandboxTestCase(test_name, new T);
}
};
diff --git a/chrome/common/sandbox_mac_unittest_helper.mm b/chrome/common/sandbox_mac_unittest_helper.mm
index 749bcc1..328e411 100644
--- a/chrome/common/sandbox_mac_unittest_helper.mm
+++ b/chrome/common/sandbox_mac_unittest_helper.mm
@@ -24,11 +24,23 @@ namespace sandboxtest {
// Support infrastructure for REGISTER_SANDBOX_TEST_CASE macro.
namespace internal {
+typedef std::map<std::string,MacSandboxTestCase*> SandboxTestMap;
+
+// A function that returns a common map from string -> test case class.
SandboxTestMap& GetSandboxTestMap() {
static SandboxTestMap test_map;
return test_map;
}
+void AddSandboxTestCase(const char* test_name, MacSandboxTestCase* test_class) {
+ SandboxTestMap& test_map = GetSandboxTestMap();
+ if (test_map.find(test_name) != test_map.end()) {
+ LOG(ERROR) << "Trying to register duplicate test" << test_name;
+ NOTREACHED();
+ }
+ test_map[test_name] = test_class;
+}
+
} // namespace internal
bool MacSandboxTest:: RunTestInAllSandboxTypes(const char* test_name,