• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
3  * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1.  Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer.
11  * 2.  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15  *     its contributors may be used to endorse or promote products derived
16  *     from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 #include "config.h"
30 #include "LayoutTestControllerQt.h"
31 
32 #include "DumpRenderTreeQt.h"
33 #include "WorkQueue.h"
34 #include "WorkQueueItemQt.h"
35 #include <QDir>
36 #include <QLocale>
37 #include <qwebsettings.h>
38 
39 extern void qt_dump_editing_callbacks(bool b);
40 extern void qt_dump_frame_loader(bool b);
41 extern void qt_dump_resource_load_callbacks(bool b);
42 extern void qt_drt_setFrameSetFlatteningEnabled(QWebPage*, bool);
43 extern void qt_drt_setJavaScriptProfilingEnabled(QWebFrame*, bool enabled);
44 extern bool qt_drt_pauseAnimation(QWebFrame*, const QString& name, double time, const QString& elementId);
45 extern bool qt_drt_pauseTransitionOfProperty(QWebFrame*, const QString& name, double time, const QString& elementId);
46 extern bool qt_drt_pauseSVGAnimation(QWebFrame*, const QString& animationId, double time, const QString& elementId);
47 extern int qt_drt_numberOfActiveAnimations(QWebFrame*);
48 extern void qt_drt_setDomainRelaxationForbiddenForURLScheme(bool forbidden, const QString& scheme);
49 
50 extern void qt_drt_whiteListAccessFromOrigin(const QString& sourceOrigin, const QString& destinationProtocol, const QString& destinationHost, bool allowDestinationSubdomains);
51 extern QString qt_drt_counterValueForElementById(QWebFrame* qFrame, const QString& id);
52 extern int qt_drt_workerThreadCount();
53 extern int qt_drt_pageNumberForElementById(QWebFrame* qFrame, const QString& id, float width, float height);
54 
LayoutTestController(WebCore::DumpRenderTree * drt)55 LayoutTestController::LayoutTestController(WebCore::DumpRenderTree* drt)
56     : QObject()
57     , m_drt(drt)
58 {
59     reset();
60 }
61 
reset()62 void LayoutTestController::reset()
63 {
64     m_hasDumped = false;
65     m_loadFinished = false;
66     m_textDump = false;
67     m_dumpBackForwardList = false;
68     m_dumpChildrenAsText = false;
69     m_canOpenWindows = false;
70     m_waitForDone = false;
71     m_dumpTitleChanges = false;
72     m_dumpDatabaseCallbacks = false;
73     m_dumpStatusCallbacks = false;
74     m_timeoutTimer.stop();
75     m_topLoadingFrame = 0;
76     m_waitForPolicy = false;
77     m_handleErrorPages = false;
78     m_webHistory = 0;
79     m_globalFlag = false;
80     qt_dump_editing_callbacks(false);
81     qt_dump_frame_loader(false);
82     qt_dump_resource_load_callbacks(false);
83     emit hidePage();
84 }
85 
processWork()86 void LayoutTestController::processWork()
87 {
88     // qDebug() << ">>>processWork";
89 
90     // if we didn't start a new load, then we finished all the commands, so we're ready to dump state
91     if (WorkQueue::shared()->processWork() && !shouldWaitUntilDone()) {
92         emit done();
93         m_hasDumped = true;
94     }
95 }
96 
97 // Called on loadFinished on WebPage
maybeDump(bool success)98 void LayoutTestController::maybeDump(bool success)
99 {
100 
101     // This can happen on any of the http/tests/security/window-events-*.html tests, where the test opens
102     // a new window, calls the unload and load event handlers on the window's page, and then immediately
103     // issues a notifyDone. Needs investigation.
104     if (!m_topLoadingFrame)
105         return;
106 
107     // It is possible that we get called by windows created from the main page that have finished
108     // loading, so we don't ASSERT here. At the moment we do not gather results from such windows,
109     // but may need to in future.
110     if (sender() != m_topLoadingFrame->page())
111         return;
112 
113     m_loadFinished = true;
114     // as the function is called on loadFinished, the test might
115     // already have dumped and thus no longer be active, thus
116     // bail out here.
117     if (m_hasDumped)
118         return;
119 
120     WorkQueue::shared()->setFrozen(true); // first complete load freezes the queue for the rest of this test
121     if (WorkQueue::shared()->count())
122         QTimer::singleShot(0, this, SLOT(processWork()));
123     else if (!shouldWaitUntilDone()) {
124         if (success)
125             emit done();
126         m_hasDumped = true;
127     }
128 }
129 
waitUntilDone()130 void LayoutTestController::waitUntilDone()
131 {
132     //qDebug() << ">>>>waitForDone";
133     m_waitForDone = true;
134     m_timeoutTimer.start(15000, this);
135 }
136 
counterValueForElementById(const QString & id)137 QString LayoutTestController::counterValueForElementById(const QString& id)
138 {
139     return qt_drt_counterValueForElementById(m_drt->webPage()->mainFrame(), id);
140 }
141 
webHistoryItemCount()142 int LayoutTestController::webHistoryItemCount()
143 {
144     if (!m_webHistory)
145         return -1;
146 
147     // Subtract one here as our QWebHistory::count() includes the actual page,
148     // which is not considered in the DRT tests.
149     return m_webHistory->count() - 1;
150 }
151 
keepWebHistory()152 void LayoutTestController::keepWebHistory()
153 {
154     m_webHistory = m_drt->webPage()->history();
155 }
156 
notifyDone()157 void LayoutTestController::notifyDone()
158 {
159     qDebug() << ">>>>notifyDone";
160 
161     if (!m_timeoutTimer.isActive())
162         return;
163 
164     m_timeoutTimer.stop();
165     m_waitForDone = false;
166 
167     // If the page has not finished loading (i.e. loadFinished() has not been emitted) then
168     // content created by the likes of document.write() JS methods will not be available yet.
169     // When the page has finished loading, maybeDump above will dump the results now that we have
170     // just set shouldWaitUntilDone to false.
171     if (!m_loadFinished)
172         return;
173 
174     emit done();
175 
176     // FIXME: investigate why always resetting these result in timeouts
177     m_hasDumped = true;
178     m_waitForPolicy = false;
179 }
180 
windowCount()181 int LayoutTestController::windowCount()
182 {
183     return m_drt->windowCount();
184 }
185 
display()186 void LayoutTestController::display()
187 {
188     emit showPage();
189 }
190 
clearBackForwardList()191 void LayoutTestController::clearBackForwardList()
192 {
193     m_drt->webPage()->history()->clear();
194 }
195 
pathToLocalResource(const QString & url)196 QString LayoutTestController::pathToLocalResource(const QString& url)
197 {
198     // Function introduced in r28690.
199     return QDir::toNativeSeparators(url);
200 }
201 
dumpEditingCallbacks()202 void LayoutTestController::dumpEditingCallbacks()
203 {
204     qDebug() << ">>>dumpEditingCallbacks";
205     qt_dump_editing_callbacks(true);
206 }
207 
dumpFrameLoadCallbacks()208 void LayoutTestController::dumpFrameLoadCallbacks()
209 {
210     qt_dump_frame_loader(true);
211 }
212 
dumpResourceLoadCallbacks()213 void LayoutTestController::dumpResourceLoadCallbacks()
214 {
215     qt_dump_resource_load_callbacks(true);
216 }
217 
queueBackNavigation(int howFarBackward)218 void LayoutTestController::queueBackNavigation(int howFarBackward)
219 {
220     //qDebug() << ">>>queueBackNavigation" << howFarBackward;
221     WorkQueue::shared()->queue(new BackItem(howFarBackward, m_drt->webPage()));
222 }
223 
queueForwardNavigation(int howFarForward)224 void LayoutTestController::queueForwardNavigation(int howFarForward)
225 {
226     //qDebug() << ">>>queueForwardNavigation" << howFarForward;
227     WorkQueue::shared()->queue(new ForwardItem(howFarForward, m_drt->webPage()));
228 }
229 
queueLoad(const QString & url,const QString & target)230 void LayoutTestController::queueLoad(const QString& url, const QString& target)
231 {
232     //qDebug() << ">>>queueLoad" << url << target;
233     QUrl mainResourceUrl = m_drt->webPage()->mainFrame()->url();
234     QString absoluteUrl = mainResourceUrl.resolved(QUrl(url)).toEncoded();
235     WorkQueue::shared()->queue(new LoadItem(absoluteUrl, target, m_drt->webPage()));
236 }
237 
queueReload()238 void LayoutTestController::queueReload()
239 {
240     //qDebug() << ">>>queueReload";
241     WorkQueue::shared()->queue(new ReloadItem(m_drt->webPage()));
242 }
243 
queueLoadingScript(const QString & script)244 void LayoutTestController::queueLoadingScript(const QString& script)
245 {
246     //qDebug() << ">>>queueLoadingScript" << script;
247     WorkQueue::shared()->queue(new LoadingScriptItem(script, m_drt->webPage()));
248 }
249 
queueNonLoadingScript(const QString & script)250 void LayoutTestController::queueNonLoadingScript(const QString& script)
251 {
252     //qDebug() << ">>>queueNonLoadingScript" << script;
253     WorkQueue::shared()->queue(new NonLoadingScriptItem(script, m_drt->webPage()));
254 }
255 
provisionalLoad()256 void LayoutTestController::provisionalLoad()
257 {
258     QWebFrame* frame = qobject_cast<QWebFrame*>(sender());
259     if (!m_topLoadingFrame && !m_hasDumped)
260         m_topLoadingFrame = frame;
261 }
262 
timerEvent(QTimerEvent * ev)263 void LayoutTestController::timerEvent(QTimerEvent *ev)
264 {
265     if (ev->timerId() == m_timeoutTimer.timerId()) {
266         const char* message = "FAIL: Timed out waiting for notifyDone to be called\n";
267         fprintf(stderr, "%s", message);
268         fprintf(stdout, "%s", message);
269         notifyDone();
270     } else
271         QObject::timerEvent(ev);
272 }
273 
encodeHostName(const QString & host)274 QString LayoutTestController::encodeHostName(const QString& host)
275 {
276     QString encoded = QString::fromLatin1(QUrl::toAce(host + QLatin1String(".no")));
277     encoded.truncate(encoded.length() - 3); // strip .no
278     return encoded;
279 }
280 
decodeHostName(const QString & host)281 QString LayoutTestController::decodeHostName(const QString& host)
282 {
283     QString decoded = QUrl::fromAce(host.toLatin1() + QByteArray(".no"));
284     decoded.truncate(decoded.length() - 3);
285     return decoded;
286 }
287 
showWebInspector()288 void LayoutTestController::showWebInspector()
289 {
290     m_drt->webPage()->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);
291     m_drt->webPage()->webInspector()->show();
292 }
293 
hideWebInspector()294 void LayoutTestController::hideWebInspector()
295 {
296     m_drt->webPage()->webInspector()->hide();
297 }
298 
setFrameSetFlatteningEnabled(bool enabled)299 void LayoutTestController::setFrameSetFlatteningEnabled(bool enabled)
300 {
301     qt_drt_setFrameSetFlatteningEnabled(m_drt->webPage(), enabled);
302 }
303 
setAllowUniversalAccessFromFileURLs(bool enabled)304 void LayoutTestController::setAllowUniversalAccessFromFileURLs(bool enabled)
305 {
306     m_drt->webPage()->settings()->setAttribute(QWebSettings::LocalContentCanAccessRemoteUrls, enabled);
307 }
308 
setJavaScriptProfilingEnabled(bool enable)309 void LayoutTestController::setJavaScriptProfilingEnabled(bool enable)
310 {
311     m_topLoadingFrame->page()->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);
312     qt_drt_setJavaScriptProfilingEnabled(m_topLoadingFrame, enable);
313 }
314 
setFixedContentsSize(int width,int height)315 void LayoutTestController::setFixedContentsSize(int width, int height)
316 {
317     m_topLoadingFrame->page()->setPreferredContentsSize(QSize(width, height));
318 }
319 
setPrivateBrowsingEnabled(bool enable)320 void LayoutTestController::setPrivateBrowsingEnabled(bool enable)
321 {
322     m_drt->webPage()->settings()->setAttribute(QWebSettings::PrivateBrowsingEnabled, enable);
323 }
324 
setPopupBlockingEnabled(bool enable)325 void LayoutTestController::setPopupBlockingEnabled(bool enable)
326 {
327     m_drt->webPage()->settings()->setAttribute(QWebSettings::JavascriptCanOpenWindows, !enable);
328 }
329 
setPOSIXLocale(const QString & locale)330 void LayoutTestController::setPOSIXLocale(const QString& locale)
331 {
332     QLocale qlocale(locale);
333     QLocale::setDefault(qlocale);
334 }
335 
setWindowIsKey(bool isKey)336 void LayoutTestController::setWindowIsKey(bool isKey)
337 {
338     m_drt->switchFocus(isKey);
339 }
340 
setMainFrameIsFirstResponder(bool isFirst)341 void LayoutTestController::setMainFrameIsFirstResponder(bool isFirst)
342 {
343     //FIXME: only need this for the moment: https://bugs.webkit.org/show_bug.cgi?id=32990
344 }
345 
setXSSAuditorEnabled(bool enable)346 void LayoutTestController::setXSSAuditorEnabled(bool enable)
347 {
348     // Set XSSAuditorEnabled globally so that windows created by the test inherit it too.
349     // resetSettings() will call this to reset the page and global setting to false again.
350     // Needed by http/tests/security/xssAuditor/link-opens-new-window.html
351     QWebSettings* globalSettings = QWebSettings::globalSettings();
352     globalSettings->setAttribute(QWebSettings::XSSAuditorEnabled, enable);
353     m_drt->webPage()->settings()->setAttribute(QWebSettings::XSSAuditorEnabled, enable);
354 }
355 
pauseAnimationAtTimeOnElementWithId(const QString & animationName,double time,const QString & elementId)356 bool LayoutTestController::pauseAnimationAtTimeOnElementWithId(const QString& animationName,
357                                                                double time,
358                                                                const QString& elementId)
359 {
360     QWebFrame* frame = m_drt->webPage()->mainFrame();
361     Q_ASSERT(frame);
362     return qt_drt_pauseAnimation(frame, animationName, time, elementId);
363 }
364 
pauseTransitionAtTimeOnElementWithId(const QString & propertyName,double time,const QString & elementId)365 bool LayoutTestController::pauseTransitionAtTimeOnElementWithId(const QString& propertyName,
366                                                                 double time,
367                                                                 const QString& elementId)
368 {
369     QWebFrame* frame = m_drt->webPage()->mainFrame();
370     Q_ASSERT(frame);
371     return qt_drt_pauseTransitionOfProperty(frame, propertyName, time, elementId);
372 }
373 
sampleSVGAnimationForElementAtTime(const QString & animationId,double time,const QString & elementId)374 bool LayoutTestController::sampleSVGAnimationForElementAtTime(const QString& animationId,
375                                                               double time,
376                                                               const QString& elementId)
377 {
378     QWebFrame* frame = m_drt->webPage()->mainFrame();
379     Q_ASSERT(frame);
380     return qt_drt_pauseSVGAnimation(frame, animationId, time, elementId);
381 }
382 
numberOfActiveAnimations() const383 unsigned LayoutTestController::numberOfActiveAnimations() const
384 {
385     QWebFrame* frame = m_drt->webPage()->mainFrame();
386     Q_ASSERT(frame);
387     return qt_drt_numberOfActiveAnimations(frame);
388 }
389 
disableImageLoading()390 void LayoutTestController::disableImageLoading()
391 {
392     // FIXME: Implement for testing fix for https://bugs.webkit.org/show_bug.cgi?id=27896
393     // Also need to make sure image loading is re-enabled for each new test.
394 }
395 
dispatchPendingLoadRequests()396 void LayoutTestController::dispatchPendingLoadRequests()
397 {
398     // FIXME: Implement for testing fix for 6727495
399 }
400 
setDatabaseQuota(int size)401 void LayoutTestController::setDatabaseQuota(int size)
402 {
403     if (!m_topLoadingFrame)
404         return;
405     m_topLoadingFrame->securityOrigin().setDatabaseQuota(size);
406 }
407 
clearAllDatabases()408 void LayoutTestController::clearAllDatabases()
409 {
410     QWebDatabase::removeAllDatabases();
411 }
412 
whiteListAccessFromOrigin(const QString & sourceOrigin,const QString & destinationProtocol,const QString & destinationHost,bool allowDestinationSubdomains)413 void LayoutTestController::whiteListAccessFromOrigin(const QString& sourceOrigin, const QString& destinationProtocol, const QString& destinationHost, bool allowDestinationSubdomains)
414 {
415     qt_drt_whiteListAccessFromOrigin(sourceOrigin, destinationProtocol, destinationHost, allowDestinationSubdomains);
416 }
417 
waitForPolicyDelegate()418 void LayoutTestController::waitForPolicyDelegate()
419 {
420     m_waitForPolicy = true;
421     waitUntilDone();
422 }
423 
overridePreference(const QString & name,const QVariant & value)424 void LayoutTestController::overridePreference(const QString& name, const QVariant& value)
425 {
426     QWebSettings* settings = m_topLoadingFrame->page()->settings();
427 
428     if (name == "WebKitJavaScriptEnabled")
429         settings->setAttribute(QWebSettings::JavascriptEnabled, value.toBool());
430     else if (name == "WebKitTabToLinksPreferenceKey")
431         settings->setAttribute(QWebSettings::LinksIncludedInFocusChain, value.toBool());
432     else if (name == "WebKitOfflineWebApplicationCacheEnabled")
433         settings->setAttribute(QWebSettings::OfflineWebApplicationCacheEnabled, value.toBool());
434     else if (name == "WebKitDefaultFontSize")
435         settings->setFontSize(QWebSettings::DefaultFontSize, value.toInt());
436     else if (name == "WebKitUsesPageCachePreferenceKey")
437         QWebSettings::setMaximumPagesInCache(value.toInt());
438     else
439         printf("ERROR: LayoutTestController::overridePreference() does not support the '%s' preference\n",
440             name.toLatin1().data());
441 }
442 
setUserStyleSheetLocation(const QString & url)443 void LayoutTestController::setUserStyleSheetLocation(const QString& url)
444 {
445     m_userStyleSheetLocation = QUrl(url);
446 }
447 
setUserStyleSheetEnabled(bool enabled)448 void LayoutTestController::setUserStyleSheetEnabled(bool enabled)
449 {
450     if (enabled)
451         m_drt->webPage()->settings()->setUserStyleSheetUrl(m_userStyleSheetLocation);
452     else
453         m_drt->webPage()->settings()->setUserStyleSheetUrl(QUrl());
454 }
455 
setDomainRelaxationForbiddenForURLScheme(bool forbidden,const QString & scheme)456 void LayoutTestController::setDomainRelaxationForbiddenForURLScheme(bool forbidden, const QString& scheme)
457 {
458     qt_drt_setDomainRelaxationForbiddenForURLScheme(forbidden, scheme);
459 }
460 
workerThreadCount()461 int LayoutTestController::workerThreadCount()
462 {
463     return qt_drt_workerThreadCount();
464 }
465 
pageNumberForElementById(const QString & id,float width,float height)466 int LayoutTestController::pageNumberForElementById(const QString& id, float width, float height)
467 {
468     // If no size specified, webpage viewport size is used
469     if (!width && !height) {
470         width = m_drt->webPage()->viewportSize().width();
471         height = m_drt->webPage()->viewportSize().height();
472     }
473 
474     return qt_drt_pageNumberForElementById(m_drt->webPage()->mainFrame(), id, width, height);
475 }
476