OLD | NEW |
| (Empty) |
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 #include "build/build_config.h" | |
6 | |
7 #include <Carbon/Carbon.h> | |
8 // #include <ApplicationServices/ApplicationServices.h> | |
9 #import <Cocoa/Cocoa.h> | |
10 #import <objc/objc-runtime.h> | |
11 #include <mach/task.h> | |
12 | |
13 #include "base/command_line.h" | |
14 #include "base/logging.h" | |
15 #include "base/message_pump_mac.h" | |
16 #import "base/test/mock_chrome_application_mac.h" | |
17 #include "webkit/tools/test_shell/test_shell.h" | |
18 #include "webkit/tools/test_shell/test_shell_platform_delegate.h" | |
19 #include "webkit/tools/test_shell/test_shell_switches.h" | |
20 | |
21 static NSAutoreleasePool *gTestShellAutoreleasePool = nil; | |
22 | |
23 static void SetDefaultsToLayoutTestValues(void) { | |
24 // So we can match the WebKit layout tests, we want to force a bunch of | |
25 // preferences that control appearance to match. | |
26 // (We want to do this as early as possible in application startup so | |
27 // the settings are in before any higher layers could cache values.) | |
28 | |
29 // This is inspired by resetDefaultsToConsistentValues() in | |
30 // WebKit/Tools/DumpRenderTree/mac/DumpRenderTree.mm . | |
31 | |
32 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; | |
33 | |
34 const NSInteger kMinFontSizeCGSmoothes = 4; | |
35 const NSInteger kNoFontSmoothing = 0; | |
36 const NSInteger kBlueTintedAppearance = 1; | |
37 [defaults setInteger:kMinFontSizeCGSmoothes | |
38 forKey:@"AppleAntiAliasingThreshold"]; | |
39 [defaults setInteger:kNoFontSmoothing | |
40 forKey:@"AppleFontSmoothing"]; | |
41 [defaults setInteger:kBlueTintedAppearance | |
42 forKey:@"AppleAquaColorVariant"]; | |
43 [defaults setObject:@"0.709800 0.835300 1.000000" | |
44 forKey:@"AppleHighlightColor"]; | |
45 [defaults setObject:@"0.500000 0.500000 0.500000" | |
46 forKey:@"AppleOtherHighlightColor"]; | |
47 [defaults setObject:[NSArray arrayWithObject:@"en"] | |
48 forKey:@"AppleLanguages"]; | |
49 | |
50 // AppKit pulls scrollbar style from NSUserDefaults. HIToolbox uses | |
51 // CFPreferences, but AnyApplication, so we set it, force it to load, and | |
52 // then reset the pref to what it was (HIToolbox will cache what it loaded). | |
53 [defaults setObject:@"DoubleMax" forKey:@"AppleScrollBarVariant"]; | |
54 CFTypeRef initialValue = | |
55 CFPreferencesCopyValue(CFSTR("AppleScrollBarVariant"), | |
56 kCFPreferencesAnyApplication, | |
57 kCFPreferencesCurrentUser, | |
58 kCFPreferencesAnyHost); | |
59 CFPreferencesSetValue(CFSTR("AppleScrollBarVariant"), | |
60 CFSTR("DoubleMax"), | |
61 kCFPreferencesAnyApplication, | |
62 kCFPreferencesCurrentUser, | |
63 kCFPreferencesAnyHost); | |
64 #ifndef __LP64__ | |
65 // Make HIToolbox read from CFPreferences. | |
66 // HIToolbox is not available in 64-bit. DumpRenderTree comments out this | |
67 // call with a note to rdar://6347388 . No clue, sorry. | |
68 ThemeScrollBarArrowStyle style; | |
69 GetThemeScrollBarArrowStyle(&style); | |
70 #endif // __LP64__ | |
71 if (initialValue) { | |
72 // Reset the preference to what it was | |
73 CFPreferencesSetValue(CFSTR("AppleScrollBarVariant"), | |
74 initialValue, | |
75 kCFPreferencesAnyApplication, | |
76 kCFPreferencesCurrentUser, | |
77 kCFPreferencesAnyHost); | |
78 CFRelease(initialValue); | |
79 } | |
80 } | |
81 | |
82 static void ClearAnyDefaultsForLayoutTests(void) { | |
83 // Not running a test, clear the keys so the TestShell looks right to the | |
84 // running user. | |
85 | |
86 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; | |
87 | |
88 [defaults removeObjectForKey:@"AppleAntiAliasingThreshold"]; | |
89 [defaults removeObjectForKey:@"AppleFontSmoothing"]; | |
90 [defaults removeObjectForKey:@"AppleAquaColorVariant"]; | |
91 [defaults removeObjectForKey:@"AppleHighlightColor"]; | |
92 [defaults removeObjectForKey:@"AppleOtherHighlightColor"]; | |
93 [defaults removeObjectForKey:@"AppleLanguages"]; | |
94 [defaults removeObjectForKey:@"AppleScrollBarVariant"]; | |
95 } | |
96 | |
97 #if OBJC_API_VERSION == 2 | |
98 static void SwizzleAllMethods(Class imposter, Class original) { | |
99 unsigned int imposterMethodCount = 0; | |
100 Method* imposterMethods = | |
101 class_copyMethodList(imposter, &imposterMethodCount); | |
102 | |
103 unsigned int originalMethodCount = 0; | |
104 Method* originalMethods = | |
105 class_copyMethodList(original, &originalMethodCount); | |
106 | |
107 for (unsigned int i = 0; i < imposterMethodCount; i++) { | |
108 SEL imposterMethodName = method_getName(imposterMethods[i]); | |
109 | |
110 // Attempt to add the method to the original class. If it fails, the method | |
111 // already exists and we should instead exchange the implementations. | |
112 if (class_addMethod(original, | |
113 imposterMethodName, | |
114 method_getImplementation(originalMethods[i]), | |
115 method_getTypeEncoding(originalMethods[i]))) { | |
116 continue; | |
117 } | |
118 | |
119 unsigned int j = 0; | |
120 for (; j < originalMethodCount; j++) { | |
121 SEL originalMethodName = method_getName(originalMethods[j]); | |
122 if (sel_isEqual(imposterMethodName, originalMethodName)) { | |
123 break; | |
124 } | |
125 } | |
126 | |
127 // If class_addMethod failed above then the method must exist on the | |
128 // original class. | |
129 DCHECK(j < originalMethodCount) << "method wasn't found?"; | |
130 method_exchangeImplementations(imposterMethods[i], originalMethods[j]); | |
131 } | |
132 | |
133 if (imposterMethods) { | |
134 free(imposterMethods); | |
135 } | |
136 if (originalMethods) { | |
137 free(originalMethods); | |
138 } | |
139 } | |
140 #endif | |
141 | |
142 static void SwizzleNSPasteboard(void) { | |
143 // We replace NSPaseboard w/ the shim (from WebKit) that avoids having | |
144 // sideeffects w/ whatever the user does at the same time. | |
145 | |
146 Class imposterClass = objc_getClass("DumpRenderTreePasteboard"); | |
147 Class originalClass = objc_getClass("NSPasteboard"); | |
148 #if OBJC_API_VERSION == 0 | |
149 class_poseAs(imposterClass, originalClass); | |
150 #else | |
151 // Swizzle instance methods... | |
152 SwizzleAllMethods(imposterClass, originalClass); | |
153 // and then class methods. | |
154 SwizzleAllMethods(object_getClass(imposterClass), | |
155 object_getClass(originalClass)); | |
156 #endif | |
157 } | |
158 | |
159 TestShellPlatformDelegate::TestShellPlatformDelegate( | |
160 const CommandLine &command_line) | |
161 : command_line_(command_line) { | |
162 gTestShellAutoreleasePool = [[NSAutoreleasePool alloc] init]; | |
163 // Force AppKit to init itself, but don't start the runloop yet | |
164 [MockCrApp sharedApplication]; | |
165 [NSBundle loadNibNamed:@"MainMenu" owner:NSApp]; | |
166 } | |
167 | |
168 TestShellPlatformDelegate::~TestShellPlatformDelegate() { | |
169 [gTestShellAutoreleasePool drain]; | |
170 } | |
171 | |
172 bool TestShellPlatformDelegate::CheckLayoutTestSystemDependencies() { | |
173 return true; | |
174 } | |
175 | |
176 void TestShellPlatformDelegate::InitializeGUI() { | |
177 // Make sure any settings from a previous layout run are cleared | |
178 ClearAnyDefaultsForLayoutTests(); | |
179 } | |
180 | |
181 void TestShellPlatformDelegate::PreflightArgs(int *argc, char ***argv) { | |
182 } | |
183 | |
184 void TestShellPlatformDelegate::SetWindowPositionForRecording(TestShell *) { | |
185 } | |
186 | |
187 void TestShellPlatformDelegate::SelectUnifiedTheme() { | |
188 SetDefaultsToLayoutTestValues(); | |
189 SwizzleNSPasteboard(); | |
190 } | |
191 | |
192 void TestShellPlatformDelegate::SuppressErrorReporting() { | |
193 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); | |
194 | |
195 // If we die during tests, we don't want to be spamming the user's crash | |
196 // reporter. Set our exception port to null and add signal handlers. | |
197 // Both of these are necessary to avoid the crash reporter. Although, we do | |
198 // still seem to be missing some cases. | |
199 if (!parsed_command_line.HasSwitch(test_shell::kGDB)) { | |
200 task_set_exception_ports(mach_task_self(), EXC_MASK_ALL, MACH_PORT_NULL, | |
201 EXCEPTION_DEFAULT, THREAD_STATE_NONE); | |
202 } | |
203 } | |
OLD | NEW |