0b2cfc9ae4086efa1331bb8e4bbce98d2ac77379
[WebKit-https.git] / Tools / DumpRenderTree / chromium / LayoutTestController.cpp
1 /*
2  * Copyright (C) 2010 Google Inc. All rights reserved.
3  * Copyright (C) 2010 Pawel Hajdan (phajdan.jr@chromium.org)
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *     * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include "config.h"
33 #include "LayoutTestController.h"
34
35 #include "DRTDevToolsAgent.h"
36 #include "TestShell.h"
37 #include "WebAnimationController.h"
38 #include "WebBindings.h"
39 #include "WebConsoleMessage.h"
40 #include "WebData.h"
41 #include "WebDeviceOrientation.h"
42 #include "WebDeviceOrientationClientMock.h"
43 #include "WebDocument.h"
44 #include "WebElement.h"
45 #include "WebFrame.h"
46 #include "WebGeolocationClientMock.h"
47 #include "WebInputElement.h"
48 #include "WebKit.h"
49 #include "WebNotificationPresenter.h"
50 #include "WebScriptSource.h"
51 #include "WebSecurityPolicy.h"
52 #include "WebSettings.h"
53 #include "WebSize.h"
54 #include "WebSpeechInputControllerMock.h"
55 #include "WebURL.h"
56 #include "WebView.h"
57 #include "WebViewHost.h"
58 #include "webkit/support/webkit_support.h"
59 #include <algorithm>
60 #include <cstdlib>
61 #include <limits>
62 #include <wtf/text/WTFString.h>
63
64 #if OS(WINDOWS)
65 #include <wtf/OwnArrayPtr.h>
66 #endif
67
68 using namespace WebCore;
69 using namespace WebKit;
70 using namespace std;
71
72 LayoutTestController::LayoutTestController(TestShell* shell)
73     : m_shell(shell)
74     , m_closeRemainingWindows(false)
75     , m_deferMainResourceDataLoad(false)
76     , m_workQueue(this)
77 {
78
79     // Initialize the map that associates methods of this class with the names
80     // they will use when called by JavaScript.  The actual binding of those
81     // names to their methods will be done by calling bindToJavaScript() (defined
82     // by CppBoundClass, the parent to LayoutTestController).
83     bindMethod("addFileToPasteboardOnDrag", &LayoutTestController::addFileToPasteboardOnDrag);
84     bindMethod("addOriginAccessWhitelistEntry", &LayoutTestController::addOriginAccessWhitelistEntry);
85     bindMethod("addUserScript", &LayoutTestController::addUserScript);
86     bindMethod("addUserStyleSheet", &LayoutTestController::addUserStyleSheet);
87     bindMethod("clearAllDatabases", &LayoutTestController::clearAllDatabases);
88     bindMethod("closeWebInspector", &LayoutTestController::closeWebInspector);
89     bindMethod("counterValueForElementById", &LayoutTestController::counterValueForElementById);
90     bindMethod("disableImageLoading", &LayoutTestController::disableImageLoading);
91     bindMethod("display", &LayoutTestController::display);
92     bindMethod("dumpAsText", &LayoutTestController::dumpAsText);
93     bindMethod("dumpBackForwardList", &LayoutTestController::dumpBackForwardList);
94     bindMethod("dumpChildFramesAsText", &LayoutTestController::dumpChildFramesAsText);
95     bindMethod("dumpChildFrameScrollPositions", &LayoutTestController::dumpChildFrameScrollPositions);
96     bindMethod("dumpDatabaseCallbacks", &LayoutTestController::dumpDatabaseCallbacks);
97     bindMethod("dumpEditingCallbacks", &LayoutTestController::dumpEditingCallbacks);
98     bindMethod("dumpFrameLoadCallbacks", &LayoutTestController::dumpFrameLoadCallbacks);
99     bindMethod("dumpUserGestureInFrameLoadCallbacks", &LayoutTestController::dumpUserGestureInFrameLoadCallbacks);
100     bindMethod("dumpResourceLoadCallbacks", &LayoutTestController::dumpResourceLoadCallbacks);
101     bindMethod("dumpResourceResponseMIMETypes", &LayoutTestController::dumpResourceResponseMIMETypes);
102     bindMethod("dumpSelectionRect", &LayoutTestController::dumpSelectionRect);
103     bindMethod("dumpStatusCallbacks", &LayoutTestController::dumpWindowStatusChanges);
104     bindMethod("dumpTitleChanges", &LayoutTestController::dumpTitleChanges);
105     bindMethod("elementDoesAutoCompleteForElementWithId", &LayoutTestController::elementDoesAutoCompleteForElementWithId);
106     bindMethod("evaluateInWebInspector", &LayoutTestController::evaluateInWebInspector);
107     bindMethod("evaluateScriptInIsolatedWorld", &LayoutTestController::evaluateScriptInIsolatedWorld);
108     bindMethod("execCommand", &LayoutTestController::execCommand);
109     bindMethod("forceRedSelectionColors", &LayoutTestController::forceRedSelectionColors);
110     bindMethod("grantDesktopNotificationPermission", &LayoutTestController::grantDesktopNotificationPermission);
111     bindMethod("isCommandEnabled", &LayoutTestController::isCommandEnabled);
112     bindMethod("layerTreeAsText", &LayoutTestController::layerTreeAsText);
113     bindMethod("markerTextForListItem", &LayoutTestController::markerTextForListItem);
114     bindMethod("hasSpellingMarker", &LayoutTestController::hasSpellingMarker);
115     bindMethod("notifyDone", &LayoutTestController::notifyDone);
116     bindMethod("numberOfActiveAnimations", &LayoutTestController::numberOfActiveAnimations);
117     bindMethod("numberOfPages", &LayoutTestController::numberOfPages);
118     bindMethod("objCIdentityIsEqual", &LayoutTestController::objCIdentityIsEqual);
119     bindMethod("overridePreference", &LayoutTestController::overridePreference);
120     bindMethod("pageNumberForElementById", &LayoutTestController::pageNumberForElementById);
121     bindMethod("pathToLocalResource", &LayoutTestController::pathToLocalResource);
122     bindMethod("pauseAnimationAtTimeOnElementWithId", &LayoutTestController::pauseAnimationAtTimeOnElementWithId);
123     bindMethod("pauseTransitionAtTimeOnElementWithId", &LayoutTestController::pauseTransitionAtTimeOnElementWithId);
124     bindMethod("queueBackNavigation", &LayoutTestController::queueBackNavigation);
125     bindMethod("queueForwardNavigation", &LayoutTestController::queueForwardNavigation);
126     bindMethod("queueLoadingScript", &LayoutTestController::queueLoadingScript);
127     bindMethod("queueLoad", &LayoutTestController::queueLoad);
128     bindMethod("queueLoadHTMLString", &LayoutTestController::queueLoadHTMLString);
129     bindMethod("queueNonLoadingScript", &LayoutTestController::queueNonLoadingScript);
130     bindMethod("queueReload", &LayoutTestController::queueReload);
131     bindMethod("removeOriginAccessWhitelistEntry", &LayoutTestController::removeOriginAccessWhitelistEntry);
132     bindMethod("repaintSweepHorizontally", &LayoutTestController::repaintSweepHorizontally);
133     bindMethod("resumeAnimations", &LayoutTestController::resumeAnimations);
134     bindMethod("sampleSVGAnimationForElementAtTime", &LayoutTestController::sampleSVGAnimationForElementAtTime);
135     bindMethod("setAcceptsEditing", &LayoutTestController::setAcceptsEditing);
136     bindMethod("setAllowFileAccessFromFileURLs", &LayoutTestController::setAllowFileAccessFromFileURLs);
137     bindMethod("setAllowUniversalAccessFromFileURLs", &LayoutTestController::setAllowUniversalAccessFromFileURLs);
138     bindMethod("setAlwaysAcceptCookies", &LayoutTestController::setAlwaysAcceptCookies);
139     bindMethod("setAuthorAndUserStylesEnabled", &LayoutTestController::setAuthorAndUserStylesEnabled);
140     bindMethod("setCanOpenWindows", &LayoutTestController::setCanOpenWindows);
141     bindMethod("setCloseRemainingWindowsWhenComplete", &LayoutTestController::setCloseRemainingWindowsWhenComplete);
142     bindMethod("setCustomPolicyDelegate", &LayoutTestController::setCustomPolicyDelegate);
143     bindMethod("setDatabaseQuota", &LayoutTestController::setDatabaseQuota);
144     bindMethod("setDeferMainResourceDataLoad", &LayoutTestController::setDeferMainResourceDataLoad);
145     bindMethod("setDomainRelaxationForbiddenForURLScheme", &LayoutTestController::setDomainRelaxationForbiddenForURLScheme);
146     bindMethod("setEditingBehavior", &LayoutTestController::setEditingBehavior);
147     bindMethod("setGeolocationPermission", &LayoutTestController::setGeolocationPermission);
148     bindMethod("setIconDatabaseEnabled", &LayoutTestController::setIconDatabaseEnabled);
149     bindMethod("setJavaScriptCanAccessClipboard", &LayoutTestController::setJavaScriptCanAccessClipboard);
150     bindMethod("setMockDeviceOrientation", &LayoutTestController::setMockDeviceOrientation);
151     bindMethod("setMockGeolocationError", &LayoutTestController::setMockGeolocationError);
152     bindMethod("setMockGeolocationPosition", &LayoutTestController::setMockGeolocationPosition);
153     bindMethod("addMockSpeechInputResult", &LayoutTestController::addMockSpeechInputResult);
154     bindMethod("setPopupBlockingEnabled", &LayoutTestController::setPopupBlockingEnabled);
155     bindMethod("setPOSIXLocale", &LayoutTestController::setPOSIXLocale);
156     bindMethod("setScrollbarPolicy", &LayoutTestController::setScrollbarPolicy);
157     bindMethod("setSelectTrailingWhitespaceEnabled", &LayoutTestController::setSelectTrailingWhitespaceEnabled);
158     bindMethod("setSmartInsertDeleteEnabled", &LayoutTestController::setSmartInsertDeleteEnabled);
159     bindMethod("setStopProvisionalFrameLoads", &LayoutTestController::setStopProvisionalFrameLoads);
160     bindMethod("setTabKeyCyclesThroughElements", &LayoutTestController::setTabKeyCyclesThroughElements);
161     bindMethod("setTimelineProfilingEnabled", &LayoutTestController::setTimelineProfilingEnabled);
162     bindMethod("setUserStyleSheetEnabled", &LayoutTestController::setUserStyleSheetEnabled);
163     bindMethod("setUserStyleSheetLocation", &LayoutTestController::setUserStyleSheetLocation);
164     bindMethod("setWillSendRequestClearHeader", &LayoutTestController::setWillSendRequestClearHeader);
165     bindMethod("setWillSendRequestReturnsNull", &LayoutTestController::setWillSendRequestReturnsNull);
166     bindMethod("setWillSendRequestReturnsNullOnRedirect", &LayoutTestController::setWillSendRequestReturnsNullOnRedirect);
167     bindMethod("setWindowIsKey", &LayoutTestController::setWindowIsKey);
168     bindMethod("setXSSAuditorEnabled", &LayoutTestController::setXSSAuditorEnabled);
169     bindMethod("setAsynchronousSpellCheckingEnabled", &LayoutTestController::setAsynchronousSpellCheckingEnabled);
170     bindMethod("showWebInspector", &LayoutTestController::showWebInspector);
171     bindMethod("simulateDesktopNotificationClick", &LayoutTestController::simulateDesktopNotificationClick);
172     bindMethod("suspendAnimations", &LayoutTestController::suspendAnimations);
173     bindMethod("testRepaint", &LayoutTestController::testRepaint);
174     bindMethod("waitForPolicyDelegate", &LayoutTestController::waitForPolicyDelegate);
175     bindMethod("waitUntilDone", &LayoutTestController::waitUntilDone);
176     bindMethod("windowCount", &LayoutTestController::windowCount);
177
178     // The following are stubs.
179     bindMethod("abortModal", &LayoutTestController::abortModal);
180     bindMethod("accessStoredWebScriptObject", &LayoutTestController::accessStoredWebScriptObject);
181     bindMethod("addDisallowedURL", &LayoutTestController::addDisallowedURL);
182     bindMethod("callShouldCloseOnWebView", &LayoutTestController::callShouldCloseOnWebView);
183     bindMethod("clearAllApplicationCaches", &LayoutTestController::clearAllApplicationCaches);
184     bindMethod("clearBackForwardList", &LayoutTestController::clearBackForwardList);
185     bindMethod("dumpAsWebArchive", &LayoutTestController::dumpAsWebArchive);
186     bindMethod("keepWebHistory", &LayoutTestController::keepWebHistory);
187     bindMethod("objCClassNameOf", &LayoutTestController::objCClassNameOf);
188     bindMethod("setApplicationCacheOriginQuota", &LayoutTestController::setApplicationCacheOriginQuota);
189     bindMethod("setCallCloseOnWebViews", &LayoutTestController::setCallCloseOnWebViews);
190     bindMethod("setMainFrameIsFirstResponder", &LayoutTestController::setMainFrameIsFirstResponder);
191     bindMethod("setPrivateBrowsingEnabled", &LayoutTestController::setPrivateBrowsingEnabled);
192     bindMethod("setUseDashboardCompatibilityMode", &LayoutTestController::setUseDashboardCompatibilityMode);
193     bindMethod("storeWebScriptObject", &LayoutTestController::storeWebScriptObject);
194
195     // The fallback method is called when an unknown method is invoked.
196     bindFallbackMethod(&LayoutTestController::fallbackMethod);
197
198     // Shared properties.
199     // globalFlag is used by a number of layout tests in
200     // LayoutTests\http\tests\security\dataURL.
201     bindProperty("globalFlag", &m_globalFlag);
202     // webHistoryItemCount is used by tests in LayoutTests\http\tests\history
203     bindProperty("webHistoryItemCount", &m_webHistoryItemCount);
204 }
205
206 LayoutTestController::~LayoutTestController()
207 {
208 }
209
210 LayoutTestController::WorkQueue::~WorkQueue()
211 {
212     reset();
213 }
214
215 void LayoutTestController::WorkQueue::processWorkSoon()
216 {
217     if (m_controller->m_shell->webViewHost()->topLoadingFrame())
218         return;
219
220     if (!m_queue.isEmpty()) {
221         // We delay processing queued work to avoid recursion problems.
222         postTask(new WorkQueueTask(this));
223     } else if (!m_controller->m_waitUntilDone)
224         m_controller->m_shell->testFinished();
225 }
226
227 void LayoutTestController::WorkQueue::processWork()
228 {
229     TestShell* shell = m_controller->m_shell;
230     // Quit doing work once a load is in progress.
231     while (!m_queue.isEmpty()) {
232         bool startedLoad = m_queue.first()->run(shell);
233         delete m_queue.takeFirst();
234         if (startedLoad)
235             return;
236     }
237
238     if (!m_controller->m_waitUntilDone && !shell->webViewHost()->topLoadingFrame())
239         shell->testFinished();
240 }
241
242 void LayoutTestController::WorkQueue::reset()
243 {
244     m_frozen = false;
245     while (!m_queue.isEmpty()) {
246         delete m_queue.takeFirst();
247     }
248 }
249
250 void LayoutTestController::WorkQueue::addWork(WorkItem* work)
251 {
252     if (m_frozen) {
253         delete work;
254         return;
255     }
256     m_queue.append(work);
257 }
258
259 void LayoutTestController::dumpAsText(const CppArgumentList& arguments, CppVariant* result)
260 {
261     m_dumpAsText = true;
262     m_generatePixelResults = false;
263
264     // Optional paramater, describing whether it's allowed to dump pixel results in dumpAsText mode.
265     if (arguments.size() > 0 && arguments[0].isBool())
266         m_generatePixelResults = arguments[0].value.boolValue;
267
268     result->setNull();
269 }
270
271 void LayoutTestController::dumpDatabaseCallbacks(const CppArgumentList&, CppVariant* result)
272 {
273     // Do nothing; we don't use this flag anywhere for now
274     result->setNull();
275 }
276
277 void LayoutTestController::dumpEditingCallbacks(const CppArgumentList&, CppVariant* result)
278 {
279     m_dumpEditingCallbacks = true;
280     result->setNull();
281 }
282
283 void LayoutTestController::dumpBackForwardList(const CppArgumentList&, CppVariant* result)
284 {
285     m_dumpBackForwardList = true;
286     result->setNull();
287 }
288
289 void LayoutTestController::dumpFrameLoadCallbacks(const CppArgumentList&, CppVariant* result)
290 {
291     m_dumpFrameLoadCallbacks = true;
292     result->setNull();
293 }
294
295 void LayoutTestController::dumpUserGestureInFrameLoadCallbacks(const CppArgumentList&, CppVariant* result)
296 {
297     m_dumpUserGestureInFrameLoadCallbacks = true;
298     result->setNull();
299 }
300
301 void LayoutTestController::dumpResourceLoadCallbacks(const CppArgumentList&, CppVariant* result)
302 {
303     m_dumpResourceLoadCallbacks = true;
304     result->setNull();
305 }
306
307 void LayoutTestController::dumpResourceResponseMIMETypes(const CppArgumentList&, CppVariant* result)
308 {
309     m_dumpResourceResponseMIMETypes = true;
310     result->setNull();
311 }
312
313 void LayoutTestController::dumpChildFrameScrollPositions(const CppArgumentList&, CppVariant* result)
314 {
315     m_dumpChildFrameScrollPositions = true;
316     result->setNull();
317 }
318
319 void LayoutTestController::dumpChildFramesAsText(const CppArgumentList&, CppVariant* result)
320 {
321     m_dumpChildFramesAsText = true;
322     result->setNull();
323 }
324
325 void LayoutTestController::dumpWindowStatusChanges(const CppArgumentList&, CppVariant* result)
326 {
327     m_dumpWindowStatusChanges = true;
328     result->setNull();
329 }
330
331 void LayoutTestController::dumpTitleChanges(const CppArgumentList&, CppVariant* result)
332 {
333     m_dumpTitleChanges = true;
334     result->setNull();
335 }
336
337 void LayoutTestController::setAcceptsEditing(const CppArgumentList& arguments, CppVariant* result)
338 {
339     if (arguments.size() > 0 && arguments[0].isBool())
340         m_acceptsEditing = arguments[0].value.boolValue;
341     result->setNull();
342 }
343
344 void LayoutTestController::waitUntilDone(const CppArgumentList&, CppVariant* result)
345 {
346     if (!webkit_support::BeingDebugged())
347         postDelayedTask(new NotifyDoneTimedOutTask(this), m_shell->layoutTestTimeout());
348     m_waitUntilDone = true;
349     result->setNull();
350 }
351
352 void LayoutTestController::notifyDone(const CppArgumentList&, CppVariant* result)
353 {
354     // Test didn't timeout. Kill the timeout timer.
355     m_taskList.revokeAll();
356
357     completeNotifyDone(false);
358     result->setNull();
359 }
360
361 void LayoutTestController::completeNotifyDone(bool isTimeout)
362 {
363     if (m_waitUntilDone && !m_shell->webViewHost()->topLoadingFrame() && m_workQueue.isEmpty()) {
364         if (isTimeout)
365             m_shell->testTimedOut();
366         else
367             m_shell->testFinished();
368     }
369     m_waitUntilDone = false;
370 }
371
372 class WorkItemBackForward : public LayoutTestController::WorkItem {
373 public:
374     WorkItemBackForward(int distance) : m_distance(distance) {}
375     bool run(TestShell* shell)
376     {
377         shell->goToOffset(m_distance);
378         return true; // FIXME: Did it really start a navigation?
379     }
380 private:
381     int m_distance;
382 };
383
384 void LayoutTestController::queueBackNavigation(const CppArgumentList& arguments, CppVariant* result)
385 {
386     if (arguments.size() > 0 && arguments[0].isNumber())
387         m_workQueue.addWork(new WorkItemBackForward(-arguments[0].toInt32()));
388     result->setNull();
389 }
390
391 void LayoutTestController::queueForwardNavigation(const CppArgumentList& arguments, CppVariant* result)
392 {
393     if (arguments.size() > 0 && arguments[0].isNumber())
394         m_workQueue.addWork(new WorkItemBackForward(arguments[0].toInt32()));
395     result->setNull();
396 }
397
398 class WorkItemReload : public LayoutTestController::WorkItem {
399 public:
400     bool run(TestShell* shell)
401     {
402         shell->reload();
403         return true;
404     }
405 };
406
407 void LayoutTestController::queueReload(const CppArgumentList&, CppVariant* result)
408 {
409     m_workQueue.addWork(new WorkItemReload);
410     result->setNull();
411 }
412
413 class WorkItemLoadingScript : public LayoutTestController::WorkItem {
414 public:
415     WorkItemLoadingScript(const string& script) : m_script(script) {}
416     bool run(TestShell* shell)
417     {
418         shell->webView()->mainFrame()->executeScript(WebScriptSource(WebString::fromUTF8(m_script)));
419         return true; // FIXME: Did it really start a navigation?
420     }
421 private:
422     string m_script;
423 };
424
425 class WorkItemNonLoadingScript : public LayoutTestController::WorkItem {
426 public:
427     WorkItemNonLoadingScript(const string& script) : m_script(script) {}
428     bool run(TestShell* shell)
429     {
430         shell->webView()->mainFrame()->executeScript(WebScriptSource(WebString::fromUTF8(m_script)));
431         return false;
432     }
433 private:
434     string m_script;
435 };
436
437 void LayoutTestController::queueLoadingScript(const CppArgumentList& arguments, CppVariant* result)
438 {
439     if (arguments.size() > 0 && arguments[0].isString())
440         m_workQueue.addWork(new WorkItemLoadingScript(arguments[0].toString()));
441     result->setNull();
442 }
443
444 void LayoutTestController::queueNonLoadingScript(const CppArgumentList& arguments, CppVariant* result)
445 {
446     if (arguments.size() > 0 && arguments[0].isString())
447         m_workQueue.addWork(new WorkItemNonLoadingScript(arguments[0].toString()));
448     result->setNull();
449 }
450
451 class WorkItemLoad : public LayoutTestController::WorkItem {
452 public:
453     WorkItemLoad(const WebURL& url, const WebString& target)
454         : m_url(url)
455         , m_target(target) {}
456     bool run(TestShell* shell)
457     {
458         shell->webViewHost()->loadURLForFrame(m_url, m_target);
459         return true; // FIXME: Did it really start a navigation?
460     }
461 private:
462     WebURL m_url;
463     WebString m_target;
464 };
465
466 void LayoutTestController::queueLoad(const CppArgumentList& arguments, CppVariant* result)
467 {
468     if (arguments.size() > 0 && arguments[0].isString()) {
469         // FIXME: Implement WebURL::resolve() and avoid GURL.
470         GURL currentURL = m_shell->webView()->mainFrame()->url();
471         GURL fullURL = currentURL.Resolve(arguments[0].toString());
472
473         string target = "";
474         if (arguments.size() > 1 && arguments[1].isString())
475             target = arguments[1].toString();
476
477         m_workQueue.addWork(new WorkItemLoad(fullURL, WebString::fromUTF8(target)));
478     }
479     result->setNull();
480 }
481
482 class WorkItemLoadHTMLString : public LayoutTestController::WorkItem  {
483 public:
484     WorkItemLoadHTMLString(const std::string& html, const WebURL& baseURL)
485         : m_html(html)
486         , m_baseURL(baseURL) {}
487     bool run(TestShell* shell)
488     {
489         shell->webView()->mainFrame()->loadHTMLString(
490             WebKit::WebData(m_html.data(), m_html.length()), m_baseURL);
491         return true;
492     }
493 private:
494     std::string m_html;
495     WebURL m_baseURL;
496 };
497
498 void LayoutTestController::queueLoadHTMLString(const CppArgumentList& arguments, CppVariant* result)
499 {
500     if (arguments.size() > 0 && arguments[0].isString()) {
501         string html = arguments[0].toString();
502         WebURL baseURL;
503         if (arguments.size() > 1 && arguments[1].isString())
504             baseURL = WebURL(GURL(arguments[1].toString()));
505         m_workQueue.addWork(new WorkItemLoadHTMLString(html, baseURL));
506     }
507     result->setNull();
508 }
509
510 void LayoutTestController::objCIdentityIsEqual(const CppArgumentList& arguments, CppVariant* result)
511 {
512     if (arguments.size() < 2) {
513         // This is the best we can do to return an error.
514         result->setNull();
515         return;
516     }
517     result->set(arguments[0].isEqual(arguments[1]));
518 }
519
520 void LayoutTestController::reset()
521 {
522     if (m_shell) {
523         m_shell->webView()->setZoomLevel(false, 0);
524         m_shell->webView()->setTabKeyCyclesThroughElements(true);
525 #if !OS(DARWIN) && !OS(WINDOWS) // Actually, TOOLKIT_GTK
526         // (Constants copied because we can't depend on the header that defined
527         // them from this file.)
528         m_shell->webView()->setSelectionColors(0xff1e90ff, 0xff000000, 0xffc8c8c8, 0xff323232);
529 #endif
530         m_shell->webView()->removeAllUserContent();
531     }
532     m_dumpAsText = false;
533     m_dumpEditingCallbacks = false;
534     m_dumpFrameLoadCallbacks = false;
535     m_dumpUserGestureInFrameLoadCallbacks = false;
536     m_dumpResourceLoadCallbacks = false;
537     m_dumpResourceResponseMIMETypes = false;
538     m_dumpBackForwardList = false;
539     m_dumpChildFrameScrollPositions = false;
540     m_dumpChildFramesAsText = false;
541     m_dumpWindowStatusChanges = false;
542     m_dumpSelectionRect = false;
543     m_dumpTitleChanges = false;
544     m_generatePixelResults = true;
545     m_acceptsEditing = true;
546     m_waitUntilDone = false;
547     m_canOpenWindows = false;
548     m_testRepaint = false;
549     m_sweepHorizontally = false;
550     m_shouldAddFileToPasteboard = false;
551     m_stopProvisionalFrameLoads = false;
552     m_deferMainResourceDataLoad = true;
553     m_globalFlag.set(false);
554     m_webHistoryItemCount.set(0);
555     m_userStyleSheetLocation = WebURL();
556
557     webkit_support::SetAcceptAllCookies(false);
558     WebSecurityPolicy::resetOriginAccessWhitelists();
559
560     // Reset the default quota for each origin to 5MB
561     webkit_support::SetDatabaseQuota(5 * 1024 * 1024);
562
563     setlocale(LC_ALL, "");
564
565     if (m_closeRemainingWindows)
566         m_shell->closeRemainingWindows();
567     else
568         m_closeRemainingWindows = true;
569     m_workQueue.reset();
570     m_taskList.revokeAll();
571 }
572
573 void LayoutTestController::locationChangeDone()
574 {
575     m_webHistoryItemCount.set(m_shell->navigationEntryCount());
576
577     // No more new work after the first complete load.
578     m_workQueue.setFrozen(true);
579
580     if (!m_waitUntilDone)
581         m_workQueue.processWorkSoon();
582 }
583
584 void LayoutTestController::policyDelegateDone()
585 {
586     ASSERT(m_waitUntilDone);
587     m_shell->testFinished();
588     m_waitUntilDone = false;
589 }
590
591 void LayoutTestController::setCanOpenWindows(const CppArgumentList&, CppVariant* result)
592 {
593     m_canOpenWindows = true;
594     result->setNull();
595 }
596
597 void LayoutTestController::setTabKeyCyclesThroughElements(const CppArgumentList& arguments, CppVariant* result)
598 {
599     if (arguments.size() > 0 && arguments[0].isBool())
600         m_shell->webView()->setTabKeyCyclesThroughElements(arguments[0].toBoolean());
601     result->setNull();
602 }
603
604 void LayoutTestController::windowCount(const CppArgumentList&, CppVariant* result)
605 {
606     result->set(static_cast<int>(m_shell->windowCount()));
607 }
608
609 void LayoutTestController::setCloseRemainingWindowsWhenComplete(const CppArgumentList& arguments, CppVariant* result)
610 {
611     if (arguments.size() > 0 && arguments[0].isBool())
612         m_closeRemainingWindows = arguments[0].value.boolValue;
613     result->setNull();
614 }
615
616 void LayoutTestController::setAlwaysAcceptCookies(const CppArgumentList& arguments, CppVariant* result)
617 {
618     if (arguments.size() > 0)
619         webkit_support::SetAcceptAllCookies(cppVariantToBool(arguments[0]));
620     result->setNull();
621 }
622
623 void LayoutTestController::setAsynchronousSpellCheckingEnabled(const CppArgumentList&, CppVariant*)
624 {
625     // FIXME: Implement this.
626 }
627
628 void LayoutTestController::showWebInspector(const CppArgumentList&, CppVariant* result)
629 {
630     m_shell->showDevTools();
631     result->setNull();
632 }
633
634 void LayoutTestController::closeWebInspector(const CppArgumentList& args, CppVariant* result)
635 {
636     m_shell->closeDevTools();
637     result->setNull();
638 }
639
640 void LayoutTestController::setWindowIsKey(const CppArgumentList& arguments, CppVariant* result)
641 {
642     if (arguments.size() > 0 && arguments[0].isBool())
643         m_shell->setFocus(m_shell->webView(), arguments[0].value.boolValue);
644     result->setNull();
645 }
646
647 void LayoutTestController::setUserStyleSheetEnabled(const CppArgumentList& arguments, CppVariant* result)
648 {
649     if (arguments.size() > 0 && arguments[0].isBool()) {
650         m_shell->preferences()->userStyleSheetLocation = arguments[0].value.boolValue ? m_userStyleSheetLocation : WebURL();
651         m_shell->applyPreferences();
652     }
653     result->setNull();
654 }
655
656 void LayoutTestController::setUserStyleSheetLocation(const CppArgumentList& arguments, CppVariant* result)
657 {
658     if (arguments.size() > 0 && arguments[0].isString()) {
659         m_userStyleSheetLocation = webkit_support::LocalFileToDataURL(
660             webkit_support::RewriteLayoutTestsURL(arguments[0].toString()));
661         m_shell->preferences()->userStyleSheetLocation = m_userStyleSheetLocation;
662         m_shell->applyPreferences();
663     }
664     result->setNull();
665 }
666
667 void LayoutTestController::setAuthorAndUserStylesEnabled(const CppArgumentList& arguments, CppVariant* result)
668 {
669     if (arguments.size() > 0 && arguments[0].isBool()) {
670         m_shell->preferences()->authorAndUserStylesEnabled = arguments[0].value.boolValue;
671         m_shell->applyPreferences();
672     }
673     result->setNull();
674 }
675
676 void LayoutTestController::execCommand(const CppArgumentList& arguments, CppVariant* result)
677 {
678     result->setNull();
679     if (arguments.size() <= 0 || !arguments[0].isString())
680         return;
681
682     std::string command = arguments[0].toString();
683     std::string value("");
684     // Ignore the second parameter (which is userInterface)
685     // since this command emulates a manual action.
686     if (arguments.size() >= 3 && arguments[2].isString())
687         value = arguments[2].toString();
688
689     // Note: webkit's version does not return the boolean, so neither do we.
690     m_shell->webView()->focusedFrame()->executeCommand(WebString::fromUTF8(command), WebString::fromUTF8(value));
691 }
692
693 void LayoutTestController::isCommandEnabled(const CppArgumentList& arguments, CppVariant* result)
694 {
695     if (arguments.size() <= 0 || !arguments[0].isString()) {
696         result->setNull();
697         return;
698     }
699
700     std::string command = arguments[0].toString();
701     bool rv = m_shell->webView()->focusedFrame()->isCommandEnabled(WebString::fromUTF8(command));
702     result->set(rv);
703 }
704
705 void LayoutTestController::setPopupBlockingEnabled(const CppArgumentList& arguments, CppVariant* result)
706 {
707     if (arguments.size() > 0 && arguments[0].isBool()) {
708         bool blockPopups = arguments[0].toBoolean();
709         m_shell->preferences()->javaScriptCanOpenWindowsAutomatically = !blockPopups;
710         m_shell->applyPreferences();
711     }
712     result->setNull();
713 }
714
715 void LayoutTestController::setUseDashboardCompatibilityMode(const CppArgumentList&, CppVariant* result)
716 {
717     // We have no need to support Dashboard Compatibility Mode (mac-only)
718     result->setNull();
719 }
720
721 void LayoutTestController::clearAllApplicationCaches(const CppArgumentList&, CppVariant* result)
722 {
723     // FIXME: implement to support Application Cache Quotas.
724     result->setNull();
725 }
726
727 void LayoutTestController::setApplicationCacheOriginQuota(const CppArgumentList&, CppVariant* result)
728 {
729     // FIXME: implement to support Application Cache Quotas.
730     result->setNull();
731 }
732
733 void LayoutTestController::setScrollbarPolicy(const CppArgumentList&, CppVariant* result)
734 {
735     // FIXME: implement.
736     // Currently only has a non-null implementation on QT.
737     result->setNull();
738 }
739
740 void LayoutTestController::setCustomPolicyDelegate(const CppArgumentList& arguments, CppVariant* result)
741 {
742     if (arguments.size() > 0 && arguments[0].isBool()) {
743         bool enable = arguments[0].value.boolValue;
744         bool permissive = false;
745         if (arguments.size() > 1 && arguments[1].isBool())
746             permissive = arguments[1].value.boolValue;
747         m_shell->webViewHost()->setCustomPolicyDelegate(enable, permissive);
748     }
749     result->setNull();
750 }
751
752 void LayoutTestController::waitForPolicyDelegate(const CppArgumentList&, CppVariant* result)
753 {
754     m_shell->webViewHost()->waitForPolicyDelegate();
755     m_waitUntilDone = true;
756     result->setNull();
757 }
758
759 void LayoutTestController::setWillSendRequestClearHeader(const CppArgumentList& arguments, CppVariant* result)
760 {
761     if (arguments.size() > 0 && arguments[0].isString()) {
762         string header = arguments[0].toString();
763         if (!header.empty())
764             m_shell->webViewHost()->addClearHeader(String::fromUTF8(header.c_str()));
765     }
766     result->setNull();
767 }
768
769 void LayoutTestController::setWillSendRequestReturnsNullOnRedirect(const CppArgumentList& arguments, CppVariant* result)
770 {
771     if (arguments.size() > 0 && arguments[0].isBool())
772         m_shell->webViewHost()->setBlockRedirects(arguments[0].value.boolValue);
773     result->setNull();
774 }
775
776 void LayoutTestController::setWillSendRequestReturnsNull(const CppArgumentList& arguments, CppVariant* result)
777 {
778     if (arguments.size() > 0 && arguments[0].isBool())
779         m_shell->webViewHost()->setRequestReturnNull(arguments[0].value.boolValue);
780     result->setNull();
781 }
782
783 void LayoutTestController::pathToLocalResource(const CppArgumentList& arguments, CppVariant* result)
784 {
785     result->setNull();
786     if (arguments.size() <= 0 || !arguments[0].isString())
787         return;
788
789     string url = arguments[0].toString();
790 #if OS(WINDOWS)
791     if (!url.find("/tmp/")) {
792         // We want a temp file.
793         const unsigned tempPrefixLength = 5;
794         size_t bufferSize = MAX_PATH;
795         OwnArrayPtr<WCHAR> tempPath(new WCHAR[bufferSize]);
796         DWORD tempLength = ::GetTempPathW(bufferSize, tempPath.get());
797         if (tempLength + url.length() - tempPrefixLength + 1 > bufferSize) {
798             bufferSize = tempLength + url.length() - tempPrefixLength + 1;
799             tempPath.set(new WCHAR[bufferSize]);
800             tempLength = GetTempPathW(bufferSize, tempPath.get());
801             ASSERT(tempLength < bufferSize);
802         }
803         string resultPath(WebString(tempPath.get(), tempLength).utf8());
804         resultPath.append(url.substr(tempPrefixLength));
805         result->set(resultPath);
806         return;
807     }
808 #endif
809
810     // Some layout tests use file://// which we resolve as a UNC path.  Normalize
811     // them to just file:///.
812     string lowerUrl = url;
813     transform(lowerUrl.begin(), lowerUrl.end(), lowerUrl.begin(), ::tolower);
814     while (!lowerUrl.find("file:////")) {
815         url = url.substr(0, 8) + url.substr(9);
816         lowerUrl = lowerUrl.substr(0, 8) + lowerUrl.substr(9);
817     }
818     result->set(webkit_support::RewriteLayoutTestsURL(url).spec());
819 }
820
821 void LayoutTestController::addFileToPasteboardOnDrag(const CppArgumentList&, CppVariant* result)
822 {
823     result->setNull();
824     m_shouldAddFileToPasteboard = true;
825 }
826
827 void LayoutTestController::setStopProvisionalFrameLoads(const CppArgumentList&, CppVariant* result)
828 {
829     result->setNull();
830     m_stopProvisionalFrameLoads = true;
831 }
832
833 void LayoutTestController::setSmartInsertDeleteEnabled(const CppArgumentList& arguments, CppVariant* result)
834 {
835     if (arguments.size() > 0 && arguments[0].isBool())
836         m_shell->webViewHost()->setSmartInsertDeleteEnabled(arguments[0].value.boolValue);
837     result->setNull();
838 }
839
840 void LayoutTestController::setSelectTrailingWhitespaceEnabled(const CppArgumentList& arguments, CppVariant* result)
841 {
842     if (arguments.size() > 0 && arguments[0].isBool())
843         m_shell->webViewHost()->setSelectTrailingWhitespaceEnabled(arguments[0].value.boolValue);
844     result->setNull();
845 }
846
847 bool LayoutTestController::pauseAnimationAtTimeOnElementWithId(const WebString& animationName, double time, const WebString& elementId)
848 {
849     WebFrame* webFrame = m_shell->webView()->mainFrame();
850     if (!webFrame)
851         return false;
852
853     WebAnimationController* controller = webFrame->animationController();
854     if (!controller)
855         return false;
856
857     WebElement element = webFrame->document().getElementById(elementId);
858     if (element.isNull())
859         return false;
860     return controller->pauseAnimationAtTime(element, animationName, time);
861 }
862
863 bool LayoutTestController::pauseTransitionAtTimeOnElementWithId(const WebString& propertyName, double time, const WebString& elementId)
864 {
865     WebFrame* webFrame = m_shell->webView()->mainFrame();
866     if (!webFrame)
867         return false;
868
869     WebAnimationController* controller = webFrame->animationController();
870     if (!controller)
871         return false;
872
873     WebElement element = webFrame->document().getElementById(elementId);
874     if (element.isNull())
875         return false;
876     return controller->pauseTransitionAtTime(element, propertyName, time);
877 }
878
879 bool LayoutTestController::elementDoesAutoCompleteForElementWithId(const WebString& elementId)
880 {
881     WebFrame* webFrame = m_shell->webView()->mainFrame();
882     if (!webFrame)
883         return false;
884
885     WebElement element = webFrame->document().getElementById(elementId);
886     if (element.isNull() || !element.hasTagName("input"))
887         return false;
888
889     WebInputElement inputElement = element.to<WebInputElement>();
890     return inputElement.autoComplete();
891 }
892
893 int LayoutTestController::numberOfActiveAnimations()
894 {
895     WebFrame* webFrame = m_shell->webView()->mainFrame();
896     if (!webFrame)
897         return -1;
898
899     WebAnimationController* controller = webFrame->animationController();
900     if (!controller)
901         return -1;
902
903     return controller->numberOfActiveAnimations();
904 }
905
906 void LayoutTestController::suspendAnimations()
907 {
908     WebFrame* webFrame = m_shell->webView()->mainFrame();
909     if (!webFrame)
910         return;
911
912     WebAnimationController* controller = webFrame->animationController();
913     if (!controller)
914         return;
915
916     controller->suspendAnimations();
917 }
918
919 void LayoutTestController::resumeAnimations()
920 {
921     WebFrame* webFrame = m_shell->webView()->mainFrame();
922     if (!webFrame)
923         return;
924
925     WebAnimationController* controller = webFrame->animationController();
926     if (!controller)
927         return;
928
929     controller->resumeAnimations();
930 }
931
932 void LayoutTestController::pauseAnimationAtTimeOnElementWithId(const CppArgumentList& arguments, CppVariant* result)
933 {
934     result->set(false);
935     if (arguments.size() > 2 && arguments[0].isString() && arguments[1].isNumber() && arguments[2].isString()) {
936         WebString animationName = cppVariantToWebString(arguments[0]);
937         double time = arguments[1].toDouble();
938         WebString elementId = cppVariantToWebString(arguments[2]);
939         result->set(pauseAnimationAtTimeOnElementWithId(animationName, time, elementId));
940     }
941 }
942
943 void LayoutTestController::pauseTransitionAtTimeOnElementWithId(const CppArgumentList& arguments, CppVariant* result)
944 {
945     result->set(false);
946     if (arguments.size() > 2 && arguments[0].isString() && arguments[1].isNumber() && arguments[2].isString()) {
947         WebString propertyName = cppVariantToWebString(arguments[0]);
948         double time = arguments[1].toDouble();
949         WebString elementId = cppVariantToWebString(arguments[2]);
950         result->set(pauseTransitionAtTimeOnElementWithId(propertyName, time, elementId));
951     }
952 }
953
954 void LayoutTestController::elementDoesAutoCompleteForElementWithId(const CppArgumentList& arguments, CppVariant* result)
955 {
956     if (arguments.size() != 1 || !arguments[0].isString()) {
957         result->set(false);
958         return;
959     }
960     WebString elementId = cppVariantToWebString(arguments[0]);
961     result->set(elementDoesAutoCompleteForElementWithId(elementId));
962 }
963
964 void LayoutTestController::numberOfActiveAnimations(const CppArgumentList&, CppVariant* result)
965 {
966     result->set(numberOfActiveAnimations());
967 }
968
969 void LayoutTestController::suspendAnimations(const CppArgumentList&, CppVariant* result)
970 {
971     suspendAnimations();
972     result->setNull();
973 }
974
975 void LayoutTestController::resumeAnimations(const CppArgumentList&, CppVariant* result)
976 {
977     resumeAnimations();
978     result->setNull();
979 }
980
981 void LayoutTestController::sampleSVGAnimationForElementAtTime(const CppArgumentList& arguments, CppVariant* result)
982 {
983     if (arguments.size() != 3) {
984         result->setNull();
985         return;
986     }
987     WebString animationId = cppVariantToWebString(arguments[0]);
988     double time = arguments[1].toDouble();
989     WebString elementId = cppVariantToWebString(arguments[2]);
990     bool success = m_shell->webView()->mainFrame()->pauseSVGAnimation(animationId, time, elementId);
991     result->set(success);
992 }
993
994 void LayoutTestController::disableImageLoading(const CppArgumentList&, CppVariant* result)
995 {
996     m_shell->preferences()->loadsImagesAutomatically = false;
997     m_shell->applyPreferences();
998     result->setNull();
999 }
1000
1001 void LayoutTestController::setIconDatabaseEnabled(const CppArgumentList&, CppVariant* result)
1002 {
1003     // We don't use the WebKit icon database.
1004     result->setNull();
1005 }
1006
1007 void LayoutTestController::callShouldCloseOnWebView(const CppArgumentList&, CppVariant* result)
1008 {
1009     result->set(m_shell->webView()->dispatchBeforeUnloadEvent());
1010 }
1011
1012 void LayoutTestController::grantDesktopNotificationPermission(const CppArgumentList& arguments, CppVariant* result)
1013 {
1014     if (arguments.size() != 1 || !arguments[0].isString()) {
1015         result->set(false);
1016         return;
1017     }
1018     m_shell->notificationPresenter()->grantPermission(cppVariantToWebString(arguments[0]));
1019     result->set(true);
1020 }
1021
1022 void LayoutTestController::simulateDesktopNotificationClick(const CppArgumentList& arguments, CppVariant* result)
1023 {
1024     if (arguments.size() != 1 || !arguments[0].isString()) {
1025         result->set(false);
1026         return;
1027     }
1028     if (m_shell->notificationPresenter()->simulateClick(cppVariantToWebString(arguments[0])))
1029         result->set(true);
1030     else
1031         result->set(false);
1032 }
1033
1034 void LayoutTestController::setDomainRelaxationForbiddenForURLScheme(const CppArgumentList& arguments, CppVariant* result)
1035 {
1036     if (arguments.size() != 2 || !arguments[0].isBool() || !arguments[1].isString())
1037         return;
1038     m_shell->webView()->setDomainRelaxationForbidden(cppVariantToBool(arguments[0]), cppVariantToWebString(arguments[1]));
1039 }
1040
1041 void LayoutTestController::setDeferMainResourceDataLoad(const CppArgumentList& arguments, CppVariant* result)
1042 {
1043     if (arguments.size() == 1)
1044         m_deferMainResourceDataLoad = cppVariantToBool(arguments[0]);
1045 }
1046
1047 //
1048 // Unimplemented stubs
1049 //
1050
1051 void LayoutTestController::dumpAsWebArchive(const CppArgumentList& arguments, CppVariant* result)
1052 {
1053     result->setNull();
1054 }
1055
1056 void LayoutTestController::setMainFrameIsFirstResponder(const CppArgumentList& arguments, CppVariant* result)
1057 {
1058     result->setNull();
1059 }
1060
1061 void LayoutTestController::dumpSelectionRect(const CppArgumentList& arguments, CppVariant* result)
1062 {
1063     m_dumpSelectionRect = true;
1064     result->setNull();
1065 }
1066
1067 void LayoutTestController::display(const CppArgumentList& arguments, CppVariant* result)
1068 {
1069     WebViewHost* host = m_shell->webViewHost();
1070     const WebKit::WebSize& size = m_shell->webView()->size();
1071     WebRect rect(0, 0, size.width, size.height);
1072     host->updatePaintRect(rect);
1073     host->paintInvalidatedRegion();
1074     host->displayRepaintMask();
1075     result->setNull();
1076 }
1077
1078 void LayoutTestController::testRepaint(const CppArgumentList&, CppVariant* result)
1079 {
1080     m_testRepaint = true;
1081     result->setNull();
1082 }
1083
1084 void LayoutTestController::repaintSweepHorizontally(const CppArgumentList&, CppVariant* result)
1085 {
1086     m_sweepHorizontally = true;
1087     result->setNull();
1088 }
1089
1090 void LayoutTestController::clearBackForwardList(const CppArgumentList& arguments, CppVariant* result)
1091 {
1092     result->setNull();
1093 }
1094
1095 void LayoutTestController::keepWebHistory(const CppArgumentList& arguments,  CppVariant* result)
1096 {
1097     result->setNull();
1098 }
1099
1100 void LayoutTestController::storeWebScriptObject(const CppArgumentList& arguments, CppVariant* result)
1101 {
1102     result->setNull();
1103 }
1104
1105 void LayoutTestController::accessStoredWebScriptObject(const CppArgumentList& arguments, CppVariant* result)
1106 {
1107     result->setNull();
1108 }
1109
1110 void LayoutTestController::objCClassNameOf(const CppArgumentList& arguments, CppVariant* result)
1111 {
1112     result->setNull();
1113 }
1114
1115 void LayoutTestController::addDisallowedURL(const CppArgumentList& arguments, CppVariant* result)
1116 {
1117     result->setNull();
1118 }
1119
1120 void LayoutTestController::setCallCloseOnWebViews(const CppArgumentList& arguments, CppVariant* result)
1121 {
1122     result->setNull();
1123 }
1124
1125 void LayoutTestController::setPrivateBrowsingEnabled(const CppArgumentList& arguments, CppVariant* result)
1126 {
1127     result->setNull();
1128 }
1129
1130 void LayoutTestController::setJavaScriptCanAccessClipboard(const CppArgumentList& arguments, CppVariant* result)
1131 {
1132     if (arguments.size() > 0 && arguments[0].isBool()) {
1133         m_shell->preferences()->javaScriptCanAccessClipboard = arguments[0].value.boolValue;
1134         m_shell->applyPreferences();
1135     }
1136     result->setNull();
1137 }
1138
1139 void LayoutTestController::setXSSAuditorEnabled(const CppArgumentList& arguments, CppVariant* result)
1140 {
1141     if (arguments.size() > 0 && arguments[0].isBool()) {
1142         m_shell->preferences()->XSSAuditorEnabled = arguments[0].value.boolValue;
1143         m_shell->applyPreferences();
1144     }
1145     result->setNull();
1146 }
1147
1148 void LayoutTestController::evaluateScriptInIsolatedWorld(const CppArgumentList& arguments, CppVariant* result)
1149 {
1150     if (arguments.size() >= 2 && arguments[0].isNumber() && arguments[1].isString()) {
1151         WebScriptSource source(cppVariantToWebString(arguments[1]));
1152         // This relies on the iframe focusing itself when it loads. This is a bit
1153         // sketchy, but it seems to be what other tests do.
1154         m_shell->webView()->focusedFrame()->executeScriptInIsolatedWorld(arguments[0].toInt32(), &source, 1, 1);
1155     }
1156     result->setNull();
1157 }
1158
1159 void LayoutTestController::setAllowUniversalAccessFromFileURLs(const CppArgumentList& arguments, CppVariant* result)
1160 {
1161     if (arguments.size() > 0 && arguments[0].isBool()) {
1162         m_shell->preferences()->allowUniversalAccessFromFileURLs = arguments[0].value.boolValue;
1163         m_shell->applyPreferences();
1164     }
1165     result->setNull();
1166 }
1167
1168 void LayoutTestController::setAllowFileAccessFromFileURLs(const CppArgumentList& arguments, CppVariant* result)
1169 {
1170     if (arguments.size() > 0 && arguments[0].isBool()) {
1171         m_shell->preferences()->allowFileAccessFromFileURLs = arguments[0].value.boolValue;
1172         m_shell->applyPreferences();
1173     }
1174     result->setNull();
1175 }
1176
1177 // Need these conversions because the format of the value for booleans
1178 // may vary - for example, on mac "1" and "0" are used for boolean.
1179 bool LayoutTestController::cppVariantToBool(const CppVariant& value)
1180 {
1181     if (value.isBool())
1182         return value.toBoolean();
1183     if (value.isNumber())
1184         return value.toInt32();
1185     if (value.isString()) {
1186         string valueString = value.toString();
1187         if (valueString == "true" || valueString == "1")
1188             return true;
1189         if (valueString == "false" || valueString == "0")
1190             return false;
1191     }
1192     logErrorToConsole("Invalid value. Expected boolean value.");
1193     return false;
1194 }
1195
1196 int32_t LayoutTestController::cppVariantToInt32(const CppVariant& value)
1197 {
1198     if (value.isNumber())
1199         return value.toInt32();
1200     if (value.isString()) {
1201         string stringSource = value.toString();
1202         const char* source = stringSource.data();
1203         char* end;
1204         long number = strtol(source, &end, 10);
1205         if (end == source + stringSource.length() && number >= numeric_limits<int32_t>::min() && number <= numeric_limits<int32_t>::max())
1206             return static_cast<int32_t>(number);
1207     }
1208     logErrorToConsole("Invalid value for preference. Expected integer value.");
1209     return 0;
1210 }
1211
1212 WebString LayoutTestController::cppVariantToWebString(const CppVariant& value)
1213 {
1214     if (!value.isString()) {
1215         logErrorToConsole("Invalid value for preference. Expected string value.");
1216         return WebString();
1217     }
1218     return WebString::fromUTF8(value.toString());
1219 }
1220
1221 void LayoutTestController::overridePreference(const CppArgumentList& arguments, CppVariant* result)
1222 {
1223     result->setNull();
1224     if (arguments.size() != 2 || !arguments[0].isString())
1225         return;
1226
1227     string key = arguments[0].toString();
1228     CppVariant value = arguments[1];
1229     WebPreferences* prefs = m_shell->preferences();
1230     if (key == "WebKitStandardFont")
1231         prefs->standardFontFamily = cppVariantToWebString(value);
1232     else if (key == "WebKitFixedFont")
1233         prefs->fixedFontFamily = cppVariantToWebString(value);
1234     else if (key == "WebKitSerifFont")
1235         prefs->serifFontFamily = cppVariantToWebString(value);
1236     else if (key == "WebKitSansSerifFont")
1237         prefs->sansSerifFontFamily = cppVariantToWebString(value);
1238     else if (key == "WebKitCursiveFont")
1239         prefs->cursiveFontFamily = cppVariantToWebString(value);
1240     else if (key == "WebKitFantasyFont")
1241         prefs->fantasyFontFamily = cppVariantToWebString(value);
1242     else if (key == "WebKitDefaultFontSize")
1243         prefs->defaultFontSize = cppVariantToInt32(value);
1244     else if (key == "WebKitDefaultFixedFontSize")
1245         prefs->defaultFixedFontSize = cppVariantToInt32(value);
1246     else if (key == "WebKitMinimumFontSize")
1247         prefs->minimumFontSize = cppVariantToInt32(value);
1248     else if (key == "WebKitMinimumLogicalFontSize")
1249         prefs->minimumLogicalFontSize = cppVariantToInt32(value);
1250     else if (key == "WebKitDefaultTextEncodingName")
1251         prefs->defaultTextEncodingName = cppVariantToWebString(value);
1252     else if (key == "WebKitJavaScriptEnabled")
1253         prefs->javaScriptEnabled = cppVariantToBool(value);
1254     else if (key == "WebKitWebSecurityEnabled")
1255         prefs->webSecurityEnabled = cppVariantToBool(value);
1256     else if (key == "WebKitJavaScriptCanOpenWindowsAutomatically")
1257         prefs->javaScriptCanOpenWindowsAutomatically = cppVariantToBool(value);
1258     else if (key == "WebKitDisplayImagesKey")
1259         prefs->loadsImagesAutomatically = cppVariantToBool(value);
1260     else if (key == "WebKitPluginsEnabled")
1261         prefs->pluginsEnabled = cppVariantToBool(value);
1262     else if (key == "WebKitDOMPasteAllowedPreferenceKey")
1263         prefs->DOMPasteAllowed = cppVariantToBool(value);
1264     else if (key == "WebKitDeveloperExtrasEnabledPreferenceKey")
1265         prefs->developerExtrasEnabled = cppVariantToBool(value);
1266     else if (key == "WebKitShrinksStandaloneImagesToFit")
1267         prefs->shrinksStandaloneImagesToFit = cppVariantToBool(value);
1268     else if (key == "WebKitTextAreasAreResizable")
1269         prefs->textAreasAreResizable = cppVariantToBool(value);
1270     else if (key == "WebKitJavaEnabled")
1271         prefs->javaEnabled = cppVariantToBool(value);
1272     else if (key == "WebKitUsesPageCachePreferenceKey")
1273         prefs->usesPageCache = cppVariantToBool(value);
1274     else if (key == "WebKitJavaScriptCanAccessClipboard")
1275         prefs->javaScriptCanAccessClipboard = cppVariantToBool(value);
1276     else if (key == "WebKitXSSAuditorEnabled")
1277         prefs->XSSAuditorEnabled = cppVariantToBool(value);
1278     else if (key == "WebKitLocalStorageEnabledPreferenceKey")
1279         prefs->localStorageEnabled = cppVariantToBool(value);
1280     else if (key == "WebKitOfflineWebApplicationCacheEnabled")
1281         prefs->offlineWebApplicationCacheEnabled = cppVariantToBool(value);
1282     else if (key == "WebKitTabToLinksPreferenceKey")
1283         prefs->tabsToLinks = cppVariantToBool(value);
1284     else if (key == "WebKitWebGLEnabled")
1285         prefs->experimentalWebGLEnabled = cppVariantToBool(value);
1286     else if (key == "WebKitHyperlinkAuditingEnabled")
1287         prefs->hyperlinkAuditingEnabled = cppVariantToBool(value);
1288     else if (key == "WebKitEnableCaretBrowsing")
1289         prefs->caretBrowsingEnabled = cppVariantToBool(value);
1290     else {
1291         string message("Invalid name for preference: ");
1292         message.append(key);
1293         logErrorToConsole(message);
1294     }
1295     m_shell->applyPreferences();
1296 }
1297
1298 void LayoutTestController::fallbackMethod(const CppArgumentList&, CppVariant* result)
1299 {
1300     printf("CONSOLE MESSAGE: JavaScript ERROR: unknown method called on LayoutTestController\n");
1301     result->setNull();
1302 }
1303
1304 void LayoutTestController::addOriginAccessWhitelistEntry(const CppArgumentList& arguments, CppVariant* result)
1305 {
1306     result->setNull();
1307
1308     if (arguments.size() != 4 || !arguments[0].isString() || !arguments[1].isString()
1309         || !arguments[2].isString() || !arguments[3].isBool())
1310         return;
1311
1312     WebKit::WebURL url(GURL(arguments[0].toString()));
1313     if (!url.isValid())
1314         return;
1315
1316     WebSecurityPolicy::addOriginAccessWhitelistEntry(
1317         url,
1318         cppVariantToWebString(arguments[1]),
1319         cppVariantToWebString(arguments[2]),
1320         arguments[3].toBoolean());
1321 }
1322
1323 void LayoutTestController::removeOriginAccessWhitelistEntry(const CppArgumentList& arguments, CppVariant* result)
1324 {
1325     result->setNull();
1326
1327     if (arguments.size() != 4 || !arguments[0].isString() || !arguments[1].isString()
1328         || !arguments[2].isString() || !arguments[3].isBool())
1329         return;
1330
1331     WebKit::WebURL url(GURL(arguments[0].toString()));
1332     if (!url.isValid())
1333         return;
1334
1335     WebSecurityPolicy::removeOriginAccessWhitelistEntry(
1336         url,
1337         cppVariantToWebString(arguments[1]),
1338         cppVariantToWebString(arguments[2]),
1339         arguments[3].toBoolean());
1340 }
1341
1342 void LayoutTestController::clearAllDatabases(const CppArgumentList& arguments, CppVariant* result)
1343 {
1344     result->setNull();
1345     webkit_support::ClearAllDatabases();
1346 }
1347
1348 void LayoutTestController::setDatabaseQuota(const CppArgumentList& arguments, CppVariant* result)
1349 {
1350     result->setNull();
1351     if ((arguments.size() >= 1) && arguments[0].isNumber())
1352         webkit_support::SetDatabaseQuota(arguments[0].toInt32());
1353 }
1354
1355 void LayoutTestController::setPOSIXLocale(const CppArgumentList& arguments, CppVariant* result)
1356 {
1357     result->setNull();
1358     if (arguments.size() == 1 && arguments[0].isString())
1359         setlocale(LC_ALL, arguments[0].toString().c_str());
1360 }
1361
1362 void LayoutTestController::counterValueForElementById(const CppArgumentList& arguments, CppVariant* result)
1363 {
1364     result->setNull();
1365     if (arguments.size() < 1 || !arguments[0].isString())
1366         return;
1367     WebFrame* frame = m_shell->webView()->mainFrame();
1368     if (!frame)
1369         return;
1370     WebString counterValue = frame->counterValueForElementById(cppVariantToWebString(arguments[0]));
1371     if (counterValue.isNull())
1372         return;
1373     result->set(counterValue.utf8());
1374 }
1375
1376 static bool parsePageSizeParameters(const CppArgumentList& arguments,
1377                                     int argOffset,
1378                                     int* pageWidthInPixels,
1379                                     int* pageHeightInPixels)
1380 {
1381     // WebKit is using the window width/height of DumpRenderTree as the
1382     // default value of the page size.
1383     // FIXME: share these values with other ports.
1384     *pageWidthInPixels = 800;
1385     *pageHeightInPixels = 600;
1386     switch (arguments.size() - argOffset) {
1387     case 2:
1388         if (!arguments[argOffset].isNumber() || !arguments[1 + argOffset].isNumber())
1389             return false;
1390         *pageWidthInPixels = arguments[argOffset].toInt32();
1391         *pageHeightInPixels = arguments[1 + argOffset].toInt32();
1392         // fall through.
1393     case 0:
1394         break;
1395     default:
1396         return false;
1397     }
1398     return true;
1399 }
1400
1401 void LayoutTestController::pageNumberForElementById(const CppArgumentList& arguments, CppVariant* result)
1402 {
1403     result->setNull();
1404     int pageWidthInPixels = 0;
1405     int pageHeightInPixels = 0;
1406     if (!parsePageSizeParameters(arguments, 1,
1407                                  &pageWidthInPixels, &pageHeightInPixels))
1408         return;
1409     if (!arguments[0].isString())
1410         return;
1411     WebFrame* frame = m_shell->webView()->mainFrame();
1412     if (!frame)
1413         return;
1414     result->set(frame->pageNumberForElementById(cppVariantToWebString(arguments[0]),
1415                                                 static_cast<float>(pageWidthInPixels),
1416                                                 static_cast<float>(pageHeightInPixels)));
1417 }
1418
1419 void LayoutTestController::numberOfPages(const CppArgumentList& arguments, CppVariant* result)
1420 {
1421     result->setNull();
1422     int pageWidthInPixels = 0;
1423     int pageHeightInPixels = 0;
1424     if (!parsePageSizeParameters(arguments, 0, &pageWidthInPixels, &pageHeightInPixels))
1425         return;
1426
1427     WebFrame* frame = m_shell->webView()->mainFrame();
1428     if (!frame)
1429         return;
1430     WebSize size(pageWidthInPixels, pageHeightInPixels);
1431     int numberOfPages = frame->printBegin(size);
1432     frame->printEnd();
1433     result->set(numberOfPages);
1434 }
1435
1436 void LayoutTestController::logErrorToConsole(const std::string& text)
1437 {
1438     m_shell->webViewHost()->didAddMessageToConsole(
1439         WebConsoleMessage(WebConsoleMessage::LevelError, WebString::fromUTF8(text)),
1440         WebString(), 0);
1441 }
1442
1443 void LayoutTestController::setTimelineProfilingEnabled(const CppArgumentList& arguments, CppVariant* result)
1444 {
1445     result->setNull();
1446     if (arguments.size() < 1 || !arguments[0].isBool())
1447         return;
1448     m_shell->drtDevToolsAgent()->setTimelineProfilingEnabled(arguments[0].toBoolean());
1449 }
1450
1451 void LayoutTestController::evaluateInWebInspector(const CppArgumentList& arguments, CppVariant* result)
1452 {
1453     result->setNull();
1454     if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isString())
1455         return;
1456     m_shell->drtDevToolsAgent()->evaluateInWebInspector(arguments[0].toInt32(), arguments[1].toString());
1457 }
1458
1459 void LayoutTestController::forceRedSelectionColors(const CppArgumentList& arguments, CppVariant* result)
1460 {
1461     result->setNull();
1462     m_shell->webView()->setSelectionColors(0xffee0000, 0xff00ee00, 0xff000000, 0xffc0c0c0);
1463 }
1464
1465 void LayoutTestController::addUserScript(const CppArgumentList& arguments, CppVariant* result)
1466 {
1467     result->setNull();
1468     if (arguments.size() < 3 || !arguments[0].isString() || !arguments[1].isBool() || !arguments[2].isBool())
1469         return;
1470     WebView::addUserScript(
1471         cppVariantToWebString(arguments[0]), WebVector<WebString>(),
1472         arguments[1].toBoolean() ? WebView::UserScriptInjectAtDocumentStart : WebView::UserScriptInjectAtDocumentEnd,
1473         arguments[2].toBoolean() ? WebView::UserContentInjectInAllFrames : WebView::UserContentInjectInTopFrameOnly);
1474 }
1475
1476 void LayoutTestController::addUserStyleSheet(const CppArgumentList& arguments, CppVariant* result)
1477 {
1478     result->setNull();
1479     if (arguments.size() < 2 || !arguments[0].isString() || !arguments[1].isBool())
1480         return;
1481     WebView::addUserStyleSheet(
1482         cppVariantToWebString(arguments[0]), WebVector<WebString>(),
1483         arguments[1].toBoolean() ? WebView::UserContentInjectInAllFrames : WebView::UserContentInjectInTopFrameOnly,
1484         // Chromium defaults to InjectInSubsequentDocuments, but for compatibility
1485         // with the other ports' DRTs, we use UserStyleInjectInExistingDocuments.
1486         WebView::UserStyleInjectInExistingDocuments);
1487 }
1488
1489 void LayoutTestController::setEditingBehavior(const CppArgumentList& arguments, CppVariant* results)
1490 {
1491     string key = arguments[0].toString();
1492     if (key == "mac") {
1493         m_shell->preferences()->editingBehavior = WebSettings::EditingBehaviorMac;
1494         m_shell->applyPreferences();
1495     } else if (key == "win") {
1496         m_shell->preferences()->editingBehavior = WebSettings::EditingBehaviorWin;
1497         m_shell->applyPreferences();
1498     } else if (key == "unix") {
1499         m_shell->preferences()->editingBehavior = WebSettings::EditingBehaviorUnix;
1500         m_shell->applyPreferences();
1501     } else
1502         logErrorToConsole("Passed invalid editing behavior. Should be 'mac', 'win', or 'unix'.");
1503 }
1504
1505 void LayoutTestController::setMockDeviceOrientation(const CppArgumentList& arguments, CppVariant* result)
1506 {
1507     result->setNull();
1508     if (arguments.size() < 6 || !arguments[0].isBool() || !arguments[1].isNumber() || !arguments[2].isBool() || !arguments[3].isNumber() || !arguments[4].isBool() || !arguments[5].isNumber())
1509         return;
1510
1511     WebDeviceOrientation orientation(arguments[0].toBoolean(), arguments[1].toDouble(), arguments[2].toBoolean(), arguments[3].toDouble(), arguments[4].toBoolean(), arguments[5].toDouble());
1512     // Note that we only call setOrientation on the main page's mock since this is all that the
1513     // tests require. If necessary, we could get a list of WebViewHosts from the TestShell and
1514     // call setOrientation on each DeviceOrientationClientMock.
1515     m_shell->webViewHost()->deviceOrientationClientMock()->setOrientation(orientation);
1516 }
1517
1518 void LayoutTestController::setGeolocationPermission(const CppArgumentList& arguments, CppVariant* result)
1519 {
1520     result->setNull();
1521     if (arguments.size() < 1 || !arguments[0].isBool())
1522         return;
1523     m_shell->webViewHost()->geolocationClientMock()->setPermission(arguments[0].toBoolean());
1524 }
1525
1526 void LayoutTestController::setMockGeolocationPosition(const CppArgumentList& arguments, CppVariant* result)
1527 {
1528     result->setNull();
1529     if (arguments.size() < 3 || !arguments[0].isNumber() || !arguments[1].isNumber() || !arguments[2].isNumber())
1530         return;
1531     m_shell->webViewHost()->geolocationClientMock()->setPosition(arguments[0].toDouble(), arguments[1].toDouble(), arguments[2].toDouble());
1532 }
1533
1534 void LayoutTestController::setMockGeolocationError(const CppArgumentList& arguments, CppVariant* result)
1535 {
1536     result->setNull();
1537     if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isString())
1538         return;
1539     m_shell->webViewHost()->geolocationClientMock()->setError(arguments[0].toInt32(), cppVariantToWebString(arguments[1]));
1540 }
1541
1542 void LayoutTestController::abortModal(const CppArgumentList& arguments, CppVariant* result)
1543 {
1544     result->setNull();
1545 }
1546
1547 void LayoutTestController::addMockSpeechInputResult(const CppArgumentList& arguments, CppVariant* result)
1548 {
1549     result->setNull();
1550     if (arguments.size() < 3 || !arguments[0].isString() || !arguments[1].isNumber() || !arguments[2].isString())
1551         return;
1552
1553     m_shell->webViewHost()->speechInputControllerMock()->addMockRecognitionResult(cppVariantToWebString(arguments[0]), arguments[1].toDouble(), cppVariantToWebString(arguments[2]));
1554 }
1555
1556 void LayoutTestController::layerTreeAsText(const CppArgumentList& args, CppVariant* result)
1557 {
1558     result->set(m_shell->webView()->mainFrame()->layerTreeAsText().utf8());
1559 }
1560
1561 void LayoutTestController::markerTextForListItem(const CppArgumentList& args, CppVariant* result)
1562 {
1563     WebElement element;
1564     if (!WebBindings::getElement(args[0].value.objectValue, &element))
1565         result->setNull();
1566     else
1567         result->set(element.document().frame()->markerTextForListItem(element).utf8());
1568 }
1569
1570 void LayoutTestController::hasSpellingMarker(const CppArgumentList& arguments, CppVariant* result)
1571 {
1572     if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isNumber())
1573         return;
1574     result->set(m_shell->webView()->mainFrame()->selectionStartHasSpellingMarkerFor(arguments[0].toInt32(), arguments[1].toInt32()));
1575 }