summaryrefslogtreecommitdiffstats
path: root/webkit/support/platform_support_mac.mm
blob: a9ab216030ce6a76f1d5c4dc2802d208a68e3850 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
// Copyright (c) 2012 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 "webkit/support/platform_support.h"

#import <AppKit/AppKit.h>
#include <AvailabilityMacros.h>
#import <Foundation/Foundation.h>
#import <objc/objc-runtime.h>

#include "base/base_paths.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/mac/bundle_locations.h"
#include "base/mac/mac_util.h"
#include "base/path_service.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "grit/webkit_resources.h"
#include "ui/base/resource/data_pack.h"
#include "webkit/plugins/npapi/plugin_list.h"
#import "webkit/support/drt_application_mac.h"
#import "webkit/support/mac/DumpRenderTreePasteboard.h"
#include "webkit/support/test_webkit_platform_support.h"

static ui::DataPack* g_resource_data_pack = NULL;

namespace webkit_support {

static NSAutoreleasePool* autorelease_pool;

void BeforeInitialize() {
  [CrDrtApplication sharedApplication];
  autorelease_pool = [[NSAutoreleasePool alloc] init];
  DCHECK(autorelease_pool);
}

#if OBJC_API_VERSION == 2
static void SwizzleAllMethods(Class imposter, Class original) {
  unsigned int imposterMethodCount = 0;
  Method* imposterMethods =
      class_copyMethodList(imposter, &imposterMethodCount);

  unsigned int originalMethodCount = 0;
  Method* originalMethods =
      class_copyMethodList(original, &originalMethodCount);

  for (unsigned int i = 0; i < imposterMethodCount; i++) {
    SEL imposterMethodName = method_getName(imposterMethods[i]);

    // Attempt to add the method to the original class.  If it fails, the method
    // already exists and we should instead exchange the implementations.
    if (class_addMethod(original,
                        imposterMethodName,
                        method_getImplementation(originalMethods[i]),
                        method_getTypeEncoding(originalMethods[i]))) {
      continue;
    }

    unsigned int j = 0;
    for (; j < originalMethodCount; j++) {
      SEL originalMethodName = method_getName(originalMethods[j]);
      if (sel_isEqual(imposterMethodName, originalMethodName)) {
        break;
      }
    }

    // If class_addMethod failed above then the method must exist on the
    // original class.
    DCHECK(j < originalMethodCount) << "method wasn't found?";
    method_exchangeImplementations(imposterMethods[i], originalMethods[j]);
  }

  if (imposterMethods) {
    free(imposterMethods);
  }
  if (originalMethods) {
    free(originalMethods);
  }
}
#endif

static void SwizzleNSPasteboard() {
  // We replace NSPaseboard w/ the shim (from WebKit) that avoids having
  // sideeffects w/ whatever the user does at the same time.

  Class imposterClass = objc_getClass("DumpRenderTreePasteboard");
  Class originalClass = objc_getClass("NSPasteboard");
#if OBJC_API_VERSION == 0
  class_poseAs(imposterClass, originalClass);
#else
  // Swizzle instance methods...
  SwizzleAllMethods(imposterClass, originalClass);
  // and then class methods.
  SwizzleAllMethods(object_getClass(imposterClass),
                    object_getClass(originalClass));
#endif
}

void AfterInitialize() {
  // Load a data pack.
  g_resource_data_pack = new ui::DataPack(ui::SCALE_FACTOR_100P);
  base::FilePath resources_pak_path;
  PathService::Get(base::DIR_EXE, &resources_pak_path);
  resources_pak_path = resources_pak_path.Append("Content Shell.app")
      .Append("Contents")
      .Append("Frameworks")
      .Append("Content Shell Framework.framework")
      .Append("Resources")
      .Append("content_shell.pak");
  if (!g_resource_data_pack->LoadFromPath(resources_pak_path)) {
    LOG(FATAL) << "failed to load DumpRenderTree.pak";
  }
}

void BeforeShutdown() {
}

void AfterShutdown() {
  [DumpRenderTreePasteboard releaseLocalPasteboards];
  [autorelease_pool drain];
  delete g_resource_data_pack;
}

}  // namespace webkit_support

base::string16 TestWebKitPlatformSupport::GetLocalizedString(int message_id) {
  // |g_resource_data_pack| is null on unit tests.
  // But som unit tests reach GetLocalizedString().
  if (!g_resource_data_pack)
    return base::string16();
  base::StringPiece res;
  if (!g_resource_data_pack->GetStringPiece(message_id, &res)) {
    LOG(FATAL) << "failed to load webkit string with id " << message_id;
  }

  // Data packs hold strings as either UTF8 or UTF16.
  base::string16 msg;
  switch (g_resource_data_pack->GetTextEncodingType()) {
  case ui::DataPack::UTF8:
    msg = UTF8ToUTF16(res);
    break;
  case ui::DataPack::UTF16:
    msg = base::string16(reinterpret_cast<const char16*>(res.data()),
                   res.length() / 2);
    break;
  case ui::DataPack::BINARY:
    NOTREACHED();
    break;
  }

  return msg;
}

// Helper method for getting the path to the test shell resources directory.
static base::FilePath GetResourcesFilePath() {
  base::FilePath path;
  // We assume the application is bundled.
  if (!base::mac::AmIBundled()) {
    LOG(FATAL) << "Failed to locate resources. The applicaiton is not bundled.";
  }
  PathService::Get(base::DIR_EXE, &path);
  path = path.Append(base::FilePath::kParentDirectory);
  return path.AppendASCII("Resources");
}

base::StringPiece TestWebKitPlatformSupport::GetDataResource(
    int resource_id,
    ui::ScaleFactor scale_factor) {
  switch (resource_id) {
  case IDR_BROKENIMAGE: {
    // Use webkit's broken image icon (16x16)
    CR_DEFINE_STATIC_LOCAL(std::string, broken_image_data, ());
    if (broken_image_data.empty()) {
      base::FilePath path = GetResourcesFilePath();
      // In order to match WebKit's colors for the missing image, we have to
      // use a PNG. The GIF doesn't have the color range needed to correctly
      // match the TIFF they use in Safari.
      path = base::MakeAbsoluteFilePath(path.AppendASCII("missingImage.png"));
      bool success = file_util::ReadFileToString(path, &broken_image_data);
      if (!success) {
        LOG(FATAL) << "Failed reading: " << path.value();
      }
    }
    return broken_image_data;
  }
  case IDR_TEXTAREA_RESIZER: {
    // Use webkit's text area resizer image.
    CR_DEFINE_STATIC_LOCAL(std::string, resize_corner_data, ());
    if (resize_corner_data.empty()) {
      base::FilePath path = GetResourcesFilePath();
      path = base::MakeAbsoluteFilePath(
          path.AppendASCII("textAreaResizeCorner.png"));
      bool success = file_util::ReadFileToString(path, &resize_corner_data);
      if (!success) {
        LOG(FATAL) << "Failed reading: " << path.value();
      }
    }
    return resize_corner_data;
  }
  }
  base::StringPiece res;
  if (g_resource_data_pack)
    g_resource_data_pack->GetStringPiece(resource_id, &res);
  return res;
}