summaryrefslogtreecommitdiffstats
path: root/Tools/DumpRenderTree/qt
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2011-05-05 14:36:32 +0100
committerBen Murdoch <benm@google.com>2011-05-10 15:38:30 +0100
commitf05b935882198ccf7d81675736e3aeb089c5113a (patch)
tree4ea0ca838d9ef1b15cf17ddb3928efb427c7e5a1 /Tools/DumpRenderTree/qt
parent60fbdcc62bced8db2cb1fd233cc4d1e4ea17db1b (diff)
downloadexternal_webkit-f05b935882198ccf7d81675736e3aeb089c5113a.zip
external_webkit-f05b935882198ccf7d81675736e3aeb089c5113a.tar.gz
external_webkit-f05b935882198ccf7d81675736e3aeb089c5113a.tar.bz2
Merge WebKit at r74534: Initial merge by git.
Change-Id: I6ccd1154fa1b19c2ec2a66878eb675738735f1eb
Diffstat (limited to 'Tools/DumpRenderTree/qt')
-rw-r--r--Tools/DumpRenderTree/qt/DumpRenderTree.pro53
-rw-r--r--Tools/DumpRenderTree/qt/DumpRenderTreeQt.cpp1151
-rw-r--r--Tools/DumpRenderTree/qt/DumpRenderTreeQt.h232
-rw-r--r--Tools/DumpRenderTree/qt/EventSenderQt.cpp653
-rw-r--r--Tools/DumpRenderTree/qt/EventSenderQt.h112
-rw-r--r--Tools/DumpRenderTree/qt/GCControllerQt.cpp54
-rw-r--r--Tools/DumpRenderTree/qt/GCControllerQt.h50
-rw-r--r--Tools/DumpRenderTree/qt/ImageDiff.cpp149
-rw-r--r--Tools/DumpRenderTree/qt/ImageDiff.pro16
-rw-r--r--Tools/DumpRenderTree/qt/LayoutTestControllerQt.cpp834
-rw-r--r--Tools/DumpRenderTree/qt/LayoutTestControllerQt.h289
-rw-r--r--Tools/DumpRenderTree/qt/PlainTextControllerQt.cpp44
-rw-r--r--Tools/DumpRenderTree/qt/PlainTextControllerQt.h47
-rw-r--r--Tools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro46
-rw-r--r--Tools/DumpRenderTree/qt/TextInputControllerQt.cpp158
-rw-r--r--Tools/DumpRenderTree/qt/TextInputControllerQt.h57
-rw-r--r--Tools/DumpRenderTree/qt/WorkQueueItemQt.cpp106
-rw-r--r--Tools/DumpRenderTree/qt/WorkQueueItemQt.h159
-rw-r--r--Tools/DumpRenderTree/qt/fonts.conf258
-rw-r--r--Tools/DumpRenderTree/qt/fonts/AHEM____.TTFbin0 -> 12480 bytes
-rw-r--r--Tools/DumpRenderTree/qt/main.cpp173
-rw-r--r--Tools/DumpRenderTree/qt/testplugin.cpp67
-rw-r--r--Tools/DumpRenderTree/qt/testplugin.h45
23 files changed, 4753 insertions, 0 deletions
diff --git a/Tools/DumpRenderTree/qt/DumpRenderTree.pro b/Tools/DumpRenderTree/qt/DumpRenderTree.pro
new file mode 100644
index 0000000..e8831a3
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/DumpRenderTree.pro
@@ -0,0 +1,53 @@
+TARGET = DumpRenderTree
+CONFIG -= app_bundle
+CONFIG += uitools
+
+BASEDIR = $$PWD/../
+isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../..
+
+include(../../../WebKit.pri)
+INCLUDEPATH += ../../..
+INCLUDEPATH += ../../../JavaScriptCore
+INCLUDEPATH += ../../../JavaScriptCore/ForwardingHeaders
+INCLUDEPATH += $$BASEDIR
+DESTDIR = ../../../bin
+
+unix:!mac:!symbian {
+ CONFIG += link_pkgconfig
+ PKGCONFIG += fontconfig
+}
+
+QT = core gui network testlib
+macx: QT += xml
+
+HEADERS = $$BASEDIR/WorkQueue.h \
+ DumpRenderTreeQt.h \
+ EventSenderQt.h \
+ TextInputControllerQt.h \
+ WorkQueueItemQt.h \
+ LayoutTestControllerQt.h \
+ GCControllerQt.h \
+ PlainTextControllerQt.h \
+ testplugin.h
+SOURCES = ../../../JavaScriptCore/wtf/Assertions.cpp \
+ $$BASEDIR/WorkQueue.cpp \
+ DumpRenderTreeQt.cpp \
+ EventSenderQt.cpp \
+ TextInputControllerQt.cpp \
+ PlainTextControllerQt.cpp \
+ WorkQueueItemQt.cpp \
+ LayoutTestControllerQt.cpp \
+ GCControllerQt.cpp \
+ testplugin.cpp \
+ main.cpp
+
+unix:!mac {
+ QMAKE_RPATHDIR = $$OUTPUT_DIR/lib $$QMAKE_RPATHDIR
+}
+
+wince*: {
+ INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/ce-compat $$WCECOMPAT/include
+ LIBS += $$WCECOMPAT/lib/wcecompat.lib
+}
+
+DEFINES+=USE_SYSTEM_MALLOC
diff --git a/Tools/DumpRenderTree/qt/DumpRenderTreeQt.cpp b/Tools/DumpRenderTree/qt/DumpRenderTreeQt.cpp
new file mode 100644
index 0000000..935a307
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/DumpRenderTreeQt.cpp
@@ -0,0 +1,1151 @@
+/*
+ * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "DumpRenderTreeQt.h"
+#include "../../../WebKit/qt/WebCoreSupport/DumpRenderTreeSupportQt.h"
+#include "EventSenderQt.h"
+#include "GCControllerQt.h"
+#include "LayoutTestControllerQt.h"
+#include "TextInputControllerQt.h"
+#include "PlainTextControllerQt.h"
+#include "testplugin.h"
+#include "WorkQueue.h"
+
+#include <QApplication>
+#include <QBuffer>
+#include <QCryptographicHash>
+#include <QDir>
+#include <QFile>
+#include <QFileInfo>
+#include <QFocusEvent>
+#include <QFontDatabase>
+#include <QLocale>
+#include <QNetworkAccessManager>
+#include <QNetworkReply>
+#include <QNetworkRequest>
+#include <QPaintDevice>
+#include <QPaintEngine>
+#ifndef QT_NO_PRINTER
+#include <QPrinter>
+#endif
+#include <QUndoStack>
+#include <QUrl>
+
+#include <qwebsettings.h>
+#include <qwebsecurityorigin.h>
+
+#ifndef QT_NO_UITOOLS
+#include <QtUiTools/QUiLoader>
+#endif
+
+#ifdef Q_WS_X11
+#include <fontconfig/fontconfig.h>
+#endif
+
+#include <limits.h>
+#include <locale.h>
+
+#ifndef Q_OS_WIN
+#include <unistd.h>
+#endif
+
+#include <qdebug.h>
+
+namespace WebCore {
+
+NetworkAccessManager::NetworkAccessManager(QObject* parent)
+ : QNetworkAccessManager(parent)
+{
+#ifndef QT_NO_OPENSSL
+ connect(this, SIGNAL(sslErrors(QNetworkReply*, const QList<QSslError>&)),
+ this, SLOT(sslErrorsEncountered(QNetworkReply*, const QList<QSslError>&)));
+#endif
+}
+
+#ifndef QT_NO_OPENSSL
+void NetworkAccessManager::sslErrorsEncountered(QNetworkReply* reply, const QList<QSslError>& errors)
+{
+ if (reply->url().host() == "127.0.0.1" || reply->url().host() == "localhost") {
+ bool ignore = true;
+
+ // Accept any HTTPS certificate.
+ foreach (const QSslError& error, errors) {
+ if (error.error() < QSslError::UnableToGetIssuerCertificate || error.error() > QSslError::HostNameMismatch) {
+ ignore = false;
+ break;
+ }
+ }
+
+ if (ignore)
+ reply->ignoreSslErrors();
+ }
+}
+#endif
+
+
+#ifndef QT_NO_PRINTER
+class NullPrinter : public QPrinter {
+public:
+ class NullPaintEngine : public QPaintEngine {
+ public:
+ virtual bool begin(QPaintDevice*) { return true; }
+ virtual bool end() { return true; }
+ virtual QPaintEngine::Type type() const { return QPaintEngine::User; }
+ virtual void drawPixmap(const QRectF& r, const QPixmap& pm, const QRectF& sr) { }
+ virtual void updateState(const QPaintEngineState& state) { }
+ };
+
+ virtual QPaintEngine* paintEngine() const { return const_cast<NullPaintEngine*>(&m_engine); }
+
+ NullPaintEngine m_engine;
+};
+#endif
+
+WebPage::WebPage(QObject* parent, DumpRenderTree* drt)
+ : QWebPage(parent)
+ , m_webInspector(0)
+ , m_drt(drt)
+{
+ QWebSettings* globalSettings = QWebSettings::globalSettings();
+
+ globalSettings->setFontSize(QWebSettings::MinimumFontSize, 0);
+ globalSettings->setFontSize(QWebSettings::MinimumLogicalFontSize, 5);
+ globalSettings->setFontSize(QWebSettings::DefaultFontSize, 16);
+ globalSettings->setFontSize(QWebSettings::DefaultFixedFontSize, 13);
+
+ globalSettings->setAttribute(QWebSettings::JavascriptCanOpenWindows, true);
+ globalSettings->setAttribute(QWebSettings::JavascriptCanAccessClipboard, true);
+ globalSettings->setAttribute(QWebSettings::LinksIncludedInFocusChain, false);
+ globalSettings->setAttribute(QWebSettings::PluginsEnabled, true);
+ globalSettings->setAttribute(QWebSettings::LocalContentCanAccessRemoteUrls, true);
+ globalSettings->setAttribute(QWebSettings::JavascriptEnabled, true);
+ globalSettings->setAttribute(QWebSettings::PrivateBrowsingEnabled, false);
+ globalSettings->setAttribute(QWebSettings::SpatialNavigationEnabled, false);
+
+ connect(this, SIGNAL(geometryChangeRequested(const QRect &)),
+ this, SLOT(setViewGeometry(const QRect & )));
+
+ setNetworkAccessManager(m_drt->networkAccessManager());
+ setPluginFactory(new TestPlugin(this));
+
+ connect(this, SIGNAL(featurePermissionRequested(QWebFrame*, QWebPage::Feature)), this, SLOT(requestPermission(QWebFrame*, QWebPage::Feature)));
+ connect(this, SIGNAL(featurePermissionRequestCanceled(QWebFrame*, QWebPage::Feature)), this, SLOT(cancelPermission(QWebFrame*, QWebPage::Feature)));
+}
+
+WebPage::~WebPage()
+{
+ delete m_webInspector;
+}
+
+QWebInspector* WebPage::webInspector()
+{
+ if (!m_webInspector) {
+ m_webInspector = new QWebInspector;
+ m_webInspector->setPage(this);
+ }
+ return m_webInspector;
+}
+
+void WebPage::resetSettings()
+{
+ // After each layout test, reset the settings that may have been changed by
+ // layoutTestController.overridePreference() or similar.
+ settings()->resetFontSize(QWebSettings::DefaultFontSize);
+ settings()->resetAttribute(QWebSettings::JavascriptCanOpenWindows);
+ settings()->resetAttribute(QWebSettings::JavascriptEnabled);
+ settings()->resetAttribute(QWebSettings::PrivateBrowsingEnabled);
+ settings()->resetAttribute(QWebSettings::SpatialNavigationEnabled);
+ settings()->resetAttribute(QWebSettings::LinksIncludedInFocusChain);
+ settings()->resetAttribute(QWebSettings::OfflineWebApplicationCacheEnabled);
+ settings()->resetAttribute(QWebSettings::LocalContentCanAccessRemoteUrls);
+ settings()->resetAttribute(QWebSettings::PluginsEnabled);
+ settings()->resetAttribute(QWebSettings::JavascriptCanAccessClipboard);
+ settings()->resetAttribute(QWebSettings::AutoLoadImages);
+
+ m_drt->layoutTestController()->setCaretBrowsingEnabled(false);
+ m_drt->layoutTestController()->setFrameFlatteningEnabled(false);
+ m_drt->layoutTestController()->setSmartInsertDeleteEnabled(true);
+ m_drt->layoutTestController()->setSelectTrailingWhitespaceEnabled(false);
+
+ // globalSettings must be reset explicitly.
+ m_drt->layoutTestController()->setXSSAuditorEnabled(false);
+
+ QWebSettings::setMaximumPagesInCache(0); // reset to default
+ settings()->setUserStyleSheetUrl(QUrl()); // reset to default
+
+ m_pendingGeolocationRequests.clear();
+}
+
+QWebPage *WebPage::createWindow(QWebPage::WebWindowType)
+{
+ return m_drt->createWindow();
+}
+
+void WebPage::javaScriptAlert(QWebFrame*, const QString& message)
+{
+ if (!isTextOutputEnabled())
+ return;
+
+ fprintf(stdout, "ALERT: %s\n", message.toUtf8().constData());
+}
+
+void WebPage::requestPermission(QWebFrame* frame, QWebPage::Feature feature)
+{
+ switch (feature) {
+ case Notifications:
+ if (!m_drt->layoutTestController()->ignoreReqestForPermission())
+ setFeaturePermission(frame, feature, PermissionGrantedByUser);
+ break;
+ case Geolocation:
+ if (m_drt->layoutTestController()->isGeolocationPermissionSet())
+ if (m_drt->layoutTestController()->geolocationPermission())
+ setFeaturePermission(frame, feature, PermissionGrantedByUser);
+ else
+ setFeaturePermission(frame, feature, PermissionDeniedByUser);
+ else
+ m_pendingGeolocationRequests.append(frame);
+ break;
+ default:
+ break;
+ }
+}
+
+void WebPage::cancelPermission(QWebFrame* frame, QWebPage::Feature feature)
+{
+ switch (feature) {
+ case Geolocation:
+ m_pendingGeolocationRequests.removeOne(frame);
+ break;
+ default:
+ break;
+ }
+}
+
+void WebPage::permissionSet(QWebPage::Feature feature)
+{
+ switch (feature) {
+ case Geolocation:
+ {
+ Q_ASSERT(m_drt->layoutTestController()->isGeolocationPermissionSet());
+ foreach (QWebFrame* frame, m_pendingGeolocationRequests)
+ if (m_drt->layoutTestController()->geolocationPermission())
+ setFeaturePermission(frame, feature, PermissionGrantedByUser);
+ else
+ setFeaturePermission(frame, feature, PermissionDeniedByUser);
+
+ m_pendingGeolocationRequests.clear();
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static QString urlSuitableForTestResult(const QString& url)
+{
+ if (url.isEmpty() || !url.startsWith(QLatin1String("file://")))
+ return url;
+
+ return QFileInfo(url).fileName();
+}
+
+void WebPage::javaScriptConsoleMessage(const QString& message, int lineNumber, const QString&)
+{
+ if (!isTextOutputEnabled())
+ return;
+
+ QString newMessage;
+ if (!message.isEmpty()) {
+ newMessage = message;
+
+ size_t fileProtocol = newMessage.indexOf(QLatin1String("file://"));
+ if (fileProtocol != -1) {
+ newMessage = newMessage.left(fileProtocol) + urlSuitableForTestResult(newMessage.mid(fileProtocol));
+ }
+ }
+
+ fprintf (stdout, "CONSOLE MESSAGE: line %d: %s\n", lineNumber, newMessage.toUtf8().constData());
+}
+
+bool WebPage::javaScriptConfirm(QWebFrame*, const QString& msg)
+{
+ if (!isTextOutputEnabled())
+ return true;
+
+ fprintf(stdout, "CONFIRM: %s\n", msg.toUtf8().constData());
+ return true;
+}
+
+bool WebPage::javaScriptPrompt(QWebFrame*, const QString& msg, const QString& defaultValue, QString* result)
+{
+ if (!isTextOutputEnabled())
+ return true;
+
+ fprintf(stdout, "PROMPT: %s, default text: %s\n", msg.toUtf8().constData(), defaultValue.toUtf8().constData());
+ *result = defaultValue;
+ return true;
+}
+
+bool WebPage::acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, NavigationType type)
+{
+ if (m_drt->layoutTestController()->waitForPolicy()) {
+ QString url = QString::fromUtf8(request.url().toEncoded());
+ QString typeDescription;
+
+ switch (type) {
+ case NavigationTypeLinkClicked:
+ typeDescription = "link clicked";
+ break;
+ case NavigationTypeFormSubmitted:
+ typeDescription = "form submitted";
+ break;
+ case NavigationTypeBackOrForward:
+ typeDescription = "back/forward";
+ break;
+ case NavigationTypeReload:
+ typeDescription = "reload";
+ break;
+ case NavigationTypeFormResubmitted:
+ typeDescription = "form resubmitted";
+ break;
+ case NavigationTypeOther:
+ typeDescription = "other";
+ break;
+ default:
+ typeDescription = "illegal value";
+ }
+
+ if (isTextOutputEnabled())
+ fprintf(stdout, "Policy delegate: attempt to load %s with navigation type '%s'\n",
+ url.toUtf8().constData(), typeDescription.toUtf8().constData());
+
+ m_drt->layoutTestController()->notifyDone();
+ }
+ return QWebPage::acceptNavigationRequest(frame, request, type);
+}
+
+bool WebPage::supportsExtension(QWebPage::Extension extension) const
+{
+ if (extension == QWebPage::ErrorPageExtension)
+ return m_drt->layoutTestController()->shouldHandleErrorPages();
+
+ return false;
+}
+
+bool WebPage::extension(Extension extension, const ExtensionOption *option, ExtensionReturn *output)
+{
+ const QWebPage::ErrorPageExtensionOption* info = static_cast<const QWebPage::ErrorPageExtensionOption*>(option);
+
+ // Lets handle error pages for the main frame for now.
+ if (info->frame != mainFrame())
+ return false;
+
+ QWebPage::ErrorPageExtensionReturn* errorPage = static_cast<QWebPage::ErrorPageExtensionReturn*>(output);
+
+ errorPage->content = QString("data:text/html,<body/>").toUtf8();
+
+ return true;
+}
+
+QObject* WebPage::createPlugin(const QString& classId, const QUrl& url, const QStringList& paramNames, const QStringList& paramValues)
+{
+ Q_UNUSED(url);
+ Q_UNUSED(paramNames);
+ Q_UNUSED(paramValues);
+#ifndef QT_NO_UITOOLS
+ QUiLoader loader;
+ return loader.createWidget(classId, view());
+#else
+ Q_UNUSED(classId);
+ return 0;
+#endif
+}
+
+void WebPage::setViewGeometry(const QRect& rect)
+{
+ if (WebViewGraphicsBased* v = qobject_cast<WebViewGraphicsBased*>(view()))
+ v->scene()->setSceneRect(QRectF(rect));
+ else if (QWidget *v = view())
+ v->setGeometry(rect);
+}
+
+WebViewGraphicsBased::WebViewGraphicsBased(QWidget* parent)
+ : m_item(new QGraphicsWebView)
+{
+ setScene(new QGraphicsScene(this));
+ scene()->addItem(m_item);
+}
+
+DumpRenderTree::DumpRenderTree()
+ : m_dumpPixels(false)
+ , m_stdin(0)
+ , m_enableTextOutput(false)
+ , m_standAloneMode(false)
+ , m_graphicsBased(false)
+ , m_persistentStoragePath(QString(getenv("DUMPRENDERTREE_TEMP")))
+{
+
+ QByteArray viewMode = getenv("QT_DRT_WEBVIEW_MODE");
+ if (viewMode == "graphics")
+ setGraphicsBased(true);
+
+ DumpRenderTreeSupportQt::overwritePluginDirectories();
+ DumpRenderTreeSupportQt::activeMockDeviceOrientationClient(true);
+ QWebSettings::enablePersistentStorage(m_persistentStoragePath);
+
+ m_networkAccessManager = new NetworkAccessManager(this);
+ // create our primary testing page/view.
+ if (isGraphicsBased()) {
+ WebViewGraphicsBased* view = new WebViewGraphicsBased(0);
+ m_page = new WebPage(view, this);
+ view->setPage(m_page);
+ m_mainView = view;
+ } else {
+ QWebView* view = new QWebView(0);
+ m_page = new WebPage(view, this);
+ view->setPage(m_page);
+ m_mainView = view;
+ }
+ // Use a frame group name for all pages created by DumpRenderTree to allow
+ // testing of cross-page frame lookup.
+ DumpRenderTreeSupportQt::webPageSetGroupName(m_page, "org.webkit.qt.DumpRenderTree");
+
+ m_mainView->setContextMenuPolicy(Qt::NoContextMenu);
+ m_mainView->resize(QSize(LayoutTestController::maxViewWidth, LayoutTestController::maxViewHeight));
+
+ // clean up cache by resetting quota.
+ qint64 quota = webPage()->settings()->offlineWebApplicationCacheQuota();
+ webPage()->settings()->setOfflineWebApplicationCacheQuota(quota);
+
+ // create our controllers. This has to be done before connectFrame,
+ // as it exports there to the JavaScript DOM window.
+ m_controller = new LayoutTestController(this);
+ connect(m_controller, SIGNAL(showPage()), this, SLOT(showPage()));
+ connect(m_controller, SIGNAL(hidePage()), this, SLOT(hidePage()));
+
+ // async geolocation permission set by controller
+ connect(m_controller, SIGNAL(geolocationPermissionSet()), this, SLOT(geolocationPermissionSet()));
+
+ connect(m_controller, SIGNAL(done()), this, SLOT(dump()));
+ m_eventSender = new EventSender(m_page);
+ m_textInputController = new TextInputController(m_page);
+ m_plainTextController = new PlainTextController(m_page);
+ m_gcController = new GCController(m_page);
+
+ // now connect our different signals
+ connect(m_page, SIGNAL(frameCreated(QWebFrame *)),
+ this, SLOT(connectFrame(QWebFrame *)));
+ connectFrame(m_page->mainFrame());
+
+ connect(m_page, SIGNAL(loadFinished(bool)),
+ m_controller, SLOT(maybeDump(bool)));
+ // We need to connect to loadStarted() because notifyDone should only
+ // dump results itself when the last page loaded in the test has finished loading.
+ connect(m_page, SIGNAL(loadStarted()),
+ m_controller, SLOT(resetLoadFinished()));
+ connect(m_page, SIGNAL(windowCloseRequested()), this, SLOT(windowCloseRequested()));
+ connect(m_page, SIGNAL(printRequested(QWebFrame*)), this, SLOT(dryRunPrint(QWebFrame*)));
+
+ connect(m_page->mainFrame(), SIGNAL(titleChanged(const QString&)),
+ SLOT(titleChanged(const QString&)));
+ connect(m_page, SIGNAL(databaseQuotaExceeded(QWebFrame*,QString)),
+ this, SLOT(dumpDatabaseQuota(QWebFrame*,QString)));
+ connect(m_page, SIGNAL(applicationCacheQuotaExceeded(QWebSecurityOrigin *, quint64)),
+ this, SLOT(dumpApplicationCacheQuota(QWebSecurityOrigin *, quint64)));
+ connect(m_page, SIGNAL(statusBarMessage(const QString&)),
+ this, SLOT(statusBarMessage(const QString&)));
+
+ QObject::connect(this, SIGNAL(quit()), qApp, SLOT(quit()), Qt::QueuedConnection);
+
+ DumpRenderTreeSupportQt::setDumpRenderTreeModeEnabled(true);
+ QFocusEvent event(QEvent::FocusIn, Qt::ActiveWindowFocusReason);
+ QApplication::sendEvent(m_mainView, &event);
+}
+
+DumpRenderTree::~DumpRenderTree()
+{
+ delete m_mainView;
+ delete m_stdin;
+ DumpRenderTreeSupportQt::removeMockDeviceOrientation();
+}
+
+static void clearHistory(QWebPage* page)
+{
+ // QWebHistory::clear() leaves current page, so remove it as well by setting
+ // max item count to 0, and then setting it back to it's original value.
+
+ QWebHistory* history = page->history();
+ int itemCount = history->maximumItemCount();
+
+ history->clear();
+ history->setMaximumItemCount(0);
+ history->setMaximumItemCount(itemCount);
+}
+
+void DumpRenderTree::dryRunPrint(QWebFrame* frame)
+{
+#ifndef QT_NO_PRINTER
+ NullPrinter printer;
+ frame->print(&printer);
+#endif
+}
+
+void DumpRenderTree::resetToConsistentStateBeforeTesting()
+{
+ // reset so that any current loads are stopped
+ // NOTE: that this has to be done before the layoutTestController is
+ // reset or we get timeouts for some tests.
+ m_page->blockSignals(true);
+ m_page->triggerAction(QWebPage::Stop);
+ m_page->blockSignals(false);
+
+ // reset the layoutTestController at this point, so that we under no
+ // circumstance dump (stop the waitUntilDone timer) during the reset
+ // of the DRT.
+ m_controller->reset();
+
+ // reset mouse clicks counter
+ m_eventSender->resetClickCount();
+
+ closeRemainingWindows();
+
+ m_page->resetSettings();
+ m_page->undoStack()->clear();
+ m_page->mainFrame()->setZoomFactor(1.0);
+ clearHistory(m_page);
+ DumpRenderTreeSupportQt::clearFrameName(m_page->mainFrame());
+
+ m_page->mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAsNeeded);
+ m_page->mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAsNeeded);
+
+ WorkQueue::shared()->clear();
+ WorkQueue::shared()->setFrozen(false);
+
+ DumpRenderTreeSupportQt::resetOriginAccessWhiteLists();
+
+ // Qt defaults to Windows editing behavior.
+ DumpRenderTreeSupportQt::setEditingBehavior(m_page, "win");
+
+ QLocale::setDefault(QLocale::c());
+
+#ifndef Q_OS_WINCE
+ setlocale(LC_ALL, "");
+#endif
+}
+
+static bool isGlobalHistoryTest(const QUrl& url)
+{
+ if (url.path().contains("globalhistory/"))
+ return true;
+ return false;
+}
+
+static bool isWebInspectorTest(const QUrl& url)
+{
+ if (url.path().contains("inspector/"))
+ return true;
+ return false;
+}
+
+static bool shouldEnableDeveloperExtras(const QUrl& url)
+{
+ return true;
+}
+
+void DumpRenderTree::open(const QUrl& url)
+{
+ DumpRenderTreeSupportQt::dumpResourceLoadCallbacksPath(QFileInfo(url.toString()).path());
+ resetToConsistentStateBeforeTesting();
+
+ if (shouldEnableDeveloperExtras(m_page->mainFrame()->url())) {
+ layoutTestController()->closeWebInspector();
+ layoutTestController()->setDeveloperExtrasEnabled(false);
+ }
+
+ if (shouldEnableDeveloperExtras(url)) {
+ layoutTestController()->setDeveloperExtrasEnabled(true);
+ if (isWebInspectorTest(url))
+ layoutTestController()->showWebInspector();
+ }
+
+ if (isGlobalHistoryTest(url))
+ layoutTestController()->dumpHistoryCallbacks();
+
+ // W3C SVG tests expect to be 480x360
+ bool isW3CTest = url.toString().contains("svg/W3C-SVG-1.1");
+ int width = isW3CTest ? 480 : LayoutTestController::maxViewWidth;
+ int height = isW3CTest ? 360 : LayoutTestController::maxViewHeight;
+ m_mainView->resize(QSize(width, height));
+ m_page->setPreferredContentsSize(QSize());
+ m_page->setViewportSize(QSize(width, height));
+
+ QFocusEvent ev(QEvent::FocusIn);
+ m_page->event(&ev);
+
+ QWebSettings::clearMemoryCaches();
+#if !(defined(Q_OS_SYMBIAN) && QT_VERSION <= QT_VERSION_CHECK(4, 6, 2))
+ QFontDatabase::removeAllApplicationFonts();
+#endif
+#if defined(Q_WS_X11)
+ initializeFonts();
+#endif
+
+ DumpRenderTreeSupportQt::dumpFrameLoader(url.toString().contains("loading/"));
+ setTextOutputEnabled(true);
+ m_page->mainFrame()->load(url);
+}
+
+void DumpRenderTree::readLine()
+{
+ if (!m_stdin) {
+ m_stdin = new QFile;
+ m_stdin->open(stdin, QFile::ReadOnly);
+
+ if (!m_stdin->isReadable()) {
+ emit quit();
+ return;
+ }
+ }
+
+ QByteArray line = m_stdin->readLine().trimmed();
+
+ if (line.isEmpty()) {
+ emit quit();
+ return;
+ }
+
+ processLine(QString::fromLocal8Bit(line.constData(), line.length()));
+}
+
+void DumpRenderTree::processArgsLine(const QStringList &args)
+{
+ setStandAloneMode(true);
+
+ for (int i = 1; i < args.size(); ++i)
+ if (!args.at(i).startsWith('-'))
+ m_standAloneModeTestList.append(args[i]);
+
+ QFileInfo firstEntry(m_standAloneModeTestList.first());
+ if (firstEntry.isDir()) {
+ QDir folderEntry(m_standAloneModeTestList.first());
+ QStringList supportedExt;
+ // Check for all supported extensions (from Scripts/webkitpy/layout_tests/layout_package/test_files.py).
+ supportedExt << "*.html" << "*.shtml" << "*.xml" << "*.xhtml" << "*.xhtmlmp" << "*.pl" << "*.php" << "*.svg";
+ m_standAloneModeTestList = folderEntry.entryList(supportedExt, QDir::Files);
+ for (int i = 0; i < m_standAloneModeTestList.size(); ++i)
+ m_standAloneModeTestList[i] = folderEntry.absoluteFilePath(m_standAloneModeTestList[i]);
+ }
+
+ processLine(m_standAloneModeTestList.first());
+ m_standAloneModeTestList.removeFirst();
+
+ connect(this, SIGNAL(ready()), this, SLOT(loadNextTestInStandAloneMode()));
+}
+
+void DumpRenderTree::loadNextTestInStandAloneMode()
+{
+ if (m_standAloneModeTestList.isEmpty()) {
+ emit quit();
+ return;
+ }
+
+ processLine(m_standAloneModeTestList.first());
+ m_standAloneModeTestList.removeFirst();
+}
+
+void DumpRenderTree::processLine(const QString &input)
+{
+ QString line = input;
+
+ m_expectedHash = QString();
+ if (m_dumpPixels) {
+ // single quote marks the pixel dump hash
+ int i = line.indexOf('\'');
+ if (i > -1) {
+ m_expectedHash = line.mid(i + 1, line.length());
+ line.remove(i, line.length());
+ }
+ }
+
+ if (line.startsWith(QLatin1String("http:"))
+ || line.startsWith(QLatin1String("https:"))
+ || line.startsWith(QLatin1String("file:"))) {
+ open(QUrl(line));
+ } else {
+ QFileInfo fi(line);
+
+ if (!fi.exists()) {
+ QDir currentDir = QDir::currentPath();
+
+ // Try to be smart about where the test is located
+ if (currentDir.dirName() == QLatin1String("LayoutTests"))
+ fi = QFileInfo(currentDir, line.replace(QRegExp(".*?LayoutTests/(.*)"), "\\1"));
+ else if (!line.contains(QLatin1String("LayoutTests")))
+ fi = QFileInfo(currentDir, line.prepend(QLatin1String("LayoutTests/")));
+
+ if (!fi.exists()) {
+ emit ready();
+ return;
+ }
+ }
+
+ open(QUrl::fromLocalFile(fi.absoluteFilePath()));
+ }
+
+ fflush(stdout);
+}
+
+void DumpRenderTree::setDumpPixels(bool dump)
+{
+ m_dumpPixels = dump;
+}
+
+void DumpRenderTree::closeRemainingWindows()
+{
+ foreach (QObject* widget, windows)
+ delete widget;
+ windows.clear();
+}
+
+void DumpRenderTree::initJSObjects()
+{
+ QWebFrame *frame = qobject_cast<QWebFrame*>(sender());
+ Q_ASSERT(frame);
+ frame->addToJavaScriptWindowObject(QLatin1String("layoutTestController"), m_controller);
+ frame->addToJavaScriptWindowObject(QLatin1String("eventSender"), m_eventSender);
+ frame->addToJavaScriptWindowObject(QLatin1String("textInputController"), m_textInputController);
+ frame->addToJavaScriptWindowObject(QLatin1String("GCController"), m_gcController);
+ frame->addToJavaScriptWindowObject(QLatin1String("plainText"), m_plainTextController);
+}
+
+void DumpRenderTree::showPage()
+{
+ m_mainView->show();
+ // we need a paint event but cannot process all the events
+ QPixmap pixmap(m_mainView->size());
+ m_mainView->render(&pixmap);
+}
+
+void DumpRenderTree::hidePage()
+{
+ m_mainView->hide();
+}
+
+QString DumpRenderTree::dumpFrameScrollPosition(QWebFrame* frame)
+{
+ if (!frame || !DumpRenderTreeSupportQt::hasDocumentElement(frame))
+ return QString();
+
+ QString result;
+ QPoint pos = frame->scrollPosition();
+ if (pos.x() > 0 || pos.y() > 0) {
+ QWebFrame* parent = qobject_cast<QWebFrame *>(frame->parent());
+ if (parent)
+ result.append(QString("frame '%1' ").arg(frame->title()));
+ result.append(QString("scrolled to %1,%2\n").arg(pos.x()).arg(pos.y()));
+ }
+
+ if (m_controller->shouldDumpChildFrameScrollPositions()) {
+ QList<QWebFrame*> children = frame->childFrames();
+ for (int i = 0; i < children.size(); ++i)
+ result += dumpFrameScrollPosition(children.at(i));
+ }
+ return result;
+}
+
+QString DumpRenderTree::dumpFramesAsText(QWebFrame* frame)
+{
+ if (!frame || !DumpRenderTreeSupportQt::hasDocumentElement(frame))
+ return QString();
+
+ QString result;
+ QWebFrame* parent = qobject_cast<QWebFrame*>(frame->parent());
+ if (parent) {
+ result.append(QLatin1String("\n--------\nFrame: '"));
+ result.append(frame->frameName());
+ result.append(QLatin1String("'\n--------\n"));
+ }
+
+ QString innerText = frame->toPlainText();
+ result.append(innerText);
+ result.append(QLatin1String("\n"));
+
+ if (m_controller->shouldDumpChildrenAsText()) {
+ QList<QWebFrame *> children = frame->childFrames();
+ for (int i = 0; i < children.size(); ++i)
+ result += dumpFramesAsText(children.at(i));
+ }
+
+ return result;
+}
+
+static QString dumpHistoryItem(const QWebHistoryItem& item, int indent, bool current)
+{
+ QString result;
+
+ int start = 0;
+ if (current) {
+ result.append(QLatin1String("curr->"));
+ start = 6;
+ }
+ for (int i = start; i < indent; i++)
+ result.append(' ');
+
+ QString url = item.url().toEncoded();
+ if (url.contains("file://")) {
+ static QString layoutTestsString("/LayoutTests/");
+ static QString fileTestString("(file test):");
+
+ QString res = url.mid(url.indexOf(layoutTestsString) + layoutTestsString.length());
+ if (res.isEmpty())
+ return result;
+
+ result.append(fileTestString);
+ result.append(res);
+ } else {
+ result.append(url);
+ }
+
+ QString target = DumpRenderTreeSupportQt::historyItemTarget(item);
+ if (!target.isEmpty())
+ result.append(QString(QLatin1String(" (in frame \"%1\")")).arg(target));
+
+ if (DumpRenderTreeSupportQt::isTargetItem(item))
+ result.append(QLatin1String(" **nav target**"));
+ result.append(QLatin1String("\n"));
+
+ QMap<QString, QWebHistoryItem> children = DumpRenderTreeSupportQt::getChildHistoryItems(item);
+ foreach (QWebHistoryItem item, children)
+ result += dumpHistoryItem(item, 12, false);
+
+ return result;
+}
+
+QString DumpRenderTree::dumpBackForwardList(QWebPage* page)
+{
+ QWebHistory* history = page->history();
+
+ QString result;
+ result.append(QLatin1String("\n============== Back Forward List ==============\n"));
+
+ // FORMAT:
+ // " (file test):fast/loader/resources/click-fragment-link.html **nav target**"
+ // "curr-> (file test):fast/loader/resources/click-fragment-link.html#testfragment **nav target**"
+
+ int maxItems = history->maximumItemCount();
+
+ foreach (const QWebHistoryItem item, history->backItems(maxItems)) {
+ if (!item.isValid())
+ continue;
+ result.append(dumpHistoryItem(item, 8, false));
+ }
+
+ QWebHistoryItem item = history->currentItem();
+ if (item.isValid())
+ result.append(dumpHistoryItem(item, 8, true));
+
+ foreach (const QWebHistoryItem item, history->forwardItems(maxItems)) {
+ if (!item.isValid())
+ continue;
+ result.append(dumpHistoryItem(item, 8, false));
+ }
+
+ result.append(QLatin1String("===============================================\n"));
+ return result;
+}
+
+static const char *methodNameStringForFailedTest(LayoutTestController *controller)
+{
+ const char *errorMessage;
+ if (controller->shouldDumpAsText())
+ errorMessage = "[documentElement innerText]";
+ // FIXME: Add when we have support
+ //else if (controller->dumpDOMAsWebArchive())
+ // errorMessage = "[[mainFrame DOMDocument] webArchive]";
+ //else if (controller->dumpSourceAsWebArchive())
+ // errorMessage = "[[mainFrame dataSource] webArchive]";
+ else
+ errorMessage = "[mainFrame renderTreeAsExternalRepresentation]";
+
+ return errorMessage;
+}
+
+void DumpRenderTree::dump()
+{
+ // Prevent any further frame load or resource load callbacks from appearing after we dump the result.
+ DumpRenderTreeSupportQt::dumpFrameLoader(false);
+ DumpRenderTreeSupportQt::dumpResourceLoadCallbacks(false);
+
+ QWebFrame *mainFrame = m_page->mainFrame();
+
+ if (isStandAloneMode()) {
+ QString markup = mainFrame->toHtml();
+ fprintf(stdout, "Source:\n\n%s\n", markup.toUtf8().constData());
+ }
+
+ // Dump render text...
+ QString resultString;
+ if (m_controller->shouldDumpAsText())
+ resultString = dumpFramesAsText(mainFrame);
+ else {
+ resultString = mainFrame->renderTreeDump();
+ resultString += dumpFrameScrollPosition(mainFrame);
+ }
+ if (!resultString.isEmpty()) {
+ fprintf(stdout, "Content-Type: text/plain\n");
+ fprintf(stdout, "%s", resultString.toUtf8().constData());
+
+ if (m_controller->shouldDumpBackForwardList()) {
+ fprintf(stdout, "%s", dumpBackForwardList(webPage()).toUtf8().constData());
+ foreach (QObject* widget, windows) {
+ QWebPage* page = qobject_cast<QWebPage*>(widget->findChild<QWebPage*>());
+ fprintf(stdout, "%s", dumpBackForwardList(page).toUtf8().constData());
+ }
+ }
+
+ } else
+ printf("ERROR: nil result from %s", methodNameStringForFailedTest(m_controller));
+
+ // signal end of text block
+ fputs("#EOF\n", stdout);
+ fputs("#EOF\n", stderr);
+
+ // FIXME: All other ports don't dump pixels, if generatePixelResults is false.
+ if (m_dumpPixels) {
+ QImage image(m_page->viewportSize(), QImage::Format_ARGB32);
+ image.fill(Qt::white);
+ QPainter painter(&image);
+ mainFrame->render(&painter);
+ painter.end();
+
+ QCryptographicHash hash(QCryptographicHash::Md5);
+ for (int row = 0; row < image.height(); ++row)
+ hash.addData(reinterpret_cast<const char*>(image.scanLine(row)), image.width() * 4);
+ QString actualHash = hash.result().toHex();
+
+ fprintf(stdout, "\nActualHash: %s\n", qPrintable(actualHash));
+
+ bool dumpImage = true;
+
+ if (!m_expectedHash.isEmpty()) {
+ Q_ASSERT(m_expectedHash.length() == 32);
+ fprintf(stdout, "\nExpectedHash: %s\n", qPrintable(m_expectedHash));
+
+ if (m_expectedHash == actualHash)
+ dumpImage = false;
+ }
+
+ if (dumpImage) {
+ QBuffer buffer;
+ buffer.open(QBuffer::WriteOnly);
+ image.save(&buffer, "PNG");
+ buffer.close();
+ const QByteArray &data = buffer.data();
+
+ printf("Content-Type: %s\n", "image/png");
+ printf("Content-Length: %lu\n", static_cast<unsigned long>(data.length()));
+
+ const quint32 bytesToWriteInOneChunk = 1 << 15;
+ quint32 dataRemainingToWrite = data.length();
+ const char *ptr = data.data();
+ while (dataRemainingToWrite) {
+ quint32 bytesToWriteInThisChunk = qMin(dataRemainingToWrite, bytesToWriteInOneChunk);
+ quint32 bytesWritten = fwrite(ptr, 1, bytesToWriteInThisChunk, stdout);
+ if (bytesWritten != bytesToWriteInThisChunk)
+ break;
+ dataRemainingToWrite -= bytesWritten;
+ ptr += bytesWritten;
+ }
+ }
+
+ fflush(stdout);
+ }
+
+ puts("#EOF"); // terminate the (possibly empty) pixels block
+
+ fflush(stdout);
+ fflush(stderr);
+
+ emit ready();
+}
+
+void DumpRenderTree::titleChanged(const QString &s)
+{
+ if (m_controller->shouldDumpTitleChanges())
+ printf("TITLE CHANGED: %s\n", s.toUtf8().data());
+}
+
+void DumpRenderTree::connectFrame(QWebFrame *frame)
+{
+ connect(frame, SIGNAL(javaScriptWindowObjectCleared()), this, SLOT(initJSObjects()));
+ connect(frame, SIGNAL(provisionalLoad()),
+ layoutTestController(), SLOT(provisionalLoad()));
+}
+
+void DumpRenderTree::dumpDatabaseQuota(QWebFrame* frame, const QString& dbName)
+{
+ if (!m_controller->shouldDumpDatabaseCallbacks())
+ return;
+ QWebSecurityOrigin origin = frame->securityOrigin();
+ printf("UI DELEGATE DATABASE CALLBACK: exceededDatabaseQuotaForSecurityOrigin:{%s, %s, %i} database:%s\n",
+ origin.scheme().toUtf8().data(),
+ origin.host().toUtf8().data(),
+ origin.port(),
+ dbName.toUtf8().data());
+ origin.setDatabaseQuota(5 * 1024 * 1024);
+}
+
+void DumpRenderTree::dumpApplicationCacheQuota(QWebSecurityOrigin* origin, quint64 defaultOriginQuota)
+{
+ if (!m_controller->shouldDumpApplicationCacheDelegateCallbacks())
+ return;
+
+ printf("UI DELEGATE APPLICATION CACHE CALLBACK: exceededApplicationCacheOriginQuotaForSecurityOrigin:{%s, %s, %i}\n",
+ origin->scheme().toUtf8().data(),
+ origin->host().toUtf8().data(),
+ origin->port()
+ );
+ origin->setApplicationCacheQuota(defaultOriginQuota);
+}
+
+void DumpRenderTree::statusBarMessage(const QString& message)
+{
+ if (!m_controller->shouldDumpStatusCallbacks())
+ return;
+
+ printf("UI DELEGATE STATUS CALLBACK: setStatusText:%s\n", message.toUtf8().constData());
+}
+
+QWebPage *DumpRenderTree::createWindow()
+{
+ if (!m_controller->canOpenWindows())
+ return 0;
+
+ // Create a dummy container object to track the page in DRT.
+ // QObject is used instead of QWidget to prevent DRT from
+ // showing the main view when deleting the container.
+
+ QObject* container = new QObject(m_mainView);
+ // create a QWebPage we want to return
+ QWebPage* page = static_cast<QWebPage*>(new WebPage(container, this));
+ // gets cleaned up in closeRemainingWindows()
+ windows.append(container);
+
+ // connect the needed signals to the page
+ connect(page, SIGNAL(frameCreated(QWebFrame*)), this, SLOT(connectFrame(QWebFrame*)));
+ connectFrame(page->mainFrame());
+ connect(page, SIGNAL(loadFinished(bool)), m_controller, SLOT(maybeDump(bool)));
+ connect(page, SIGNAL(windowCloseRequested()), this, SLOT(windowCloseRequested()));
+
+ // Use a frame group name for all pages created by DumpRenderTree to allow
+ // testing of cross-page frame lookup.
+ DumpRenderTreeSupportQt::webPageSetGroupName(page, "org.webkit.qt.DumpRenderTree");
+
+ return page;
+}
+
+void DumpRenderTree::windowCloseRequested()
+{
+ QWebPage* page = qobject_cast<QWebPage*>(sender());
+ QObject* container = page->parent();
+ windows.removeAll(container);
+ // Our use of container->deleteLater() means we need to remove closed pages
+ // from the org.webkit.qt.DumpRenderTree group explicitly.
+ DumpRenderTreeSupportQt::webPageSetGroupName(page, "");
+ container->deleteLater();
+}
+
+int DumpRenderTree::windowCount() const
+{
+// include the main view in the count
+ return windows.count() + 1;
+}
+
+void DumpRenderTree::geolocationPermissionSet()
+{
+ m_page->permissionSet(QWebPage::Geolocation);
+}
+
+void DumpRenderTree::switchFocus(bool focused)
+{
+ QFocusEvent event((focused) ? QEvent::FocusIn : QEvent::FocusOut, Qt::ActiveWindowFocusReason);
+ if (!isGraphicsBased())
+ QApplication::sendEvent(m_mainView, &event);
+ else {
+ if (WebViewGraphicsBased* view = qobject_cast<WebViewGraphicsBased*>(m_mainView))
+ view->scene()->sendEvent(view->graphicsView(), &event);
+ }
+
+}
+
+#if defined(Q_WS_X11)
+void DumpRenderTree::initializeFonts()
+{
+ static int numFonts = -1;
+
+ // Some test cases may add or remove application fonts (via @font-face).
+ // Make sure to re-initialize the font set if necessary.
+ FcFontSet* appFontSet = FcConfigGetFonts(0, FcSetApplication);
+ if (appFontSet && numFonts >= 0 && appFontSet->nfont == numFonts)
+ return;
+
+ QByteArray fontDir = getenv("WEBKIT_TESTFONTS");
+ if (fontDir.isEmpty() || !QDir(fontDir).exists()) {
+ fprintf(stderr,
+ "\n\n"
+ "----------------------------------------------------------------------\n"
+ "WEBKIT_TESTFONTS environment variable is not set correctly.\n"
+ "This variable has to point to the directory containing the fonts\n"
+ "you can clone from git://gitorious.org/qtwebkit/testfonts.git\n"
+ "----------------------------------------------------------------------\n"
+ );
+ exit(1);
+ }
+ char currentPath[PATH_MAX+1];
+ if (!getcwd(currentPath, PATH_MAX))
+ qFatal("Couldn't get current working directory");
+ QByteArray configFile = currentPath;
+ FcConfig *config = FcConfigCreate();
+ configFile += "/Tools/DumpRenderTree/qt/fonts.conf";
+ if (!FcConfigParseAndLoad (config, (FcChar8*) configFile.data(), true))
+ qFatal("Couldn't load font configuration file");
+ if (!FcConfigAppFontAddDir (config, (FcChar8*) fontDir.data()))
+ qFatal("Couldn't add font dir!");
+ FcConfigSetCurrent(config);
+
+ appFontSet = FcConfigGetFonts(config, FcSetApplication);
+ numFonts = appFontSet->nfont;
+}
+#endif
+
+}
diff --git a/Tools/DumpRenderTree/qt/DumpRenderTreeQt.h b/Tools/DumpRenderTree/qt/DumpRenderTreeQt.h
new file mode 100644
index 0000000..ef95bfc
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/DumpRenderTreeQt.h
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DumpRenderTreeQt_h
+#define DumpRenderTreeQt_h
+
+#include <QList>
+#include <QNetworkAccessManager>
+#include <QObject>
+#include <QTextStream>
+#include <QSocketNotifier>
+
+#ifndef QT_NO_OPENSSL
+#include <QSslError>
+#endif
+
+#include "../../../WebKit/qt/WebCoreSupport/DumpRenderTreeSupportQt.h"
+#include <qgraphicsview.h>
+#include <qgraphicswebview.h>
+#include <qwebframe.h>
+#include <qwebinspector.h>
+#include <qwebpage.h>
+#include <qwebview.h>
+
+QT_BEGIN_NAMESPACE
+class QUrl;
+class QFile;
+QT_END_NAMESPACE
+
+class QWebFrame;
+
+class LayoutTestController;
+class DumpRenderTreeSupportQt;
+class EventSender;
+class TextInputController;
+class GCController;
+class PlainTextController;
+
+namespace WebCore {
+
+class WebPage;
+class NetworkAccessManager;
+
+class DumpRenderTree : public QObject {
+Q_OBJECT
+
+public:
+ DumpRenderTree();
+ virtual ~DumpRenderTree();
+
+ // Initialize in single-file mode.
+ void open(const QUrl& url);
+
+ void setTextOutputEnabled(bool enable) { m_enableTextOutput = enable; }
+ bool isTextOutputEnabled() { return m_enableTextOutput; }
+
+ void setGraphicsBased(bool flag) { m_graphicsBased = flag; }
+ bool isGraphicsBased() { return m_graphicsBased; }
+
+ void setDumpPixels(bool);
+
+ void closeRemainingWindows();
+ void resetToConsistentStateBeforeTesting();
+
+ LayoutTestController *layoutTestController() const { return m_controller; }
+ EventSender *eventSender() const { return m_eventSender; }
+ TextInputController *textInputController() const { return m_textInputController; }
+ QString persistentStoragePath() const { return m_persistentStoragePath; }
+ NetworkAccessManager *networkAccessManager() const { return m_networkAccessManager; }
+
+ QWebPage *createWindow();
+ int windowCount() const;
+
+ void switchFocus(bool focused);
+
+ WebPage *webPage() const { return m_page; }
+
+#if defined(Q_WS_X11)
+ static void initializeFonts();
+#endif
+ void processArgsLine(const QStringList&);
+
+public Q_SLOTS:
+ void initJSObjects();
+
+ void readLine();
+ void processLine(const QString&);
+
+ void dump();
+ void titleChanged(const QString &s);
+ void connectFrame(QWebFrame *frame);
+ void dumpDatabaseQuota(QWebFrame* frame, const QString& dbName);
+ void dumpApplicationCacheQuota(QWebSecurityOrigin* origin, quint64 defaultOriginQuota);
+ void statusBarMessage(const QString& message);
+ void windowCloseRequested();
+
+Q_SIGNALS:
+ void quit();
+ void ready();
+
+private Q_SLOTS:
+ void showPage();
+ void hidePage();
+ void dryRunPrint(QWebFrame*);
+ void loadNextTestInStandAloneMode();
+ void geolocationPermissionSet();
+
+private:
+ void setStandAloneMode(bool flag) { m_standAloneMode = flag; }
+ bool isStandAloneMode() { return m_standAloneMode; }
+
+ QString dumpFramesAsText(QWebFrame* frame);
+ QString dumpBackForwardList(QWebPage* page);
+ QString dumpFrameScrollPosition(QWebFrame* frame);
+ LayoutTestController *m_controller;
+
+ bool m_dumpPixels;
+ QString m_expectedHash;
+ QStringList m_standAloneModeTestList;
+
+ WebPage *m_page;
+ QWidget* m_mainView;
+
+ EventSender *m_eventSender;
+ TextInputController *m_textInputController;
+ GCController* m_gcController;
+ PlainTextController* m_plainTextController;
+ NetworkAccessManager* m_networkAccessManager;
+
+ QFile *m_stdin;
+
+ QList<QObject*> windows;
+ bool m_enableTextOutput;
+ bool m_standAloneMode;
+ bool m_graphicsBased;
+ QString m_persistentStoragePath;
+};
+
+class NetworkAccessManager : public QNetworkAccessManager {
+ Q_OBJECT
+public:
+ NetworkAccessManager(QObject* parent);
+
+private slots:
+#ifndef QT_NO_OPENSSL
+ void sslErrorsEncountered(QNetworkReply*, const QList<QSslError>&);
+#endif
+};
+
+class WebPage : public QWebPage {
+ Q_OBJECT
+public:
+ WebPage(QObject* parent, DumpRenderTree*);
+ virtual ~WebPage();
+ QWebInspector* webInspector();
+ void closeWebInspector();
+
+ QWebPage *createWindow(QWebPage::WebWindowType);
+
+ void javaScriptAlert(QWebFrame *frame, const QString& message);
+ void javaScriptConsoleMessage(const QString& message, int lineNumber, const QString& sourceID);
+ bool javaScriptConfirm(QWebFrame *frame, const QString& msg);
+ bool javaScriptPrompt(QWebFrame *frame, const QString& msg, const QString& defaultValue, QString* result);
+
+ void resetSettings();
+
+ virtual bool supportsExtension(QWebPage::Extension extension) const;
+ virtual bool extension(Extension extension, const ExtensionOption *option, ExtensionReturn *output);
+
+ QObject* createPlugin(const QString&, const QUrl&, const QStringList&, const QStringList&);
+
+ void permissionSet(QWebPage::Feature feature);
+
+public slots:
+ bool shouldInterruptJavaScript() { return false; }
+ void requestPermission(QWebFrame* frame, QWebPage::Feature feature);
+ void cancelPermission(QWebFrame* frame, QWebPage::Feature feature);
+
+protected:
+ bool acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, NavigationType type);
+ bool isTextOutputEnabled() { return m_drt->isTextOutputEnabled(); }
+
+private slots:
+ void setViewGeometry(const QRect&);
+
+private:
+ QWebInspector* m_webInspector;
+ QList<QWebFrame*> m_pendingGeolocationRequests;
+ DumpRenderTree *m_drt;
+};
+
+class WebViewGraphicsBased : public QGraphicsView {
+ Q_OBJECT
+
+public:
+ WebViewGraphicsBased(QWidget* parent);
+ QGraphicsWebView* graphicsView() const { return m_item; }
+ void setPage(QWebPage* page) { m_item->setPage(page); }
+
+private:
+ QGraphicsWebView* m_item;
+};
+
+}
+
+#endif
diff --git a/Tools/DumpRenderTree/qt/EventSenderQt.cpp b/Tools/DumpRenderTree/qt/EventSenderQt.cpp
new file mode 100644
index 0000000..6fb75a5
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/EventSenderQt.cpp
@@ -0,0 +1,653 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "config.h"
+#include "EventSenderQt.h"
+
+#include <QGraphicsSceneMouseEvent>
+#include <QtTest/QtTest>
+
+#define KEYCODE_DEL 127
+#define KEYCODE_BACKSPACE 8
+#define KEYCODE_LEFTARROW 0xf702
+#define KEYCODE_RIGHTARROW 0xf703
+#define KEYCODE_UPARROW 0xf700
+#define KEYCODE_DOWNARROW 0xf701
+
+// Ports like Gtk and Windows expose a different approach for their zooming
+// API if compared to Qt: they have specific methods for zooming in and out,
+// as well as a settable zoom factor, while Qt has only a 'setZoomValue' method.
+// Hence Qt DRT adopts a fixed zoom-factor (1.2) for compatibility.
+#define ZOOM_STEP 1.2
+
+#define DRT_MESSAGE_DONE (QEvent::User + 1)
+
+struct DRTEventQueue {
+ QEvent* m_event;
+ int m_delay;
+};
+
+static DRTEventQueue eventQueue[1024];
+static unsigned endOfQueue;
+static unsigned startOfQueue;
+
+EventSender::EventSender(QWebPage* parent)
+ : QObject(parent)
+{
+ m_page = parent;
+ m_mouseButtonPressed = false;
+ m_drag = false;
+ memset(eventQueue, 0, sizeof(eventQueue));
+ endOfQueue = 0;
+ startOfQueue = 0;
+ m_eventLoop = 0;
+ m_currentButton = 0;
+ resetClickCount();
+ m_page->view()->installEventFilter(this);
+ // So that we can match Scrollbar::pixelsPerLineStep() in WheelEventQt.cpp and
+ // pass fast/events/platform-wheelevent-in-scrolling-div.html
+ QApplication::setWheelScrollLines(2);
+}
+
+void EventSender::mouseDown(int button)
+{
+ Qt::MouseButton mouseButton;
+ switch (button) {
+ case 0:
+ mouseButton = Qt::LeftButton;
+ break;
+ case 1:
+ mouseButton = Qt::MidButton;
+ break;
+ case 2:
+ mouseButton = Qt::RightButton;
+ break;
+ case 3:
+ // fast/events/mouse-click-events expects the 4th button to be treated as the middle button
+ mouseButton = Qt::MidButton;
+ break;
+ default:
+ mouseButton = Qt::LeftButton;
+ break;
+ }
+
+ // only consider a click to count, an event originated by the
+ // same previous button and at the same position.
+ if (m_currentButton == button
+ && m_mousePos == m_clickPos
+ && m_clickTimer.isActive())
+ m_clickCount++;
+ else
+ m_clickCount = 1;
+
+ m_currentButton = button;
+ m_clickPos = m_mousePos;
+ m_mouseButtons |= mouseButton;
+
+// qDebug() << "EventSender::mouseDown" << frame;
+ QEvent* event;
+ if (isGraphicsBased()) {
+ event = createGraphicsSceneMouseEvent((m_clickCount == 2) ?
+ QEvent::GraphicsSceneMouseDoubleClick : QEvent::GraphicsSceneMousePress,
+ m_mousePos, m_mousePos, mouseButton, m_mouseButtons, Qt::NoModifier);
+ } else {
+ event = new QMouseEvent((m_clickCount == 2) ? QEvent::MouseButtonDblClick :
+ QEvent::MouseButtonPress, m_mousePos, m_mousePos,
+ mouseButton, m_mouseButtons, Qt::NoModifier);
+ }
+
+ sendOrQueueEvent(event);
+
+ m_clickTimer.start(QApplication::doubleClickInterval(), this);
+}
+
+void EventSender::mouseUp(int button)
+{
+ Qt::MouseButton mouseButton;
+ switch (button) {
+ case 0:
+ mouseButton = Qt::LeftButton;
+ break;
+ case 1:
+ mouseButton = Qt::MidButton;
+ break;
+ case 2:
+ mouseButton = Qt::RightButton;
+ break;
+ case 3:
+ // fast/events/mouse-click-events expects the 4th button to be treated as the middle button
+ mouseButton = Qt::MidButton;
+ break;
+ default:
+ mouseButton = Qt::LeftButton;
+ break;
+ }
+
+ m_mouseButtons &= ~mouseButton;
+
+// qDebug() << "EventSender::mouseUp" << frame;
+ QEvent* event;
+ if (isGraphicsBased()) {
+ event = createGraphicsSceneMouseEvent(QEvent::GraphicsSceneMouseRelease,
+ m_mousePos, m_mousePos, mouseButton, m_mouseButtons, Qt::NoModifier);
+ } else {
+ event = new QMouseEvent(QEvent::MouseButtonRelease,
+ m_mousePos, m_mousePos, mouseButton, m_mouseButtons, Qt::NoModifier);
+ }
+
+ sendOrQueueEvent(event);
+}
+
+void EventSender::mouseMoveTo(int x, int y)
+{
+// qDebug() << "EventSender::mouseMoveTo" << x << y;
+ m_mousePos = QPoint(x, y);
+
+ QEvent* event;
+ if (isGraphicsBased()) {
+ event = createGraphicsSceneMouseEvent(QEvent::GraphicsSceneMouseMove,
+ m_mousePos, m_mousePos, Qt::NoButton, m_mouseButtons, Qt::NoModifier);
+ } else {
+ event = new QMouseEvent(QEvent::MouseMove,
+ m_mousePos, m_mousePos, Qt::NoButton, m_mouseButtons, Qt::NoModifier);
+ }
+
+ sendOrQueueEvent(event);
+}
+
+#ifndef QT_NO_WHEELEVENT
+void EventSender::mouseScrollBy(int x, int y)
+{
+ continuousMouseScrollBy((x*120), (y*120));
+}
+
+void EventSender::continuousMouseScrollBy(int x, int y)
+{
+ // continuousMouseScrollBy() mimics devices that send fine-grained scroll events where the 'delta' specified is not the usual
+ // multiple of 120. See http://doc.qt.nokia.com/4.6/qwheelevent.html#delta for a good explanation of this.
+ if (x) {
+ QEvent* event;
+ if (isGraphicsBased()) {
+ event = createGraphicsSceneWheelEvent(QEvent::GraphicsSceneWheel,
+ m_mousePos, m_mousePos, x, Qt::NoModifier, Qt::Horizontal);
+ } else
+ event = new QWheelEvent(m_mousePos, m_mousePos, x, m_mouseButtons, Qt::NoModifier, Qt::Horizontal);
+
+ sendOrQueueEvent(event);
+ }
+ if (y) {
+ QEvent* event;
+ if (isGraphicsBased()) {
+ event = createGraphicsSceneWheelEvent(QEvent::GraphicsSceneWheel,
+ m_mousePos, m_mousePos, y, Qt::NoModifier, Qt::Vertical);
+ } else
+ event = new QWheelEvent(m_mousePos, m_mousePos, y, m_mouseButtons, Qt::NoModifier, Qt::Vertical);
+
+ sendOrQueueEvent(event);
+ }
+}
+#endif
+
+void EventSender::leapForward(int ms)
+{
+ eventQueue[endOfQueue].m_delay = ms;
+ //qDebug() << "EventSender::leapForward" << ms;
+}
+
+void EventSender::keyDown(const QString& string, const QStringList& modifiers, unsigned int location)
+{
+ QString s = string;
+ Qt::KeyboardModifiers modifs = 0;
+ for (int i = 0; i < modifiers.size(); ++i) {
+ const QString& m = modifiers.at(i);
+ if (m == "ctrlKey")
+ modifs |= Qt::ControlModifier;
+ else if (m == "shiftKey")
+ modifs |= Qt::ShiftModifier;
+ else if (m == "altKey")
+ modifs |= Qt::AltModifier;
+ else if (m == "metaKey")
+ modifs |= Qt::MetaModifier;
+ }
+ if (location == 3)
+ modifs |= Qt::KeypadModifier;
+ int code = 0;
+ if (string.length() == 1) {
+ code = string.unicode()->unicode();
+ //qDebug() << ">>>>>>>>> keyDown" << code << (char)code;
+ // map special keycodes used by the tests to something that works for Qt/X11
+ if (code == '\r') {
+ code = Qt::Key_Return;
+ } else if (code == '\t') {
+ code = Qt::Key_Tab;
+ if (modifs == Qt::ShiftModifier)
+ code = Qt::Key_Backtab;
+ s = QString();
+ } else if (code == KEYCODE_DEL || code == KEYCODE_BACKSPACE) {
+ code = Qt::Key_Backspace;
+ if (modifs == Qt::AltModifier)
+ modifs = Qt::ControlModifier;
+ s = QString();
+ } else if (code == 'o' && modifs == Qt::ControlModifier) {
+ // Mimic the emacs ctrl-o binding on Mac by inserting a paragraph
+ // separator and then putting the cursor back to its original
+ // position. Allows us to pass emacs-ctrl-o.html
+ s = QLatin1String("\n");
+ code = '\n';
+ modifs = 0;
+ QKeyEvent event(QEvent::KeyPress, code, modifs, s);
+ sendEvent(m_page, &event);
+ QKeyEvent event2(QEvent::KeyRelease, code, modifs, s);
+ sendEvent(m_page, &event2);
+ s = QString();
+ code = Qt::Key_Left;
+ } else if (code == 'y' && modifs == Qt::ControlModifier) {
+ s = QLatin1String("c");
+ code = 'c';
+ } else if (code == 'k' && modifs == Qt::ControlModifier) {
+ s = QLatin1String("x");
+ code = 'x';
+ } else if (code == 'a' && modifs == Qt::ControlModifier) {
+ s = QString();
+ code = Qt::Key_Home;
+ modifs = 0;
+ } else if (code == KEYCODE_LEFTARROW) {
+ s = QString();
+ code = Qt::Key_Left;
+ if (modifs & Qt::MetaModifier) {
+ code = Qt::Key_Home;
+ modifs &= ~Qt::MetaModifier;
+ }
+ } else if (code == KEYCODE_RIGHTARROW) {
+ s = QString();
+ code = Qt::Key_Right;
+ if (modifs & Qt::MetaModifier) {
+ code = Qt::Key_End;
+ modifs &= ~Qt::MetaModifier;
+ }
+ } else if (code == KEYCODE_UPARROW) {
+ s = QString();
+ code = Qt::Key_Up;
+ if (modifs & Qt::MetaModifier) {
+ code = Qt::Key_PageUp;
+ modifs &= ~Qt::MetaModifier;
+ }
+ } else if (code == KEYCODE_DOWNARROW) {
+ s = QString();
+ code = Qt::Key_Down;
+ if (modifs & Qt::MetaModifier) {
+ code = Qt::Key_PageDown;
+ modifs &= ~Qt::MetaModifier;
+ }
+ } else if (code == 'a' && modifs == Qt::ControlModifier) {
+ s = QString();
+ code = Qt::Key_Home;
+ modifs = 0;
+ } else
+ code = string.unicode()->toUpper().unicode();
+ } else {
+ //qDebug() << ">>>>>>>>> keyDown" << string;
+
+ if (string.startsWith(QLatin1Char('F')) && string.count() <= 3) {
+ s = s.mid(1);
+ int functionKey = s.toInt();
+ Q_ASSERT(functionKey >= 1 && functionKey <= 35);
+ code = Qt::Key_F1 + (functionKey - 1);
+ // map special keycode strings used by the tests to something that works for Qt/X11
+ } else if (string == QLatin1String("leftArrow")) {
+ s = QString();
+ code = Qt::Key_Left;
+ } else if (string == QLatin1String("rightArrow")) {
+ s = QString();
+ code = Qt::Key_Right;
+ } else if (string == QLatin1String("upArrow")) {
+ s = QString();
+ code = Qt::Key_Up;
+ } else if (string == QLatin1String("downArrow")) {
+ s = QString();
+ code = Qt::Key_Down;
+ } else if (string == QLatin1String("pageUp")) {
+ s = QString();
+ code = Qt::Key_PageUp;
+ } else if (string == QLatin1String("pageDown")) {
+ s = QString();
+ code = Qt::Key_PageDown;
+ } else if (string == QLatin1String("home")) {
+ s = QString();
+ code = Qt::Key_Home;
+ } else if (string == QLatin1String("end")) {
+ s = QString();
+ code = Qt::Key_End;
+ } else if (string == QLatin1String("insert")) {
+ s = QString();
+ code = Qt::Key_Insert;
+ } else if (string == QLatin1String("delete")) {
+ s = QString();
+ code = Qt::Key_Delete;
+ } else if (string == QLatin1String("printScreen")) {
+ s = QString();
+ code = Qt::Key_Print;
+ }
+ }
+ QKeyEvent event(QEvent::KeyPress, code, modifs, s);
+ sendEvent(m_page, &event);
+ QKeyEvent event2(QEvent::KeyRelease, code, modifs, s);
+ sendEvent(m_page, &event2);
+}
+
+void EventSender::contextClick()
+{
+ QMouseEvent event(QEvent::MouseButtonPress, m_mousePos, Qt::RightButton, Qt::RightButton, Qt::NoModifier);
+ sendEvent(m_page, &event);
+ QMouseEvent event2(QEvent::MouseButtonRelease, m_mousePos, Qt::RightButton, Qt::RightButton, Qt::NoModifier);
+ sendEvent(m_page, &event2);
+
+ if (isGraphicsBased()) {
+ QGraphicsSceneContextMenuEvent ctxEvent(QEvent::GraphicsSceneContextMenu);
+ ctxEvent.setReason(QGraphicsSceneContextMenuEvent::Mouse);
+ ctxEvent.setPos(m_mousePos);
+ WebCore::WebViewGraphicsBased* view = qobject_cast<WebCore::WebViewGraphicsBased*>(m_page->view());
+ if (view)
+ sendEvent(view->graphicsView(), &ctxEvent);
+ } else {
+ QContextMenuEvent ctxEvent(QContextMenuEvent::Mouse, m_mousePos);
+ sendEvent(m_page->view(), &ctxEvent);
+ }
+}
+
+void EventSender::scheduleAsynchronousClick()
+{
+ QMouseEvent* event = new QMouseEvent(QEvent::MouseButtonPress, m_mousePos, Qt::LeftButton, Qt::RightButton, Qt::NoModifier);
+ postEvent(m_page, event);
+ QMouseEvent* event2 = new QMouseEvent(QEvent::MouseButtonRelease, m_mousePos, Qt::LeftButton, Qt::RightButton, Qt::NoModifier);
+ postEvent(m_page, event2);
+}
+
+void EventSender::addTouchPoint(int x, int y)
+{
+ // Use index to refer to the position in the vector that this touch
+ // is stored. We then create a unique id for the touch that will be
+ // passed into WebCore.
+ int index = m_touchPoints.count();
+ int id = m_touchPoints.isEmpty() ? 0 : m_touchPoints.last().id() + 1;
+ QTouchEvent::TouchPoint point(id);
+ m_touchPoints.append(point);
+ updateTouchPoint(index, x, y);
+ m_touchPoints[index].setState(Qt::TouchPointPressed);
+}
+
+void EventSender::updateTouchPoint(int index, int x, int y)
+{
+ if (index < 0 || index >= m_touchPoints.count())
+ return;
+
+ QTouchEvent::TouchPoint &p = m_touchPoints[index];
+ p.setPos(QPointF(x, y));
+ p.setState(Qt::TouchPointMoved);
+}
+
+void EventSender::setTouchModifier(const QString &modifier, bool enable)
+{
+ Qt::KeyboardModifier mod = Qt::NoModifier;
+ if (!modifier.compare(QLatin1String("shift"), Qt::CaseInsensitive))
+ mod = Qt::ShiftModifier;
+ else if (!modifier.compare(QLatin1String("alt"), Qt::CaseInsensitive))
+ mod = Qt::AltModifier;
+ else if (!modifier.compare(QLatin1String("meta"), Qt::CaseInsensitive))
+ mod = Qt::MetaModifier;
+ else if (!modifier.compare(QLatin1String("ctrl"), Qt::CaseInsensitive))
+ mod = Qt::ControlModifier;
+
+ if (enable)
+ m_touchModifiers |= mod;
+ else
+ m_touchModifiers &= ~mod;
+}
+
+void EventSender::touchStart()
+{
+ if (!m_touchActive) {
+ sendTouchEvent(QEvent::TouchBegin);
+ m_touchActive = true;
+ } else
+ sendTouchEvent(QEvent::TouchUpdate);
+}
+
+void EventSender::touchMove()
+{
+ sendTouchEvent(QEvent::TouchUpdate);
+}
+
+void EventSender::touchEnd()
+{
+ for (int i = 0; i < m_touchPoints.count(); ++i)
+ if (m_touchPoints[i].state() != Qt::TouchPointReleased) {
+ sendTouchEvent(QEvent::TouchUpdate);
+ return;
+ }
+ sendTouchEvent(QEvent::TouchEnd);
+ m_touchActive = false;
+}
+
+void EventSender::clearTouchPoints()
+{
+ m_touchPoints.clear();
+ m_touchModifiers = Qt::KeyboardModifiers();
+ m_touchActive = false;
+}
+
+void EventSender::releaseTouchPoint(int index)
+{
+ if (index < 0 || index >= m_touchPoints.count())
+ return;
+
+ m_touchPoints[index].setState(Qt::TouchPointReleased);
+}
+
+void EventSender::sendTouchEvent(QEvent::Type type)
+{
+ QTouchEvent event(type, QTouchEvent::TouchScreen, m_touchModifiers);
+ event.setTouchPoints(m_touchPoints);
+ sendEvent(m_page, &event);
+ QList<QTouchEvent::TouchPoint>::Iterator it = m_touchPoints.begin();
+ while (it != m_touchPoints.end()) {
+ if (it->state() == Qt::TouchPointReleased)
+ it = m_touchPoints.erase(it);
+ else {
+ it->setState(Qt::TouchPointStationary);
+ ++it;
+ }
+ }
+}
+
+void EventSender::zoomPageIn()
+{
+ if (QWebFrame* frame = m_page->mainFrame())
+ frame->setZoomFactor(frame->zoomFactor() * ZOOM_STEP);
+}
+
+void EventSender::zoomPageOut()
+{
+ if (QWebFrame* frame = m_page->mainFrame())
+ frame->setZoomFactor(frame->zoomFactor() / ZOOM_STEP);
+}
+
+void EventSender::textZoomIn()
+{
+ if (QWebFrame* frame = m_page->mainFrame())
+ frame->setTextSizeMultiplier(frame->textSizeMultiplier() * ZOOM_STEP);
+}
+
+void EventSender::textZoomOut()
+{
+ if (QWebFrame* frame = m_page->mainFrame())
+ frame->setTextSizeMultiplier(frame->textSizeMultiplier() / ZOOM_STEP);
+}
+
+QWebFrame* EventSender::frameUnderMouse() const
+{
+ QWebFrame* frame = m_page->mainFrame();
+
+redo:
+ QList<QWebFrame*> children = frame->childFrames();
+ for (int i = 0; i < children.size(); ++i) {
+ if (children.at(i)->geometry().contains(m_mousePos)) {
+ frame = children.at(i);
+ goto redo;
+ }
+ }
+ if (frame->geometry().contains(m_mousePos))
+ return frame;
+ return 0;
+}
+
+void EventSender::sendOrQueueEvent(QEvent* event)
+{
+ // Mouse move events are queued if
+ // 1. A previous event was queued.
+ // 2. A delay was set-up by leapForward().
+ // 3. A call to mouseMoveTo while the mouse button is pressed could initiate a drag operation, and that does not return until mouseUp is processed.
+ // To be safe and avoid a deadlock, this event is queued.
+ if (endOfQueue == startOfQueue && !eventQueue[endOfQueue].m_delay && (!(m_mouseButtonPressed && (m_eventLoop && event->type() == QEvent::MouseButtonRelease)))) {
+ sendEvent(m_page->view(), event);
+ delete event;
+ return;
+ }
+ eventQueue[endOfQueue++].m_event = event;
+ eventQueue[endOfQueue].m_delay = 0;
+ replaySavedEvents(event->type() != QEvent::MouseMove);
+}
+
+void EventSender::replaySavedEvents(bool flush)
+{
+ if (startOfQueue < endOfQueue) {
+ // First send all the events that are ready to be sent
+ while (!eventQueue[startOfQueue].m_delay && startOfQueue < endOfQueue) {
+ QEvent* ev = eventQueue[startOfQueue++].m_event;
+ postEvent(m_page->view(), ev);
+ }
+ if (startOfQueue == endOfQueue) {
+ // Reset the queue
+ startOfQueue = 0;
+ endOfQueue = 0;
+ } else {
+ QTest::qWait(eventQueue[startOfQueue].m_delay);
+ eventQueue[startOfQueue].m_delay = 0;
+ }
+ }
+ if (!flush)
+ return;
+
+ // Send a marker event, it will tell us when it is safe to exit the new event loop
+ QEvent* drtEvent = new QEvent((QEvent::Type)DRT_MESSAGE_DONE);
+ QApplication::postEvent(m_page->view(), drtEvent);
+
+ // Start an event loop for async handling of Drag & Drop
+ m_eventLoop = new QEventLoop;
+ m_eventLoop->exec();
+ delete m_eventLoop;
+ m_eventLoop = 0;
+}
+
+bool EventSender::eventFilter(QObject* watched, QEvent* event)
+{
+ if (watched != m_page->view())
+ return false;
+ switch (event->type()) {
+ case QEvent::Leave:
+ return true;
+ case QEvent::MouseButtonPress:
+ case QEvent::GraphicsSceneMousePress:
+ m_mouseButtonPressed = true;
+ break;
+ case QEvent::MouseMove:
+ case QEvent::GraphicsSceneMouseMove:
+ if (m_mouseButtonPressed)
+ m_drag = true;
+ break;
+ case QEvent::MouseButtonRelease:
+ case QEvent::GraphicsSceneMouseRelease:
+ m_mouseButtonPressed = false;
+ m_drag = false;
+ break;
+ case DRT_MESSAGE_DONE:
+ m_eventLoop->exit();
+ return true;
+ }
+ return false;
+}
+
+void EventSender::timerEvent(QTimerEvent* ev)
+{
+ m_clickTimer.stop();
+}
+
+QGraphicsSceneMouseEvent* EventSender::createGraphicsSceneMouseEvent(QEvent::Type type, const QPoint& pos, const QPoint& screenPos, Qt::MouseButton button, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
+{
+ QGraphicsSceneMouseEvent* event;
+ event = new QGraphicsSceneMouseEvent(type);
+ event->setPos(pos);
+ event->setScreenPos(screenPos);
+ event->setButton(button);
+ event->setButtons(buttons);
+ event->setModifiers(modifiers);
+
+ return event;
+}
+
+QGraphicsSceneWheelEvent* EventSender::createGraphicsSceneWheelEvent(QEvent::Type type, const QPoint& pos, const QPoint& screenPos, int delta, Qt::KeyboardModifiers modifiers, Qt::Orientation orientation)
+{
+ QGraphicsSceneWheelEvent* event;
+ event = new QGraphicsSceneWheelEvent(type);
+ event->setPos(pos);
+ event->setScreenPos(screenPos);
+ event->setDelta(delta);
+ event->setModifiers(modifiers);
+ event->setOrientation(orientation);
+
+ return event;
+}
+
+void EventSender::sendEvent(QObject* receiver, QEvent* event)
+{
+ if (WebCore::WebViewGraphicsBased* view = qobject_cast<WebCore::WebViewGraphicsBased*>(receiver))
+ view->scene()->sendEvent(view->graphicsView(), event);
+ else
+ QApplication::sendEvent(receiver, event);
+}
+
+void EventSender::postEvent(QObject* receiver, QEvent* event)
+{
+ // QGraphicsScene does not have a postEvent method, so send the event in this case
+ // and delete it after that.
+ if (WebCore::WebViewGraphicsBased* view = qobject_cast<WebCore::WebViewGraphicsBased*>(receiver)) {
+ view->scene()->sendEvent(view->graphicsView(), event);
+ delete event;
+ } else
+ QApplication::postEvent(receiver, event); // event deleted by the system
+}
diff --git a/Tools/DumpRenderTree/qt/EventSenderQt.h b/Tools/DumpRenderTree/qt/EventSenderQt.h
new file mode 100644
index 0000000..4ba8382
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/EventSenderQt.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef EventSenderQt_h
+#define EventSenderQt_h
+
+
+#include "DumpRenderTreeQt.h"
+
+#include <QApplication>
+#include <QBasicTimer>
+#include <QEvent>
+#include <QEventLoop>
+#include <QMouseEvent>
+#include <QObject>
+#include <QPoint>
+#include <QString>
+#include <QStringList>
+#include <QTouchEvent>
+
+#include <qwebpage.h>
+#include <qwebframe.h>
+
+
+class EventSender : public QObject {
+ Q_OBJECT
+public:
+ EventSender(QWebPage* parent);
+ virtual bool eventFilter(QObject* watched, QEvent* event);
+ void resetClickCount() { m_clickCount = 0; }
+
+public slots:
+ void mouseDown(int button = 0);
+ void mouseUp(int button = 0);
+ void mouseMoveTo(int x, int y);
+#ifndef QT_NO_WHEELEVENT
+ void mouseScrollBy(int x, int y);
+ void continuousMouseScrollBy(int x, int y);
+#endif
+ void leapForward(int ms);
+ void keyDown(const QString& string, const QStringList& modifiers = QStringList(), unsigned int location = 0);
+ void clearKillRing() {}
+ void contextClick();
+ void scheduleAsynchronousClick();
+ void addTouchPoint(int x, int y);
+ void updateTouchPoint(int index, int x, int y);
+ void setTouchModifier(const QString &modifier, bool enable);
+ void touchStart();
+ void touchMove();
+ void touchEnd();
+ void zoomPageIn();
+ void zoomPageOut();
+ void textZoomIn();
+ void textZoomOut();
+ void clearTouchPoints();
+ void releaseTouchPoint(int index);
+
+protected:
+ void timerEvent(QTimerEvent*);
+
+private:
+ bool isGraphicsBased() const { return qobject_cast<WebCore::WebViewGraphicsBased*>(m_page->view()); }
+ QGraphicsSceneMouseEvent* createGraphicsSceneMouseEvent(QEvent::Type, const QPoint& pos, const QPoint& screenPos, Qt::MouseButton, Qt::MouseButtons, Qt::KeyboardModifiers);
+ QGraphicsSceneWheelEvent* createGraphicsSceneWheelEvent(QEvent::Type, const QPoint& pos, const QPoint& screenPos, int delta, Qt::KeyboardModifiers, Qt::Orientation);
+ void sendEvent(QObject* receiver, QEvent* event);
+ void postEvent(QObject* receiver, QEvent* event);
+
+private:
+ void sendTouchEvent(QEvent::Type);
+ void sendOrQueueEvent(QEvent*);
+ void replaySavedEvents(bool flush);
+ QPoint m_mousePos;
+ QPoint m_clickPos;
+ Qt::MouseButtons m_mouseButtons;
+ QWebPage* m_page;
+ int m_clickCount;
+ int m_currentButton;
+ bool m_mouseButtonPressed;
+ bool m_drag;
+ QEventLoop* m_eventLoop;
+ QWebFrame* frameUnderMouse() const;
+ QBasicTimer m_clickTimer;
+ QList<QTouchEvent::TouchPoint> m_touchPoints;
+ Qt::KeyboardModifiers m_touchModifiers;
+ bool m_touchActive;
+};
+#endif // EventSenderQt_h
diff --git a/Tools/DumpRenderTree/qt/GCControllerQt.cpp b/Tools/DumpRenderTree/qt/GCControllerQt.cpp
new file mode 100644
index 0000000..3aa507f
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/GCControllerQt.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "GCControllerQt.h"
+#include "../../../WebKit/qt/WebCoreSupport/DumpRenderTreeSupportQt.h"
+
+#include <qwebpage.h>
+
+GCController::GCController(QWebPage* parent)
+ : QObject(parent)
+{
+}
+
+void GCController::collect() const
+{
+ DumpRenderTreeSupportQt::garbageCollectorCollect();
+}
+
+void GCController::collectOnAlternateThread(bool waitUntilDone) const
+{
+ DumpRenderTreeSupportQt::garbageCollectorCollectOnAlternateThread(waitUntilDone);
+}
+
+unsigned int GCController::getJSObjectCount() const
+{
+ return DumpRenderTreeSupportQt::javaScriptObjectsCount();
+}
diff --git a/Tools/DumpRenderTree/qt/GCControllerQt.h b/Tools/DumpRenderTree/qt/GCControllerQt.h
new file mode 100644
index 0000000..d3c83b9
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/GCControllerQt.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef GCControllerQt_h
+#define GCControllerQt_h
+
+#include <QObject>
+
+class QWebPage;
+class DumpRenderTreeSupportQt;
+
+class GCController : public QObject
+{
+ Q_OBJECT
+public:
+ GCController(QWebPage* parent);
+
+public slots:
+ void collect() const;
+ void collectOnAlternateThread(bool waitUntilDone) const;
+ unsigned int getJSObjectCount() const;
+
+};
+
+#endif
diff --git a/Tools/DumpRenderTree/qt/ImageDiff.cpp b/Tools/DumpRenderTree/qt/ImageDiff.cpp
new file mode 100644
index 0000000..9282e2f
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/ImageDiff.cpp
@@ -0,0 +1,149 @@
+/*
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <QtCore/qmath.h>
+
+#include <QApplication>
+#include <QBuffer>
+#include <QByteArray>
+#include <QImage>
+#include <QStringList>
+
+#include <stdio.h>
+
+int main(int argc, char* argv[])
+{
+ QCoreApplication app(argc, argv);
+
+ qreal tolerance = 0;
+
+ QStringList args = app.arguments();
+ for (int i = 0; i < argc; ++i)
+ if (args[i] == "-t" || args[i] == "--tolerance")
+ tolerance = args[i + 1].toDouble();
+
+ char buffer[2048];
+ QImage actualImage;
+ QImage baselineImage;
+
+ while (fgets(buffer, sizeof(buffer), stdin)) {
+ // remove the CR
+ char* newLineCharacter = strchr(buffer, '\n');
+ if (newLineCharacter)
+ *newLineCharacter = '\0';
+
+ if (!strncmp("Content-Length: ", buffer, 16)) {
+ strtok(buffer, " ");
+ int imageSize = strtol(strtok(0, " "), 0, 10);
+
+ if (imageSize <= 0) {
+ fputs("error, image size must be specified.\n", stdout);
+ } else {
+ unsigned char buffer[2048];
+ QBuffer data;
+
+ // Read all the incoming chunks
+ data.open(QBuffer::WriteOnly);
+ while (imageSize > 0) {
+ size_t bytesToRead = qMin(imageSize, 2048);
+ size_t bytesRead = fread(buffer, 1, bytesToRead, stdin);
+ data.write(reinterpret_cast<const char*>(buffer), bytesRead);
+ imageSize -= static_cast<int>(bytesRead);
+ }
+
+ // Convert into QImage
+ QImage decodedImage;
+ decodedImage.loadFromData(data.data(), "PNG");
+ decodedImage.convertToFormat(QImage::Format_ARGB32);
+
+ // Place it in the right place
+ if (actualImage.isNull())
+ actualImage = decodedImage;
+ else
+ baselineImage = decodedImage;
+ }
+ }
+
+ if (!actualImage.isNull() && !baselineImage.isNull()) {
+
+ if (actualImage.size() != baselineImage.size()) {
+ fprintf(stderr, "error, test and reference image have different properties.\n");
+ fflush(stderr);
+ } else {
+
+ int w = actualImage.width();
+ int h = actualImage.height();
+ QImage diffImage(w, h, QImage::Format_ARGB32);
+
+ int count = 0;
+ qreal sum = 0;
+ qreal maxDistance = 0;
+
+ for (int x = 0; x < w; ++x)
+ for (int y = 0; y < h; ++y) {
+ QRgb pixel = actualImage.pixel(x, y);
+ QRgb basePixel = baselineImage.pixel(x, y);
+ qreal red = (qRed(pixel) - qRed(basePixel)) / static_cast<float>(qMax(255 - qRed(basePixel), qRed(basePixel)));
+ qreal green = (qGreen(pixel) - qGreen(basePixel)) / static_cast<float>(qMax(255 - qGreen(basePixel), qGreen(basePixel)));
+ qreal blue = (qBlue(pixel) - qBlue(basePixel)) / static_cast<float>(qMax(255 - qBlue(basePixel), qBlue(basePixel)));
+ qreal alpha = (qAlpha(pixel) - qAlpha(basePixel)) / static_cast<float>(qMax(255 - qAlpha(basePixel), qAlpha(basePixel)));
+ qreal distance = qSqrt(red * red + green * green + blue * blue + alpha * alpha) / 2.0f;
+ int gray = distance * qreal(255);
+ diffImage.setPixel(x, y, qRgb(gray, gray, gray));
+ if (distance >= 1 / qreal(255)) {
+ count++;
+ sum += distance;
+ maxDistance = qMax(maxDistance, distance);
+ }
+ }
+
+ qreal difference = 0;
+ if (count)
+ difference = 100 * sum / static_cast<qreal>(w * h);
+ if (difference <= tolerance) {
+ difference = 0;
+ } else {
+ difference = qRound(difference * 100) / 100;
+ difference = qMax(difference, qreal(0.01));
+ }
+
+ if (!count) {
+ fprintf(stdout, "diff: %01.2f%% passed\n", difference);
+ } else {
+ QBuffer buffer;
+ buffer.open(QBuffer::WriteOnly);
+ diffImage.save(&buffer, "PNG");
+ buffer.close();
+ const QByteArray &data = buffer.data();
+ printf("Content-Length: %lu\n", static_cast<unsigned long>(data.length()));
+
+ // We have to use the return value of fwrite to avoid "ignoring return value" gcc warning
+ // See https://bugs.webkit.org/show_bug.cgi?id=45384 for details.
+ if (fwrite(data.constData(), 1, data.length(), stdout)) {}
+
+ fprintf(stdout, "diff: %01.2f%% failed\n", difference);
+ }
+
+ fflush(stdout);
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/Tools/DumpRenderTree/qt/ImageDiff.pro b/Tools/DumpRenderTree/qt/ImageDiff.pro
new file mode 100644
index 0000000..74fabf8
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/ImageDiff.pro
@@ -0,0 +1,16 @@
+TARGET = ImageDiff
+CONFIG -= app_bundle
+
+isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../..
+include(../../../WebKit.pri)
+INCLUDEPATH += ../../../JavaScriptCore
+DESTDIR = $$OUTPUT_DIR/bin
+
+QT = core gui
+
+SOURCES = ImageDiff.cpp
+
+unix:!mac {
+ QMAKE_RPATHDIR = $$OUTPUT_DIR/lib $$QMAKE_RPATHDIR
+}
+
diff --git a/Tools/DumpRenderTree/qt/LayoutTestControllerQt.cpp b/Tools/DumpRenderTree/qt/LayoutTestControllerQt.cpp
new file mode 100644
index 0000000..b8cc9be
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/LayoutTestControllerQt.cpp
@@ -0,0 +1,834 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "config.h"
+#include "LayoutTestControllerQt.h"
+#include "../../../WebKit/qt/WebCoreSupport/DumpRenderTreeSupportQt.h"
+
+#include "DumpRenderTreeQt.h"
+#include "WorkQueue.h"
+#include "WorkQueueItemQt.h"
+#include <QDir>
+#include <QLocale>
+#include <qwebsettings.h>
+
+LayoutTestController::LayoutTestController(WebCore::DumpRenderTree* drt)
+ : QObject()
+ , m_drt(drt)
+{
+ qRegisterMetaType<QWebElement>("QWebElement");
+ reset();
+ DumpRenderTreeSupportQt::dumpNotification(true);
+}
+
+void LayoutTestController::reset()
+{
+ m_hasDumped = false;
+ m_loadFinished = false;
+ m_textDump = false;
+ m_dumpBackForwardList = false;
+ m_dumpChildrenAsText = false;
+ m_dumpChildFrameScrollPositions = false;
+ m_canOpenWindows = false;
+ m_waitForDone = false;
+ m_dumpTitleChanges = false;
+ m_dumpDatabaseCallbacks = false;
+ m_dumpApplicationCacheDelegateCallbacks = false;
+ m_dumpStatusCallbacks = false;
+ m_timeoutTimer.stop();
+ m_topLoadingFrame = 0;
+ m_waitForPolicy = false;
+ m_handleErrorPages = false;
+ m_webHistory = 0;
+ m_globalFlag = false;
+ m_userStyleSheetEnabled = false;
+ m_desktopNotificationAllowedOrigins.clear();
+ m_ignoreDesktopNotification = false;
+ m_isGeolocationPermissionSet = false;
+ m_isPrinting = false;
+ m_geolocationPermission = false;
+
+ DumpRenderTreeSupportQt::dumpEditingCallbacks(false);
+ DumpRenderTreeSupportQt::dumpFrameLoader(false);
+ DumpRenderTreeSupportQt::dumpUserGestureInFrameLoader(false);
+ DumpRenderTreeSupportQt::dumpResourceLoadCallbacks(false);
+ DumpRenderTreeSupportQt::dumpResourceResponseMIMETypes(false);
+ DumpRenderTreeSupportQt::setDeferMainResourceDataLoad(true);
+ DumpRenderTreeSupportQt::setWillSendRequestReturnsNullOnRedirect(false);
+ DumpRenderTreeSupportQt::setWillSendRequestReturnsNull(false);
+ DumpRenderTreeSupportQt::setWillSendRequestClearHeaders(QStringList());
+ DumpRenderTreeSupportQt::clearScriptWorlds();
+ DumpRenderTreeSupportQt::setCustomPolicyDelegate(false, false);
+ DumpRenderTreeSupportQt::dumpHistoryCallbacks(false);
+ DumpRenderTreeSupportQt::dumpVisitedLinksCallbacks(false);
+ setIconDatabaseEnabled(false);
+
+ emit hidePage();
+}
+
+void LayoutTestController::processWork()
+{
+ // qDebug() << ">>>processWork";
+
+ // if we didn't start a new load, then we finished all the commands, so we're ready to dump state
+ if (WorkQueue::shared()->processWork() && !shouldWaitUntilDone()) {
+ emit done();
+ m_hasDumped = true;
+ }
+}
+
+// Called on loadFinished on WebPage
+void LayoutTestController::maybeDump(bool success)
+{
+
+ // This can happen on any of the http/tests/security/window-events-*.html tests, where the test opens
+ // a new window, calls the unload and load event handlers on the window's page, and then immediately
+ // issues a notifyDone. Needs investigation.
+ if (!m_topLoadingFrame)
+ return;
+
+ // It is possible that we get called by windows created from the main page that have finished
+ // loading, so we don't ASSERT here. At the moment we do not gather results from such windows,
+ // but may need to in future.
+ if (sender() != m_topLoadingFrame->page())
+ return;
+
+ m_loadFinished = true;
+ // as the function is called on loadFinished, the test might
+ // already have dumped and thus no longer be active, thus
+ // bail out here.
+ if (m_hasDumped)
+ return;
+
+ WorkQueue::shared()->setFrozen(true); // first complete load freezes the queue for the rest of this test
+ if (WorkQueue::shared()->count())
+ QTimer::singleShot(0, this, SLOT(processWork()));
+ else if (!shouldWaitUntilDone()) {
+ if (success)
+ emit done();
+ m_hasDumped = true;
+ }
+}
+
+void LayoutTestController::waitUntilDone()
+{
+ //qDebug() << ">>>>waitForDone";
+ m_waitForDone = true;
+ m_timeoutTimer.start(30000, this);
+}
+
+QString LayoutTestController::counterValueForElementById(const QString& id)
+{
+ return DumpRenderTreeSupportQt::counterValueForElementById(m_drt->webPage()->mainFrame(), id);
+}
+
+void LayoutTestController::setViewModeMediaFeature(const QString& mode)
+{
+ m_drt->webPage()->setProperty("_q_viewMode", mode);
+}
+
+int LayoutTestController::webHistoryItemCount()
+{
+ if (!m_webHistory)
+ return -1;
+
+ // Subtract one here as our QWebHistory::count() includes the actual page,
+ // which is not considered in the DRT tests.
+ return m_webHistory->count() - 1;
+}
+
+void LayoutTestController::keepWebHistory()
+{
+ m_webHistory = m_drt->webPage()->history();
+}
+
+void LayoutTestController::notifyDone()
+{
+ qDebug() << ">>>>notifyDone";
+
+ if (!m_timeoutTimer.isActive())
+ return;
+
+ m_timeoutTimer.stop();
+ m_waitForDone = false;
+
+ // If the page has not finished loading (i.e. loadFinished() has not been emitted) then
+ // content created by the likes of document.write() JS methods will not be available yet.
+ // When the page has finished loading, maybeDump above will dump the results now that we have
+ // just set shouldWaitUntilDone to false.
+ if (!m_loadFinished)
+ return;
+
+ emit done();
+
+ // FIXME: investigate why always resetting these result in timeouts
+ m_hasDumped = true;
+ m_waitForPolicy = false;
+}
+
+int LayoutTestController::windowCount()
+{
+ return m_drt->windowCount();
+}
+
+void LayoutTestController::grantDesktopNotificationPermission(const QString& origin)
+{
+ QWebFrame* frame = m_drt->webPage()->mainFrame();
+ m_drt->webPage()->setFeaturePermission(frame, QWebPage::Notifications, QWebPage::PermissionGrantedByUser);
+ m_desktopNotificationAllowedOrigins.append(origin);
+}
+
+void LayoutTestController::ignoreDesktopNotificationPermissionRequests()
+{
+ m_ignoreDesktopNotification = true;
+}
+
+bool LayoutTestController::checkDesktopNotificationPermission(const QString& origin)
+{
+ return !m_ignoreDesktopNotification && m_desktopNotificationAllowedOrigins.contains(origin);
+}
+
+void LayoutTestController::simulateDesktopNotificationClick(const QString& title)
+{
+ DumpRenderTreeSupportQt::simulateDesktopNotificationClick(title);
+}
+
+void LayoutTestController::display()
+{
+ emit showPage();
+}
+
+void LayoutTestController::clearBackForwardList()
+{
+ m_drt->webPage()->history()->clear();
+}
+
+QString LayoutTestController::pathToLocalResource(const QString& url)
+{
+ // Function introduced in r28690.
+ return QDir::toNativeSeparators(url);
+}
+
+void LayoutTestController::dumpConfigurationForViewport(int availableWidth, int availableHeight)
+{
+ QString res = DumpRenderTreeSupportQt::viewportAsText(m_drt->webPage(), QSize(availableWidth, availableHeight));
+ fputs(qPrintable(res), stdout);
+}
+
+void LayoutTestController::dumpEditingCallbacks()
+{
+ qDebug() << ">>>dumpEditingCallbacks";
+ DumpRenderTreeSupportQt::dumpEditingCallbacks(true);
+}
+
+void LayoutTestController::dumpFrameLoadCallbacks()
+{
+ DumpRenderTreeSupportQt::dumpFrameLoader(true);
+}
+
+void LayoutTestController::dumpUserGestureInFrameLoadCallbacks()
+{
+ DumpRenderTreeSupportQt::dumpUserGestureInFrameLoader(true);
+}
+
+void LayoutTestController::dumpResourceLoadCallbacks()
+{
+ DumpRenderTreeSupportQt::dumpResourceLoadCallbacks(true);
+}
+
+void LayoutTestController::dumpResourceResponseMIMETypes()
+{
+ DumpRenderTreeSupportQt::dumpResourceResponseMIMETypes(true);
+}
+
+void LayoutTestController::dumpHistoryCallbacks()
+{
+ DumpRenderTreeSupportQt::dumpHistoryCallbacks(true);
+}
+
+void LayoutTestController::setWillSendRequestReturnsNullOnRedirect(bool enabled)
+{
+ DumpRenderTreeSupportQt::setWillSendRequestReturnsNullOnRedirect(enabled);
+}
+
+void LayoutTestController::setWillSendRequestReturnsNull(bool enabled)
+{
+ DumpRenderTreeSupportQt::setWillSendRequestReturnsNull(enabled);
+}
+
+void LayoutTestController::setWillSendRequestClearHeader(const QStringList& headers)
+{
+ DumpRenderTreeSupportQt::setWillSendRequestClearHeaders(headers);
+}
+
+void LayoutTestController::setDeferMainResourceDataLoad(bool defer)
+{
+ DumpRenderTreeSupportQt::setDeferMainResourceDataLoad(defer);
+}
+
+void LayoutTestController::queueBackNavigation(int howFarBackward)
+{
+ //qDebug() << ">>>queueBackNavigation" << howFarBackward;
+ for (int i = 0; i != howFarBackward; ++i)
+ WorkQueue::shared()->queue(new BackItem(1, m_drt->webPage()));
+}
+
+void LayoutTestController::queueForwardNavigation(int howFarForward)
+{
+ //qDebug() << ">>>queueForwardNavigation" << howFarForward;
+ for (int i = 0; i != howFarForward; ++i)
+ WorkQueue::shared()->queue(new ForwardItem(1, m_drt->webPage()));
+}
+
+void LayoutTestController::queueLoad(const QString& url, const QString& target)
+{
+ //qDebug() << ">>>queueLoad" << url << target;
+ QUrl mainResourceUrl = m_drt->webPage()->mainFrame()->url();
+ QString absoluteUrl = mainResourceUrl.resolved(QUrl(url)).toEncoded();
+ WorkQueue::shared()->queue(new LoadItem(absoluteUrl, target, m_drt->webPage()));
+}
+
+void LayoutTestController::queueLoadHTMLString(const QString& content, const QString& baseURL)
+{
+ WorkQueue::shared()->queue(new LoadHTMLStringItem(content, baseURL, m_drt->webPage()));
+}
+
+void LayoutTestController::queueReload()
+{
+ //qDebug() << ">>>queueReload";
+ WorkQueue::shared()->queue(new ReloadItem(m_drt->webPage()));
+}
+
+void LayoutTestController::queueLoadingScript(const QString& script)
+{
+ //qDebug() << ">>>queueLoadingScript" << script;
+ WorkQueue::shared()->queue(new LoadingScriptItem(script, m_drt->webPage()));
+}
+
+void LayoutTestController::queueNonLoadingScript(const QString& script)
+{
+ //qDebug() << ">>>queueNonLoadingScript" << script;
+ WorkQueue::shared()->queue(new NonLoadingScriptItem(script, m_drt->webPage()));
+}
+
+void LayoutTestController::provisionalLoad()
+{
+ QWebFrame* frame = qobject_cast<QWebFrame*>(sender());
+ if (!m_topLoadingFrame && !m_hasDumped)
+ m_topLoadingFrame = frame;
+}
+
+void LayoutTestController::timerEvent(QTimerEvent *ev)
+{
+ if (ev->timerId() == m_timeoutTimer.timerId()) {
+ const char* message = "FAIL: Timed out waiting for notifyDone to be called\n";
+ fprintf(stderr, "%s", message);
+ fprintf(stdout, "%s", message);
+ notifyDone();
+ } else
+ QObject::timerEvent(ev);
+}
+
+QString LayoutTestController::encodeHostName(const QString& host)
+{
+ QString encoded = QString::fromLatin1(QUrl::toAce(host + QLatin1String(".no")));
+ encoded.truncate(encoded.length() - 3); // strip .no
+ return encoded;
+}
+
+QString LayoutTestController::decodeHostName(const QString& host)
+{
+ QString decoded = QUrl::fromAce(host.toLatin1() + QByteArray(".no"));
+ decoded.truncate(decoded.length() - 3);
+ return decoded;
+}
+
+void LayoutTestController::setMediaType(const QString& type)
+{
+ DumpRenderTreeSupportQt::setMediaType(m_drt->webPage()->mainFrame(), type);
+}
+
+void LayoutTestController::closeWebInspector()
+{
+ DumpRenderTreeSupportQt::webInspectorClose(m_drt->webPage());
+ m_drt->webPage()->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, false);
+}
+
+void LayoutTestController::setDeveloperExtrasEnabled(bool enabled)
+{
+ m_drt->webPage()->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, enabled);
+}
+
+void LayoutTestController::setAsynchronousSpellCheckingEnabled(bool)
+{
+ // FIXME: Implement this.
+}
+
+void LayoutTestController::showWebInspector()
+{
+ m_drt->webPage()->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);
+ DumpRenderTreeSupportQt::webInspectorShow(m_drt->webPage());
+}
+
+void LayoutTestController::evaluateInWebInspector(long callId, const QString& script)
+{
+ DumpRenderTreeSupportQt::webInspectorExecuteScript(m_drt->webPage(), callId, script);
+}
+
+void LayoutTestController::setFrameFlatteningEnabled(bool enabled)
+{
+ DumpRenderTreeSupportQt::setFrameFlatteningEnabled(m_drt->webPage(), enabled);
+}
+
+void LayoutTestController::setAllowUniversalAccessFromFileURLs(bool enabled)
+{
+ m_drt->webPage()->settings()->setAttribute(QWebSettings::LocalContentCanAccessRemoteUrls, enabled);
+}
+
+void LayoutTestController::setAllowFileAccessFromFileURLs(bool enabled)
+{
+ m_drt->webPage()->settings()->setAttribute(QWebSettings::LocalContentCanAccessFileUrls, enabled);
+}
+
+void LayoutTestController::setAppCacheMaximumSize(unsigned long long quota)
+{
+ m_drt->webPage()->settings()->setOfflineWebApplicationCacheQuota(quota);
+}
+
+void LayoutTestController::setJavaScriptProfilingEnabled(bool enable)
+{
+ setDeveloperExtrasEnabled(enable);
+ DumpRenderTreeSupportQt::setJavaScriptProfilingEnabled(m_topLoadingFrame, enable);
+}
+
+void LayoutTestController::setTimelineProfilingEnabled(bool enable)
+{
+ DumpRenderTreeSupportQt::setTimelineProfilingEnabled(m_drt->webPage(), enable);
+}
+
+void LayoutTestController::setFixedContentsSize(int width, int height)
+{
+ m_topLoadingFrame->page()->setPreferredContentsSize(QSize(width, height));
+}
+
+void LayoutTestController::setPrivateBrowsingEnabled(bool enable)
+{
+ m_drt->webPage()->settings()->setAttribute(QWebSettings::PrivateBrowsingEnabled, enable);
+}
+
+void LayoutTestController::setSpatialNavigationEnabled(bool enable)
+{
+ m_drt->webPage()->settings()->setAttribute(QWebSettings::SpatialNavigationEnabled, enable);
+}
+
+void LayoutTestController::setPopupBlockingEnabled(bool enable)
+{
+ m_drt->webPage()->settings()->setAttribute(QWebSettings::JavascriptCanOpenWindows, !enable);
+}
+
+void LayoutTestController::setPluginsEnabled(bool flag)
+{
+ // FIXME: Implement
+}
+
+void LayoutTestController::setPOSIXLocale(const QString& locale)
+{
+ QLocale qlocale(locale);
+ QLocale::setDefault(qlocale);
+}
+
+void LayoutTestController::setWindowIsKey(bool isKey)
+{
+ m_drt->switchFocus(isKey);
+}
+
+void LayoutTestController::setMainFrameIsFirstResponder(bool isFirst)
+{
+ //FIXME: only need this for the moment: https://bugs.webkit.org/show_bug.cgi?id=32990
+}
+
+void LayoutTestController::setJavaScriptCanAccessClipboard(bool enable)
+{
+ m_drt->webPage()->settings()->setAttribute(QWebSettings::JavascriptCanAccessClipboard, enable);
+}
+
+void LayoutTestController::setXSSAuditorEnabled(bool enable)
+{
+ // Set XSSAuditingEnabled globally so that windows created by the test inherit it too.
+ // resetSettings() will call this to reset the page and global setting to false again.
+ // Needed by http/tests/security/xssAuditor/link-opens-new-window.html
+ QWebSettings* globalSettings = QWebSettings::globalSettings();
+ globalSettings->setAttribute(QWebSettings::XSSAuditingEnabled, enable);
+ m_drt->webPage()->settings()->setAttribute(QWebSettings::XSSAuditingEnabled, enable);
+}
+
+bool LayoutTestController::pauseAnimationAtTimeOnElementWithId(const QString& animationName,
+ double time,
+ const QString& elementId)
+{
+ QWebFrame* frame = m_drt->webPage()->mainFrame();
+ Q_ASSERT(frame);
+ return DumpRenderTreeSupportQt::pauseAnimation(frame, animationName, time, elementId);
+}
+
+bool LayoutTestController::pauseTransitionAtTimeOnElementWithId(const QString& propertyName,
+ double time,
+ const QString& elementId)
+{
+ QWebFrame* frame = m_drt->webPage()->mainFrame();
+ Q_ASSERT(frame);
+ return DumpRenderTreeSupportQt::pauseTransitionOfProperty(frame, propertyName, time, elementId);
+}
+
+bool LayoutTestController::sampleSVGAnimationForElementAtTime(const QString& animationId,
+ double time,
+ const QString& elementId)
+{
+ QWebFrame* frame = m_drt->webPage()->mainFrame();
+ Q_ASSERT(frame);
+ return DumpRenderTreeSupportQt::pauseSVGAnimation(frame, animationId, time, elementId);
+}
+
+unsigned LayoutTestController::numberOfActiveAnimations() const
+{
+ QWebFrame* frame = m_drt->webPage()->mainFrame();
+ Q_ASSERT(frame);
+ return DumpRenderTreeSupportQt::numberOfActiveAnimations(frame);
+}
+
+void LayoutTestController::suspendAnimations() const
+{
+ QWebFrame* frame = m_drt->webPage()->mainFrame();
+ Q_ASSERT(frame);
+ DumpRenderTreeSupportQt::suspendAnimations(frame);
+}
+
+void LayoutTestController::resumeAnimations() const
+{
+ QWebFrame* frame = m_drt->webPage()->mainFrame();
+ Q_ASSERT(frame);
+ DumpRenderTreeSupportQt::resumeAnimations(frame);
+}
+
+void LayoutTestController::disableImageLoading()
+{
+ m_drt->webPage()->settings()->setAttribute(QWebSettings::AutoLoadImages, false);
+}
+
+void LayoutTestController::dispatchPendingLoadRequests()
+{
+ // FIXME: Implement for testing fix for 6727495
+}
+
+void LayoutTestController::clearAllApplicationCaches()
+{
+ DumpRenderTreeSupportQt::clearAllApplicationCaches();
+}
+
+void LayoutTestController::setApplicationCacheOriginQuota(unsigned long long quota)
+{
+ if (!m_topLoadingFrame)
+ return;
+ m_topLoadingFrame->securityOrigin().setApplicationCacheQuota(quota);
+}
+
+void LayoutTestController::setDatabaseQuota(int size)
+{
+ if (!m_topLoadingFrame)
+ return;
+ m_topLoadingFrame->securityOrigin().setDatabaseQuota(size);
+}
+
+void LayoutTestController::clearAllDatabases()
+{
+ QWebDatabase::removeAllDatabases();
+}
+
+void LayoutTestController::addOriginAccessWhitelistEntry(const QString& sourceOrigin, const QString& destinationProtocol, const QString& destinationHost, bool allowDestinationSubdomains)
+{
+ DumpRenderTreeSupportQt::whiteListAccessFromOrigin(sourceOrigin, destinationProtocol, destinationHost, allowDestinationSubdomains);
+}
+
+void LayoutTestController::removeOriginAccessWhitelistEntry(const QString& sourceOrigin, const QString& destinationProtocol, const QString& destinationHost, bool allowDestinationSubdomains)
+{
+ DumpRenderTreeSupportQt::removeWhiteListAccessFromOrigin(sourceOrigin, destinationProtocol, destinationHost, allowDestinationSubdomains);
+}
+
+void LayoutTestController::setCustomPolicyDelegate(bool enabled, bool permissive)
+{
+ DumpRenderTreeSupportQt::setCustomPolicyDelegate(enabled, permissive);
+}
+
+void LayoutTestController::waitForPolicyDelegate()
+{
+ m_waitForPolicy = true;
+ waitUntilDone();
+}
+
+void LayoutTestController::overridePreference(const QString& name, const QVariant& value)
+{
+ QWebSettings* settings = m_topLoadingFrame->page()->settings();
+
+ if (name == "WebKitJavaScriptEnabled")
+ settings->setAttribute(QWebSettings::JavascriptEnabled, value.toBool());
+ else if (name == "WebKitTabToLinksPreferenceKey")
+ settings->setAttribute(QWebSettings::LinksIncludedInFocusChain, value.toBool());
+ else if (name == "WebKitOfflineWebApplicationCacheEnabled")
+ settings->setAttribute(QWebSettings::OfflineWebApplicationCacheEnabled, value.toBool());
+ else if (name == "WebKitDefaultFontSize")
+ settings->setFontSize(QWebSettings::DefaultFontSize, value.toInt());
+ else if (name == "WebKitUsesPageCachePreferenceKey")
+ QWebSettings::setMaximumPagesInCache(value.toInt());
+ else if (name == "WebKitEnableCaretBrowsing")
+ setCaretBrowsingEnabled(value.toBool());
+ else if (name == "WebKitPluginsEnabled")
+ settings->setAttribute(QWebSettings::PluginsEnabled, value.toBool());
+ else if (name == "WebKitWebGLEnabled")
+ settings->setAttribute(QWebSettings::WebGLEnabled, value.toBool());
+ else if (name == "WebKitHyperlinkAuditingEnabled")
+ settings->setAttribute(QWebSettings::HyperlinkAuditingEnabled, value.toBool());
+ else
+ printf("ERROR: LayoutTestController::overridePreference() does not support the '%s' preference\n",
+ name.toLatin1().data());
+}
+
+void LayoutTestController::setUserStyleSheetLocation(const QString& url)
+{
+ m_userStyleSheetLocation = QUrl(url);
+
+ if (m_userStyleSheetEnabled)
+ setUserStyleSheetEnabled(true);
+}
+
+void LayoutTestController::setCaretBrowsingEnabled(bool value)
+{
+ DumpRenderTreeSupportQt::setCaretBrowsingEnabled(m_drt->webPage(), value);
+}
+
+void LayoutTestController::setUserStyleSheetEnabled(bool enabled)
+{
+ m_userStyleSheetEnabled = enabled;
+
+ if (enabled)
+ m_drt->webPage()->settings()->setUserStyleSheetUrl(m_userStyleSheetLocation);
+ else
+ m_drt->webPage()->settings()->setUserStyleSheetUrl(QUrl());
+}
+
+void LayoutTestController::setDomainRelaxationForbiddenForURLScheme(bool forbidden, const QString& scheme)
+{
+ DumpRenderTreeSupportQt::setDomainRelaxationForbiddenForURLScheme(forbidden, scheme);
+}
+
+int LayoutTestController::workerThreadCount()
+{
+ return DumpRenderTreeSupportQt::workerThreadCount();
+}
+
+int LayoutTestController::pageNumberForElementById(const QString& id, float width, float height)
+{
+ // If no size specified, webpage viewport size is used
+ if (!width && !height) {
+ width = m_drt->webPage()->viewportSize().width();
+ height = m_drt->webPage()->viewportSize().height();
+ }
+
+ return DumpRenderTreeSupportQt::pageNumberForElementById(m_drt->webPage()->mainFrame(), id, width, height);
+}
+
+int LayoutTestController::numberOfPages(float width, float height)
+{
+ return DumpRenderTreeSupportQt::numberOfPages(m_drt->webPage()->mainFrame(), width, height);
+}
+
+bool LayoutTestController::callShouldCloseOnWebView()
+{
+ return DumpRenderTreeSupportQt::shouldClose(m_drt->webPage()->mainFrame());
+}
+
+void LayoutTestController::setScrollbarPolicy(const QString& orientation, const QString& policy)
+{
+ Qt::Orientation o;
+ Qt::ScrollBarPolicy p;
+
+ if (orientation == "vertical")
+ o = Qt::Vertical;
+ else if (orientation == "horizontal")
+ o = Qt::Horizontal;
+ else
+ return;
+
+ if (policy == "on")
+ p = Qt::ScrollBarAlwaysOn;
+ else if (policy == "auto")
+ p = Qt::ScrollBarAsNeeded;
+ else if (policy == "off")
+ p = Qt::ScrollBarAlwaysOff;
+ else
+ return;
+
+ m_drt->webPage()->mainFrame()->setScrollBarPolicy(o, p);
+}
+
+void LayoutTestController::setSmartInsertDeleteEnabled(bool enable)
+{
+ DumpRenderTreeSupportQt::setSmartInsertDeleteEnabled(m_drt->webPage(), enable);
+}
+
+void LayoutTestController::setSelectTrailingWhitespaceEnabled(bool enable)
+{
+ DumpRenderTreeSupportQt::setSelectTrailingWhitespaceEnabled(m_drt->webPage(), enable);
+}
+
+void LayoutTestController::execCommand(const QString& name, const QString& value)
+{
+ DumpRenderTreeSupportQt::executeCoreCommandByName(m_drt->webPage(), name, value);
+}
+
+bool LayoutTestController::isCommandEnabled(const QString& name) const
+{
+ return DumpRenderTreeSupportQt::isCommandEnabled(m_drt->webPage(), name);
+}
+
+bool LayoutTestController::findString(const QString& string, const QStringList& optionArray)
+{
+ return DumpRenderTreeSupportQt::findString(m_drt->webPage(), string, optionArray);
+}
+
+QString LayoutTestController::markerTextForListItem(const QWebElement& listItem)
+{
+ return DumpRenderTreeSupportQt::markerTextForListItem(listItem);
+}
+
+QVariantMap LayoutTestController::computedStyleIncludingVisitedInfo(const QWebElement& element) const
+{
+ return DumpRenderTreeSupportQt::computedStyleIncludingVisitedInfo(element);
+}
+
+bool LayoutTestController::elementDoesAutoCompleteForElementWithId(const QString& elementId)
+{
+ return DumpRenderTreeSupportQt::elementDoesAutoCompleteForElementWithId(m_drt->webPage()->mainFrame(), elementId);
+}
+
+void LayoutTestController::authenticateSession(const QString&, const QString&, const QString&)
+{
+ // FIXME: If there is a concept per-session (per-process) credential storage, the credentials should be added to it for later use.
+}
+
+void LayoutTestController::setIconDatabaseEnabled(bool enable)
+{
+ if (enable && !m_drt->persistentStoragePath().isEmpty())
+ QWebSettings::setIconDatabasePath(m_drt->persistentStoragePath());
+ else
+ QWebSettings::setIconDatabasePath(QString());
+}
+
+void LayoutTestController::setEditingBehavior(const QString& editingBehavior)
+{
+ DumpRenderTreeSupportQt::setEditingBehavior(m_drt->webPage(), editingBehavior);
+}
+
+void LayoutTestController::setMockDeviceOrientation(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma)
+{
+ DumpRenderTreeSupportQt::setMockDeviceOrientation(canProvideAlpha, alpha, canProvideBeta, beta, canProvideGamma, gamma);
+}
+
+void LayoutTestController::setGeolocationPermission(bool allow)
+{
+ setGeolocationPermissionCommon(allow);
+ emit geolocationPermissionSet();
+}
+
+void LayoutTestController::setGeolocationPermissionCommon(bool allow)
+{
+ m_isGeolocationPermissionSet = true;
+ m_geolocationPermission = allow;
+}
+
+void LayoutTestController::setMockGeolocationError(int code, const QString& message)
+{
+ DumpRenderTreeSupportQt::setMockGeolocationError(code, message);
+}
+
+void LayoutTestController::setMockGeolocationPosition(double latitude, double longitude, double accuracy)
+{
+ DumpRenderTreeSupportQt::setMockGeolocationPosition(latitude, longitude, accuracy);
+}
+
+void LayoutTestController::addMockSpeechInputResult(const QString& result, double confidence, const QString& language)
+{
+ // FIXME: Implement for speech input layout tests.
+ // See https://bugs.webkit.org/show_bug.cgi?id=39485.
+}
+
+void LayoutTestController::evaluateScriptInIsolatedWorld(int worldID, const QString& script)
+{
+ DumpRenderTreeSupportQt::evaluateScriptInIsolatedWorld(m_drt->webPage()->mainFrame(), worldID, script);
+}
+
+bool LayoutTestController::isPageBoxVisible(int pageIndex)
+{
+ return DumpRenderTreeSupportQt::isPageBoxVisible(m_drt->webPage()->mainFrame(), pageIndex);
+}
+
+QString LayoutTestController::pageSizeAndMarginsInPixels(int pageIndex, int width, int height, int marginTop, int marginRight, int marginBottom, int marginLeft)
+{
+ return DumpRenderTreeSupportQt::pageSizeAndMarginsInPixels(m_drt->webPage()->mainFrame(), pageIndex,
+ width, height, marginTop, marginRight, marginBottom, marginLeft);
+}
+
+QString LayoutTestController::pageProperty(const QString& propertyName, int pageNumber)
+{
+ return DumpRenderTreeSupportQt::pageProperty(m_drt->webPage()->mainFrame(), propertyName, pageNumber);
+}
+
+void LayoutTestController::addUserStyleSheet(const QString& sourceCode)
+{
+ DumpRenderTreeSupportQt::addUserStyleSheet(m_drt->webPage(), sourceCode);
+}
+
+void LayoutTestController::removeAllVisitedLinks()
+{
+ QWebHistory* history = m_drt->webPage()->history();
+ history->clear();
+ DumpRenderTreeSupportQt::dumpVisitedLinksCallbacks(true);
+}
+
+bool LayoutTestController::hasSpellingMarker(int, int)
+{
+ // FIXME: Implement.
+ return false;
+}
+
+QVariantList LayoutTestController::nodesFromRect(const QWebElement& document, int x, int y, unsigned top, unsigned right, unsigned bottom, unsigned left, bool ignoreClipping)
+{
+ return DumpRenderTreeSupportQt::nodesFromRect(document, x, y, top, right, bottom, left, ignoreClipping);
+}
+
+const unsigned LayoutTestController::maxViewWidth = 800;
+const unsigned LayoutTestController::maxViewHeight = 600;
diff --git a/Tools/DumpRenderTree/qt/LayoutTestControllerQt.h b/Tools/DumpRenderTree/qt/LayoutTestControllerQt.h
new file mode 100644
index 0000000..0048a7e
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/LayoutTestControllerQt.h
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LayoutTestControllerQt_h
+#define LayoutTestControllerQt_h
+
+#include <QBasicTimer>
+#include <QObject>
+#include <QSize>
+#include <QString>
+#include <QtDebug>
+#include <QTimer>
+#include <QTimerEvent>
+#include <QVariant>
+
+#include <qwebdatabase.h>
+#include <qwebelement.h>
+#include <qwebframe.h>
+#include <qwebhistory.h>
+#include <qwebpage.h>
+#include <qwebsecurityorigin.h>
+
+class QWebFrame;
+class DumpRenderTreeSupportQt;
+namespace WebCore {
+ class DumpRenderTree;
+}
+class LayoutTestController : public QObject {
+ Q_OBJECT
+ Q_PROPERTY(int webHistoryItemCount READ webHistoryItemCount)
+ Q_PROPERTY(int workerThreadCount READ workerThreadCount)
+ Q_PROPERTY(bool globalFlag READ globalFlag WRITE setGlobalFlag)
+public:
+ LayoutTestController(WebCore::DumpRenderTree* drt);
+
+ bool shouldDumpAsText() const { return m_textDump; }
+ bool shouldDumpBackForwardList() const { return m_dumpBackForwardList; }
+ bool shouldDumpChildrenAsText() const { return m_dumpChildrenAsText; }
+ bool shouldDumpChildFrameScrollPositions() const { return m_dumpChildFrameScrollPositions; }
+ bool shouldDumpDatabaseCallbacks() const { return m_dumpDatabaseCallbacks; }
+ bool shouldDumpApplicationCacheDelegateCallbacks() const { return m_dumpApplicationCacheDelegateCallbacks; }
+ bool shouldDumpStatusCallbacks() const { return m_dumpStatusCallbacks; }
+ bool shouldWaitUntilDone() const { return m_waitForDone; }
+ bool shouldHandleErrorPages() const { return m_handleErrorPages; }
+ bool canOpenWindows() const { return m_canOpenWindows; }
+ bool shouldDumpTitleChanges() const { return m_dumpTitleChanges; }
+ bool waitForPolicy() const { return m_waitForPolicy; }
+ bool ignoreReqestForPermission() const { return m_ignoreDesktopNotification; }
+ bool isPrinting() { return m_isPrinting; }
+
+ void reset();
+
+ static const unsigned int maxViewWidth;
+ static const unsigned int maxViewHeight;
+
+protected:
+ void timerEvent(QTimerEvent*);
+
+signals:
+ void done();
+
+ void showPage();
+ void hidePage();
+ void geolocationPermissionSet();
+
+public slots:
+ void maybeDump(bool ok);
+ void dumpAsText() { m_textDump = true; }
+ void dumpChildFramesAsText() { m_dumpChildrenAsText = true; }
+ void dumpChildFrameScrollPositions() { m_dumpChildFrameScrollPositions = true; }
+ void dumpDatabaseCallbacks() { m_dumpDatabaseCallbacks = true; }
+ void dumpApplicationCacheDelegateCallbacks() { m_dumpApplicationCacheDelegateCallbacks = true;}
+ void dumpStatusCallbacks() { m_dumpStatusCallbacks = true; }
+ void setCanOpenWindows() { m_canOpenWindows = true; }
+ void setPrinting() { m_isPrinting = true; }
+ void waitUntilDone();
+ QString counterValueForElementById(const QString& id);
+ int webHistoryItemCount();
+ void keepWebHistory();
+ void notifyDone();
+ void dumpBackForwardList() { m_dumpBackForwardList = true; }
+ bool globalFlag() const { return m_globalFlag; }
+ void setGlobalFlag(bool flag) { m_globalFlag = flag; }
+ void handleErrorPages() { m_handleErrorPages = true; }
+ void dumpEditingCallbacks();
+ void dumpFrameLoadCallbacks();
+ void dumpUserGestureInFrameLoadCallbacks();
+ void dumpResourceLoadCallbacks();
+ void dumpResourceResponseMIMETypes();
+ void dumpHistoryCallbacks();
+ void dumpConfigurationForViewport(int availableWidth, int availableHeight);
+ void setWillSendRequestReturnsNullOnRedirect(bool enabled);
+ void setWillSendRequestReturnsNull(bool enabled);
+ void setWillSendRequestClearHeader(const QStringList& headers);
+ void queueBackNavigation(int howFarBackward);
+ void queueForwardNavigation(int howFarForward);
+ void queueLoad(const QString& url, const QString& target = QString());
+ void queueLoadHTMLString(const QString& content, const QString& baseURL = QString());
+ void queueReload();
+ void queueLoadingScript(const QString& script);
+ void queueNonLoadingScript(const QString& script);
+ void provisionalLoad();
+ void setCloseRemainingWindowsWhenComplete(bool = false) {}
+ int windowCount();
+ void grantDesktopNotificationPermission(const QString& origin);
+ void ignoreDesktopNotificationPermissionRequests();
+ bool checkDesktopNotificationPermission(const QString& origin);
+ void simulateDesktopNotificationClick(const QString& title);
+ void display();
+ void clearBackForwardList();
+ QString pathToLocalResource(const QString& url);
+ void dumpTitleChanges() { m_dumpTitleChanges = true; }
+ QString encodeHostName(const QString& host);
+ QString decodeHostName(const QString& host);
+ void dumpSelectionRect() const {}
+ void setDeveloperExtrasEnabled(bool);
+ void setAsynchronousSpellCheckingEnabled(bool);
+ void showWebInspector();
+ void closeWebInspector();
+ void evaluateInWebInspector(long callId, const QString& script);
+ void removeAllVisitedLinks();
+
+ void setMediaType(const QString& type);
+ void setFrameFlatteningEnabled(bool enable);
+ void setAllowUniversalAccessFromFileURLs(bool enable);
+ void setAllowFileAccessFromFileURLs(bool enable);
+ void setAppCacheMaximumSize(unsigned long long quota);
+ void setJavaScriptProfilingEnabled(bool enable);
+ void setTimelineProfilingEnabled(bool enable);
+ void setFixedContentsSize(int width, int height);
+ void setPrivateBrowsingEnabled(bool enable);
+ void setSpatialNavigationEnabled(bool enabled);
+ void setPluginsEnabled(bool flag);
+ void setPopupBlockingEnabled(bool enable);
+ void setPOSIXLocale(const QString& locale);
+ void resetLoadFinished() { m_loadFinished = false; }
+ void setWindowIsKey(bool isKey);
+ void setMainFrameIsFirstResponder(bool isFirst);
+ void setDeferMainResourceDataLoad(bool);
+ void setJavaScriptCanAccessClipboard(bool enable);
+ void setXSSAuditorEnabled(bool enable);
+ void setCaretBrowsingEnabled(bool enable);
+ void setViewModeMediaFeature(const QString& mode);
+ void setSmartInsertDeleteEnabled(bool enable);
+ void setSelectTrailingWhitespaceEnabled(bool enable);
+ void execCommand(const QString& name, const QString& value = QString());
+ bool isCommandEnabled(const QString& name) const;
+ bool findString(const QString& string, const QStringList& optionArray);
+
+ bool pauseAnimationAtTimeOnElementWithId(const QString& animationName, double time, const QString& elementId);
+ bool pauseTransitionAtTimeOnElementWithId(const QString& propertyName, double time, const QString& elementId);
+ bool sampleSVGAnimationForElementAtTime(const QString& animationId, double time, const QString& elementId);
+ bool elementDoesAutoCompleteForElementWithId(const QString& elementId);
+
+ unsigned numberOfActiveAnimations() const;
+ void suspendAnimations() const;
+ void resumeAnimations() const;
+
+ void addOriginAccessWhitelistEntry(const QString& sourceOrigin, const QString& destinationProtocol, const QString& destinationHost, bool allowDestinationSubdomains);
+ void removeOriginAccessWhitelistEntry(const QString& sourceOrigin, const QString& destinationProtocol, const QString& destinationHost, bool allowDestinationSubdomains);
+
+ void dispatchPendingLoadRequests();
+ void disableImageLoading();
+
+ void clearAllApplicationCaches();
+ void setApplicationCacheOriginQuota(unsigned long long quota);
+
+ void setDatabaseQuota(int size);
+ void clearAllDatabases();
+ void setIconDatabaseEnabled(bool enable);
+
+ void setCustomPolicyDelegate(bool enabled, bool permissive = true);
+ void waitForPolicyDelegate();
+
+ void overridePreference(const QString& name, const QVariant& value);
+ void setUserStyleSheetLocation(const QString& url);
+ void setUserStyleSheetEnabled(bool enabled);
+ void setDomainRelaxationForbiddenForURLScheme(bool forbidden, const QString& scheme);
+ int workerThreadCount();
+ int pageNumberForElementById(const QString& id, float width = 0, float height = 0);
+ int numberOfPages(float width = maxViewWidth, float height = maxViewHeight);
+ bool callShouldCloseOnWebView();
+ // For now, this is a no-op. This may change depending on outcome of
+ // https://bugs.webkit.org/show_bug.cgi?id=33333
+ void setCallCloseOnWebViews() {}
+ // This is a no-op - it allows us to pass
+ // plugins/get-url-that-the-resource-load-delegate-will-disallow.html
+ // which is a Mac-specific test.
+ void addDisallowedURL(const QString&) {}
+
+ void setMockDeviceOrientation(bool canProvideAlpha, double alpha, bool canProvideBeta, double beta, bool canProvideGamma, double gamma);
+
+ void setMockGeolocationError(int code, const QString& message);
+ void setMockGeolocationPosition(double latitude, double longitude, double accuracy);
+ void setGeolocationPermission(bool allow);
+ bool isGeolocationPermissionSet() const { return m_isGeolocationPermissionSet; }
+ bool geolocationPermission() const { return m_geolocationPermission; }
+
+ void addMockSpeechInputResult(const QString& result, double confidence, const QString& language);
+
+ // Empty stub method to keep parity with object model exposed by global LayoutTestController.
+ void abortModal() {}
+ bool hasSpellingMarker(int from, int length);
+
+ QVariantList nodesFromRect(const QWebElement& document, int x, int y, unsigned top, unsigned right, unsigned bottom, unsigned left, bool ignoreClipping);
+
+ /*
+ Policy values: 'on', 'auto' or 'off'.
+ Orientation values: 'vertical' or 'horizontal'.
+ */
+ void setScrollbarPolicy(const QString& orientation, const QString& policy);
+
+ QString markerTextForListItem(const QWebElement& listItem);
+ QVariantMap computedStyleIncludingVisitedInfo(const QWebElement& element) const;
+
+ // Simulate a request an embedding application could make, populating per-session credential storage.
+ void authenticateSession(const QString& url, const QString& username, const QString& password);
+
+ void setEditingBehavior(const QString& editingBehavior);
+
+ void evaluateScriptInIsolatedWorld(int worldID, const QString& script);
+ bool isPageBoxVisible(int pageIndex);
+ QString pageSizeAndMarginsInPixels(int pageIndex, int width, int height, int marginTop, int marginRight, int marginBottom, int marginLeft);
+ QString pageProperty(const QString& propertyName, int pageNumber);
+ void addUserStyleSheet(const QString& sourceCode);
+
+private slots:
+ void processWork();
+
+private:
+ void setGeolocationPermissionCommon(bool allow);
+
+private:
+ bool m_hasDumped;
+ bool m_textDump;
+ bool m_dumpBackForwardList;
+ bool m_dumpChildrenAsText;
+ bool m_dumpChildFrameScrollPositions;
+ bool m_canOpenWindows;
+ bool m_waitForDone;
+ bool m_dumpTitleChanges;
+ bool m_dumpDatabaseCallbacks;
+ bool m_dumpApplicationCacheDelegateCallbacks;
+ bool m_dumpStatusCallbacks;
+ bool m_waitForPolicy;
+ bool m_handleErrorPages;
+ bool m_loadFinished;
+ bool m_globalFlag;
+ bool m_userStyleSheetEnabled;
+ bool m_isGeolocationPermissionSet;
+ bool m_isPrinting;
+ bool m_geolocationPermission;
+
+ QUrl m_userStyleSheetLocation;
+ QBasicTimer m_timeoutTimer;
+ QWebFrame* m_topLoadingFrame;
+ WebCore::DumpRenderTree* m_drt;
+ QWebHistory* m_webHistory;
+ QStringList m_desktopNotificationAllowedOrigins;
+ bool m_ignoreDesktopNotification;
+};
+
+#endif // LayoutTestControllerQt_h
diff --git a/Tools/DumpRenderTree/qt/PlainTextControllerQt.cpp b/Tools/DumpRenderTree/qt/PlainTextControllerQt.cpp
new file mode 100644
index 0000000..441a37c
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/PlainTextControllerQt.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2010 Robert Hogan <robert@roberthogan.net>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "config.h"
+#include "PlainTextControllerQt.h"
+
+#include "../../../WebKit/qt/WebCoreSupport/DumpRenderTreeSupportQt.h"
+#include <QApplication>
+#include <QInputMethodEvent>
+#include <QKeyEvent>
+
+PlainTextController::PlainTextController(QWebPage* parent)
+ : QObject(parent)
+{
+}
+
+QString PlainTextController::plainText(const QVariant& range)
+{
+ return DumpRenderTreeSupportQt::plainText(range);
+}
diff --git a/Tools/DumpRenderTree/qt/PlainTextControllerQt.h b/Tools/DumpRenderTree/qt/PlainTextControllerQt.h
new file mode 100644
index 0000000..e78e110
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/PlainTextControllerQt.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2010 Robert Hogan <robert@roberthogan.net>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef PlainTextControllerQt_h
+#define PlainTextControllerQt_h
+
+#include <QList>
+#include <QObject>
+#include <QString>
+#include <QVariant>
+
+#include "qwebpage.h"
+
+class PlainTextController : public QObject {
+ Q_OBJECT
+public:
+ PlainTextController(QWebPage* parent);
+
+public slots:
+ QString plainText(const QVariant& range);
+};
+
+#endif // PlainTextControllerQt_h
diff --git a/Tools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro b/Tools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro
new file mode 100644
index 0000000..de3cf6a
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro
@@ -0,0 +1,46 @@
+TEMPLATE = lib
+TARGET = TestNetscapePlugIn
+
+VPATH = ../../unix/TestNetscapePlugin ../../TestNetscapePlugIn
+isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../../..
+include(../../../../WebKit.pri)
+
+DESTDIR = $$OUTPUT_DIR/lib/plugins
+
+mac {
+ CONFIG += plugin
+ CONFIG += plugin_bundle
+ QMAKE_INFO_PLIST = ../../TestNetscapePlugIn/mac/Info.plist
+ QMAKE_PLUGIN_BUNDLE_NAME = $$TARGET
+ QMAKE_BUNDLE_LOCATION += "Contents/MacOS"
+
+ !build_pass:CONFIG += build_all
+ debug_and_release:TARGET = $$qtLibraryTarget($$TARGET)
+}
+
+INCLUDEPATH += ../../../../JavaScriptCore \
+ ../../unix/TestNetscapePlugin/ForwardingHeaders \
+ ../../unix/TestNetscapePlugin/ForwardingHeaders/WebKit \
+ ../../../../WebCore \
+ ../../../../WebCore/bridge \
+ ../../TestNetscapePlugIn
+
+SOURCES = PluginObject.cpp \
+ PluginTest.cpp \
+ TestObject.cpp \
+ Tests/DocumentOpenInDestroyStream.cpp \
+ Tests/EvaluateJSAfterRemovingPluginElement.cpp \
+ Tests/GetUserAgentWithNullNPPFromNPPNew.cpp \
+ Tests/NPRuntimeObjectFromDestroyedPlugin.cpp \
+ Tests/NPRuntimeRemoveProperty.cpp \
+ Tests/NullNPPGetValuePointer.cpp \
+ Tests/PassDifferentNPPStruct.cpp \
+ Tests/PluginScriptableNPObjectInvokeDefault.cpp
+
+mac {
+ SOURCES += ../../TestNetscapePlugIn/main.cpp
+ OBJECTIVE_SOURCES += PluginObjectMac.mm
+ LIBS += -framework Carbon -framework Cocoa -framework QuartzCore
+} else {
+ SOURCES += ../../unix/TestNetscapePlugin/TestNetscapePlugin.cpp
+}
diff --git a/Tools/DumpRenderTree/qt/TextInputControllerQt.cpp b/Tools/DumpRenderTree/qt/TextInputControllerQt.cpp
new file mode 100644
index 0000000..08d8850
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/TextInputControllerQt.cpp
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "config.h"
+#include "TextInputControllerQt.h"
+#include "../../../WebKit/qt/WebCoreSupport/DumpRenderTreeSupportQt.h"
+
+#include <QApplication>
+#include <QInputMethodEvent>
+#include <QKeyEvent>
+
+TextInputController::TextInputController(QWebPage* parent)
+ : QObject(parent)
+{
+}
+
+void TextInputController::doCommand(const QString& command)
+{
+ Qt::KeyboardModifiers modifiers = Qt::NoModifier;
+ int keycode = 0;
+ if (command == "moveBackwardAndModifySelection:") {
+ modifiers |= Qt::ShiftModifier;
+ keycode = Qt::Key_Left;
+ } else if (command =="moveDown:") {
+ keycode = Qt::Key_Down;
+ } else if (command =="moveDownAndModifySelection:") {
+ modifiers |= Qt::ShiftModifier;
+ keycode = Qt::Key_Down;
+ } else if (command =="moveForward:") {
+ keycode = Qt::Key_Right;
+ } else if (command =="moveForwardAndModifySelection:") {
+ modifiers |= Qt::ShiftModifier;
+ keycode = Qt::Key_Right;
+ } else if (command =="moveLeft:") {
+ keycode = Qt::Key_Left;
+ } else if (command =="moveLeftAndModifySelection:") {
+ modifiers |= Qt::ShiftModifier;
+ keycode = Qt::Key_Left;
+ } else if (command =="moveRight:") {
+ keycode = Qt::Key_Right;
+ } else if (command =="moveRightAndModifySelection:") {
+ modifiers |= Qt::ShiftModifier;
+ keycode = Qt::Key_Right;
+ } else if (command =="moveToBeginningOfDocument:") {
+ modifiers |= Qt::ControlModifier;
+ keycode = Qt::Key_Home;
+ } else if (command =="moveToBeginningOfLine:") {
+ keycode = Qt::Key_Home;
+// } else if (command =="moveToBeginningOfParagraph:") {
+ } else if (command =="moveToEndOfDocument:") {
+ modifiers |= Qt::ControlModifier;
+ keycode = Qt::Key_End;
+ } else if (command =="moveToEndOfLine:") {
+ keycode = Qt::Key_End;
+// } else if (command =="moveToEndOfParagraph:") {
+ } else if (command =="moveUp:") {
+ keycode = Qt::Key_Up;
+ } else if (command =="moveUpAndModifySelection:") {
+ modifiers |= Qt::ShiftModifier;
+ keycode = Qt::Key_Up;
+ } else if (command =="moveWordBackward:") {
+ modifiers |= Qt::ControlModifier;
+ keycode = Qt::Key_Up;
+ } else if (command =="moveWordBackwardAndModifySelection:") {
+ modifiers |= Qt::ShiftModifier;
+ modifiers |= Qt::ControlModifier;
+ keycode = Qt::Key_Left;
+ } else if (command =="moveWordForward:") {
+ modifiers |= Qt::ControlModifier;
+ keycode = Qt::Key_Right;
+ } else if (command =="moveWordForwardAndModifySelection:") {
+ modifiers |= Qt::ControlModifier;
+ modifiers |= Qt::ShiftModifier;
+ keycode = Qt::Key_Right;
+ } else if (command =="moveWordLeft:") {
+ modifiers |= Qt::ControlModifier;
+ keycode = Qt::Key_Left;
+ } else if (command =="moveWordRight:") {
+ modifiers |= Qt::ControlModifier;
+ keycode = Qt::Key_Left;
+ } else if (command =="moveWordRightAndModifySelection:") {
+ modifiers |= Qt::ShiftModifier;
+ modifiers |= Qt::ControlModifier;
+ keycode = Qt::Key_Right;
+ } else if (command =="moveWordLeftAndModifySelection:") {
+ modifiers |= Qt::ShiftModifier;
+ modifiers |= Qt::ControlModifier;
+ keycode = Qt::Key_Left;
+ } else if (command =="pageDown:") {
+ keycode = Qt::Key_PageDown;
+ } else if (command =="pageUp:") {
+ keycode = Qt::Key_PageUp;
+ } else if (command == "deleteWordBackward:") {
+ modifiers |= Qt::ControlModifier;
+ keycode = Qt::Key_Backspace;
+ } else if (command == "deleteBackward:") {
+ keycode = Qt::Key_Backspace;
+ } else if (command == "deleteForward:") {
+ keycode = Qt::Key_Delete;
+ }
+
+ QKeyEvent event(QEvent::KeyPress, keycode, modifiers);
+ QApplication::sendEvent(parent(), &event);
+ QKeyEvent event2(QEvent::KeyRelease, keycode, modifiers);
+ QApplication::sendEvent(parent(), &event2);
+}
+
+void TextInputController::setMarkedText(const QString& string, int start, int end)
+{
+ QList<QInputMethodEvent::Attribute> attributes;
+ QInputMethodEvent::Attribute selection(QInputMethodEvent::Selection, start, end, QVariant());
+ attributes << selection;
+ QInputMethodEvent event(string, attributes);
+ QApplication::sendEvent(parent(), &event);
+}
+
+void TextInputController::insertText(const QString& string)
+{
+ QList<QInputMethodEvent::Attribute> attributes;
+ QInputMethodEvent event(string, attributes);
+ event.setCommitString(string);
+ QApplication::sendEvent(parent(), &event);
+}
+
+QVariantList TextInputController::selectedRange()
+{
+ return DumpRenderTreeSupportQt::selectedRange(qobject_cast<QWebPage*>(parent()));
+}
+
+QVariantList TextInputController::firstRectForCharacterRange(int location, int length)
+{
+ return DumpRenderTreeSupportQt::firstRectForCharacterRange(qobject_cast<QWebPage*>(parent()), location, length);
+}
diff --git a/Tools/DumpRenderTree/qt/TextInputControllerQt.h b/Tools/DumpRenderTree/qt/TextInputControllerQt.h
new file mode 100644
index 0000000..0210984
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/TextInputControllerQt.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef TextInputControllerQt_h
+#define TextInputControllerQt_h
+
+#include <QList>
+#include <QObject>
+#include <QVariant>
+#include <QString>
+#include "qwebpage.h"
+
+class TextInputController : public QObject {
+ Q_OBJECT
+public:
+ TextInputController(QWebPage* parent);
+
+public slots:
+ void doCommand(const QString& command);
+ void setMarkedText(const QString& string, int start, int end);
+// bool hasMarkedText();
+// void unmarkText();
+// QList<int> markedRange();
+ QVariantList selectedRange();
+// void validAttributesForMarkedText();
+ void insertText(const QString& string);
+ QVariantList firstRectForCharacterRange(int location, int length);
+// void characterIndexForPoint(int, int);
+// void substringFromRange(int, int);
+// void conversationIdentifier();
+};
+#endif // TextInputControllerQt_h
diff --git a/Tools/DumpRenderTree/qt/WorkQueueItemQt.cpp b/Tools/DumpRenderTree/qt/WorkQueueItemQt.cpp
new file mode 100644
index 0000000..d1baf08
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/WorkQueueItemQt.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "config.h"
+#include "WorkQueueItemQt.h"
+
+QWebFrame* findFrameNamed(const QString& frameName, QWebFrame* frame)
+{
+ if (frame->frameName() == frameName)
+ return frame;
+
+ foreach (QWebFrame* childFrame, frame->childFrames())
+ if (QWebFrame* f = findFrameNamed(frameName, childFrame))
+ return f;
+
+ return 0;
+}
+
+bool LoadItem::invoke() const
+{
+ //qDebug() << ">>>LoadItem::invoke";
+ Q_ASSERT(m_webPage);
+
+ QWebFrame* frame = 0;
+ const QString t = target();
+ if (t.isEmpty())
+ frame = m_webPage->mainFrame();
+ else
+ frame = findFrameNamed(t, m_webPage->mainFrame());
+
+ if (!frame)
+ return false;
+
+ frame->load(url());
+ return true;
+}
+
+bool LoadHTMLStringItem::invoke() const
+{
+ Q_ASSERT(m_webPage);
+
+ QWebFrame* frame = m_webPage->mainFrame();
+ if (!frame)
+ return false;
+
+ frame->setHtml(m_content, QUrl(m_baseURL));
+ return true;
+}
+
+bool ReloadItem::invoke() const
+{
+ //qDebug() << ">>>ReloadItem::invoke";
+ Q_ASSERT(m_webPage);
+ m_webPage->triggerAction(QWebPage::Reload);
+ return true;
+}
+
+bool ScriptItem::invoke() const
+{
+ //qDebug() << ">>>ScriptItem::invoke";
+ Q_ASSERT(m_webPage);
+ m_webPage->mainFrame()->evaluateJavaScript(script());
+ return true;
+}
+
+bool BackForwardItem::invoke() const
+{
+ //qDebug() << ">>>BackForwardItem::invoke";
+ Q_ASSERT(m_webPage);
+ if (!m_howFar)
+ return false;
+
+ if (m_howFar > 0) {
+ for (int i = 0; i != m_howFar; ++i)
+ m_webPage->triggerAction(QWebPage::Forward);
+ } else {
+ for (int i = 0; i != m_howFar; --i)
+ m_webPage->triggerAction(QWebPage::Back);
+ }
+ return true;
+}
diff --git a/Tools/DumpRenderTree/qt/WorkQueueItemQt.h b/Tools/DumpRenderTree/qt/WorkQueueItemQt.h
new file mode 100644
index 0000000..97c9b04
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/WorkQueueItemQt.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WorkQueueItemQt_h
+#define WorkQueueItemQt_h
+
+#include <QPointer>
+#include <QString>
+#include <qwebframe.h>
+#include <qwebpage.h>
+
+class WorkQueueItem {
+public:
+ WorkQueueItem(QWebPage *page) : m_webPage(page) {}
+ virtual ~WorkQueueItem() { }
+ virtual bool invoke() const = 0;
+
+protected:
+ QPointer<QWebPage> m_webPage;
+};
+
+class LoadItem : public WorkQueueItem {
+public:
+ LoadItem(const QString &url, const QString &target, QWebPage *page)
+ : WorkQueueItem(page)
+ , m_url(url)
+ , m_target(target)
+ {
+ }
+
+ QString url() const { return m_url; }
+ QString target() const { return m_target; }
+
+ virtual bool invoke() const;
+
+private:
+ QString m_url;
+ QString m_target;
+};
+
+class LoadHTMLStringItem : public WorkQueueItem {
+public:
+ LoadHTMLStringItem(const QString& content, const QString &baseURL, QWebPage *page)
+ : WorkQueueItem(page)
+ , m_content(content)
+ , m_baseURL(baseURL)
+ {
+ }
+
+private:
+ virtual bool invoke() const;
+
+ QString m_content;
+ QString m_baseURL;
+};
+
+class ReloadItem : public WorkQueueItem {
+public:
+ ReloadItem(QWebPage *page)
+ : WorkQueueItem(page)
+ {
+ }
+ virtual bool invoke() const;
+};
+
+class ScriptItem : public WorkQueueItem {
+public:
+ ScriptItem(const QString &script, QWebPage *page)
+ : WorkQueueItem(page)
+ , m_script(script)
+ {
+ }
+
+ QString script() const { return m_script; }
+
+ virtual bool invoke() const;
+
+private:
+ QString m_script;
+};
+
+class LoadingScriptItem : public ScriptItem {
+public:
+ LoadingScriptItem(const QString& script, QWebPage* page)
+ : ScriptItem(script, page)
+ {
+ }
+
+ virtual bool invoke() const { return ScriptItem::invoke(); }
+};
+
+class NonLoadingScriptItem : public ScriptItem {
+public:
+ NonLoadingScriptItem(const QString& script, QWebPage* page)
+ : ScriptItem(script, page)
+ {
+ }
+
+ virtual bool invoke() const { ScriptItem::invoke(); return false; }
+};
+
+
+class BackForwardItem : public WorkQueueItem {
+public:
+ virtual bool invoke() const;
+
+protected:
+ BackForwardItem(int howFar, QWebPage *page)
+ : WorkQueueItem(page)
+ , m_howFar(howFar)
+ {
+ }
+
+ int m_howFar;
+};
+
+class BackItem : public BackForwardItem {
+public:
+ BackItem(unsigned howFar, QWebPage *page)
+ : BackForwardItem(-howFar, page)
+ {
+ }
+};
+
+class ForwardItem : public BackForwardItem {
+public:
+ ForwardItem(unsigned howFar, QWebPage *page)
+ : BackForwardItem(howFar, page)
+ {
+ }
+};
+
+#endif // !defined(WorkQueueItemQt_h)
diff --git a/Tools/DumpRenderTree/qt/fonts.conf b/Tools/DumpRenderTree/qt/fonts.conf
new file mode 100644
index 0000000..3540c47
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/fonts.conf
@@ -0,0 +1,258 @@
+<?xml version="1.0"?>
+<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
+<fontconfig>
+
+<!--
+ Accept deprecated 'mono' alias, replacing it with 'monospace'
+-->
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>mono</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>monospace</string>
+ </edit>
+ </match>
+
+<!--
+ Accept alternate 'sans serif' spelling, replacing it with 'sans-serif'
+-->
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>sans serif</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>sans-serif</string>
+ </edit>
+ </match>
+
+<!--
+ Accept deprecated 'sans' alias, replacing it with 'sans-serif'
+-->
+ <match target="pattern">
+ <test qual="any" name="family">
+ <string>sans</string>
+ </test>
+ <edit name="family" mode="assign">
+ <string>sans-serif</string>
+ </edit>
+ </match>
+
+
+ <config>
+<!--
+ These are the default Unicode chars that are expected to be blank
+ in fonts. All other blank chars are assumed to be broken and
+ won't appear in the resulting charsets
+ -->
+ <blank>
+ <int>0x0020</int> <!-- SPACE -->
+ <int>0x00A0</int> <!-- NO-BREAK SPACE -->
+ <int>0x00AD</int> <!-- SOFT HYPHEN -->
+ <int>0x034F</int> <!-- COMBINING GRAPHEME JOINER -->
+ <int>0x0600</int> <!-- ARABIC NUMBER SIGN -->
+ <int>0x0601</int> <!-- ARABIC SIGN SANAH -->
+ <int>0x0602</int> <!-- ARABIC FOOTNOTE MARKER -->
+ <int>0x0603</int> <!-- ARABIC SIGN SAFHA -->
+ <int>0x06DD</int> <!-- ARABIC END OF AYAH -->
+ <int>0x070F</int> <!-- SYRIAC ABBREVIATION MARK -->
+ <int>0x115F</int> <!-- HANGUL CHOSEONG FILLER -->
+ <int>0x1160</int> <!-- HANGUL JUNGSEONG FILLER -->
+ <int>0x1680</int> <!-- OGHAM SPACE MARK -->
+ <int>0x17B4</int> <!-- KHMER VOWEL INHERENT AQ -->
+ <int>0x17B5</int> <!-- KHMER VOWEL INHERENT AA -->
+ <int>0x180E</int> <!-- MONGOLIAN VOWEL SEPARATOR -->
+ <int>0x2000</int> <!-- EN QUAD -->
+ <int>0x2001</int> <!-- EM QUAD -->
+ <int>0x2002</int> <!-- EN SPACE -->
+ <int>0x2003</int> <!-- EM SPACE -->
+ <int>0x2004</int> <!-- THREE-PER-EM SPACE -->
+ <int>0x2005</int> <!-- FOUR-PER-EM SPACE -->
+ <int>0x2006</int> <!-- SIX-PER-EM SPACE -->
+ <int>0x2007</int> <!-- FIGURE SPACE -->
+ <int>0x2008</int> <!-- PUNCTUATION SPACE -->
+ <int>0x2009</int> <!-- THIN SPACE -->
+ <int>0x200A</int> <!-- HAIR SPACE -->
+ <int>0x200B</int> <!-- ZERO WIDTH SPACE -->
+ <int>0x200C</int> <!-- ZERO WIDTH NON-JOINER -->
+ <int>0x200D</int> <!-- ZERO WIDTH JOINER -->
+ <int>0x200E</int> <!-- LEFT-TO-RIGHT MARK -->
+ <int>0x200F</int> <!-- RIGHT-TO-LEFT MARK -->
+ <int>0x2028</int> <!-- LINE SEPARATOR -->
+ <int>0x2029</int> <!-- PARAGRAPH SEPARATOR -->
+ <int>0x202A</int> <!-- LEFT-TO-RIGHT EMBEDDING -->
+ <int>0x202B</int> <!-- RIGHT-TO-LEFT EMBEDDING -->
+ <int>0x202C</int> <!-- POP DIRECTIONAL FORMATTING -->
+ <int>0x202D</int> <!-- LEFT-TO-RIGHT OVERRIDE -->
+ <int>0x202E</int> <!-- RIGHT-TO-LEFT OVERRIDE -->
+ <int>0x202F</int> <!-- NARROW NO-BREAK SPACE -->
+ <int>0x205F</int> <!-- MEDIUM MATHEMATICAL SPACE -->
+ <int>0x2060</int> <!-- WORD JOINER -->
+ <int>0x2061</int> <!-- FUNCTION APPLICATION -->
+ <int>0x2062</int> <!-- INVISIBLE TIMES -->
+ <int>0x2063</int> <!-- INVISIBLE SEPARATOR -->
+ <int>0x206A</int> <!-- INHIBIT SYMMETRIC SWAPPING -->
+ <int>0x206B</int> <!-- ACTIVATE SYMMETRIC SWAPPING -->
+ <int>0x206C</int> <!-- INHIBIT ARABIC FORM SHAPING -->
+ <int>0x206D</int> <!-- ACTIVATE ARABIC FORM SHAPING -->
+ <int>0x206E</int> <!-- NATIONAL DIGIT SHAPES -->
+ <int>0x206F</int> <!-- NOMINAL DIGIT SHAPES -->
+ <int>0x3000</int> <!-- IDEOGRAPHIC SPACE -->
+ <int>0x3164</int> <!-- HANGUL FILLER -->
+ <int>0xFEFF</int> <!-- ZERO WIDTH NO-BREAK SPACE -->
+ <int>0xFFA0</int> <!-- HALFWIDTH HANGUL FILLER -->
+ <int>0xFFF9</int> <!-- INTERLINEAR ANNOTATION ANCHOR -->
+ <int>0xFFFA</int> <!-- INTERLINEAR ANNOTATION SEPARATOR -->
+ <int>0xFFFB</int> <!-- INTERLINEAR ANNOTATION TERMINATOR -->
+ </blank>
+<!--
+ Rescan configuration every 30 seconds when FcFontSetList is called
+ -->
+ <rescan>
+ <int>30</int>
+ </rescan>
+ </config>
+
+<!--
+ URW provides metric and shape compatible fonts for these 10 Adobe families.
+
+ However, these fonts are quite ugly and do not render well on-screen,
+ so we avoid matching them if the application said `anymetrics'; in that
+ case, a more generic font with different metrics but better appearance
+ will be used.
+ -->
+ <match target="pattern">
+ <test name="family">
+ <string>Avant Garde</string>
+ </test>
+ <test name="anymetrics" qual="all" compare="not_eq">
+ <bool>true</bool>
+ </test>
+ <edit name="family" mode="append">
+ <string>URW Gothic L</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test name="family">
+ <string>Bookman</string>
+ </test>
+ <test name="anymetrics" qual="all" compare="not_eq">
+ <bool>true</bool>
+ </test>
+ <edit name="family" mode="append">
+ <string>URW Bookman L</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test name="family">
+ <string>Courier</string>
+ </test>
+ <test name="anymetrics" qual="all" compare="not_eq">
+ <bool>true</bool>
+ </test>
+ <edit name="family" mode="append">
+ <string>Nimbus Mono L</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test name="family">
+ <string>Helvetica</string>
+ </test>
+ <test name="anymetrics" qual="all" compare="not_eq">
+ <bool>true</bool>
+ </test>
+ <edit name="family" mode="append">
+ <string>Nimbus Sans L</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test name="family">
+ <string>New Century Schoolbook</string>
+ </test>
+ <test name="anymetrics" qual="all" compare="not_eq">
+ <bool>true</bool>
+ </test>
+ <edit name="family" mode="append">
+ <string>Century Schoolbook L</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test name="family">
+ <string>Palatino</string>
+ </test>
+ <test name="anymetrics" qual="all" compare="not_eq">
+ <bool>true</bool>
+ </test>
+ <edit name="family" mode="append">
+ <string>URW Palladio L</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test name="family">
+ <string>Times</string>
+ </test>
+ <test name="anymetrics" qual="all" compare="not_eq">
+ <bool>true</bool>
+ </test>
+ <edit name="family" mode="append">
+ <string>Nimbus Roman No9 L</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test name="family">
+ <string>Zapf Chancery</string>
+ </test>
+ <test name="anymetrics" qual="all" compare="not_eq">
+ <bool>true</bool>
+ </test>
+ <edit name="family" mode="append">
+ <string>URW Chancery L</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test name="family">
+ <string>Zapf Dingbats</string>
+ </test>
+ <test name="anymetrics" qual="all" compare="not_eq">
+ <bool>true</bool>
+ </test>
+ <edit name="family" mode="append">
+ <string>Dingbats</string>
+ </edit>
+ </match>
+ <match target="pattern">
+ <test name="family">
+ <string>Symbol</string>
+ </test>
+ <test name="anymetrics" qual="all" compare="not_eq">
+ <bool>true</bool>
+ </test>
+ <edit name="family" mode="append" binding="same">
+ <string>Standard Symbols L</string>
+ </edit>
+ </match>
+
+<!--
+ Serif faces
+ -->
+ <alias>
+ <family>Nimbus Roman No9 L</family>
+ <default><family>serif</family></default>
+ </alias>
+<!--
+ Sans-serif faces
+ -->
+ <alias>
+ <family>Nimbus Sans L</family>
+ <default><family>sans-serif</family></default>
+ </alias>
+<!--
+ Monospace faces
+ -->
+ <alias>
+ <family>Nimbus Mono L</family>
+ <default><family>monospace</family></default>
+ </alias>
+
+
+</fontconfig>
diff --git a/Tools/DumpRenderTree/qt/fonts/AHEM____.TTF b/Tools/DumpRenderTree/qt/fonts/AHEM____.TTF
new file mode 100644
index 0000000..ac81cb0
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/fonts/AHEM____.TTF
Binary files differ
diff --git a/Tools/DumpRenderTree/qt/main.cpp b/Tools/DumpRenderTree/qt/main.cpp
new file mode 100644
index 0000000..8349d73
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/main.cpp
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "DumpRenderTreeQt.h"
+
+#include <wtf/AlwaysInline.h>
+
+#include <qstringlist.h>
+#include <qapplication.h>
+#include <qurl.h>
+#include <qdir.h>
+#include <qdebug.h>
+#include <qfont.h>
+#include <qwebdatabase.h>
+#include <qtimer.h>
+#include <qwindowsstyle.h>
+
+#ifdef Q_WS_X11
+#include <qx11info_x11.h>
+#include <fontconfig/fontconfig.h>
+#endif
+
+#ifdef Q_OS_WIN
+#include <io.h>
+#include <fcntl.h>
+#endif
+
+#include <limits.h>
+#include <signal.h>
+
+#if defined(__GLIBC__)
+#include <execinfo.h>
+#endif
+
+void messageHandler(QtMsgType type, const char *message)
+{
+ if (type == QtCriticalMsg) {
+ fprintf(stderr, "%s\n", message);
+ return;
+ }
+ // do nothing
+}
+
+QString get_backtrace() {
+ QString s;
+
+#if defined(__GLIBC__)
+ void* array[256];
+ size_t size; /* number of stack frames */
+
+ size = backtrace(array, 256);
+
+ if (!size)
+ return s;
+
+ char** strings = backtrace_symbols(array, size);
+ for (int i = 0; i < int(size); ++i) {
+ s += QString::number(i) +
+ QLatin1String(": ") +
+ QLatin1String(strings[i]) + QLatin1String("\n");
+ }
+
+ if (strings)
+ free (strings);
+#endif
+
+ return s;
+}
+
+#if HAVE(SIGNAL_H)
+static NO_RETURN void crashHandler(int sig)
+{
+ fprintf(stderr, "%s\n", strsignal(sig));
+ fprintf(stderr, "%s\n", get_backtrace().toLatin1().constData());
+ exit(128 + sig);
+}
+#endif
+
+int main(int argc, char* argv[])
+{
+#ifdef Q_OS_WIN
+ _setmode(1, _O_BINARY);
+ _setmode(2, _O_BINARY);
+#endif
+
+#ifdef Q_WS_X11
+ FcInit();
+ WebCore::DumpRenderTree::initializeFonts();
+#endif
+
+ QApplication::setGraphicsSystem("raster");
+ QApplication::setStyle(new QWindowsStyle);
+
+ QFont f("Sans Serif");
+ f.setPointSize(9);
+ f.setWeight(QFont::Normal);
+ f.setStyle(QFont::StyleNormal);
+ QApplication::setFont(f);
+
+ QApplication app(argc, argv);
+#ifdef Q_WS_X11
+ QX11Info::setAppDpiY(0, 96);
+ QX11Info::setAppDpiX(0, 96);
+#endif
+
+#if HAVE(SIGNAL_H)
+ signal(SIGILL, crashHandler); /* 4: illegal instruction (not reset when caught) */
+ signal(SIGTRAP, crashHandler); /* 5: trace trap (not reset when caught) */
+ signal(SIGFPE, crashHandler); /* 8: floating point exception */
+ signal(SIGBUS, crashHandler); /* 10: bus error */
+ signal(SIGSEGV, crashHandler); /* 11: segmentation violation */
+ signal(SIGSYS, crashHandler); /* 12: bad argument to system call */
+ signal(SIGPIPE, crashHandler); /* 13: write on a pipe with no reader */
+ signal(SIGXCPU, crashHandler); /* 24: exceeded CPU time limit */
+ signal(SIGXFSZ, crashHandler); /* 25: exceeded file size limit */
+#endif
+
+ QStringList args = app.arguments();
+ if (args.count() < 2) {
+ qDebug() << "Usage: DumpRenderTree [-v|--pixel-tests] filename [filename2..n]";
+ qDebug() << "Or folder containing test files: DumpRenderTree [-v|--pixel-tests] dirpath";
+ exit(0);
+ }
+
+ // Suppress debug output from Qt if not started with -v
+ if (!args.contains(QLatin1String("-v")))
+ qInstallMsgHandler(messageHandler);
+
+ WebCore::DumpRenderTree dumper;
+
+ if (args.contains(QLatin1String("--pixel-tests")))
+ dumper.setDumpPixels(true);
+
+ QWebDatabase::removeAllDatabases();
+
+ if (args.contains(QLatin1String("-"))) {
+ QObject::connect(&dumper, SIGNAL(ready()), &dumper, SLOT(readLine()), Qt::QueuedConnection);
+ QTimer::singleShot(0, &dumper, SLOT(readLine()));
+ } else
+ dumper.processArgsLine(args);
+
+ return app.exec();
+
+#ifdef Q_WS_X11
+ FcConfigSetCurrent(0);
+#endif
+}
diff --git a/Tools/DumpRenderTree/qt/testplugin.cpp b/Tools/DumpRenderTree/qt/testplugin.cpp
new file mode 100644
index 0000000..d5b8bc7
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/testplugin.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "testplugin.h"
+
+TestPlugin::TestPlugin(QObject *parent)
+ : QWebPluginFactory(parent)
+{
+}
+
+TestPlugin::~TestPlugin()
+{
+}
+
+QList<QWebPluginFactory::Plugin> TestPlugin::plugins() const
+{
+ QWebPluginFactory::Plugin plugin;
+
+ plugin.name = "testplugin";
+ plugin.description = "testdescription";
+ MimeType mimeType;
+ mimeType.name = "testtype";
+ mimeType.fileExtensions.append("testsuffixes");
+ plugin.mimeTypes.append(mimeType);
+
+ plugin.name = "testplugin2";
+ plugin.description = "testdescription2";
+ mimeType.name = "testtype2";
+ mimeType.fileExtensions.append("testsuffixes2");
+ mimeType.fileExtensions.append("testsuffixes3");
+ plugin.mimeTypes.append(mimeType);
+
+ return QList<QWebPluginFactory::Plugin>() << plugin;
+}
+
+QObject *TestPlugin::create(const QString&,
+ const QUrl&,
+ const QStringList&,
+ const QStringList&) const
+{
+ return 0;
+}
+
diff --git a/Tools/DumpRenderTree/qt/testplugin.h b/Tools/DumpRenderTree/qt/testplugin.h
new file mode 100644
index 0000000..3d8a28c
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/testplugin.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <qwebpluginfactory.h>
+
+
+class TestPlugin : public QWebPluginFactory
+{
+public:
+ explicit TestPlugin(QObject *parent = 0);
+ virtual ~TestPlugin();
+
+ virtual QList<Plugin> plugins() const;
+
+ virtual QObject *create(const QString &mimeType,
+ const QUrl &url,
+ const QStringList &argumentNames,
+ const QStringList &argumentValues) const;
+
+};
+