• 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 <jsobjects.h>
30 #include <qwebpage.h>
31 #include <qwebhistory.h>
32 #include <qwebframe.h>
33 #include <qwebsecurityorigin.h>
34 #include <qwebdatabase.h>
35 #include <qevent.h>
36 #include <qapplication.h>
37 #include <qevent.h>
38 #include <qtimer.h>
39 
40 #include "DumpRenderTree.h"
41 #include "WorkQueueItem.h"
42 #include "WorkQueue.h"
43 extern void qt_dump_editing_callbacks(bool b);
44 extern void qt_dump_resource_load_callbacks(bool b);
45 extern void qt_drt_setJavaScriptProfilingEnabled(QWebFrame*, bool enabled);
46 extern bool qt_drt_pauseAnimation(QWebFrame*, const QString &name, double time, const QString &elementId);
47 extern bool qt_drt_pauseTransitionOfProperty(QWebFrame*, const QString &name, double time, const QString &elementId);
48 extern int qt_drt_numberOfActiveAnimations(QWebFrame*);
49 
findFrameNamed(const QString & frameName,QWebFrame * frame)50 QWebFrame *findFrameNamed(const QString &frameName, QWebFrame *frame)
51 {
52     if (frame->frameName() == frameName)
53         return frame;
54 
55     foreach (QWebFrame *childFrame, frame->childFrames())
56         if (QWebFrame *f = findFrameNamed(frameName, childFrame))
57             return f;
58 
59     return 0;
60 }
61 
invoke() const62 bool LoadItem::invoke() const
63 {
64     //qDebug() << ">>>LoadItem::invoke";
65     Q_ASSERT(m_webPage);
66 
67     QWebFrame *frame = 0;
68     const QString t = target();
69     if (t.isEmpty())
70         frame = m_webPage->mainFrame();
71     else
72         frame = findFrameNamed(t, m_webPage->mainFrame());
73 
74     if (!frame)
75         return false;
76 
77     frame->load(url());
78     return true;
79 }
80 
invoke() const81 bool ReloadItem::invoke() const
82 {
83     //qDebug() << ">>>ReloadItem::invoke";
84     Q_ASSERT(m_webPage);
85     m_webPage->triggerAction(QWebPage::Reload);
86     return true;
87 }
88 
invoke() const89 bool ScriptItem::invoke() const
90 {
91     //qDebug() << ">>>ScriptItem::invoke";
92     Q_ASSERT(m_webPage);
93     m_webPage->mainFrame()->evaluateJavaScript(script());
94     return true;
95 }
96 
invoke() const97 bool BackForwardItem::invoke() const
98 {
99     //qDebug() << ">>>BackForwardItem::invoke";
100     Q_ASSERT(m_webPage);
101     if (!m_howFar)
102         return false;
103 
104     if (m_howFar > 0) {
105         for (int i = 0; i != m_howFar; ++i)
106             m_webPage->triggerAction(QWebPage::Forward);
107     } else {
108         for (int i = 0; i != m_howFar; --i)
109             m_webPage->triggerAction(QWebPage::Back);
110     }
111     return true;
112 }
113 
LayoutTestController(WebCore::DumpRenderTree * drt)114 LayoutTestController::LayoutTestController(WebCore::DumpRenderTree *drt)
115     : QObject()
116     , m_drt(drt)
117 {
118     reset();
119 }
120 
reset()121 void LayoutTestController::reset()
122 {
123     m_isLoading = true;
124     m_textDump = false;
125     m_dumpBackForwardList = false;
126     m_dumpChildrenAsText = false;
127     m_canOpenWindows = false;
128     m_waitForDone = false;
129     m_dumpTitleChanges = false;
130     m_dumpDatabaseCallbacks = false;
131     m_timeoutTimer.stop();
132     m_topLoadingFrame = 0;
133     qt_dump_editing_callbacks(false);
134     qt_dump_resource_load_callbacks(false);
135     QWebSettings::globalSettings()->setAttribute(QWebSettings::PrivateBrowsingEnabled, false);
136 }
137 
processWork()138 void LayoutTestController::processWork()
139 {
140     qDebug() << ">>>processWork";
141 
142     // if we didn't start a new load, then we finished all the commands, so we're ready to dump state
143     if (!WorkQueue::shared()->processWork() && !shouldWaitUntilDone()) {
144         emit done();
145         m_isLoading = false;
146     }
147 }
148 
149 // Called on loadFinished on mainFrame.
maybeDump(bool success)150 void LayoutTestController::maybeDump(bool success)
151 {
152     Q_ASSERT(sender() == m_topLoadingFrame);
153 
154     m_topLoadingFrame = 0;
155     WorkQueue::shared()->setFrozen(true); // first complete load freezes the queue for the rest of this test
156 
157     if (!shouldWaitUntilDone()) {
158         if (WorkQueue::shared()->count())
159             QTimer::singleShot(0, this, SLOT(processWork()));
160         else {
161             if (success)
162                 emit done();
163             m_isLoading = false;
164         }
165     }
166 }
167 
waitUntilDone()168 void LayoutTestController::waitUntilDone()
169 {
170     //qDebug() << ">>>>waitForDone";
171     m_waitForDone = true;
172     m_timeoutTimer.start(11000, this);
173 }
174 
notifyDone()175 void LayoutTestController::notifyDone()
176 {
177     //qDebug() << ">>>>notifyDone";
178     if (!m_timeoutTimer.isActive())
179         return;
180     m_timeoutTimer.stop();
181     emit done();
182     m_isLoading = false;
183 }
184 
windowCount()185 int LayoutTestController::windowCount()
186 {
187     return m_drt->windowCount();
188 }
189 
clearBackForwardList()190 void LayoutTestController::clearBackForwardList()
191 {
192     m_drt->webPage()->history()->clear();
193 }
194 
dumpEditingCallbacks()195 void LayoutTestController::dumpEditingCallbacks()
196 {
197     qDebug() << ">>>dumpEditingCallbacks";
198     qt_dump_editing_callbacks(true);
199 }
200 
dumpResourceLoadCallbacks()201 void LayoutTestController::dumpResourceLoadCallbacks()
202 {
203     qt_dump_resource_load_callbacks(true);
204 }
205 
queueBackNavigation(int howFarBackward)206 void LayoutTestController::queueBackNavigation(int howFarBackward)
207 {
208     //qDebug() << ">>>queueBackNavigation" << howFarBackward;
209     WorkQueue::shared()->queue(new BackItem(howFarBackward, m_drt->webPage()));
210 }
211 
queueForwardNavigation(int howFarForward)212 void LayoutTestController::queueForwardNavigation(int howFarForward)
213 {
214     //qDebug() << ">>>queueForwardNavigation" << howFarForward;
215     WorkQueue::shared()->queue(new ForwardItem(howFarForward, m_drt->webPage()));
216 }
217 
queueLoad(const QString & url,const QString & target)218 void LayoutTestController::queueLoad(const QString &url, const QString &target)
219 {
220     //qDebug() << ">>>queueLoad" << url << target;
221     QUrl mainResourceUrl = m_drt->webPage()->mainFrame()->url();
222     QString absoluteUrl = mainResourceUrl.resolved(QUrl(url)).toEncoded();
223     WorkQueue::shared()->queue(new LoadItem(absoluteUrl, target, m_drt->webPage()));
224 }
225 
queueReload()226 void LayoutTestController::queueReload()
227 {
228     //qDebug() << ">>>queueReload";
229     WorkQueue::shared()->queue(new ReloadItem(m_drt->webPage()));
230 }
231 
queueScript(const QString & url)232 void LayoutTestController::queueScript(const QString &url)
233 {
234     //qDebug() << ">>>queueScript" << url;
235     WorkQueue::shared()->queue(new ScriptItem(url, m_drt->webPage()));
236 }
237 
provisionalLoad()238 void LayoutTestController::provisionalLoad()
239 {
240     QWebFrame *frame = qobject_cast<QWebFrame*>(sender());
241     if (!m_topLoadingFrame && m_isLoading)
242         m_topLoadingFrame = frame;
243 }
244 
timerEvent(QTimerEvent * ev)245 void LayoutTestController::timerEvent(QTimerEvent *ev)
246 {
247     if (ev->timerId() == m_timeoutTimer.timerId()) {
248         qDebug() << ">>>>>>>>>>>>> timeout";
249         notifyDone();
250     } else {
251         QObject::timerEvent(ev);
252     }
253 }
254 
encodeHostName(const QString & host)255 QString LayoutTestController::encodeHostName(const QString &host)
256 {
257     QString encoded = QString::fromLatin1(QUrl::toAce(host + QLatin1String(".no")));
258     encoded.truncate(encoded.length() - 3); // strip .no
259     return encoded;
260 }
261 
decodeHostName(const QString & host)262 QString LayoutTestController::decodeHostName(const QString &host)
263 {
264     QString decoded = QUrl::fromAce(host.toLatin1() + QByteArray(".no"));
265     decoded.truncate(decoded.length() - 3);
266     return decoded;
267 }
268 
setJavaScriptProfilingEnabled(bool enable)269 void LayoutTestController::setJavaScriptProfilingEnabled(bool enable)
270 {
271     m_topLoadingFrame->page()->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);
272     qt_drt_setJavaScriptProfilingEnabled(m_topLoadingFrame, enable);
273 }
274 
setFixedContentsSize(int width,int height)275 void LayoutTestController::setFixedContentsSize(int width, int height)
276 {
277     m_topLoadingFrame->page()->setFixedContentsSize(QSize(width, height));
278 }
279 
setPrivateBrowsingEnabled(bool enable)280 void LayoutTestController::setPrivateBrowsingEnabled(bool enable)
281 {
282     QWebSettings::globalSettings()->setAttribute(QWebSettings::PrivateBrowsingEnabled, enable);
283 }
284 
pauseAnimationAtTimeOnElementWithId(const QString & animationName,double time,const QString & elementId)285 bool LayoutTestController::pauseAnimationAtTimeOnElementWithId(const QString &animationName,
286                                                                double time,
287                                                                const QString &elementId)
288 {
289     QWebFrame *frame = m_drt->webPage()->mainFrame();
290     Q_ASSERT(frame);
291     return qt_drt_pauseAnimation(frame, animationName, time, elementId);
292 }
293 
pauseTransitionAtTimeOnElementWithId(const QString & propertyName,double time,const QString & elementId)294 bool LayoutTestController::pauseTransitionAtTimeOnElementWithId(const QString &propertyName,
295                                                                 double time,
296                                                                 const QString &elementId)
297 {
298     QWebFrame *frame = m_drt->webPage()->mainFrame();
299     Q_ASSERT(frame);
300     return qt_drt_pauseTransitionOfProperty(frame, propertyName, time, elementId);
301 }
302 
numberOfActiveAnimations() const303 unsigned LayoutTestController::numberOfActiveAnimations() const
304 {
305     QWebFrame *frame = m_drt->webPage()->mainFrame();
306     Q_ASSERT(frame);
307     return qt_drt_numberOfActiveAnimations(frame);
308 }
309 
disableImageLoading()310 void LayoutTestController::disableImageLoading()
311 {
312     // FIXME: Implement for testing fix for https://bugs.webkit.org/show_bug.cgi?id=27896
313     // Also need to make sure image loading is re-enabled for each new test.
314 }
315 
dispatchPendingLoadRequests()316 void LayoutTestController::dispatchPendingLoadRequests()
317 {
318     // FIXME: Implement for testing fix for 6727495
319 }
320 
setDatabaseQuota(int size)321 void LayoutTestController::setDatabaseQuota(int size)
322 {
323     if (!m_topLoadingFrame)
324         return;
325     m_topLoadingFrame->securityOrigin().setDatabaseQuota(size);
326 }
327 
clearAllDatabases()328 void LayoutTestController::clearAllDatabases()
329 {
330     QWebDatabase::removeAllDatabases();
331 }
332 
EventSender(QWebPage * parent)333 EventSender::EventSender(QWebPage *parent)
334     : QObject(parent)
335 {
336     m_page = parent;
337 }
338 
mouseDown()339 void EventSender::mouseDown()
340 {
341 //     qDebug() << "EventSender::mouseDown" << frame;
342     QMouseEvent event(QEvent::MouseButtonPress, m_mousePos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
343     QApplication::sendEvent(m_page, &event);
344 }
345 
mouseUp()346 void EventSender::mouseUp()
347 {
348 //     qDebug() << "EventSender::mouseUp" << frame;
349     QMouseEvent event(QEvent::MouseButtonRelease, m_mousePos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
350     QApplication::sendEvent(m_page, &event);
351 }
352 
mouseMoveTo(int x,int y)353 void EventSender::mouseMoveTo(int x, int y)
354 {
355 //     qDebug() << "EventSender::mouseMoveTo" << x << y;
356     m_mousePos = QPoint(x, y);
357     QMouseEvent event(QEvent::MouseMove, m_mousePos, Qt::NoButton, Qt::NoButton, Qt::NoModifier);
358     QApplication::sendEvent(m_page, &event);
359 }
360 
leapForward(int ms)361 void EventSender::leapForward(int ms)
362 {
363     m_timeLeap += ms;
364     qDebug() << "EventSender::leapForward" << ms;
365 }
366 
keyDown(const QString & string,const QStringList & modifiers)367 void EventSender::keyDown(const QString &string, const QStringList &modifiers)
368 {
369     QString s = string;
370     Qt::KeyboardModifiers modifs = 0;
371     for (int i = 0; i < modifiers.size(); ++i) {
372         const QString &m = modifiers.at(i);
373         if (m == "ctrlKey")
374             modifs |= Qt::ControlModifier;
375         else if (m == "shiftKey")
376             modifs |= Qt::ShiftModifier;
377         else if (m == "altKey")
378             modifs |= Qt::AltModifier;
379         else if (m == "metaKey")
380             modifs |= Qt::MetaModifier;
381     }
382     int code = 0;
383     if (string.length() == 1) {
384         code = string.unicode()->unicode();
385         qDebug() << ">>>>>>>>> keyDown" << code << (char)code;
386         // map special keycodes used by the tests to something that works for Qt/X11
387         if (code == '\t') {
388             code = Qt::Key_Tab;
389             if (modifs == Qt::ShiftModifier)
390                 code = Qt::Key_Backtab;
391             s = QString();
392         } else if (code == 127) {
393             code = Qt::Key_Backspace;
394             if (modifs == Qt::AltModifier)
395                 modifs = Qt::ControlModifier;
396             s = QString();
397         } else if (code == 'o' && modifs == Qt::ControlModifier) {
398             s = QLatin1String("\n");
399             code = '\n';
400             modifs = 0;
401         } else if (code == 'y' && modifs == Qt::ControlModifier) {
402             s = QLatin1String("c");
403             code = 'c';
404         } else if (code == 'k' && modifs == Qt::ControlModifier) {
405             s = QLatin1String("x");
406             code = 'x';
407         } else if (code == 'a' && modifs == Qt::ControlModifier) {
408             s = QString();
409             code = Qt::Key_Home;
410             modifs = 0;
411         } else if (code == 0xf702) {
412             s = QString();
413             code = Qt::Key_Left;
414             if (modifs & Qt::MetaModifier) {
415                 code = Qt::Key_Home;
416                 modifs &= ~Qt::MetaModifier;
417             }
418         } else if (code == 0xf703) {
419             s = QString();
420             code = Qt::Key_Right;
421             if (modifs & Qt::MetaModifier) {
422                 code = Qt::Key_End;
423                 modifs &= ~Qt::MetaModifier;
424             }
425         } else if (code == 0xf700) {
426             s = QString();
427             code = Qt::Key_Up;
428             if (modifs & Qt::MetaModifier) {
429                 code = Qt::Key_PageUp;
430                 modifs &= ~Qt::MetaModifier;
431             }
432         } else if (code == 0xf701) {
433             s = QString();
434             code = Qt::Key_Down;
435             if (modifs & Qt::MetaModifier) {
436                 code = Qt::Key_PageDown;
437                 modifs &= ~Qt::MetaModifier;
438             }
439         } else if (code == 'a' && modifs == Qt::ControlModifier) {
440             s = QString();
441             code = Qt::Key_Home;
442             modifs = 0;
443         } else {
444             code = string.unicode()->toUpper().unicode();
445         }
446     }
447     QKeyEvent event(QEvent::KeyPress, code, modifs, s);
448     QApplication::sendEvent(m_page, &event);
449 }
450 
frameUnderMouse() const451 QWebFrame *EventSender::frameUnderMouse() const
452 {
453     QWebFrame *frame = m_page->mainFrame();
454 
455 redo:
456     QList<QWebFrame*> children = frame->childFrames();
457     for (int i = 0; i < children.size(); ++i) {
458         if (children.at(i)->geometry().contains(m_mousePos)) {
459             frame = children.at(i);
460             goto redo;
461         }
462     }
463     if (frame->geometry().contains(m_mousePos))
464         return frame;
465     return 0;
466 }
467 
468 
TextInputController(QWebPage * parent)469 TextInputController::TextInputController(QWebPage *parent)
470     : QObject(parent)
471 {
472 }
473 
doCommand(const QString & command)474 void TextInputController::doCommand(const QString &command)
475 {
476     Qt::KeyboardModifiers modifiers = Qt::NoModifier;
477     int keycode = 0;
478     if (command == "moveBackwardAndModifySelection:") {
479         modifiers |= Qt::ShiftModifier;
480         keycode = Qt::Key_Left;
481     } else if(command =="moveDown:") {
482         keycode = Qt::Key_Down;
483     } else if(command =="moveDownAndModifySelection:") {
484         modifiers |= Qt::ShiftModifier;
485         keycode = Qt::Key_Down;
486     } else if(command =="moveForward:") {
487         keycode = Qt::Key_Right;
488     } else if(command =="moveForwardAndModifySelection:") {
489         modifiers |= Qt::ShiftModifier;
490         keycode = Qt::Key_Right;
491     } else if(command =="moveLeft:") {
492         keycode = Qt::Key_Left;
493     } else if(command =="moveLeftAndModifySelection:") {
494         modifiers |= Qt::ShiftModifier;
495         keycode = Qt::Key_Left;
496     } else if(command =="moveRight:") {
497         keycode = Qt::Key_Right;
498     } else if(command =="moveRightAndModifySelection:") {
499         modifiers |= Qt::ShiftModifier;
500         keycode = Qt::Key_Right;
501     } else if(command =="moveToBeginningOfDocument:") {
502         modifiers |= Qt::ControlModifier;
503         keycode = Qt::Key_Home;
504     } else if(command =="moveToBeginningOfLine:") {
505         keycode = Qt::Key_Home;
506 //     } else if(command =="moveToBeginningOfParagraph:") {
507     } else if(command =="moveToEndOfDocument:") {
508         modifiers |= Qt::ControlModifier;
509         keycode = Qt::Key_End;
510     } else if(command =="moveToEndOfLine:") {
511         keycode = Qt::Key_End;
512 //     } else if(command =="moveToEndOfParagraph:") {
513     } else if(command =="moveUp:") {
514         keycode = Qt::Key_Up;
515     } else if(command =="moveUpAndModifySelection:") {
516         modifiers |= Qt::ShiftModifier;
517         keycode = Qt::Key_Up;
518     } else if(command =="moveWordBackward:") {
519         modifiers |= Qt::ControlModifier;
520         keycode = Qt::Key_Up;
521     } else if(command =="moveWordBackwardAndModifySelection:") {
522         modifiers |= Qt::ShiftModifier;
523         modifiers |= Qt::ControlModifier;
524         keycode = Qt::Key_Left;
525     } else if(command =="moveWordForward:") {
526         modifiers |= Qt::ControlModifier;
527         keycode = Qt::Key_Right;
528     } else if(command =="moveWordForwardAndModifySelection:") {
529         modifiers |= Qt::ControlModifier;
530         modifiers |= Qt::ShiftModifier;
531         keycode = Qt::Key_Right;
532     } else if(command =="moveWordLeft:") {
533         modifiers |= Qt::ControlModifier;
534         keycode = Qt::Key_Left;
535     } else if(command =="moveWordRight:") {
536         modifiers |= Qt::ControlModifier;
537         keycode = Qt::Key_Left;
538     } else if(command =="moveWordRightAndModifySelection:") {
539         modifiers |= Qt::ShiftModifier;
540         modifiers |= Qt::ControlModifier;
541         keycode = Qt::Key_Right;
542     } else if(command =="moveWordLeftAndModifySelection:") {
543         modifiers |= Qt::ShiftModifier;
544         modifiers |= Qt::ControlModifier;
545         keycode = Qt::Key_Left;
546     } else if(command =="pageDown:") {
547         keycode = Qt::Key_PageDown;
548     } else if(command =="pageUp:") {
549         keycode = Qt::Key_PageUp;
550     } else if(command == "deleteWordBackward:") {
551         modifiers |= Qt::ControlModifier;
552         keycode = Qt::Key_Backspace;
553     } else if(command == "deleteBackward:") {
554         keycode = Qt::Key_Backspace;
555     } else if(command == "deleteForward:") {
556         keycode = Qt::Key_Delete;
557     }
558     QKeyEvent event(QEvent::KeyPress, keycode, modifiers);
559     QApplication::sendEvent(parent(), &event);
560     QKeyEvent event2(QEvent::KeyRelease, keycode, modifiers);
561     QApplication::sendEvent(parent(), &event2);
562 }
563 
GCController(QWebPage * parent)564 GCController::GCController(QWebPage* parent)
565     : QObject(parent)
566 {
567 }
568 
569 extern int qt_drt_javaScriptObjectsCount();
570 extern void qt_drt_garbageCollector_collect();
571 
572 extern void qt_drt_garbageCollector_collectOnAlternateThread(bool waitUntilDone);
573 
collect() const574 void GCController::collect() const
575 {
576     qt_drt_garbageCollector_collect();
577 }
578 
collectOnAlternateThread(bool waitUntilDone) const579 void GCController::collectOnAlternateThread(bool waitUntilDone) const
580 {
581     qt_drt_garbageCollector_collectOnAlternateThread(waitUntilDone);
582 }
583 
getJSObjectCount() const584 size_t GCController::getJSObjectCount() const
585 {
586     return qt_drt_javaScriptObjectsCount();
587 }
588