1// Copyright (c) 2012 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#import <Cocoa/Cocoa.h>
6
7#include "base/files/file_util.h"
8#include "base/files/scoped_file.h"
9#include "base/logging.h"
10#include "base/mac/scoped_cftyperef.h"
11#include "base/memory/scoped_ptr.h"
12#include "base/memory/shared_memory.h"
13#include "content/common/mac/font_descriptor.h"
14#include "content/common/mac/font_loader.h"
15#include "content/common/sandbox_mac_unittest_helper.h"
16#include "testing/gtest/include/gtest/gtest.h"
17
18namespace content {
19
20class FontLoadingTestCase : public MacSandboxTestCase {
21 public:
22  FontLoadingTestCase() : font_data_length_(-1) {}
23  virtual bool BeforeSandboxInit() OVERRIDE;
24  virtual bool SandboxedTest() OVERRIDE;
25 private:
26  scoped_ptr<base::SharedMemory> font_shmem_;
27  size_t font_data_length_;
28};
29REGISTER_SANDBOX_TEST_CASE(FontLoadingTestCase);
30
31
32// Load raw font data into shared memory object.
33bool FontLoadingTestCase::BeforeSandboxInit() {
34  std::string font_data;
35  if (!base::ReadFileToString(base::FilePath(test_data_.c_str()), &font_data)) {
36    LOG(ERROR) << "Failed to read font data from file (" << test_data_ << ")";
37    return false;
38  }
39
40  font_data_length_ = font_data.length();
41  if (font_data_length_ <= 0) {
42    LOG(ERROR) << "No font data: " << font_data_length_;
43    return false;
44  }
45
46  font_shmem_.reset(new base::SharedMemory);
47  if (!font_shmem_) {
48    LOG(ERROR) << "Failed to create shared memory object.";
49    return false;
50  }
51
52  if (!font_shmem_->CreateAndMapAnonymous(font_data_length_)) {
53    LOG(ERROR) << "SharedMemory::Create failed";
54    return false;
55  }
56
57  memcpy(font_shmem_->memory(), font_data.c_str(), font_data_length_);
58  if (!font_shmem_->Unmap())  {
59    LOG(ERROR) << "SharedMemory::Unmap failed";
60    return false;
61  }
62  return true;
63}
64
65bool FontLoadingTestCase::SandboxedTest() {
66  base::SharedMemoryHandle shmem_handle;
67  if (!font_shmem_->ShareToProcess(base::kNullProcessHandle, &shmem_handle)) {
68    LOG(ERROR) << "SharedMemory::ShareToProcess failed";
69    return false;
70  }
71
72  CGFontRef cg_font_ref;
73  if (!FontLoader::CGFontRefFromBuffer(shmem_handle, font_data_length_,
74                                       &cg_font_ref)) {
75    LOG(ERROR) << "Call to CreateCGFontFromBuffer() failed";
76    return false;
77  }
78
79  if (!cg_font_ref) {
80    LOG(ERROR) << "Got NULL CGFontRef";
81    return false;
82  }
83  base::ScopedCFTypeRef<CGFontRef> cgfont(cg_font_ref);
84
85  CTFontRef ct_font_ref =
86      CTFontCreateWithGraphicsFont(cgfont.get(), 16.0, NULL, NULL);
87  base::ScopedCFTypeRef<CTFontRef> ctfont(ct_font_ref);
88
89  if (!ct_font_ref) {
90    LOG(ERROR) << "CTFontCreateWithGraphicsFont() failed";
91    return false;
92  }
93
94  // Do something with the font to make sure it's loaded.
95  CGFloat cap_height = CTFontGetCapHeight(ct_font_ref);
96
97  if (cap_height <= 0.0) {
98    LOG(ERROR) << "Got bad value for CTFontGetCapHeight " << cap_height;
99    return false;
100  }
101
102  return true;
103}
104
105TEST_F(MacSandboxTest, FontLoadingTest) {
106  base::FilePath temp_file_path;
107  FILE* temp_file = base::CreateAndOpenTemporaryFile(&temp_file_path);
108  ASSERT_TRUE(temp_file);
109  base::ScopedFILE temp_file_closer(temp_file);
110
111  NSFont* srcFont = [NSFont fontWithName:@"Geeza Pro" size:16.0];
112  FontDescriptor descriptor(srcFont);
113  FontLoader::Result result;
114  FontLoader::LoadFont(descriptor, &result);
115  EXPECT_GT(result.font_data_size, 0U);
116  EXPECT_GT(result.font_id, 0U);
117
118  base::WriteFileDescriptor(fileno(temp_file),
119      static_cast<const char *>(result.font_data.memory()),
120      result.font_data_size);
121
122  ASSERT_TRUE(RunTestInSandbox(SANDBOX_TYPE_RENDERER,
123                  "FontLoadingTestCase", temp_file_path.value().c_str()));
124  temp_file_closer.reset();
125  ASSERT_TRUE(base::DeleteFile(temp_file_path, false));
126}
127
128}  // namespace content
129