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