diff options
Diffstat (limited to 'Tools/DumpRenderTree/qt')
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 Binary files differnew file mode 100644 index 0000000..ac81cb0 --- /dev/null +++ b/Tools/DumpRenderTree/qt/fonts/AHEM____.TTF 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; + +}; + |