diff options
author | Allan Sandfeld Jensen <allan.jensen@theqtcompany.com> | 2015-11-20 16:01:37 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@theqtcompany.com> | 2015-11-20 16:04:42 +0100 |
commit | 1f474fcc4cd47a85ce8d99f07d18b46ef2af5898 (patch) | |
tree | d4e52b5ac98343b4c2417d622164bf320d781a59 | |
parent | 4cc28c7c89f794d469f5e8f778ff05effe8c646f (diff) | |
parent | 1173d48149a8133b607894b67e1ec32de68e21e8 (diff) |
Merge branch '5.6' into dev
Change-Id: I05fe27b8321944cf68cc96dfa9dfcaeb54c8c8cd
130 files changed, 3285 insertions, 429 deletions
diff --git a/dist/changes-5.5.2 b/dist/changes-5.5.2 new file mode 100644 index 000000000..fe4b88cb0 --- /dev/null +++ b/dist/changes-5.5.2 @@ -0,0 +1,46 @@ +Qt 5.5.2 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.5.0. + +Qt 5.5 introduces many new features and improvements as well as bugfixes +over the 5.4.x series. For more details, refer to the online documentation +included in this distribution. The documentation is also available online: + + http://doc.qt.io/qt-5/index.html + +The Qt version 5.5 series is binary compatible with the 5.4.x series. +Applications compiled for 5.4 will continue to run with 5.5. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + + https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* General * +**************************************************************************** + +QtWebEngineCore +-------- + - [QTBUG-48309] Fixed old-style QObject connections to + QWebEngineDownloadItem::stateChanged. + - [QTBUG-47976] Fixed httpUserAgent setting after the view's + initialization. + - [QTBUG-48206] Parse suggested filename from content-disposition response + header field. + - Fixed crash on malformed URL (Chromium issue 533361). + +**************************************************************************** +* Platform Specific Changes * +**************************************************************************** + +OS X +---- + - [QTBUG-48228] Enabled 32 bit build. + +Windows +------- + - [QTBUG-48285] Fixed installation of PDB files. + diff --git a/examples/examples.pro b/examples/examples.pro index d6960e017..c93886989 100644 --- a/examples/examples.pro +++ b/examples/examples.pro @@ -7,5 +7,6 @@ qtHaveModule(webengine) { qtHaveModule(webenginewidgets) { SUBDIRS += \ webenginewidgets/demobrowser \ - webenginewidgets/contentmanipulation + webenginewidgets/contentmanipulation \ + webenginewidgets/markdowneditor } diff --git a/examples/webengine/quicknanobrowser/BrowserWindow.qml b/examples/webengine/quicknanobrowser/BrowserWindow.qml index 123a7cc8d..e8a9cb9ce 100644 --- a/examples/webengine/quicknanobrowser/BrowserWindow.qml +++ b/examples/webengine/quicknanobrowser/BrowserWindow.qml @@ -59,8 +59,10 @@ ApplicationWindow { // This is for the case where the system forces us to leave fullscreen. if (currentWebView && !isFullScreen) { currentWebView.state = "" - if (currentWebView.isFullScreen) + if (currentWebView.isFullScreen) { currentWebView.fullScreenCancelled() + fullScreenNotification.hide() + } } } @@ -83,6 +85,7 @@ ApplicationWindow { property alias javaScriptEnabled: javaScriptEnabled.checked; property alias errorPageEnabled: errorPageEnabled.checked; property alias pluginsEnabled: pluginsEnabled.checked; + property alias fullScreenSupportEnabled: fullScreenSupportEnabled.checked; } Action { @@ -268,7 +271,13 @@ ApplicationWindow { id: pluginsEnabled text: "Plugins On" checkable: true - checked: true + checked: WebEngine.settings.pluginsEnabled + } + MenuItem { + id: fullScreenSupportEnabled + text: "FullScreen On" + checkable: true + checked: WebEngine.settings.fullScreenSupportEnabled } MenuItem { id: offTheRecordEnabled @@ -354,6 +363,7 @@ ApplicationWindow { settings.javascriptEnabled: appSettings.javaScriptEnabled settings.errorPageEnabled: appSettings.errorPageEnabled settings.pluginsEnabled: appSettings.pluginsEnabled + settings.fullScreenSupportEnabled: appSettings.fullScreenSupportEnabled onCertificateError: { error.defer() @@ -384,9 +394,11 @@ ApplicationWindow { webEngineView.state = "FullScreen" browserWindow.previousVisibility = browserWindow.visibility browserWindow.showFullScreen() + fullScreenNotification.show() } else { webEngineView.state = "" browserWindow.visibility = browserWindow.previousVisibility + fullScreenNotification.hide() } request.accept() } @@ -460,6 +472,11 @@ ApplicationWindow { visible = certErrors.length > 0 } } + + FullScreenNotification { + id: fullScreenNotification + } + DownloadView { id: downloadView visible: false diff --git a/examples/webengine/quicknanobrowser/FullScreenNotification.qml b/examples/webengine/quicknanobrowser/FullScreenNotification.qml new file mode 100644 index 000000000..80a63d479 --- /dev/null +++ b/examples/webengine/quicknanobrowser/FullScreenNotification.qml @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * 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. +** * Neither the name of The Qt Company Ltd 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +** OWNER OR 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." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.5 + +Rectangle { + id: fullScreenNotification + width: 500 + height: 40 + color: "white" + radius: 7 + + visible: false + opacity: 0 + + function show() { + visible = true + opacity = 1 + reset.start() + } + + function hide() { + reset.stop() + opacity = 0 + } + + Behavior on opacity { + NumberAnimation { + duration: 750 + onStopped: { + if (opacity == 0) + visible = false + } + } + } + + Timer { + id: reset + interval: 5000 + onTriggered: hide() + } + + anchors.horizontalCenter: parent.horizontalCenter + y: 125 + + Text { + id: message + width: parent.width + + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + + wrapMode: Text.WordWrap + elide: Text.ElideNone + clip: true + + text: qsTr("You are now in fullscreen mode. Press ESC to quit!") + } +} diff --git a/examples/webengine/quicknanobrowser/quicknanobrowser.pro b/examples/webengine/quicknanobrowser/quicknanobrowser.pro index 1447af927..6cf556984 100644 --- a/examples/webengine/quicknanobrowser/quicknanobrowser.pro +++ b/examples/webengine/quicknanobrowser/quicknanobrowser.pro @@ -9,7 +9,8 @@ SOURCES = main.cpp OTHER_FILES += ApplicationRoot.qml \ BrowserDialog.qml \ BrowserWindow.qml \ - DownloadView.qml + DownloadView.qml \ + FullScreenNotification.qml RESOURCES += resources.qrc diff --git a/examples/webengine/quicknanobrowser/resources.qrc b/examples/webengine/quicknanobrowser/resources.qrc index 28fd7b7dc..694f8d19b 100644 --- a/examples/webengine/quicknanobrowser/resources.qrc +++ b/examples/webengine/quicknanobrowser/resources.qrc @@ -4,6 +4,7 @@ <file>BrowserDialog.qml</file> <file>BrowserWindow.qml</file> <file>DownloadView.qml</file> + <file>FullScreenNotification.qml</file> </qresource> <qresource prefix="icons"> <file alias="go-next.png">icons/go-next.png</file> diff --git a/examples/webenginewidgets/demobrowser/demobrowser.pro b/examples/webenginewidgets/demobrowser/demobrowser.pro index 14347de71..113eeb40e 100644 --- a/examples/webenginewidgets/demobrowser/demobrowser.pro +++ b/examples/webenginewidgets/demobrowser/demobrowser.pro @@ -28,6 +28,7 @@ HEADERS += \ edittableview.h \ edittreeview.h \ featurepermissionbar.h\ + fullscreennotification.h \ history.h \ modelmenu.h \ searchlineedit.h \ @@ -49,6 +50,7 @@ SOURCES += \ edittableview.cpp \ edittreeview.cpp \ featurepermissionbar.cpp\ + fullscreennotification.cpp \ history.cpp \ modelmenu.cpp \ searchlineedit.cpp \ diff --git a/examples/webenginewidgets/demobrowser/doc/images/browser-demo.png b/examples/webenginewidgets/demobrowser/doc/images/browser-demo.png Binary files differindex 09d065095..e8695dbca 100644 --- a/examples/webenginewidgets/demobrowser/doc/images/browser-demo.png +++ b/examples/webenginewidgets/demobrowser/doc/images/browser-demo.png diff --git a/examples/webenginewidgets/demobrowser/downloadmanager.h b/examples/webenginewidgets/demobrowser/downloadmanager.h index 877682d77..cd96f35a5 100644 --- a/examples/webenginewidgets/demobrowser/downloadmanager.h +++ b/examples/webenginewidgets/demobrowser/downloadmanager.h @@ -98,7 +98,6 @@ class DownloadManager : public QDialog, public Ui_DownloadDialog { Q_OBJECT Q_PROPERTY(RemovePolicy removePolicy READ removePolicy WRITE setRemovePolicy) - Q_ENUMS(RemovePolicy) public: enum RemovePolicy { @@ -106,6 +105,7 @@ public: Exit, SuccessFullDownload }; + Q_ENUM(RemovePolicy) DownloadManager(QWidget *parent = 0); ~DownloadManager(); diff --git a/examples/webenginewidgets/demobrowser/fullscreennotification.cpp b/examples/webenginewidgets/demobrowser/fullscreennotification.cpp new file mode 100644 index 000000000..8ee968bec --- /dev/null +++ b/examples/webenginewidgets/demobrowser/fullscreennotification.cpp @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the demonstration applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "fullscreennotification.h" + +#include <QApplication> +#include <QDesktopWidget> +#include <QGridLayout> +#include <QLabel> +#include <QPropertyAnimation> +#include <QTimer> + +FullScreenNotification::FullScreenNotification(QWidget *parent) + : QWidget(parent) + , width(400) + , height(80) + , x((parent->geometry().width() - width) / 2) + , y(80) +{ + setVisible(false); + setWindowFlags(Qt::ToolTip | Qt::WindowDoesNotAcceptFocus); + + QGridLayout *layout = new QGridLayout(this); + + m_label = new QLabel(tr("You are now in fullscreen mode. Press ESC to quit!"), this); + layout->addWidget(m_label, 0, 0, 0, 0, Qt::AlignHCenter | Qt::AlignVCenter); + + setGeometry(x, y, width, height); + + setStyleSheet("background-color: white;\ + color: black;"); + + m_animation = new QPropertyAnimation(this, "windowOpacity"); + connect(m_animation, SIGNAL(finished()), this, SLOT(fadeOutFinished())); +} + +FullScreenNotification::~FullScreenNotification() +{ +} + +void FullScreenNotification::show() +{ + setWindowOpacity(1.0); + QTimer::singleShot(300, [&] { + QWidget *parent = parentWidget(); + x = (parent->geometry().width() - width) / 2; + QPoint topLeft = parent->mapToGlobal(QPoint(x, y)); + QWidget::move(topLeft.x(), topLeft.y()); + QWidget::show(); + QWidget::raise(); + }); + QTimer::singleShot(5000, this, SLOT(fadeOut())); +} + +void FullScreenNotification::hide() +{ + QWidget::hide(); + m_animation->stop(); +} + +void FullScreenNotification::fadeOut() +{ + m_animation->setDuration(800); + m_animation->setStartValue(1.0); + m_animation->setEndValue(0.0); + m_animation->setEasingCurve(QEasingCurve::OutQuad); + m_animation->start(); +} + +void FullScreenNotification::fadeOutFinished() +{ + hide(); + setWindowOpacity(1.0); +} diff --git a/examples/webenginewidgets/demobrowser/fullscreennotification.h b/examples/webenginewidgets/demobrowser/fullscreennotification.h new file mode 100644 index 000000000..051075ab3 --- /dev/null +++ b/examples/webenginewidgets/demobrowser/fullscreennotification.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the demonstration applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FULLSCREENNOTIFICATION_H +#define FULLSCREENNOTIFICATION_H + +#include <QWidget> + +class QLabel; +class QGridLayout; +class QPropertyAnimation; + +class FullScreenNotification : public QWidget +{ + Q_OBJECT +public: + FullScreenNotification(QWidget *parent = 0); + ~FullScreenNotification(); + + void show(); + void hide(); + +public slots: + void fadeOut(); + void fadeOutFinished(); + +private: + QLabel *m_label; + QGridLayout *m_layout; + QPropertyAnimation *m_animation; + int width; + int height; + int x; + int y; +}; + + +#endif // FULLSCREENNOTIFICATION_H diff --git a/examples/webenginewidgets/demobrowser/tabwidget.cpp b/examples/webenginewidgets/demobrowser/tabwidget.cpp index 4e2073b11..95b79aaac 100644 --- a/examples/webenginewidgets/demobrowser/tabwidget.cpp +++ b/examples/webenginewidgets/demobrowser/tabwidget.cpp @@ -44,6 +44,7 @@ #include "browserapplication.h" #include "browsermainwindow.h" #include "downloadmanager.h" +#include "fullscreennotification.h" #include "history.h" #include "urllineedit.h" #include "webview.h" @@ -88,6 +89,7 @@ TabBar::TabBar(QWidget *parent) TabWidget::~TabWidget() { + delete m_fullScreenNotification; delete m_fullScreenView; } @@ -220,6 +222,7 @@ TabWidget::TabWidget(QWidget *parent) , m_tabBar(new TabBar(this)) , m_profile(QWebEngineProfile::defaultProfile()) , m_fullScreenView(0) + , m_fullScreenNotification(0) { setElideMode(Qt::ElideRight); @@ -322,8 +325,8 @@ void TabWidget::currentChanged(int index) this, SIGNAL(loadProgress(int))); disconnect(oldWebView->page()->profile(), SIGNAL(downloadRequested(QWebEngineDownloadItem*)), this, SLOT(downloadRequested(QWebEngineDownloadItem*))); - disconnect(oldWebView->page(), SIGNAL(fullScreenRequested(const QWebEngineFullScreenRequest&)), - this, SLOT(fullScreenRequested(const QWebEngineFullScreenRequest&))); + disconnect(oldWebView->page(), SIGNAL(fullScreenRequested(QWebEngineFullScreenRequest)), + this, SLOT(fullScreenRequested(QWebEngineFullScreenRequest))); } #if defined(QWEBENGINEVIEW_STATUSBARMESSAGE) @@ -336,8 +339,8 @@ void TabWidget::currentChanged(int index) this, SIGNAL(loadProgress(int))); connect(webView->page()->profile(), SIGNAL(downloadRequested(QWebEngineDownloadItem*)), this, SLOT(downloadRequested(QWebEngineDownloadItem*))); - connect(webView->page(), SIGNAL(fullScreenRequested(const QWebEngineFullScreenRequest&)), - this, SLOT(fullScreenRequested(const QWebEngineFullScreenRequest&))); + connect(webView->page(), SIGNAL(fullScreenRequested(QWebEngineFullScreenRequest)), + this, SLOT(fullScreenRequested(QWebEngineFullScreenRequest))); for (int i = 0; i < m_actions.count(); ++i) { WebActionMapper *mapper = m_actions[i]; @@ -353,25 +356,35 @@ void TabWidget::currentChanged(int index) webView->setFocus(); } -void TabWidget::fullScreenRequested(const QWebEngineFullScreenRequest &request) +void TabWidget::fullScreenRequested(QWebEngineFullScreenRequest request) { + WebPage *webPage = qobject_cast<WebPage*>(sender()); if (request.toggleOn()) { - if (!m_fullScreenView) + if (!m_fullScreenView) { m_fullScreenView = new QWebEngineView(); - WebPage *webPage = qobject_cast<WebPage*>(sender()); + m_fullScreenNotification = new FullScreenNotification(m_fullScreenView); + + QAction *exitFullScreenAction = new QAction(m_fullScreenView); + exitFullScreenAction->setShortcut(Qt::Key_Escape); + connect(exitFullScreenAction, &QAction::triggered, [webPage] { + webPage->triggerAction(QWebEnginePage::ExitFullScreen); + }); + m_fullScreenView->addAction(exitFullScreenAction); + } webPage->setView(m_fullScreenView); request.accept(); m_fullScreenView->showFullScreen(); m_fullScreenView->raise(); + m_fullScreenNotification->show(); } else { if (!m_fullScreenView) return; - WebPage *webPage = qobject_cast<WebPage*>(sender()); WebView *oldWebView = this->webView(m_lineEdits->currentIndex()); webPage->setView(oldWebView); request.accept(); raise(); m_fullScreenView->hide(); + m_fullScreenNotification->hide(); } } diff --git a/examples/webenginewidgets/demobrowser/tabwidget.h b/examples/webenginewidgets/demobrowser/tabwidget.h index 3a1fe7171..b00131130 100644 --- a/examples/webenginewidgets/demobrowser/tabwidget.h +++ b/examples/webenginewidgets/demobrowser/tabwidget.h @@ -42,8 +42,8 @@ #ifndef TABWIDGET_H #define TABWIDGET_H +#include <QtWebEngineWidgets/QWebEngineFullScreenRequest> #include <QtWidgets/QTabBar> - #include <QtWidgets/QShortcut> QT_BEGIN_NAMESPACE @@ -129,6 +129,7 @@ private: #include <QtCore/QUrl> #include <QtWidgets/QTabWidget> QT_BEGIN_NAMESPACE +class FullScreenNotification; class QCompleter; class QLineEdit; class QMenu; @@ -216,7 +217,7 @@ private slots: void lineEditReturnPressed(); void windowCloseRequested(); void moveTab(int fromIndex, int toIndex); - void fullScreenRequested(const QWebEngineFullScreenRequest& request); + void fullScreenRequested(QWebEngineFullScreenRequest request); private: QAction *m_recentlyClosedTabsAction; @@ -235,6 +236,7 @@ private: TabBar *m_tabBar; QWebEngineProfile *m_profile; QWebEngineView *m_fullScreenView; + FullScreenNotification *m_fullScreenNotification; }; #endif // TABWIDGET_H diff --git a/examples/webenginewidgets/demobrowser/webview.cpp b/examples/webenginewidgets/demobrowser/webview.cpp index c12f3db36..79a6cf344 100644 --- a/examples/webenginewidgets/demobrowser/webview.cpp +++ b/examples/webenginewidgets/demobrowser/webview.cpp @@ -315,23 +315,6 @@ void WebPage::proxyAuthenticationRequired(const QUrl &requestUrl, QAuthenticator } } -void WebPage::javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString& message, int /*lineNumber*/, const QString& sourceID) -{ - QUrl url; - url.setUrl(sourceID); - switch (level) { - case InfoMessageLevel: - // Ignore these, they can still be found in the inspector. - break; - case WarningMessageLevel: - qInfo() << "JavaScript WARNING:" << url.host() << message; - break; - case ErrorMessageLevel: - qInfo() << "JavaScript ERROR:" << url.host() << message; - break; - } -} - WebView::WebView(QWidget* parent) : QWebEngineView(parent) , m_progress(0) diff --git a/examples/webenginewidgets/demobrowser/webview.h b/examples/webenginewidgets/demobrowser/webview.h index cb78fdd8a..34188a259 100644 --- a/examples/webenginewidgets/demobrowser/webview.h +++ b/examples/webenginewidgets/demobrowser/webview.h @@ -65,13 +65,12 @@ public: BrowserMainWindow *mainWindow(); protected: - bool acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame); - QWebEnginePage *createWindow(QWebEnginePage::WebWindowType type); + bool acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame) Q_DECL_OVERRIDE; + QWebEnginePage *createWindow(QWebEnginePage::WebWindowType type) Q_DECL_OVERRIDE; #if !defined(QT_NO_UITOOLS) QObject *createPlugin(const QString &classId, const QUrl &url, const QStringList ¶mNames, const QStringList ¶mValues); #endif virtual bool certificateError(const QWebEngineCertificateError &error) Q_DECL_OVERRIDE; - virtual void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString& message, int lineNumber, const QString& sourceID) Q_DECL_OVERRIDE; private slots: #if defined(QWEBENGINEPAGE_UNSUPPORTEDCONTENT) diff --git a/examples/webenginewidgets/markdowneditor/3RDPARTY.md b/examples/webenginewidgets/markdowneditor/3RDPARTY.md new file mode 100644 index 000000000..9e91ab302 --- /dev/null +++ b/examples/webenginewidgets/markdowneditor/3RDPARTY.md @@ -0,0 +1,23 @@ +## markd license + +``` +Copyright (c) 2011-2014, Christopher Jeffrey (https://github.com/chjj/) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +``` diff --git a/examples/webenginewidgets/markdowneditor/doc/images/markdowneditor-example.png b/examples/webenginewidgets/markdowneditor/doc/images/markdowneditor-example.png Binary files differnew file mode 100644 index 000000000..9f456c4db --- /dev/null +++ b/examples/webenginewidgets/markdowneditor/doc/images/markdowneditor-example.png diff --git a/examples/webenginewidgets/markdowneditor/doc/src/markdowneditor.qdoc b/examples/webenginewidgets/markdowneditor/doc/src/markdowneditor.qdoc new file mode 100644 index 000000000..44b1246b3 --- /dev/null +++ b/examples/webenginewidgets/markdowneditor/doc/src/markdowneditor.qdoc @@ -0,0 +1,164 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example webenginewidgets/markdowneditor + \title Markdown Editor Example + \ingroup webengine-widgetexamples + \brief Demonstrates how to integrate a web engine in a hybrid desktop + application. + + \image markdowneditor-example.png + + \e {Markdown Editor} demonstrates how to use QWebChannel and JavaScript + libraries to provide a rich text preview tool for a custom markup language. + + \l{http://daringfireball.net/projects/markdown/}{Markdown} is a lightweight + markup language with a plain text formatting syntax. + Some services, such as \l{http://github.com}{github}, acknowledge the + format, and render the content as rich text when viewed in a browser. + + The Markdown Editor main window is split into an editor and a preview area. + The editor supports the Markdown syntax and is implemented by using + QPlainTextEdit. The document is rendered as rich text in the preview area, + which is implemented by using QWebEngineView. To render the text, the + Markdown text is converted to HTML format with the help of a JavaScript + library inside the web engine. The preview is updated from the editor + through QWebChannel. + + \include examples-run.qdocinc + + \section1 Exposing Document Text + + Because we expose the current Markdown text to be rendered to the web engine + through QWebChannel, we need to somehow make the current text available + through the Qt metatype system. This is done by using a dedicated + \c Document class that exposes the document text as a \c{Q_PROPERTY}: + + \quotefromfile webenginewidgets/markdowneditor/document.h + \skipto class Document + \printto #endif + + The \c Document class wraps a QString to be set on the C++ side with + the \c setText() method and exposes it at runtime as a \c text property + with a \c textChanged signal. + + We define the \c setText method as follows: + + \quotefromfile webenginewidgets/markdowneditor/document.cpp + \skipto Document::setText + \printuntil + + \section1 Previewing Text + + We implement our own \c PreviewPage class that publicly inherits from + \c QWebEnginePage: + + \quotefromfile webenginewidgets/markdowneditor/previewpage.h + \skipto class PreviewPage + \printto #endif + + We reimplement the virtual \c acceptNavigationRequest method to + stop the page from navigating away from the current document. Instead, + we redirect external links to the system browser: + + \quotefromfile webenginewidgets/markdowneditor/previewpage.cpp + \skipto acceptNavigationRequest + \printuntil + + \section1 Creating the Main Window + + The \c MainWindow class inherits the QMainWindow class: + + \quotefromfile webenginewidgets/markdowneditor/mainwindow.h + \skipto class MainWindow : + \printto endif + + The class declares private slots that match the actions in the menu, + as well as the \c isModified() helper method. + + The actual layout of the main window is specified in a \c .ui file. + The widgets and actions are available at runtime in the \c ui member + variable. + + \c m_filePath holds the file path to the currently loaded document. + \c m_content is an instance of the \c Document class. + + The actual setup of the different objects is done in the \c MainWindow + constructor: + + \quotefromfile webenginewidgets/markdowneditor/mainwindow.cpp + \skipto MainWindow::MainWindow + \printto connect + + The constructor first calls \c setupUi to construct the widgets and menu + actions according to the UI file. It then makes sure our custom + \c PreviewPage is used by the QWebEngineView instance in \c{ui->preview}. + + \printto ui->preview + + Here the \c textChanged signal of the editor is connected to a lambda that + updates the text in \c m_content. This object is then exposed to the JS side + by \c QWebChannel under the name \c{content}. + + \printto connect + + Now we can actually load the \e index.html file from the + resources. For more information about the file, see + \l{Creating an Index File}. + + \printto defaultTextFile + + The menu items are connected to the mapping member slots. The + \uicontrol Save item is activated or deactivated depending on whether + the user has edited the content. + + \printuntil } + + Finally, we load a default document \e default.md from the resources. + + \section1 Creating an Index File + + \quotefile webenginewidgets/markdowneditor/resources/index.html + + In the \e index.html, we load a custom stylesheet and two JavaScript + libraries. \l{http://kevinburke.bitbucket.org/markdowncss/}{markdown.css} is + a markdown-friendly stylesheet created by Kevin Burke. + \l{https://github.com/chjj/marked}{marked.min.js} is a markdown parser and + compiler designed for speed written by Christopher Jeffrey and + \e qwebchannel.js is part of the \l{QWebChannel} module. + + In the \c <body> element we first define a \c placeholder element, and + make it available as a JavaScript variable. We then define the \c updateText + helper method that updates the content of \c placeholder with the HTML + that the JavaScript method \c marked() returns. + + Finally, we set up the web channel to access the \c content proxy object + and make sure that \c updateText() is called whenever \c content.text + changes. +*/ + diff --git a/examples/webenginewidgets/markdowneditor/document.cpp b/examples/webenginewidgets/markdowneditor/document.cpp new file mode 100644 index 000000000..98665680c --- /dev/null +++ b/examples/webenginewidgets/markdowneditor/document.cpp @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the demonstration applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "document.h" + +void Document::setText(const QString &text) +{ + if (text == m_text) + return; + m_text = text; + emit textChanged(m_text); +} diff --git a/examples/webenginewidgets/markdowneditor/document.h b/examples/webenginewidgets/markdowneditor/document.h new file mode 100644 index 000000000..d2f33ec81 --- /dev/null +++ b/examples/webenginewidgets/markdowneditor/document.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the demonstration applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DOCUMENT_H +#define DOCUMENT_H + +#include <QObject> +#include <QString> + +class Document : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString text MEMBER m_text NOTIFY textChanged) +public: + explicit Document(QObject *parent = nullptr) : QObject(parent) {} + + void setText(const QString &text); + +signals: + void textChanged(const QString &text); + +private: + QString m_text; +}; + +#endif // DOCUMENT_H diff --git a/examples/webenginewidgets/markdowneditor/main.cpp b/examples/webenginewidgets/markdowneditor/main.cpp new file mode 100644 index 000000000..2cf4e1f60 --- /dev/null +++ b/examples/webenginewidgets/markdowneditor/main.cpp @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the demonstration applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "document.h" +#include "mainwindow.h" + +#include <QApplication> +#include <QFile> + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + + MainWindow window; + window.show(); + + return a.exec(); +} diff --git a/examples/webenginewidgets/markdowneditor/mainwindow.cpp b/examples/webenginewidgets/markdowneditor/mainwindow.cpp new file mode 100644 index 000000000..fec7c661e --- /dev/null +++ b/examples/webenginewidgets/markdowneditor/mainwindow.cpp @@ -0,0 +1,172 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the demonstration applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mainwindow.h" +#include "previewpage.h" +#include "ui_mainwindow.h" + +#include <QFile> +#include <QFileDialog> +#include <QMessageBox> +#include <QTextStream> +#include <QWebChannel> + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow) +{ + ui->setupUi(this); + + PreviewPage *page = new PreviewPage(this); + ui->preview->setPage(page); + + connect(ui->editor, &QPlainTextEdit::textChanged, + [this]() { m_content.setText(ui->editor->toPlainText()); }); + + QWebChannel *channel = new QWebChannel(this); + channel->registerObject(QStringLiteral("content"), &m_content); + page->setWebChannel(channel); + + ui->preview->setUrl(QUrl("qrc:/index.html")); + + connect(ui->actionNew, &QAction::triggered, this, &MainWindow::onFileNew); + connect(ui->actionOpen, &QAction::triggered, this, &MainWindow::onFileOpen); + connect(ui->actionSave, &QAction::triggered, this, &MainWindow::onFileSave); + connect(ui->actionSaveAs, &QAction::triggered, this, &MainWindow::onFileSaveAs); + connect(ui->actionExit, &QAction::triggered, this, &MainWindow::onExit); + + connect(ui->editor->document(), &QTextDocument::modificationChanged, + ui->actionSave, &QAction::setEnabled); + + QFile defaultTextFile(":/default.md"); + defaultTextFile.open(QIODevice::ReadOnly); + ui->editor->setPlainText(defaultTextFile.readAll()); +} + +MainWindow::~MainWindow() +{ + delete ui; +} + +bool MainWindow::isModified() const +{ + return ui->editor->document()->isModified(); +} + +void MainWindow::onFileNew() +{ + if (isModified()) { + QMessageBox::StandardButton button = QMessageBox::question(this, windowTitle(), + tr("You have unsaved changes. Do you want to create a new document anyway?")); + if (button != QMessageBox::Yes) + return; + } + + m_filePath.clear(); + ui->editor->setPlainText(tr("## New document")); + ui->editor->document()->setModified(false); +} + +void MainWindow::onFileOpen() +{ + if (isModified()) { + QMessageBox::StandardButton button = QMessageBox::question(this, windowTitle(), + tr("You have unsaved changes. Do you want to open a new document anyway?")); + if (button != QMessageBox::Yes) + return; + } + + QString path = QFileDialog::getOpenFileName(this, + tr("Open MarkDown File"), "", tr("MarkDown File (*.md)")); + if (path.isEmpty()) + return; + + QFile f(path); + if (!f.open(QIODevice::ReadOnly)) { + QMessageBox::warning(this, windowTitle(), + tr("Could not open file %1: %2").arg( + QDir::toNativeSeparators(path), f.errorString())); + return; + } + m_filePath = path; + ui->editor->setPlainText(f.readAll()); +} + +void MainWindow::onFileSave() +{ + if (m_filePath.isEmpty()) { + onFileSaveAs(); + return; + } + + QFile f(m_filePath); + if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) { + QMessageBox::warning(this, windowTitle(), + tr("Could not write to file %1: %2").arg( + QDir::toNativeSeparators(m_filePath), f.errorString())); + return; + } + QTextStream str(&f); + str << ui->editor->toPlainText(); + + ui->editor->document()->setModified(false); +} + +void MainWindow::onFileSaveAs() +{ + QString path = QFileDialog::getSaveFileName(this, + tr("Save MarkDown File"), "", tr("MarkDown File (*.md, *.markdown)")); + if (path.isEmpty()) + return; + m_filePath = path; + onFileSave(); +} + +void MainWindow::onExit() +{ + if (isModified()) { + QMessageBox::StandardButton button = QMessageBox::question(this, windowTitle(), + tr("You have unsaved changes. Do you want to exit anyway?")); + if (button != QMessageBox::Yes) + return; + } + close(); +} diff --git a/examples/webenginewidgets/markdowneditor/mainwindow.h b/examples/webenginewidgets/markdowneditor/mainwindow.h new file mode 100644 index 000000000..6099f1f79 --- /dev/null +++ b/examples/webenginewidgets/markdowneditor/mainwindow.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the demonstration applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include "document.h" + +#include <QMainWindow> +#include <QString> + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + +private slots: + void onFileNew(); + void onFileOpen(); + void onFileSave(); + void onFileSaveAs(); + void onExit(); + +private: + bool isModified() const; + + Ui::MainWindow *ui; + QString m_filePath; + Document m_content; +}; + +#endif // MAINWINDOW_H diff --git a/examples/webenginewidgets/markdowneditor/mainwindow.ui b/examples/webenginewidgets/markdowneditor/mainwindow.ui new file mode 100644 index 000000000..36ab352b7 --- /dev/null +++ b/examples/webenginewidgets/markdowneditor/mainwindow.ui @@ -0,0 +1,115 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MainWindow</class> + <widget class="QMainWindow" name="MainWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>800</width> + <height>600</height> + </rect> + </property> + <property name="windowTitle"> + <string>MarkDown Editor</string> + </property> + <widget class="QWidget" name="centralwidget"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QSplitter" name="splitter"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <widget class="QPlainTextEdit" name="editor"/> + <widget class="QWebEngineView" name="preview" native="true"/> + </widget> + </item> + </layout> + </widget> + <widget class="QMenuBar" name="menubar"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>800</width> + <height>26</height> + </rect> + </property> + <widget class="QMenu" name="menu_File"> + <property name="title"> + <string>&File</string> + </property> + <addaction name="actionNew"/> + <addaction name="actionOpen"/> + <addaction name="actionSave"/> + <addaction name="actionSaveAs"/> + <addaction name="separator"/> + <addaction name="actionExit"/> + </widget> + <addaction name="menu_File"/> + </widget> + <widget class="QStatusBar" name="statusbar"/> + <action name="actionOpen"> + <property name="text"> + <string>&Open...</string> + </property> + <property name="toolTip"> + <string>Open document</string> + </property> + <property name="shortcut"> + <string>Ctrl+O</string> + </property> + </action> + <action name="actionSave"> + <property name="text"> + <string>&Save</string> + </property> + <property name="toolTip"> + <string>Save current document</string> + </property> + <property name="shortcut"> + <string>Ctrl+S</string> + </property> + </action> + <action name="actionExit"> + <property name="text"> + <string>E&xit</string> + </property> + <property name="toolTip"> + <string>Exit editor</string> + </property> + <property name="shortcut"> + <string>Ctrl+Q</string> + </property> + </action> + <action name="actionSaveAs"> + <property name="text"> + <string>Save &As...</string> + </property> + <property name="toolTip"> + <string>Save document under different name</string> + </property> + </action> + <action name="actionNew"> + <property name="text"> + <string>&New</string> + </property> + <property name="toolTip"> + <string>Create new document</string> + </property> + <property name="shortcut"> + <string>Ctrl+N</string> + </property> + </action> + </widget> + <customwidgets> + <customwidget> + <class>QWebEngineView</class> + <extends>QWidget</extends> + <header>qwebengineview.h</header> + <container>1</container> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/examples/webenginewidgets/markdowneditor/markdowneditor.pro b/examples/webenginewidgets/markdowneditor/markdowneditor.pro new file mode 100644 index 000000000..bfd16698a --- /dev/null +++ b/examples/webenginewidgets/markdowneditor/markdowneditor.pro @@ -0,0 +1,28 @@ +TEMPLATE = app + +QT += webenginewidgets webchannel +CONFIG += c++11 + +HEADERS += \ + mainwindow.h \ + previewpage.h \ + document.h + +SOURCES = \ + main.cpp \ + mainwindow.cpp \ + previewpage.cpp \ + document.cpp + +RESOURCES = \ + resources/markdowneditor.qrc + +FORMS += \ + mainwindow.ui + +DISTFILES += \ + 3RDPARTY.md + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/webenginewidgets/markdowneditor +INSTALLS += target diff --git a/examples/webenginewidgets/markdowneditor/previewpage.cpp b/examples/webenginewidgets/markdowneditor/previewpage.cpp new file mode 100644 index 000000000..2d4322664 --- /dev/null +++ b/examples/webenginewidgets/markdowneditor/previewpage.cpp @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the demonstration applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "previewpage.h" + +#include <QDesktopServices> + +bool PreviewPage::acceptNavigationRequest(const QUrl &url, + QWebEnginePage::NavigationType /*type*/, + bool /*isMainFrame*/) +{ + // Only allow qrc:/index.html. + if (url.scheme() == QString("qrc")) + return true; + QDesktopServices::openUrl(url); + return false; +} diff --git a/examples/webenginewidgets/markdowneditor/previewpage.h b/examples/webenginewidgets/markdowneditor/previewpage.h new file mode 100644 index 000000000..53b0e23e6 --- /dev/null +++ b/examples/webenginewidgets/markdowneditor/previewpage.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the demonstration applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PREVIEWPAGE_H +#define PREVIEWPAGE_H + +#include <QWebEnginePage> + +class PreviewPage : public QWebEnginePage +{ + Q_OBJECT +public: + explicit PreviewPage(QObject *parent = nullptr) : QWebEnginePage(parent) {} + +protected: + bool acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame); +}; + +#endif // PREVIEWPAGE_H diff --git a/examples/webenginewidgets/markdowneditor/resources/default.md b/examples/webenginewidgets/markdowneditor/resources/default.md new file mode 100644 index 000000000..e5905b101 --- /dev/null +++ b/examples/webenginewidgets/markdowneditor/resources/default.md @@ -0,0 +1,12 @@ +## Markdown Editor Example + +This example uses [QWebEngineView](http://doc.qt.io/qt-5/qwebengineview.html) +to preview text written using the [Markdown](https://en.wikipedia.org/wiki/Markdown) +syntax. + +### Acknowledgments + +The conversion from Markdown to HTML is done with the help of the +[marked JavaScript library](https://github.com/chjj/marked) by _Christopher Jeffrey_. +The [style sheet](http://kevinburke.bitbucket.org/markdowncss/markdown.css) +was created by _Kevin Burke_. diff --git a/examples/webenginewidgets/markdowneditor/resources/index.html b/examples/webenginewidgets/markdowneditor/resources/index.html new file mode 100644 index 000000000..2f45479ed --- /dev/null +++ b/examples/webenginewidgets/markdowneditor/resources/index.html @@ -0,0 +1,32 @@ +<!doctype html> +<html lang="en"> +<meta charset="utf-8"> +<head> + <link rel="stylesheet" type="text/css" href="markdown.css"> + <script src="marked.min.js"></script> + <script src="qwebchannel.js"></script> +</head> +<body> + <div id="placeholder"></div> + <script> + 'use strict'; + + var placeholder = document.getElementById('placeholder'); + + var updateText = function(text) { + placeholder.innerHTML = marked(text); + } + + new QWebChannel(qt.webChannelTransport, + function(channel) { + var content = channel.objects.content; + updateText(content.text); + content.textChanged.connect(updateText); + } + ); + </script> +</body> +</html> + + + diff --git a/examples/webenginewidgets/markdowneditor/resources/markdown.css b/examples/webenginewidgets/markdowneditor/resources/markdown.css new file mode 100644 index 000000000..24fc2ffe2 --- /dev/null +++ b/examples/webenginewidgets/markdowneditor/resources/markdown.css @@ -0,0 +1,260 @@ +body{ + margin: 0 auto; + font-family: Georgia, Palatino, serif; + color: #444444; + line-height: 1; + max-width: 960px; + padding: 30px; +} +h1, h2, h3, h4 { + color: #111111; + font-weight: 400; +} +h1, h2, h3, h4, h5, p { + margin-bottom: 24px; + padding: 0; +} +h1 { + font-size: 48px; +} +h2 { + font-size: 36px; + /* The bottom margin is small. It's designed to be used with gray meta text + * below a post title. */ + margin: 24px 0 6px; +} +h3 { + font-size: 24px; +} +h4 { + font-size: 21px; +} +h5 { + font-size: 18px; +} +a { + color: #0099ff; + margin: 0; + padding: 0; + vertical-align: baseline; +} +a:hover { + text-decoration: none; + color: #ff6600; +} +a:visited { + color: purple; +} +ul, ol { + padding: 0; + margin: 0; +} +li { + line-height: 24px; +} +li ul, li ul { + margin-left: 24px; +} +p, ul, ol { + font-size: 16px; + line-height: 24px; + max-width: 540px; +} +pre { + padding: 0px 24px; + max-width: 800px; + white-space: pre-wrap; +} +code { + font-family: Consolas, Monaco, Andale Mono, monospace; + line-height: 1.5; + font-size: 13px; +} +aside { + display: block; + float: right; + width: 390px; +} +blockquote { + border-left:.5em solid #eee; + padding: 0 2em; + margin-left:0; + max-width: 476px; +} +blockquote cite { + font-size:14px; + line-height:20px; + color:#bfbfbf; +} +blockquote cite:before { + content: '\2014 \00A0'; +} + +blockquote p { + color: #666; + max-width: 460px; +} +hr { + width: 540px; + text-align: left; + margin: 0 auto 0 0; + color: #999; +} + +/* Code below this line is copyright Twitter Inc. */ + +button, +input, +select, +textarea { + font-size: 100%; + margin: 0; + vertical-align: baseline; + *vertical-align: middle; +} +button, input { + line-height: normal; + *overflow: visible; +} +button::-moz-focus-inner, input::-moz-focus-inner { + border: 0; + padding: 0; +} +button, +input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} +input[type=checkbox], input[type=radio] { + cursor: pointer; +} +/* override default chrome & firefox settings */ +input:not([type="image"]), textarea { + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} + +input[type="search"] { + -webkit-appearance: textfield; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} +label, +input, +select, +textarea { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + font-weight: normal; + line-height: normal; + margin-bottom: 18px; +} +input[type=checkbox], input[type=radio] { + cursor: pointer; + margin-bottom: 0; +} +input[type=text], +input[type=password], +textarea, +select { + display: inline-block; + width: 210px; + padding: 4px; + font-size: 13px; + font-weight: normal; + line-height: 18px; + height: 18px; + color: #808080; + border: 1px solid #ccc; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} +select, input[type=file] { + height: 27px; + line-height: 27px; +} +textarea { + height: auto; +} + +/* grey out placeholders */ +:-moz-placeholder { + color: #bfbfbf; +} +::-webkit-input-placeholder { + color: #bfbfbf; +} + +input[type=text], +input[type=password], +select, +textarea { + -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; + -moz-transition: border linear 0.2s, box-shadow linear 0.2s; + transition: border linear 0.2s, box-shadow linear 0.2s; + -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1); +} +input[type=text]:focus, input[type=password]:focus, textarea:focus { + outline: none; + border-color: rgba(82, 168, 236, 0.8); + -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 8px rgba(82, 168, 236, 0.6); + -moz-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 8px rgba(82, 168, 236, 0.6); + box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 8px rgba(82, 168, 236, 0.6); +} + +/* buttons */ +button { + display: inline-block; + padding: 4px 14px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + line-height: 18px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + background-color: #0064cd; + background-repeat: repeat-x; + background-image: -khtml-gradient(linear, left top, left bottom, from(#049cdb), to(#0064cd)); + background-image: -moz-linear-gradient(top, #049cdb, #0064cd); + background-image: -ms-linear-gradient(top, #049cdb, #0064cd); + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #049cdb), color-stop(100%, #0064cd)); + background-image: -webkit-linear-gradient(top, #049cdb, #0064cd); + background-image: -o-linear-gradient(top, #049cdb, #0064cd); + background-image: linear-gradient(top, #049cdb, #0064cd); + color: #fff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + border: 1px solid #004b9a; + border-bottom-color: #003f81; + -webkit-transition: 0.1s linear all; + -moz-transition: 0.1s linear all; + transition: 0.1s linear all; + border-color: #0064cd #0064cd #003f81; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); +} +button:hover { + color: #fff; + background-position: 0 -15px; + text-decoration: none; +} +button:active { + -webkit-box-shadow: inset 0 3px 7px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 3px 7px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 3px 7px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} +button::-moz-focus-inner { + padding: 0; + border: 0; +} diff --git a/examples/webenginewidgets/markdowneditor/resources/markdowneditor.qrc b/examples/webenginewidgets/markdowneditor/resources/markdowneditor.qrc new file mode 100644 index 000000000..8b7471a9c --- /dev/null +++ b/examples/webenginewidgets/markdowneditor/resources/markdowneditor.qrc @@ -0,0 +1,9 @@ +<RCC> + <qresource prefix="/"> + <file>index.html</file> + <file>qwebchannel.js</file> + <file>marked.min.js</file> + <file>default.md</file> + <file>markdown.css</file> + </qresource> +</RCC> diff --git a/examples/webenginewidgets/markdowneditor/resources/marked.min.js b/examples/webenginewidgets/markdowneditor/resources/marked.min.js new file mode 100644 index 000000000..f3542fff0 --- /dev/null +++ b/examples/webenginewidgets/markdowneditor/resources/marked.min.js @@ -0,0 +1,6 @@ +/** + * marked - a markdown parser + * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed) + * https://github.com/chjj/marked + */ +(function(){var block={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:noop,hr:/^( *[-*_]){3,} *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,nptable:noop,lheading:/^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,blockquote:/^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,list:/^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:/^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,def:/^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,table:noop,paragraph:/^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,text:/^[^\n]+/};block.bullet=/(?:[*+-]|\d+\.)/;block.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;block.item=replace(block.item,"gm")(/bull/g,block.bullet)();block.list=replace(block.list)(/bull/g,block.bullet)("hr","\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))")("def","\\n+(?="+block.def.source+")")();block.blockquote=replace(block.blockquote)("def",block.def)();block._tag="(?!(?:"+"a|em|strong|small|s|cite|q|dfn|abbr|data|time|code"+"|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo"+"|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b";block.html=replace(block.html)("comment",/<!--[\s\S]*?-->/)("closed",/<(tag)[\s\S]+?<\/\1>/)("closing",/<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)(/tag/g,block._tag)();block.paragraph=replace(block.paragraph)("hr",block.hr)("heading",block.heading)("lheading",block.lheading)("blockquote",block.blockquote)("tag","<"+block._tag)("def",block.def)();block.normal=merge({},block);block.gfm=merge({},block.normal,{fences:/^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,paragraph:/^/,heading:/^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/});block.gfm.paragraph=replace(block.paragraph)("(?!","(?!"+block.gfm.fences.source.replace("\\1","\\2")+"|"+block.list.source.replace("\\1","\\3")+"|")();block.tables=merge({},block.gfm,{nptable:/^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,table:/^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/});function Lexer(options){this.tokens=[];this.tokens.links={};this.options=options||marked.defaults;this.rules=block.normal;if(this.options.gfm){if(this.options.tables){this.rules=block.tables}else{this.rules=block.gfm}}}Lexer.rules=block;Lexer.lex=function(src,options){var lexer=new Lexer(options);return lexer.lex(src)};Lexer.prototype.lex=function(src){src=src.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n");return this.token(src,true)};Lexer.prototype.token=function(src,top,bq){var src=src.replace(/^ +$/gm,""),next,loose,cap,bull,b,item,space,i,l;while(src){if(cap=this.rules.newline.exec(src)){src=src.substring(cap[0].length);if(cap[0].length>1){this.tokens.push({type:"space"})}}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);cap=cap[0].replace(/^ {4}/gm,"");this.tokens.push({type:"code",text:!this.options.pedantic?cap.replace(/\n+$/,""):cap});continue}if(cap=this.rules.fences.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"code",lang:cap[2],text:cap[3]||""});continue}if(cap=this.rules.heading.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"heading",depth:cap[1].length,text:cap[2]});continue}if(top&&(cap=this.rules.nptable.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/\n$/,"").split("\n")};for(i=0;i<item.align.length;i++){if(/^ *-+: *$/.test(item.align[i])){item.align[i]="right"}else if(/^ *:-+: *$/.test(item.align[i])){item.align[i]="center"}else if(/^ *:-+ *$/.test(item.align[i])){item.align[i]="left"}else{item.align[i]=null}}for(i=0;i<item.cells.length;i++){item.cells[i]=item.cells[i].split(/ *\| */)}this.tokens.push(item);continue}if(cap=this.rules.lheading.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"heading",depth:cap[2]==="="?1:2,text:cap[1]});continue}if(cap=this.rules.hr.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"hr"});continue}if(cap=this.rules.blockquote.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"blockquote_start"});cap=cap[0].replace(/^ *> ?/gm,"");this.token(cap,top,true);this.tokens.push({type:"blockquote_end"});continue}if(cap=this.rules.list.exec(src)){src=src.substring(cap[0].length);bull=cap[2];this.tokens.push({type:"list_start",ordered:bull.length>1});cap=cap[0].match(this.rules.item);next=false;l=cap.length;i=0;for(;i<l;i++){item=cap[i];space=item.length;item=item.replace(/^ *([*+-]|\d+\.) +/,"");if(~item.indexOf("\n ")){space-=item.length;item=!this.options.pedantic?item.replace(new RegExp("^ {1,"+space+"}","gm"),""):item.replace(/^ {1,4}/gm,"")}if(this.options.smartLists&&i!==l-1){b=block.bullet.exec(cap[i+1])[0];if(bull!==b&&!(bull.length>1&&b.length>1)){src=cap.slice(i+1).join("\n")+src;i=l-1}}loose=next||/\n\n(?!\s*$)/.test(item);if(i!==l-1){next=item.charAt(item.length-1)==="\n";if(!loose)loose=next}this.tokens.push({type:loose?"loose_item_start":"list_item_start"});this.token(item,false,bq);this.tokens.push({type:"list_item_end"})}this.tokens.push({type:"list_end"});continue}if(cap=this.rules.html.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:this.options.sanitize?"paragraph":"html",pre:!this.options.sanitizer&&(cap[1]==="pre"||cap[1]==="script"||cap[1]==="style"),text:cap[0]});continue}if(!bq&&top&&(cap=this.rules.def.exec(src))){src=src.substring(cap[0].length);this.tokens.links[cap[1].toLowerCase()]={href:cap[2],title:cap[3]};continue}if(top&&(cap=this.rules.table.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/(?: *\| *)?\n$/,"").split("\n")};for(i=0;i<item.align.length;i++){if(/^ *-+: *$/.test(item.align[i])){item.align[i]="right"}else if(/^ *:-+: *$/.test(item.align[i])){item.align[i]="center"}else if(/^ *:-+ *$/.test(item.align[i])){item.align[i]="left"}else{item.align[i]=null}}for(i=0;i<item.cells.length;i++){item.cells[i]=item.cells[i].replace(/^ *\| *| *\| *$/g,"").split(/ *\| */)}this.tokens.push(item);continue}if(top&&(cap=this.rules.paragraph.exec(src))){src=src.substring(cap[0].length);this.tokens.push({type:"paragraph",text:cap[1].charAt(cap[1].length-1)==="\n"?cap[1].slice(0,-1):cap[1]});continue}if(cap=this.rules.text.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"text",text:cap[0]});continue}if(src){throw new Error("Infinite loop on byte: "+src.charCodeAt(0))}}return this.tokens};var inline={escape:/^\\([\\`*{}\[\]()#+\-.!_>])/,autolink:/^<([^ >]+(@|:\/)[^ >]+)>/,url:noop,tag:/^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,link:/^!?\[(inside)\]\(href\)/,reflink:/^!?\[(inside)\]\s*\[([^\]]*)\]/,nolink:/^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,strong:/^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,em:/^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,code:/^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,br:/^ {2,}\n(?!\s*$)/,del:noop,text:/^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/};inline._inside=/(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;inline._href=/\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;inline.link=replace(inline.link)("inside",inline._inside)("href",inline._href)();inline.reflink=replace(inline.reflink)("inside",inline._inside)();inline.normal=merge({},inline);inline.pedantic=merge({},inline.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/});inline.gfm=merge({},inline.normal,{escape:replace(inline.escape)("])","~|])")(),url:/^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,del:/^~~(?=\S)([\s\S]*?\S)~~/,text:replace(inline.text)("]|","~]|")("|","|https?://|")()});inline.breaks=merge({},inline.gfm,{br:replace(inline.br)("{2,}","*")(),text:replace(inline.gfm.text)("{2,}","*")()});function InlineLexer(links,options){this.options=options||marked.defaults;this.links=links;this.rules=inline.normal;this.renderer=this.options.renderer||new Renderer;this.renderer.options=this.options;if(!this.links){throw new Error("Tokens array requires a `links` property.")}if(this.options.gfm){if(this.options.breaks){this.rules=inline.breaks}else{this.rules=inline.gfm}}else if(this.options.pedantic){this.rules=inline.pedantic}}InlineLexer.rules=inline;InlineLexer.output=function(src,links,options){var inline=new InlineLexer(links,options);return inline.output(src)};InlineLexer.prototype.output=function(src){var out="",link,text,href,cap;while(src){if(cap=this.rules.escape.exec(src)){src=src.substring(cap[0].length);out+=cap[1];continue}if(cap=this.rules.autolink.exec(src)){src=src.substring(cap[0].length);if(cap[2]==="@"){text=cap[1].charAt(6)===":"?this.mangle(cap[1].substring(7)):this.mangle(cap[1]);href=this.mangle("mailto:")+text}else{text=escape(cap[1]);href=text}out+=this.renderer.link(href,null,text);continue}if(!this.inLink&&(cap=this.rules.url.exec(src))){src=src.substring(cap[0].length);text=escape(cap[1]);href=text;out+=this.renderer.link(href,null,text);continue}if(cap=this.rules.tag.exec(src)){if(!this.inLink&&/^<a /i.test(cap[0])){this.inLink=true}else if(this.inLink&&/^<\/a>/i.test(cap[0])){this.inLink=false}src=src.substring(cap[0].length);out+=this.options.sanitize?this.options.sanitizer?this.options.sanitizer(cap[0]):escape(cap[0]):cap[0];continue}if(cap=this.rules.link.exec(src)){src=src.substring(cap[0].length);this.inLink=true;out+=this.outputLink(cap,{href:cap[2],title:cap[3]});this.inLink=false;continue}if((cap=this.rules.reflink.exec(src))||(cap=this.rules.nolink.exec(src))){src=src.substring(cap[0].length);link=(cap[2]||cap[1]).replace(/\s+/g," ");link=this.links[link.toLowerCase()];if(!link||!link.href){out+=cap[0].charAt(0);src=cap[0].substring(1)+src;continue}this.inLink=true;out+=this.outputLink(cap,link);this.inLink=false;continue}if(cap=this.rules.strong.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.strong(this.output(cap[2]||cap[1]));continue}if(cap=this.rules.em.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.em(this.output(cap[2]||cap[1]));continue}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.codespan(escape(cap[2],true));continue}if(cap=this.rules.br.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.br();continue}if(cap=this.rules.del.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.del(this.output(cap[1]));continue}if(cap=this.rules.text.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.text(escape(this.smartypants(cap[0])));continue}if(src){throw new Error("Infinite loop on byte: "+src.charCodeAt(0))}}return out};InlineLexer.prototype.outputLink=function(cap,link){var href=escape(link.href),title=link.title?escape(link.title):null;return cap[0].charAt(0)!=="!"?this.renderer.link(href,title,this.output(cap[1])):this.renderer.image(href,title,escape(cap[1]))};InlineLexer.prototype.smartypants=function(text){if(!this.options.smartypants)return text;return text.replace(/---/g,"—").replace(/--/g,"–").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…")};InlineLexer.prototype.mangle=function(text){if(!this.options.mangle)return text;var out="",l=text.length,i=0,ch;for(;i<l;i++){ch=text.charCodeAt(i);if(Math.random()>.5){ch="x"+ch.toString(16)}out+="&#"+ch+";"}return out};function Renderer(options){this.options=options||{}}Renderer.prototype.code=function(code,lang,escaped){if(this.options.highlight){var out=this.options.highlight(code,lang);if(out!=null&&out!==code){escaped=true;code=out}}if(!lang){return"<pre><code>"+(escaped?code:escape(code,true))+"\n</code></pre>"}return'<pre><code class="'+this.options.langPrefix+escape(lang,true)+'">'+(escaped?code:escape(code,true))+"\n</code></pre>\n"};Renderer.prototype.blockquote=function(quote){return"<blockquote>\n"+quote+"</blockquote>\n"};Renderer.prototype.html=function(html){return html};Renderer.prototype.heading=function(text,level,raw){return"<h"+level+' id="'+this.options.headerPrefix+raw.toLowerCase().replace(/[^\w]+/g,"-")+'">'+text+"</h"+level+">\n"};Renderer.prototype.hr=function(){return this.options.xhtml?"<hr/>\n":"<hr>\n"};Renderer.prototype.list=function(body,ordered){var type=ordered?"ol":"ul";return"<"+type+">\n"+body+"</"+type+">\n"};Renderer.prototype.listitem=function(text){return"<li>"+text+"</li>\n"};Renderer.prototype.paragraph=function(text){return"<p>"+text+"</p>\n"};Renderer.prototype.table=function(header,body){return"<table>\n"+"<thead>\n"+header+"</thead>\n"+"<tbody>\n"+body+"</tbody>\n"+"</table>\n"};Renderer.prototype.tablerow=function(content){return"<tr>\n"+content+"</tr>\n"};Renderer.prototype.tablecell=function(content,flags){var type=flags.header?"th":"td";var tag=flags.align?"<"+type+' style="text-align:'+flags.align+'">':"<"+type+">";return tag+content+"</"+type+">\n"};Renderer.prototype.strong=function(text){return"<strong>"+text+"</strong>"};Renderer.prototype.em=function(text){return"<em>"+text+"</em>"};Renderer.prototype.codespan=function(text){return"<code>"+text+"</code>"};Renderer.prototype.br=function(){return this.options.xhtml?"<br/>":"<br>"};Renderer.prototype.del=function(text){return"<del>"+text+"</del>"};Renderer.prototype.link=function(href,title,text){if(this.options.sanitize){try{var prot=decodeURIComponent(unescape(href)).replace(/[^\w:]/g,"").toLowerCase()}catch(e){return""}if(prot.indexOf("javascript:")===0||prot.indexOf("vbscript:")===0){return""}}var out='<a href="'+href+'"';if(title){out+=' title="'+title+'"'}out+=">"+text+"</a>";return out};Renderer.prototype.image=function(href,title,text){var out='<img src="'+href+'" alt="'+text+'"';if(title){out+=' title="'+title+'"'}out+=this.options.xhtml?"/>":">";return out};Renderer.prototype.text=function(text){return text};function Parser(options){this.tokens=[];this.token=null;this.options=options||marked.defaults;this.options.renderer=this.options.renderer||new Renderer;this.renderer=this.options.renderer;this.renderer.options=this.options}Parser.parse=function(src,options,renderer){var parser=new Parser(options,renderer);return parser.parse(src)};Parser.prototype.parse=function(src){this.inline=new InlineLexer(src.links,this.options,this.renderer);this.tokens=src.reverse();var out="";while(this.next()){out+=this.tok()}return out};Parser.prototype.next=function(){return this.token=this.tokens.pop()};Parser.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0};Parser.prototype.parseText=function(){var body=this.token.text;while(this.peek().type==="text"){body+="\n"+this.next().text}return this.inline.output(body)};Parser.prototype.tok=function(){switch(this.token.type){case"space":{return""}case"hr":{return this.renderer.hr()}case"heading":{return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,this.token.text)}case"code":{return this.renderer.code(this.token.text,this.token.lang,this.token.escaped)}case"table":{var header="",body="",i,row,cell,flags,j;cell="";for(i=0;i<this.token.header.length;i++){flags={header:true,align:this.token.align[i]};cell+=this.renderer.tablecell(this.inline.output(this.token.header[i]),{header:true,align:this.token.align[i]})}header+=this.renderer.tablerow(cell);for(i=0;i<this.token.cells.length;i++){row=this.token.cells[i];cell="";for(j=0;j<row.length;j++){cell+=this.renderer.tablecell(this.inline.output(row[j]),{header:false,align:this.token.align[j]})}body+=this.renderer.tablerow(cell)}return this.renderer.table(header,body)}case"blockquote_start":{var body="";while(this.next().type!=="blockquote_end"){body+=this.tok()}return this.renderer.blockquote(body)}case"list_start":{var body="",ordered=this.token.ordered;while(this.next().type!=="list_end"){body+=this.tok()}return this.renderer.list(body,ordered)}case"list_item_start":{var body="";while(this.next().type!=="list_item_end"){body+=this.token.type==="text"?this.parseText():this.tok()}return this.renderer.listitem(body)}case"loose_item_start":{var body="";while(this.next().type!=="list_item_end"){body+=this.tok()}return this.renderer.listitem(body)}case"html":{var html=!this.token.pre&&!this.options.pedantic?this.inline.output(this.token.text):this.token.text;return this.renderer.html(html)}case"paragraph":{return this.renderer.paragraph(this.inline.output(this.token.text))}case"text":{return this.renderer.paragraph(this.parseText())}}};function escape(html,encode){return html.replace(!encode?/&(?!#?\w+;)/g:/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function unescape(html){return html.replace(/&([#\w]+);/g,function(_,n){n=n.toLowerCase();if(n==="colon")return":";if(n.charAt(0)==="#"){return n.charAt(1)==="x"?String.fromCharCode(parseInt(n.substring(2),16)):String.fromCharCode(+n.substring(1))}return""})}function replace(regex,opt){regex=regex.source;opt=opt||"";return function self(name,val){if(!name)return new RegExp(regex,opt);val=val.source||val;val=val.replace(/(^|[^\[])\^/g,"$1");regex=regex.replace(name,val);return self}}function noop(){}noop.exec=noop;function merge(obj){var i=1,target,key;for(;i<arguments.length;i++){target=arguments[i];for(key in target){if(Object.prototype.hasOwnProperty.call(target,key)){obj[key]=target[key]}}}return obj}function marked(src,opt,callback){if(callback||typeof opt==="function"){if(!callback){callback=opt;opt=null}opt=merge({},marked.defaults,opt||{});var highlight=opt.highlight,tokens,pending,i=0;try{tokens=Lexer.lex(src,opt)}catch(e){return callback(e)}pending=tokens.length;var done=function(err){if(err){opt.highlight=highlight;return callback(err)}var out;try{out=Parser.parse(tokens,opt)}catch(e){err=e}opt.highlight=highlight;return err?callback(err):callback(null,out)};if(!highlight||highlight.length<3){return done()}delete opt.highlight;if(!pending)return done();for(;i<tokens.length;i++){(function(token){if(token.type!=="code"){return--pending||done()}return highlight(token.text,token.lang,function(err,code){if(err)return done(err);if(code==null||code===token.text){return--pending||done()}token.text=code;token.escaped=true;--pending||done()})})(tokens[i])}return}try{if(opt)opt=merge({},marked.defaults,opt);return Parser.parse(Lexer.lex(src,opt),opt)}catch(e){e.message+="\nPlease report this to https://github.com/chjj/marked.";if((opt||marked.defaults).silent){return"<p>An error occurred:</p><pre>"+escape(e.message+"",true)+"</pre>"}throw e}}marked.options=marked.setOptions=function(opt){merge(marked.defaults,opt);return marked};marked.defaults={gfm:true,tables:true,breaks:false,pedantic:false,sanitize:false,sanitizer:null,mangle:true,smartLists:false,silent:false,highlight:null,langPrefix:"lang-",smartypants:false,headerPrefix:"",renderer:new Renderer,xhtml:false};marked.Parser=Parser;marked.parser=Parser.parse;marked.Renderer=Renderer;marked.Lexer=Lexer;marked.lexer=Lexer.lex;marked.InlineLexer=InlineLexer;marked.inlineLexer=InlineLexer.output;marked.parse=marked;if(typeof module!=="undefined"&&typeof exports==="object"){module.exports=marked}else if(typeof define==="function"&&define.amd){define(function(){return marked})}else{this.marked=marked}}).call(function(){return this||(typeof window!=="undefined"?window:global)}());
\ No newline at end of file diff --git a/examples/webenginewidgets/markdowneditor/resources/qwebchannel.js b/examples/webenginewidgets/markdowneditor/resources/qwebchannel.js new file mode 100644 index 000000000..d8c28bc66 --- /dev/null +++ b/examples/webenginewidgets/markdowneditor/resources/qwebchannel.js @@ -0,0 +1,413 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com> +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWebChannel module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +"use strict"; + +var QWebChannelMessageTypes = { + signal: 1, + propertyUpdate: 2, + init: 3, + idle: 4, + debug: 5, + invokeMethod: 6, + connectToSignal: 7, + disconnectFromSignal: 8, + setProperty: 9, + response: 10, +}; + +var QWebChannel = function(transport, initCallback) +{ + if (typeof transport !== "object" || typeof transport.send !== "function") { + console.error("The QWebChannel expects a transport object with a send function and onmessage callback property." + + " Given is: transport: " + typeof(transport) + ", transport.send: " + typeof(transport.send)); + return; + } + + var channel = this; + this.transport = transport; + + this.send = function(data) + { + if (typeof(data) !== "string") { + data = JSON.stringify(data); + } + channel.transport.send(data); + } + + this.transport.onmessage = function(message) + { + var data = message.data; + if (typeof data === "string") { + data = JSON.parse(data); + } + switch (data.type) { + case QWebChannelMessageTypes.signal: + channel.handleSignal(data); + break; + case QWebChannelMessageTypes.response: + channel.handleResponse(data); + break; + case QWebChannelMessageTypes.propertyUpdate: + channel.handlePropertyUpdate(data); + break; + default: + console.error("invalid message received:", message.data); + break; + } + } + + this.execCallbacks = {}; + this.execId = 0; + this.exec = function(data, callback) + { + if (!callback) { + // if no callback is given, send directly + channel.send(data); + return; + } + if (channel.execId === Number.MAX_VALUE) { + // wrap + channel.execId = Number.MIN_VALUE; + } + if (data.hasOwnProperty("id")) { + console.error("Cannot exec message with property id: " + JSON.stringify(data)); + return; + } + data.id = channel.execId++; + channel.execCallbacks[data.id] = callback; + channel.send(data); + }; + + this.objects = {}; + + this.handleSignal = function(message) + { + var object = channel.objects[message.object]; + if (object) { + object.signalEmitted(message.signal, message.args); + } else { + console.warn("Unhandled signal: " + message.object + "::" + message.signal); + } + } + + this.handleResponse = function(message) + { + if (!message.hasOwnProperty("id")) { + console.error("Invalid response message received: ", JSON.stringify(message)); + return; + } + channel.execCallbacks[message.id](message.data); + delete channel.execCallbacks[message.id]; + } + + this.handlePropertyUpdate = function(message) + { + for (var i in message.data) { + var data = message.data[i]; + var object = channel.objects[data.object]; + if (object) { + object.propertyUpdate(data.signals, data.properties); + } else { + console.warn("Unhandled property update: " + data.object + "::" + data.signal); + } + } + channel.exec({type: QWebChannelMessageTypes.idle}); + } + + this.debug = function(message) + { + channel.send({type: QWebChannelMessageTypes.debug, data: message}); + }; + + channel.exec({type: QWebChannelMessageTypes.init}, function(data) { + for (var objectName in data) { + var object = new QObject(objectName, data[objectName], channel); + } + // now unwrap properties, which might reference other registered objects + for (var objectName in channel.objects) { + channel.objects[objectName].unwrapProperties(); + } + if (initCallback) { + initCallback(channel); + } + channel.exec({type: QWebChannelMessageTypes.idle}); + }); +}; + +function QObject(name, data, webChannel) +{ + this.__id__ = name; + webChannel.objects[name] = this; + + // List of callbacks that get invoked upon signal emission + this.__objectSignals__ = {}; + + // Cache of all properties, updated when a notify signal is emitted + this.__propertyCache__ = {}; + + var object = this; + + // ---------------------------------------------------------------------- + + this.unwrapQObject = function(response) + { + if (response instanceof Array) { + // support list of objects + var ret = new Array(response.length); + for (var i = 0; i < response.length; ++i) { + ret[i] = object.unwrapQObject(response[i]); + } + return ret; + } + if (!response + || !response["__QObject*__"] + || response.id === undefined) { + return response; + } + + var objectId = response.id; + if (webChannel.objects[objectId]) + return webChannel.objects[objectId]; + + if (!response.data) { + console.error("Cannot unwrap unknown QObject " + objectId + " without data."); + return; + } + + var qObject = new QObject( objectId, response.data, webChannel ); + qObject.destroyed.connect(function() { + if (webChannel.objects[objectId] === qObject) { + delete webChannel.objects[objectId]; + // reset the now deleted QObject to an empty {} object + // just assigning {} though would not have the desired effect, but the + // below also ensures all external references will see the empty map + // NOTE: this detour is necessary to workaround QTBUG-40021 + var propertyNames = []; + for (var propertyName in qObject) { + propertyNames.push(propertyName); + } + for (var idx in propertyNames) { + delete qObject[propertyNames[idx]]; + } + } + }); + // here we are already initialized, and thus must directly unwrap the properties + qObject.unwrapProperties(); + return qObject; + } + + this.unwrapProperties = function() + { + for (var propertyIdx in object.__propertyCache__) { + object.__propertyCache__[propertyIdx] = object.unwrapQObject(object.__propertyCache__[propertyIdx]); + } + } + + function addSignal(signalData, isPropertyNotifySignal) + { + var signalName = signalData[0]; + var signalIndex = signalData[1]; + object[signalName] = { + connect: function(callback) { + if (typeof(callback) !== "function") { + console.error("Bad callback given to connect to signal " + signalName); + return; + } + + object.__objectSignals__[signalIndex] = object.__objectSignals__[signalIndex] || []; + object.__objectSignals__[signalIndex].push(callback); + + if (!isPropertyNotifySignal && signalName !== "destroyed") { + // only required for "pure" signals, handled separately for properties in propertyUpdate + // also note that we always get notified about the destroyed signal + webChannel.exec({ + type: QWebChannelMessageTypes.connectToSignal, + object: object.__id__, + signal: signalIndex + }); + } + }, + disconnect: function(callback) { + if (typeof(callback) !== "function") { + console.error("Bad callback given to disconnect from signal " + signalName); + return; + } + object.__objectSignals__[signalIndex] = object.__objectSignals__[signalIndex] || []; + var idx = object.__objectSignals__[signalIndex].indexOf(callback); + if (idx === -1) { + console.error("Cannot find connection of signal " + signalName + " to " + callback.name); + return; + } + object.__objectSignals__[signalIndex].splice(idx, 1); + if (!isPropertyNotifySignal && object.__objectSignals__[signalIndex].length === 0) { + // only required for "pure" signals, handled separately for properties in propertyUpdate + webChannel.exec({ + type: QWebChannelMessageTypes.disconnectFromSignal, + object: object.__id__, + signal: signalIndex + }); + } + } + }; + } + + /** + * Invokes all callbacks for the given signalname. Also works for property notify callbacks. + */ + function invokeSignalCallbacks(signalName, signalArgs) + { + var connections = object.__objectSignals__[signalName]; + if (connections) { + connections.forEach(function(callback) { + callback.apply(callback, signalArgs); + }); + } + } + + this.propertyUpdate = function(signals, propertyMap) + { + // update property cache + for (var propertyIndex in propertyMap) { + var propertyValue = propertyMap[propertyIndex]; + object.__propertyCache__[propertyIndex] = propertyValue; + } + + for (var signalName in signals) { + // Invoke all callbacks, as signalEmitted() does not. This ensures the + // property cache is updated before the callbacks are invoked. + invokeSignalCallbacks(signalName, signals[signalName]); + } + } + + this.signalEmitted = function(signalName, signalArgs) + { + invokeSignalCallbacks(signalName, signalArgs); + } + + function addMethod(methodData) + { + var methodName = methodData[0]; + var methodIdx = methodData[1]; + object[methodName] = function() { + var args = []; + var callback; + for (var i = 0; i < arguments.length; ++i) { + if (typeof arguments[i] === "function") + callback = arguments[i]; + else + args.push(arguments[i]); + } + + webChannel.exec({ + "type": QWebChannelMessageTypes.invokeMethod, + "object": object.__id__, + "method": methodIdx, + "args": args + }, function(response) { + if (response !== undefined) { + var result = object.unwrapQObject(response); + if (callback) { + (callback)(result); + } + } + }); + }; + } + + function bindGetterSetter(propertyInfo) + { + var propertyIndex = propertyInfo[0]; + var propertyName = propertyInfo[1]; + var notifySignalData = propertyInfo[2]; + // initialize property cache with current value + // NOTE: if this is an object, it is not directly unwrapped as it might + // reference other QObject that we do not know yet + object.__propertyCache__[propertyIndex] = propertyInfo[3]; + + if (notifySignalData) { + if (notifySignalData[0] === 1) { + // signal name is optimized away, reconstruct the actual name + notifySignalData[0] = propertyName + "Changed"; + } + addSignal(notifySignalData, true); + } + + Object.defineProperty(object, propertyName, { + configurable: true, + get: function () { + var propertyValue = object.__propertyCache__[propertyIndex]; + if (propertyValue === undefined) { + // This shouldn't happen + console.warn("Undefined value in property cache for property \"" + propertyName + "\" in object " + object.__id__); + } + + return propertyValue; + }, + set: function(value) { + if (value === undefined) { + console.warn("Property setter for " + propertyName + " called with undefined value!"); + return; + } + object.__propertyCache__[propertyIndex] = value; + webChannel.exec({ + "type": QWebChannelMessageTypes.setProperty, + "object": object.__id__, + "property": propertyIndex, + "value": value + }); + } + }); + + } + + // ---------------------------------------------------------------------- + + data.methods.forEach(addMethod); + + data.properties.forEach(bindGetterSetter); + + data.signals.forEach(function(signal) { addSignal(signal, false); }); + + for (var name in data.enums) { + object[name] = data.enums[name]; + } +} + +//required for use with nodejs +if (typeof module === 'object') { + module.exports = { + QWebChannel: QWebChannel + }; +} diff --git a/src/core/api/qwebenginecallback.h b/src/core/api/qwebenginecallback.h index ddee20d06..b675438f5 100644 --- a/src/core/api/qwebenginecallback.h +++ b/src/core/api/qwebenginecallback.h @@ -81,12 +81,19 @@ public: : d(new QtWebEnginePrivate::QWebEngineCallbackPrivate<T, F>(f)) { } QWebEngineCallback() { } + void swap(QWebEngineCallback &other) Q_DECL_NOTHROW { qSwap(d, other.d); } operator bool() const { return d; } private: friend class QtWebEngineCore::CallbackDirectory; QExplicitlySharedDataPointer<QtWebEnginePrivate::QWebEngineCallbackPrivateBase<T> > d; }; +Q_DECLARE_SHARED(QWebEngineCallback<int>) +Q_DECLARE_SHARED(QWebEngineCallback<const QByteArray &>) +Q_DECLARE_SHARED_NOT_MOVABLE_UNTIL_QT6(QWebEngineCallback<bool>) +Q_DECLARE_SHARED_NOT_MOVABLE_UNTIL_QT6(QWebEngineCallback<const QString &>) +Q_DECLARE_SHARED_NOT_MOVABLE_UNTIL_QT6(QWebEngineCallback<const QVariant &>) + QT_END_NAMESPACE #endif // QWEBENGINECALLBACK_H diff --git a/src/core/api/qwebenginecallback_p.h b/src/core/api/qwebenginecallback_p.h index f0c25fe9e..9bc9b9727 100644 --- a/src/core/api/qwebenginecallback_p.h +++ b/src/core/api/qwebenginecallback_p.h @@ -47,6 +47,7 @@ #include <QVariant> #include <type_traits> +// keep in sync with Q_DECLARE_SHARED... in qwebenginecallback.h #define FOR_EACH_TYPE(F) \ F(bool) \ F(int) \ @@ -227,6 +228,11 @@ void CallbackDirectory::CallbackSharedDataPointer<T>::invokeEmpty() parent->invokeEmptyInternal(callback); } +#define CHECK_RELOCATABLE(x) \ + Q_STATIC_ASSERT((QTypeInfoQuery<QWebEngineCallback< x > >::isRelocatable)); +FOR_EACH_TYPE(CHECK_RELOCATABLE) +#undef CHECK_RELOCATABLE + } // namespace QtWebEngineCore #endif // QWEBENGINECALLBACK_P_H diff --git a/src/core/api/qwebenginecookiestoreclient.cpp b/src/core/api/qwebenginecookiestoreclient.cpp index 167b3f68c..bd43b871d 100644 --- a/src/core/api/qwebenginecookiestoreclient.cpp +++ b/src/core/api/qwebenginecookiestoreclient.cpp @@ -181,7 +181,7 @@ bool QWebEngineCookieStoreClientPrivate::canSetCookie(const QUrl &firstPartyUrl, request.firstPartyUrl = firstPartyUrl; request.cookieLine = cookieLine; request.cookieSource = url; - callbackDirectory.invokeDirectly<const QWebEngineCookieStoreClient::FilterRequest&>(filterCallback, request); + callbackDirectory.invokeDirectly<QWebEngineCookieStoreClient::FilterRequest&>(filterCallback, request); return request.accepted; } return true; @@ -394,7 +394,7 @@ void QWebEngineCookieStoreClient::deleteAllCookies() \sa deleteAllCookiesWithCallback(), getAllCookies() */ -void QWebEngineCookieStoreClient::setCookieFilter(const QWebEngineCallback<const QWebEngineCookieStoreClient::FilterRequest&> &filter) +void QWebEngineCookieStoreClient::setCookieFilter(const QWebEngineCallback<QWebEngineCookieStoreClient::FilterRequest&> &filter) { Q_D(QWebEngineCookieStoreClient); d->filterCallback = filter; diff --git a/src/core/api/qwebenginecookiestoreclient.h b/src/core/api/qwebenginecookiestoreclient.h index 8bdb988e2..4664a8459 100644 --- a/src/core/api/qwebenginecookiestoreclient.h +++ b/src/core/api/qwebenginecookiestoreclient.h @@ -77,7 +77,7 @@ public: void deleteSessionCookiesWithCallback(const QWebEngineCallback<int> &resultCallback); void deleteAllCookiesWithCallback(const QWebEngineCallback<int> &resultCallback); void getAllCookies(const QWebEngineCallback<const QByteArray&> &resultCallback); - void setCookieFilter(const QWebEngineCallback<const FilterRequest&> &filterCallback); + void setCookieFilter(const QWebEngineCallback<FilterRequest&> &filterCallback); #endif void setCookie(const QNetworkCookie &cookie, const QUrl &origin = QUrl()); void deleteCookie(const QNetworkCookie &cookie, const QUrl &origin = QUrl()); diff --git a/src/core/api/qwebenginecookiestoreclient_p.h b/src/core/api/qwebenginecookiestoreclient_p.h index 43652fba6..54f3b9eb7 100644 --- a/src/core/api/qwebenginecookiestoreclient_p.h +++ b/src/core/api/qwebenginecookiestoreclient_p.h @@ -53,8 +53,7 @@ #include "qwebenginecallback_p.h" #include "qwebenginecookiestoreclient.h" -#include <QList> -#include <QMap> +#include <QVector> #include <QNetworkCookie> #include <QUrl> @@ -70,12 +69,12 @@ class QWEBENGINE_PRIVATE_EXPORT QWebEngineCookieStoreClientPrivate { QNetworkCookie cookie; QUrl origin; }; - + friend class QTypeInfo<CookieData>; public: Q_DECLARE_PUBLIC(QWebEngineCookieStoreClient) QtWebEngineCore::CallbackDirectory callbackDirectory; - QWebEngineCallback<const QWebEngineCookieStoreClient::FilterRequest&> filterCallback; - QList<CookieData> m_pendingUserCookies; + QWebEngineCallback<QWebEngineCookieStoreClient::FilterRequest&> filterCallback; + QVector<CookieData> m_pendingUserCookies; quint64 m_nextCallbackId; bool m_deleteSessionCookiesPending; bool m_deleteAllCookiesPending; @@ -102,6 +101,8 @@ public: void onCookieChanged(const QNetworkCookie &cookie, bool removed); }; +Q_DECLARE_TYPEINFO(QWebEngineCookieStoreClientPrivate::CookieData, Q_MOVABLE_TYPE); + QT_END_NAMESPACE #endif // QWEBENGINECOOKIESTORECLIENT_P_H diff --git a/src/core/api/qwebengineurlschemehandler.cpp b/src/core/api/qwebengineurlschemehandler.cpp index f887e4e98..7f9ebaf48 100644 --- a/src/core/api/qwebengineurlschemehandler.cpp +++ b/src/core/api/qwebengineurlschemehandler.cpp @@ -75,7 +75,6 @@ QWebEngineUrlSchemeHandler::QWebEngineUrlSchemeHandler(QObject *parent) QWebEngineUrlSchemeHandler::~QWebEngineUrlSchemeHandler() { Q_EMIT destroyed(this); - delete d_ptr; } /*! diff --git a/src/core/api/qwebengineurlschemehandler.h b/src/core/api/qwebengineurlschemehandler.h index 8c1e52646..66aebe00d 100644 --- a/src/core/api/qwebengineurlschemehandler.h +++ b/src/core/api/qwebengineurlschemehandler.h @@ -48,7 +48,6 @@ class URLRequestContextGetterQt; QT_BEGIN_NAMESPACE class QWebEngineUrlRequestJob; -class QWebEngineUrlSchemeHandlerPrivate; class QWEBENGINE_EXPORT QWebEngineUrlSchemeHandler : public QObject { Q_OBJECT @@ -63,8 +62,6 @@ Q_SIGNALS: private: Q_DISABLE_COPY(QWebEngineUrlSchemeHandler) - Q_DECLARE_PRIVATE(QWebEngineUrlSchemeHandler) - QWebEngineUrlSchemeHandlerPrivate *d_ptr; }; QT_END_NAMESPACE diff --git a/src/core/chrome_qt.gyp b/src/core/chrome_qt.gyp index 2d2abe802..6c8e0d4d6 100644 --- a/src/core/chrome_qt.gyp +++ b/src/core/chrome_qt.gyp @@ -20,13 +20,13 @@ '<(SHARED_INTERMEDIATE_DIR)/components/strings', ], 'sources': [ - '<(chromium_src_dir)/chrome/browser/media/desktop_streams_registry.cc', - '<(chromium_src_dir)/chrome/browser/media/desktop_streams_registry.h', - '<(chromium_src_dir)/chrome/browser/media/desktop_media_list.h', - '<(chromium_src_dir)/chrome/common/chrome_switches.cc', - '<(chromium_src_dir)/chrome/common/chrome_switches.h', - '<(chromium_src_dir)/chrome/common/localized_error.cc', - '<(chromium_src_dir)/chrome/common/localized_error.h', + '<(DEPTH)/chrome/browser/media/desktop_streams_registry.cc', + '<(DEPTH)/chrome/browser/media/desktop_streams_registry.h', + '<(DEPTH)/chrome/browser/media/desktop_media_list.h', + '<(DEPTH)/chrome/common/chrome_switches.cc', + '<(DEPTH)/chrome/common/chrome_switches.h', + '<(DEPTH)/chrome/common/localized_error.cc', + '<(DEPTH)/chrome/common/localized_error.h', ], }, { diff --git a/src/core/common/qt_messages.h b/src/core/common/qt_messages.h index 25a995b27..ae36a0d7f 100644 --- a/src/core/common/qt_messages.h +++ b/src/core/common/qt_messages.h @@ -25,13 +25,13 @@ IPC_STRUCT_TRAITS_END() // RenderView messages // These are messages sent from the browser to the renderer process. -IPC_MESSAGE_ROUTED1(QtRenderViewObserver_FetchDocumentMarkup, +IPC_MESSAGE_ROUTED1(RenderViewObserverQt_FetchDocumentMarkup, uint64 /* requestId */) -IPC_MESSAGE_ROUTED1(QtRenderViewObserver_FetchDocumentInnerText, +IPC_MESSAGE_ROUTED1(RenderViewObserverQt_FetchDocumentInnerText, uint64 /* requestId */) -IPC_MESSAGE_ROUTED1(QtRenderViewObserver_SetBackgroundColor, +IPC_MESSAGE_ROUTED1(RenderViewObserverQt_SetBackgroundColor, uint32 /* color */) IPC_MESSAGE_ROUTED1(WebChannelIPCTransport_Message, std::vector<char> /*binaryJSON*/) @@ -51,14 +51,14 @@ IPC_MESSAGE_CONTROL0(UserScriptController_ClearScripts) // WebContents messages // These are messages sent from the renderer back to the browser process. -IPC_MESSAGE_ROUTED2(QtRenderViewObserverHost_DidFetchDocumentMarkup, +IPC_MESSAGE_ROUTED2(RenderViewObserverHostQt_DidFetchDocumentMarkup, uint64 /* requestId */, base::string16 /* markup */) -IPC_MESSAGE_ROUTED2(QtRenderViewObserverHost_DidFetchDocumentInnerText, +IPC_MESSAGE_ROUTED2(RenderViewObserverHostQt_DidFetchDocumentInnerText, uint64 /* requestId */, base::string16 /* innerText */) -IPC_MESSAGE_ROUTED0(QtRenderViewObserverHost_DidFirstVisuallyNonEmptyLayout) +IPC_MESSAGE_ROUTED0(RenderViewObserverHostQt_DidFirstVisuallyNonEmptyLayout) IPC_MESSAGE_ROUTED1(WebChannelIPCTransportHost_SendMessage, std::vector<char> /*binaryJSON*/) diff --git a/src/core/common/user_script_data.h b/src/core/common/user_script_data.h index 3dfec0ec3..d0856e02a 100644 --- a/src/core/common/user_script_data.h +++ b/src/core/common/user_script_data.h @@ -60,4 +60,10 @@ struct UserScriptData { uint64 scriptId; }; +QT_BEGIN_NAMESPACE + +Q_DECLARE_TYPEINFO(UserScriptData, Q_MOVABLE_TYPE); + +QT_END_NAMESPACE + #endif // USER_SCRIPT_DATA_H diff --git a/src/core/config/linux.pri b/src/core/config/linux.pri index 85dfe69ae..c3398757e 100644 --- a/src/core/config/linux.pri +++ b/src/core/config/linux.pri @@ -27,9 +27,9 @@ GYP_CONFIG += \ contains(QT_CONFIG, system-zlib): use?(system_minizip): GYP_CONFIG += use_system_zlib=1 contains(QT_CONFIG, system-png): GYP_CONFIG += use_system_libpng=1 contains(QT_CONFIG, system-jpeg): GYP_CONFIG += use_system_libjpeg=1 +contains(QT_CONFIG, system-harfbuzz): GYP_CONFIG += use_system_harfbuzz=1 !contains(QT_CONFIG, pulseaudio): GYP_CONFIG += use_pulseaudio=0 - -use?(system_harfbuzz): GYP_CONFIG += use_system_harfbuzz=1 +!contains(QT_CONFIG, glib): GYP_CONFIG += use_glib=0 use?(system_libevent): GYP_CONFIG += use_system_libevent=1 use?(system_libwebp): GYP_CONFIG += use_system_libwebp=1 use?(system_libsrtp): GYP_CONFIG += use_system_libsrtp=1 diff --git a/src/core/cookie_monster_delegate_qt.h b/src/core/cookie_monster_delegate_qt.h index 7592d57fa..db80bf0a1 100644 --- a/src/core/cookie_monster_delegate_qt.h +++ b/src/core/cookie_monster_delegate_qt.h @@ -47,7 +47,6 @@ QT_WARNING_DISABLE_CLANG("-Wunused-parameter") #include "net/cookies/cookie_monster.h" QT_WARNING_POP -#include <QList> #include <QNetworkCookie> #include <QPointer> diff --git a/src/core/core_gyp_generator.pro b/src/core/core_gyp_generator.pro index 813626dc3..14b8d78e2 100644 --- a/src/core/core_gyp_generator.pro +++ b/src/core/core_gyp_generator.pro @@ -62,15 +62,15 @@ SOURCES = \ process_main.cpp \ proxy_config_service_qt.cpp \ qrc_protocol_handler_qt.cpp \ - qt_render_view_observer_host.cpp \ + render_view_observer_host_qt.cpp \ render_widget_host_view_qt.cpp \ renderer/content_renderer_client_qt.cpp \ renderer/pepper/pepper_flash_browser_host_qt.cpp \ renderer/pepper/pepper_flash_renderer_host_qt.cpp \ renderer/pepper/pepper_host_factory_qt.cpp \ renderer/pepper/pepper_renderer_host_factory_qt.cpp \ - renderer/qt_render_frame_observer.cpp \ - renderer/qt_render_view_observer.cpp \ + renderer/render_frame_observer_qt.cpp \ + renderer/render_view_observer_qt.cpp \ renderer/user_script_controller.cpp \ renderer/web_channel_ipc_transport.cpp \ resource_bundle_qt.cpp \ @@ -134,7 +134,7 @@ HEADERS = \ process_main.h \ proxy_config_service_qt.h \ qrc_protocol_handler_qt.h \ - qt_render_view_observer_host.h \ + render_view_observer_host_qt.h \ render_widget_host_view_qt.h \ render_widget_host_view_qt_delegate.h \ renderer/content_renderer_client_qt.h \ @@ -142,8 +142,8 @@ HEADERS = \ renderer/pepper/pepper_flash_renderer_host_qt.h \ renderer/pepper/pepper_host_factory_qt.h \ renderer/pepper/pepper_renderer_host_factory_qt.h \ - renderer/qt_render_frame_observer.h \ - renderer/qt_render_view_observer.h \ + renderer/render_frame_observer_qt.h \ + renderer/render_view_observer_qt.h \ renderer/user_script_controller.h \ renderer/web_channel_ipc_transport.h \ resource_context_qt.h \ diff --git a/src/core/delegated_frame_node.cpp b/src/core/delegated_frame_node.cpp index 724c2c9bc..a2836d5e6 100644 --- a/src/core/delegated_frame_node.cpp +++ b/src/core/delegated_frame_node.cpp @@ -56,6 +56,7 @@ #include "cc/output/delegated_frame_data.h" #include "cc/quads/debug_border_draw_quad.h" #include "cc/quads/draw_quad.h" +#include "cc/quads/io_surface_draw_quad.h" #include "cc/quads/render_pass_draw_quad.h" #include "cc/quads/solid_color_draw_quad.h" #include "cc/quads/stream_video_draw_quad.h" @@ -79,6 +80,10 @@ #define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull #endif +#ifndef GL_TEXTURE_RECTANGLE +#define GL_TEXTURE_RECTANGLE 0x84F5 +#endif + namespace QtWebEngineCore { class MailboxTexture : public QSGTexture, protected QOpenGLFunctions { @@ -130,7 +135,7 @@ private: QSGGeometry m_geometry; }; -static inline QSharedPointer<QSGLayer> findRenderPassLayer(const cc::RenderPassId &id, const QList<QPair<cc::RenderPassId, QSharedPointer<QSGLayer> > > &list) +static inline QSharedPointer<QSGLayer> findRenderPassLayer(const cc::RenderPassId &id, const QVector<QPair<cc::RenderPassId, QSharedPointer<QSGLayer> > > &list) { typedef QPair<cc::RenderPassId, QSharedPointer<QSGLayer> > Pair; Q_FOREACH (const Pair &pair, list) @@ -646,13 +651,29 @@ void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, MailboxTexture *texture = static_cast<MailboxTexture *>(initAndHoldTexture(resource, quad->ShouldDrawWithBlending())); texture->setTarget(GL_TEXTURE_EXTERNAL_OES); // since this is not default TEXTURE_2D type - StreamVideoNode *svideoNode = new StreamVideoNode(texture); + StreamVideoNode *svideoNode = new StreamVideoNode(texture, false, ExternalTarget); svideoNode->setRect(toQt(squad->rect)); svideoNode->setTextureMatrix(toQt(squad->matrix.matrix())); currentLayerChain->appendChildNode(svideoNode); break; #endif - } default: + } + case cc::DrawQuad::IO_SURFACE_CONTENT: { + const cc::IOSurfaceDrawQuad *ioquad = cc::IOSurfaceDrawQuad::MaterialCast(quad); + ResourceHolder *resource = findAndHoldResource(ioquad->io_surface_resource_id(), resourceCandidates); + MailboxTexture *texture = static_cast<MailboxTexture *>(initAndHoldTexture(resource, quad->ShouldDrawWithBlending())); + texture->setTarget(GL_TEXTURE_RECTANGLE); + + bool flip = ioquad->orientation != cc::IOSurfaceDrawQuad::FLIPPED; + StreamVideoNode *svideoNode = new StreamVideoNode(texture, flip, RectangleTarget); + QMatrix4x4 matrix; + matrix.scale(ioquad->io_surface_size.width(), ioquad->io_surface_size.height()); + svideoNode->setRect(toQt(ioquad->rect)); + svideoNode->setTextureMatrix(matrix); + currentLayerChain->appendChildNode(svideoNode); + break; + } + default: qWarning("Unimplemented quad material: %d", quad->material); } } diff --git a/src/core/delegated_frame_node.h b/src/core/delegated_frame_node.h index 60a1535d2..eed03fadd 100644 --- a/src/core/delegated_frame_node.h +++ b/src/core/delegated_frame_node.h @@ -90,9 +90,9 @@ private: QExplicitlySharedDataPointer<ChromiumCompositorData> m_chromiumCompositorData; struct SGObjects { - QList<QPair<cc::RenderPassId, QSharedPointer<QSGLayer> > > renderPassLayers; - QList<QSharedPointer<QSGRootNode> > renderPassRootNodes; - QList<QSharedPointer<QSGTexture> > textureStrongRefs; + QVector<QPair<cc::RenderPassId, QSharedPointer<QSGLayer> > > renderPassLayers; + QVector<QSharedPointer<QSGRootNode> > renderPassRootNodes; + QVector<QSharedPointer<QSGTexture> > textureStrongRefs; } m_sgObjects; int m_numPendingSyncPoints; QMap<uint32, gfx::TransferableFence> m_mailboxGLFences; diff --git a/src/core/gl_context_qt.cpp b/src/core/gl_context_qt.cpp index b350c3c5b..3c3b8225d 100644 --- a/src/core/gl_context_qt.cpp +++ b/src/core/gl_context_qt.cpp @@ -146,10 +146,14 @@ scoped_refptr<GLContext> GLContext::CreateGLContext(GLShareGroup* share_group, G { #if defined(OS_WIN) scoped_refptr<GLContext> context; - if (GetGLImplementation() == kGLImplementationDesktopGL) + if (GetGLImplementation() == kGLImplementationDesktopGL) { context = new GLContextWGL(share_group); - else + if (!context->Initialize(compatible_surface, gpu_preference)) + return nullptr; + return context; + } else { context = new GLContextEGL(share_group); + } #else scoped_refptr<GLContext> context = new GLContextEGL(share_group); #endif diff --git a/src/core/location_provider_qt.cpp b/src/core/location_provider_qt.cpp index e3be01b36..222d15354 100644 --- a/src/core/location_provider_qt.cpp +++ b/src/core/location_provider_qt.cpp @@ -88,12 +88,15 @@ QtPositioningHelper::~QtPositioningHelper() m_locationProvider->m_positioningHelper = 0; } +static bool isHighAccuracySource(const QGeoPositionInfoSource *source) +{ + return source->supportedPositioningMethods().testFlag( + QGeoPositionInfoSource::SatellitePositioningMethods); +} + void QtPositioningHelper::start(bool highAccuracy) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - Q_UNUSED(highAccuracy); - // FIXME: go through availableSources until one supports QGeoPositionInfoSource::SatellitePositioningMethods - // for the highAccuracy case. m_positionInfoSource = QGeoPositionInfoSource::createDefaultSource(this); if (!m_positionInfoSource) { qWarning("Failed to initialize location provider: The system either has no default " @@ -103,6 +106,23 @@ void QtPositioningHelper::start(bool highAccuracy) return; } + // Find high accuracy source if the default source is not already one. + if (highAccuracy && !isHighAccuracySource(m_positionInfoSource)) { + Q_FOREACH (const QString &name, QGeoPositionInfoSource::availableSources()) { + if (name == m_positionInfoSource->sourceName()) + continue; + QGeoPositionInfoSource *source = QGeoPositionInfoSource::createSource(name, this); + if (source && isHighAccuracySource(source)) { + delete m_positionInfoSource; + m_positionInfoSource = source; + break; + } + delete source; + } + m_positionInfoSource->setPreferredPositioningMethods( + QGeoPositionInfoSource::SatellitePositioningMethods); + } + connect(m_positionInfoSource, &QGeoPositionInfoSource::positionUpdated, this, &QtPositioningHelper::updatePosition); // disambiguate the error getter and the signal in QGeoPositionInfoSource. connect(m_positionInfoSource, static_cast<void (QGeoPositionInfoSource::*)(QGeoPositionInfoSource::Error)>(&QGeoPositionInfoSource::error) diff --git a/src/core/permission_manager_qt.cpp b/src/core/permission_manager_qt.cpp index d93f9c331..19204b270 100644 --- a/src/core/permission_manager_qt.cpp +++ b/src/core/permission_manager_qt.cpp @@ -83,8 +83,7 @@ void PermissionManagerQt::permissionRequestReply(const QUrl &origin, BrowserCont m_permissions[key] = reply; content::PermissionStatus status = reply ? content::PERMISSION_STATUS_GRANTED : content::PERMISSION_STATUS_DENIED; auto it = m_requests.begin(); - const auto end = m_requests.end(); - while (it != end) { + while (it != m_requests.end()) { if (it->origin == origin && it->type == type) { it->callback.Run(status); it = m_requests.erase(it); diff --git a/src/core/qtwebengine.gypi b/src/core/qtwebengine.gypi index a420918a0..96b48e2ca 100644 --- a/src/core/qtwebengine.gypi +++ b/src/core/qtwebengine.gypi @@ -13,6 +13,8 @@ '<(chromium_src_dir)/components/components.gyp:error_page_renderer', '<(chromium_src_dir)/components/components.gyp:visitedlink_browser', '<(chromium_src_dir)/components/components.gyp:visitedlink_renderer', + '<(chromium_src_dir)/components/components.gyp:web_cache_browser', + '<(chromium_src_dir)/components/components.gyp:web_cache_renderer', '<(chromium_src_dir)/content/content.gyp:content', '<(chromium_src_dir)/content/content.gyp:content_app_browser', '<(chromium_src_dir)/content/content.gyp:content_browser', diff --git a/src/core/qt_render_view_observer_host.cpp b/src/core/render_view_observer_host_qt.cpp index 97d001ed6..03c9d241f 100644 --- a/src/core/qt_render_view_observer_host.cpp +++ b/src/core/render_view_observer_host_qt.cpp @@ -34,7 +34,7 @@ ** ****************************************************************************/ -#include "qt_render_view_observer_host.h" +#include "render_view_observer_host_qt.h" #include "common/qt_messages.h" #include "content/public/browser/web_contents.h" @@ -44,31 +44,31 @@ namespace QtWebEngineCore { -QtRenderViewObserverHost::QtRenderViewObserverHost(content::WebContents *webContents, WebContentsAdapterClient *adapterClient) +RenderViewObserverHostQt::RenderViewObserverHostQt(content::WebContents *webContents, WebContentsAdapterClient *adapterClient) : content::WebContentsObserver(webContents) , m_adapterClient(adapterClient) { } -void QtRenderViewObserverHost::fetchDocumentMarkup(quint64 requestId) +void RenderViewObserverHostQt::fetchDocumentMarkup(quint64 requestId) { - Send(new QtRenderViewObserver_FetchDocumentMarkup(routing_id(), requestId)); + Send(new RenderViewObserverQt_FetchDocumentMarkup(routing_id(), requestId)); } -void QtRenderViewObserverHost::fetchDocumentInnerText(quint64 requestId) +void RenderViewObserverHostQt::fetchDocumentInnerText(quint64 requestId) { - Send(new QtRenderViewObserver_FetchDocumentInnerText(routing_id(), requestId)); + Send(new RenderViewObserverQt_FetchDocumentInnerText(routing_id(), requestId)); } -bool QtRenderViewObserverHost::OnMessageReceived(const IPC::Message& message) +bool RenderViewObserverHostQt::OnMessageReceived(const IPC::Message& message) { bool handled = true; - IPC_BEGIN_MESSAGE_MAP(QtRenderViewObserverHost, message) - IPC_MESSAGE_HANDLER(QtRenderViewObserverHost_DidFetchDocumentMarkup, + IPC_BEGIN_MESSAGE_MAP(RenderViewObserverHostQt, message) + IPC_MESSAGE_HANDLER(RenderViewObserverHostQt_DidFetchDocumentMarkup, onDidFetchDocumentMarkup) - IPC_MESSAGE_HANDLER(QtRenderViewObserverHost_DidFetchDocumentInnerText, + IPC_MESSAGE_HANDLER(RenderViewObserverHostQt_DidFetchDocumentInnerText, onDidFetchDocumentInnerText) - IPC_MESSAGE_HANDLER(QtRenderViewObserverHost_DidFirstVisuallyNonEmptyLayout, + IPC_MESSAGE_HANDLER(RenderViewObserverHostQt_DidFirstVisuallyNonEmptyLayout, onDidFirstVisuallyNonEmptyLayout) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() @@ -76,17 +76,17 @@ bool QtRenderViewObserverHost::OnMessageReceived(const IPC::Message& message) } -void QtRenderViewObserverHost::onDidFetchDocumentMarkup(quint64 requestId, const base::string16& markup) +void RenderViewObserverHostQt::onDidFetchDocumentMarkup(quint64 requestId, const base::string16& markup) { m_adapterClient->didFetchDocumentMarkup(requestId, toQt(markup)); } -void QtRenderViewObserverHost::onDidFetchDocumentInnerText(quint64 requestId, const base::string16& innerText) +void RenderViewObserverHostQt::onDidFetchDocumentInnerText(quint64 requestId, const base::string16& innerText) { m_adapterClient->didFetchDocumentInnerText(requestId, toQt(innerText)); } -void QtRenderViewObserverHost::onDidFirstVisuallyNonEmptyLayout() +void RenderViewObserverHostQt::onDidFirstVisuallyNonEmptyLayout() { RenderWidgetHostViewQt *rwhv = static_cast<RenderWidgetHostViewQt*>(web_contents()->GetRenderWidgetHostView()); if (rwhv) diff --git a/src/core/qt_render_view_observer_host.h b/src/core/render_view_observer_host_qt.h index 148fcb9da..2683e5807 100644 --- a/src/core/qt_render_view_observer_host.h +++ b/src/core/render_view_observer_host_qt.h @@ -34,8 +34,8 @@ ** ****************************************************************************/ -#ifndef QT_RENDER_VIEW_OBSERVER_HOST_H -#define QT_RENDER_VIEW_OBSERVER_HOST_H +#ifndef RENDER_VIEW_OBSERVER_HOST_QT_H +#define RENDER_VIEW_OBSERVER_HOST_QT_H #include "content/public/browser/web_contents_observer.h" @@ -49,10 +49,10 @@ namespace QtWebEngineCore { class WebContentsAdapterClient; -class QtRenderViewObserverHost : public content::WebContentsObserver +class RenderViewObserverHostQt : public content::WebContentsObserver { public: - QtRenderViewObserverHost(content::WebContents*, WebContentsAdapterClient *adapterClient); + RenderViewObserverHostQt(content::WebContents*, WebContentsAdapterClient *adapterClient); void fetchDocumentMarkup(quint64 requestId); void fetchDocumentInnerText(quint64 requestId); @@ -67,4 +67,4 @@ private: } // namespace QtWebEngineCore -#endif // QT_RENDER_VIEW_OBSERVER_HOST_H +#endif // RENDER_VIEW_OBSERVER_HOST_QT_H diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp index 94b459e74..d2d292ee9 100644 --- a/src/core/render_widget_host_view_qt.cpp +++ b/src/core/render_widget_host_view_qt.cpp @@ -186,13 +186,14 @@ static inline int flagsFromModifiers(Qt::KeyboardModifiers modifiers) static uint32 s_eventId = 0; class MotionEventQt : public ui::MotionEvent { public: - MotionEventQt(const QList<QTouchEvent::TouchPoint> &touchPoints, const base::TimeTicks &eventTime, Action action, const Qt::KeyboardModifiers modifiers, int index = -1) + MotionEventQt(const QList<QTouchEvent::TouchPoint> &touchPoints, const base::TimeTicks &eventTime, Action action, const Qt::KeyboardModifiers modifiers, float dpiScale, int index = -1) : touchPoints(touchPoints) , eventTime(eventTime) , action(action) , eventId(++s_eventId) , flags(flagsFromModifiers(modifiers)) , index(index) + , dpiScale(dpiScale) { // ACTION_DOWN and ACTION_UP must be accesssed through pointer_index 0 Q_ASSERT((action != ACTION_DOWN && action != ACTION_UP) || index == 0); @@ -203,8 +204,8 @@ public: virtual int GetActionIndex() const Q_DECL_OVERRIDE { return index; } virtual size_t GetPointerCount() const Q_DECL_OVERRIDE { return touchPoints.size(); } virtual int GetPointerId(size_t pointer_index) const Q_DECL_OVERRIDE { return touchPoints.at(pointer_index).id(); } - virtual float GetX(size_t pointer_index) const Q_DECL_OVERRIDE { return touchPoints.at(pointer_index).pos().x(); } - virtual float GetY(size_t pointer_index) const Q_DECL_OVERRIDE { return touchPoints.at(pointer_index).pos().y(); } + virtual float GetX(size_t pointer_index) const Q_DECL_OVERRIDE { return touchPoints.at(pointer_index).pos().x() / dpiScale; } + virtual float GetY(size_t pointer_index) const Q_DECL_OVERRIDE { return touchPoints.at(pointer_index).pos().y() / dpiScale; } virtual float GetRawX(size_t pointer_index) const Q_DECL_OVERRIDE { return touchPoints.at(pointer_index).screenPos().x(); } virtual float GetRawY(size_t pointer_index) const Q_DECL_OVERRIDE { return touchPoints.at(pointer_index).screenPos().y(); } virtual float GetTouchMajor(size_t pointer_index) const Q_DECL_OVERRIDE @@ -240,6 +241,7 @@ private: const uint32 eventId; int flags; int index; + float dpiScale; }; RenderWidgetHostViewQt::RenderWidgetHostViewQt(content::RenderWidgetHost* widget) @@ -413,12 +415,13 @@ gfx::Rect RenderWidgetHostViewQt::GetViewBounds() const return gfx::BoundingRect(p1, p2); } -void RenderWidgetHostViewQt::SetBackgroundColor(SkColor color) { +void RenderWidgetHostViewQt::SetBackgroundColor(SkColor color) +{ RenderWidgetHostViewBase::SetBackgroundColor(color); // Set the background of the compositor if necessary m_delegate->setClearColor(toQt(color)); // Set the background of the blink::FrameView - m_host->Send(new QtRenderViewObserver_SetBackgroundColor(m_host->GetRoutingID(), color)); + m_host->Send(new RenderViewObserverQt_SetBackgroundColor(m_host->GetRoutingID(), color)); } // Return value indicates whether the mouse is locked successfully or not. @@ -997,7 +1000,7 @@ void RenderWidgetHostViewQt::handleTouchEvent(QTouchEvent *ev) QList<QTouchEvent::TouchPoint> touchPoints = mapTouchPointIds(ev->touchPoints()); if (ev->type() == QEvent::TouchCancel) { - MotionEventQt cancelEvent(touchPoints, eventTimestamp, ui::MotionEvent::ACTION_CANCEL, ev->modifiers()); + MotionEventQt cancelEvent(touchPoints, eventTimestamp, ui::MotionEvent::ACTION_CANCEL, ev->modifiers(), dpiScale()); processMotionEvent(cancelEvent); return; } @@ -1030,7 +1033,7 @@ void RenderWidgetHostViewQt::handleTouchEvent(QTouchEvent *ev) continue; } - MotionEventQt motionEvent(touchPoints, eventTimestamp, action, ev->modifiers(), i); + MotionEventQt motionEvent(touchPoints, eventTimestamp, action, ev->modifiers(), dpiScale(), i); processMotionEvent(motionEvent); } } diff --git a/src/core/renderer/content_renderer_client_qt.cpp b/src/core/renderer/content_renderer_client_qt.cpp index 0b8262c76..db50caad8 100644 --- a/src/core/renderer/content_renderer_client_qt.cpp +++ b/src/core/renderer/content_renderer_client_qt.cpp @@ -40,6 +40,7 @@ #include "chrome/common/localized_error.h" #include "components/error_page/common/error_page_params.h" #include "components/visitedlink/renderer/visitedlink_slave.h" +#include "components/web_cache/renderer/web_cache_render_process_observer.h" #include "content/public/renderer/render_frame.h" #include "content/public/renderer/render_thread.h" #include "content/public/renderer/render_view.h" @@ -53,8 +54,8 @@ #include "content/public/common/web_preferences.h" #include "renderer/web_channel_ipc_transport.h" -#include "renderer/qt_render_frame_observer.h" -#include "renderer/qt_render_view_observer.h" +#include "renderer/render_frame_observer_qt.h" +#include "renderer/render_view_observer_qt.h" #include "renderer/user_script_controller.h" #include "grit/renderer_resources.h" @@ -77,7 +78,9 @@ void ContentRendererClientQt::RenderThreadStarted() content::RenderThread *renderThread = content::RenderThread::Get(); renderThread->RegisterExtension(WebChannelIPCTransport::getV8Extension()); m_visitedLinkSlave.reset(new visitedlink::VisitedLinkSlave); + m_webCacheObserver.reset(new web_cache::WebCacheRenderProcessObserver()); renderThread->AddObserver(m_visitedLinkSlave.data()); + renderThread->AddObserver(m_webCacheObserver.data()); renderThread->AddObserver(UserScriptController::instance()); // mark qrc as a secure scheme (avoids deprecation warnings) @@ -87,14 +90,14 @@ void ContentRendererClientQt::RenderThreadStarted() void ContentRendererClientQt::RenderViewCreated(content::RenderView* render_view) { // RenderViewObservers destroy themselves with their RenderView. - new QtRenderViewObserver(render_view); + new RenderViewObserverQt(render_view, m_webCacheObserver.data()); new WebChannelIPCTransport(render_view); UserScriptController::instance()->renderViewCreated(render_view); } void ContentRendererClientQt::RenderFrameCreated(content::RenderFrame* render_frame) { - new QtWebEngineCore::QtRenderFrameObserver(render_frame); + new QtWebEngineCore::RenderFrameObserverQt(render_frame); } bool ContentRendererClientQt::HasErrorPage(int httpStatusCode, std::string *errorDomain) diff --git a/src/core/renderer/content_renderer_client_qt.h b/src/core/renderer/content_renderer_client_qt.h index fab88441f..eb55156ad 100644 --- a/src/core/renderer/content_renderer_client_qt.h +++ b/src/core/renderer/content_renderer_client_qt.h @@ -45,6 +45,10 @@ namespace visitedlink { class VisitedLinkSlave; } +namespace web_cache { +class WebCacheRenderProcessObserver; +} + namespace QtWebEngineCore { class ContentRendererClientQt : public content::ContentRendererClient { @@ -64,6 +68,7 @@ public: private: QScopedPointer<visitedlink::VisitedLinkSlave> m_visitedLinkSlave; + QScopedPointer<web_cache::WebCacheRenderProcessObserver> m_webCacheObserver; }; } // namespace diff --git a/src/core/renderer/qt_render_frame_observer.cpp b/src/core/renderer/render_frame_observer_qt.cpp index 5f06d1e4e..8130cc53a 100644 --- a/src/core/renderer/qt_render_frame_observer.cpp +++ b/src/core/renderer/render_frame_observer_qt.cpp @@ -34,7 +34,7 @@ ** ****************************************************************************/ -#include "qt_render_frame_observer.h" +#include "render_frame_observer_qt.h" #include "content/public/renderer/renderer_ppapi_host.h" #include "ppapi/host/ppapi_host.h" @@ -44,17 +44,17 @@ namespace QtWebEngineCore { -QtRenderFrameObserver::QtRenderFrameObserver(content::RenderFrame* render_frame) +RenderFrameObserverQt::RenderFrameObserverQt(content::RenderFrame* render_frame) : RenderFrameObserver(render_frame) { } -QtRenderFrameObserver::~QtRenderFrameObserver() +RenderFrameObserverQt::~RenderFrameObserverQt() { } #if defined(ENABLE_PLUGINS) -void QtRenderFrameObserver::DidCreatePepperPlugin(content::RendererPpapiHost* host) +void RenderFrameObserverQt::DidCreatePepperPlugin(content::RendererPpapiHost* host) { host->GetPpapiHost()->AddHostFactoryFilter( scoped_ptr<ppapi::host::HostFactory>( diff --git a/src/core/renderer/qt_render_frame_observer.h b/src/core/renderer/render_frame_observer_qt.h index 42f2b7464..4835e442e 100644 --- a/src/core/renderer/qt_render_frame_observer.h +++ b/src/core/renderer/render_frame_observer_qt.h @@ -34,8 +34,8 @@ ** ****************************************************************************/ -#ifndef QT_RENDER_FRAME_OBSERVER_H -#define QT_RENDER_FRAME_OBSERVER_H +#ifndef RENDER_FRAME_OBSERVER_QT_H +#define RENDER_FRAME_OBSERVER_QT_H #include "base/basictypes.h" #include "base/compiler_specific.h" @@ -48,19 +48,19 @@ class RenderFrame; namespace QtWebEngineCore { -class QtRenderFrameObserver : public content::RenderFrameObserver { +class RenderFrameObserverQt : public content::RenderFrameObserver { public: - explicit QtRenderFrameObserver(content::RenderFrame* render_frame); - ~QtRenderFrameObserver(); + explicit RenderFrameObserverQt(content::RenderFrame* render_frame); + ~RenderFrameObserverQt(); #if defined(ENABLE_PLUGINS) void DidCreatePepperPlugin(content::RendererPpapiHost* host) override; #endif private: - DISALLOW_COPY_AND_ASSIGN(QtRenderFrameObserver); + DISALLOW_COPY_AND_ASSIGN(RenderFrameObserverQt); }; } // namespace QtWebEngineCore -#endif // QT_RENDER_FRAME_OBSERVER_H +#endif // RENDER_FRAME_OBSERVER_QT_H diff --git a/src/core/renderer/qt_render_view_observer.cpp b/src/core/renderer/render_view_observer_qt.cpp index ba91e54ae..47efd07e4 100644 --- a/src/core/renderer/qt_render_view_observer.cpp +++ b/src/core/renderer/render_view_observer_qt.cpp @@ -34,55 +34,65 @@ ** ****************************************************************************/ -#include "renderer/qt_render_view_observer.h" +#include "renderer/render_view_observer_qt.h" #include "common/qt_messages.h" +#include "components/web_cache/renderer/web_cache_render_process_observer.h" #include "content/public/renderer/render_view.h" #include "third_party/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/public/web/WebElement.h" #include "third_party/WebKit/public/web/WebFrame.h" #include "third_party/WebKit/public/web/WebView.h" -QtRenderViewObserver::QtRenderViewObserver(content::RenderView* render_view) +RenderViewObserverQt::RenderViewObserverQt( + content::RenderView* render_view, + web_cache::WebCacheRenderProcessObserver* web_cache_render_process_observer) : content::RenderViewObserver(render_view) + , m_web_cache_render_process_observer(web_cache_render_process_observer) { } -void QtRenderViewObserver::onFetchDocumentMarkup(quint64 requestId) +void RenderViewObserverQt::onFetchDocumentMarkup(quint64 requestId) { - Send(new QtRenderViewObserverHost_DidFetchDocumentMarkup( + Send(new RenderViewObserverHostQt_DidFetchDocumentMarkup( routing_id(), requestId, render_view()->GetWebView()->mainFrame()->contentAsMarkup())); } -void QtRenderViewObserver::onFetchDocumentInnerText(quint64 requestId) +void RenderViewObserverQt::onFetchDocumentInnerText(quint64 requestId) { - Send(new QtRenderViewObserverHost_DidFetchDocumentInnerText( + Send(new RenderViewObserverHostQt_DidFetchDocumentInnerText( routing_id(), requestId, render_view()->GetWebView()->mainFrame()->contentAsText(std::numeric_limits<std::size_t>::max()))); } -void QtRenderViewObserver::onSetBackgroundColor(quint32 color) +void RenderViewObserverQt::onSetBackgroundColor(quint32 color) { render_view()->GetWebView()->setBaseBackgroundColor(color); } -void QtRenderViewObserver::OnFirstVisuallyNonEmptyLayout() +void RenderViewObserverQt::OnFirstVisuallyNonEmptyLayout() { - Send(new QtRenderViewObserverHost_DidFirstVisuallyNonEmptyLayout(routing_id())); + Send(new RenderViewObserverHostQt_DidFirstVisuallyNonEmptyLayout(routing_id())); } -bool QtRenderViewObserver::OnMessageReceived(const IPC::Message& message) +bool RenderViewObserverQt::OnMessageReceived(const IPC::Message& message) { bool handled = true; - IPC_BEGIN_MESSAGE_MAP(QtRenderViewObserver, message) - IPC_MESSAGE_HANDLER(QtRenderViewObserver_FetchDocumentMarkup, onFetchDocumentMarkup) - IPC_MESSAGE_HANDLER(QtRenderViewObserver_FetchDocumentInnerText, onFetchDocumentInnerText) - IPC_MESSAGE_HANDLER(QtRenderViewObserver_SetBackgroundColor, onSetBackgroundColor) + IPC_BEGIN_MESSAGE_MAP(RenderViewObserverQt, message) + IPC_MESSAGE_HANDLER(RenderViewObserverQt_FetchDocumentMarkup, onFetchDocumentMarkup) + IPC_MESSAGE_HANDLER(RenderViewObserverQt_FetchDocumentInnerText, onFetchDocumentInnerText) + IPC_MESSAGE_HANDLER(RenderViewObserverQt_SetBackgroundColor, onSetBackgroundColor) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; } + +void RenderViewObserverQt::Navigate(const GURL &) +{ + if (m_web_cache_render_process_observer) + m_web_cache_render_process_observer->ExecutePendingClearCache(); +} diff --git a/src/core/renderer/qt_render_view_observer.h b/src/core/renderer/render_view_observer_qt.h index 3f7829a92..166dcc9ea 100644 --- a/src/core/renderer/qt_render_view_observer.h +++ b/src/core/renderer/render_view_observer_qt.h @@ -33,16 +33,21 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ -#ifndef QT_RENDER_VIEW_OBSERVER_H -#define QT_RENDER_VIEW_OBSERVER_H +#ifndef RENDER_VIEW_OBSERVER_QT_H +#define RENDER_VIEW_OBSERVER_QT_H #include "content/public/renderer/render_view_observer.h" #include <QtGlobal> -class QtRenderViewObserver : public content::RenderViewObserver { +namespace web_cache { +class WebCacheRenderProcessObserver; +} + +class RenderViewObserverQt : public content::RenderViewObserver { public: - QtRenderViewObserver(content::RenderView* render_view); + RenderViewObserverQt(content::RenderView* render_view, + web_cache::WebCacheRenderProcessObserver* web_cache_render_process_observer); private: void onFetchDocumentMarkup(quint64 requestId); @@ -52,8 +57,11 @@ private: void OnFirstVisuallyNonEmptyLayout() Q_DECL_OVERRIDE; virtual bool OnMessageReceived(const IPC::Message& message) Q_DECL_OVERRIDE; + virtual void Navigate(const GURL& url) Q_DECL_OVERRIDE; + + web_cache::WebCacheRenderProcessObserver* m_web_cache_render_process_observer; - DISALLOW_COPY_AND_ASSIGN(QtRenderViewObserver); + DISALLOW_COPY_AND_ASSIGN(RenderViewObserverQt); }; -#endif // QT_RENDER_VIEW_OBSERVER_H +#endif // RENDER_VIEW_OBSERVER_QT_H diff --git a/src/core/resources/devtools_discovery_page.html b/src/core/resources/devtools_discovery_page.html index 7aac74932..d37dbfcf4 100644 --- a/src/core/resources/devtools_discovery_page.html +++ b/src/core/resources/devtools_discovery_page.html @@ -3,44 +3,68 @@ <title>QtWebEngine Remote Debugging</title> <style> body { - background-color: rgb(245, 245, 245); + color: #222; font-family: Helvetica, Arial, sans-serif; + margin: 0; text-shadow: rgba(255, 255, 255, 0.496094) 0px 1px 0px; } #caption { - color: black; font-size: 16px; - margin-top: 30px; - margin-bottom: 0px; - margin-left: 70px; + margin-top: 15px; + margin-bottom: 10px; + margin-left: 20px; height: 20px; text-align: left; } #items { - margin-left: 60px; - margin-right: 60px; - -webkit-box-orient: horizontal; - -webkit-box-lines: multiple; + display: flex; + flex-direction: column; + margin: 10px; +} + +.item { + color: #222; + display: flex; + flex-direction: row; + text-decoration: none; + padding: 10px; + -webkit-transition-property: background-color, border-color; + -webkit-transition: background-color 0.15s, 0.15s; + -webkit-transition-delay: 0ms, 0ms; } -.frontend_ref { +.item:not(.connected):hover { + background-color: rgba(242, 242, 242, 1); + border-color: rgba(110, 116, 128, 1); color: black; - text-decoration: initial; } -.text { - background: no-repeat 0; - background-size: 16px; - font-size: 12px; - margin: 4px 0px 0px 4px; +.item.connected:hover { + border-color: rgba(184, 184, 184, 1); + color: rgb(110, 116, 128); +} + +.description { + display: flex; + flex-direction: column; +} + +.title, .subtitle { + font-size: 13px; + margin: 4px 0px 0px 6px; overflow: hidden; - padding: 2px 0px 0px 20px; - text-align: left; - text-overflow: ellipsis; - white-space: nowrap; + padding-left: 20px; } + +.title { + background-repeat: no-repeat; + background-size: 16px; + font-size: 15px; +} + + </style> <script> @@ -74,35 +98,43 @@ function overrideFrontendUrl(item) { } function appendItem(item_object) { - var frontend_ref; + var item_element; if (item_object.devtoolsFrontendUrl) { - frontend_ref = document.createElement('a'); - frontend_ref.href = overrideFrontendUrl(item_object); - frontend_ref.title = item_object.title; + item_element = document.createElement('a'); + item_element.href = overrideFrontendUrl(item_object); + item_element.title = item_object.title; } else { - frontend_ref = document.createElement('div'); - frontend_ref.title = 'The tab already has an active debug session'; + item_element = document.createElement('div'); + item_element.className = 'connected'; + item_element.title = 'The tab already has an active debug session'; } - frontend_ref.className = 'frontend_ref'; + item_element.classList.add('item'); - var text = document.createElement('div'); - text.className = 'text'; - text.innerText = item_object.description || item_object.title; - text.style.cssText = 'background-image:url(' + - item_object.faviconUrl + ')'; - frontend_ref.appendChild(text); + var description = document.createElement('div'); + description.className = 'description'; - var item = document.createElement('p'); - item.appendChild(frontend_ref); + var title = document.createElement('div'); + title.className = 'title'; + title.textContent = item_object.description || item_object.title; + title.style.cssText = 'background-image:url(' + + item_object.faviconUrl + ')'; + description.appendChild(title); - document.getElementById('items').appendChild(item); + var subtitle = document.createElement('div'); + subtitle.className = 'subtitle'; + subtitle.textContent = (item_object.url || '').substring(0, 300); + description.appendChild(subtitle); + + item_element.appendChild(description); + + document.getElementById('items').appendChild(item_element); } </script> </head> <body onload='onLoad()'> <div id='caption'>Inspectable pages</div> + <hr> <div id='items'> </div> - <hr> </body> </html> diff --git a/src/core/stream_video_node.cpp b/src/core/stream_video_node.cpp index a5a6041f3..fdae5fee2 100644 --- a/src/core/stream_video_node.cpp +++ b/src/core/stream_video_node.cpp @@ -38,9 +38,12 @@ #include <QtQuick/qsgtexture.h> +namespace QtWebEngineCore { + class StreamVideoMaterialShader : public QSGMaterialShader { public: + StreamVideoMaterialShader(TextureTarget target) : m_target(target) { } virtual void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial); virtual char const *const *attributeNames() const Q_DECL_OVERRIDE { @@ -55,7 +58,7 @@ public: protected: virtual const char *vertexShader() const Q_DECL_OVERRIDE { // Keep in sync with cc::VertexShaderVideoTransform - const char *shader = + static const char *shader = "attribute highp vec4 a_position;\n" "attribute mediump vec2 a_texCoord;\n" "uniform highp mat4 matrix;\n" @@ -70,7 +73,7 @@ protected: virtual const char *fragmentShader() const Q_DECL_OVERRIDE { // Keep in sync with cc::FragmentShaderRGBATexAlpha - static const char *shader = + static const char *shaderExternal = "#extension GL_OES_EGL_image_external : require\n" "varying mediump vec2 v_texCoord;\n" "uniform samplerExternalOES s_texture;\n" @@ -79,7 +82,19 @@ protected: " lowp vec4 texColor = texture2D(s_texture, v_texCoord);\n" " gl_FragColor = texColor * alpha;\n" "}"; - return shader; + static const char *shader2DRect = + "#extension GL_ARB_texture_rectangle : require\n" + "varying mediump vec2 v_texCoord;\n" + "uniform sampler2DRect s_texture;\n" + "uniform lowp float alpha;\n" + "void main() {\n" + " lowp vec4 texColor = texture2DRect(s_texture, v_texCoord);\n" + " gl_FragColor = texColor * alpha;\n" + "}"; + if (m_target == ExternalTarget) + return shaderExternal; + else + return shader2DRect; } virtual void initialize() { @@ -93,6 +108,7 @@ protected: int m_id_texMatrix; int m_id_sTexture; int m_id_opacity; + TextureTarget m_target; }; void StreamVideoMaterialShader::updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) @@ -113,31 +129,38 @@ void StreamVideoMaterialShader::updateState(const RenderState &state, QSGMateria program()->setUniformValue(m_id_texMatrix, mat->m_texMatrix); } -StreamVideoMaterial::StreamVideoMaterial(QSGTexture *texture) +StreamVideoMaterial::StreamVideoMaterial(QSGTexture *texture, TextureTarget target) : m_texture(texture) + , m_target(target) { } QSGMaterialShader *StreamVideoMaterial::createShader() const { - return new StreamVideoMaterialShader; + return new StreamVideoMaterialShader(m_target); } -StreamVideoNode::StreamVideoNode(QSGTexture *texture) +StreamVideoNode::StreamVideoNode(QSGTexture *texture, bool flip, TextureTarget target) : m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4) + , m_flip(flip) { setGeometry(&m_geometry); setFlag(QSGNode::OwnsMaterial); - m_material = new StreamVideoMaterial(texture); + m_material = new StreamVideoMaterial(texture, target); setMaterial(m_material); } void StreamVideoNode::setRect(const QRectF &rect) { - QSGGeometry::updateTexturedRectGeometry(geometry(), rect, QRectF(0, 0, 1, 1)); + if (m_flip) + QSGGeometry::updateTexturedRectGeometry(geometry(), rect, QRectF(0, 1, 1, -1)); + else + QSGGeometry::updateTexturedRectGeometry(geometry(), rect, QRectF(0, 0, 1, 1)); } void StreamVideoNode::setTextureMatrix(const QMatrix4x4 &matrix) { m_material->m_texMatrix = matrix; } + +} // namespace diff --git a/src/core/stream_video_node.h b/src/core/stream_video_node.h index f808bb609..92c640811 100644 --- a/src/core/stream_video_node.h +++ b/src/core/stream_video_node.h @@ -40,19 +40,22 @@ #include <QtQuick/qsgmaterial.h> #include <QtQuick/qsgnode.h> -QT_BEGIN_NAMESPACE -class QSGTexture; -QT_END_NAMESPACE +QT_FORWARD_DECLARE_CLASS(QSGTexture) + +namespace QtWebEngineCore { // These classes duplicate, QtQuick style, the logic of GLRenderer::DrawStreamVideoQuad. // Their behavior should stay as close as possible to GLRenderer. +enum TextureTarget { ExternalTarget, RectangleTarget }; + class StreamVideoMaterial : public QSGMaterial { public: - StreamVideoMaterial(QSGTexture *texture); + StreamVideoMaterial(QSGTexture *texture, TextureTarget target); - virtual QSGMaterialType *type() const Q_DECL_OVERRIDE{ + virtual QSGMaterialType *type() const Q_DECL_OVERRIDE + { static QSGMaterialType theType; return &theType; } @@ -61,18 +64,22 @@ public: QSGTexture *m_texture; QMatrix4x4 m_texMatrix; + TextureTarget m_target; }; class StreamVideoNode : public QSGGeometryNode { public: - StreamVideoNode(QSGTexture *texture); + StreamVideoNode(QSGTexture *texture, bool flip, TextureTarget target); void setRect(const QRectF &rect); void setTextureMatrix(const QMatrix4x4 &matrix); private: QSGGeometry m_geometry; + bool m_flip; StreamVideoMaterial *m_material; }; +} // namespace + #endif // STREAM_VIDEO_NODE_H diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp index 8d3345d1c..84c4e50f3 100644 --- a/src/core/web_contents_adapter.cpp +++ b/src/core/web_contents_adapter.cpp @@ -45,8 +45,8 @@ #include "browser_context_adapter.h" #include "browser_context_qt.h" #include "media_capture_devices_dispatcher.h" -#include "qt_render_view_observer_host.h" #include "qwebenginecallback_p.h" +#include "render_view_observer_host_qt.h" #include "type_conversion.h" #include "web_channel_ipc_transport_host.h" #include "web_contents_adapter_client.h" @@ -385,7 +385,7 @@ void WebContentsAdapter::initialize(WebContentsAdapterClient *adapterClient) // Create and attach observers to the WebContents. d->webContentsDelegate.reset(new WebContentsDelegateQt(d->webContents.get(), adapterClient)); - d->renderViewObserverHost.reset(new QtRenderViewObserverHost(d->webContents.get(), adapterClient)); + d->renderViewObserverHost.reset(new RenderViewObserverHostQt(d->webContents.get(), adapterClient)); // Let the WebContent's view know about the WebContentsAdapterClient. WebContentsViewQt* contentsView = static_cast<WebContentsViewQt*>(static_cast<content::WebContentsImpl*>(d->webContents.get())->GetView()); diff --git a/src/core/web_contents_adapter_p.h b/src/core/web_contents_adapter_p.h index 9b4128749..093b9059d 100644 --- a/src/core/web_contents_adapter_p.h +++ b/src/core/web_contents_adapter_p.h @@ -60,7 +60,7 @@ QT_FORWARD_DECLARE_CLASS(QWebChannel) namespace QtWebEngineCore { class BrowserContextAdapter; -class QtRenderViewObserverHost; +class RenderViewObserverHostQt; class UserScriptControllerHost; class WebChannelIPCTransportHost; class WebContentsAdapterClient; @@ -75,7 +75,7 @@ public: QExplicitlySharedDataPointer<BrowserContextAdapter> browserContextAdapter; scoped_ptr<content::WebContents> webContents; scoped_ptr<WebContentsDelegateQt> webContentsDelegate; - scoped_ptr<QtRenderViewObserverHost> renderViewObserverHost; + scoped_ptr<RenderViewObserverHostQt> renderViewObserverHost; scoped_ptr<WebChannelIPCTransportHost> webChannelTransport; QWebChannel *webChannel; WebContentsAdapterClient *adapterClient; diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp index 1f789161a..1897664e3 100644 --- a/src/core/web_contents_delegate_qt.cpp +++ b/src/core/web_contents_delegate_qt.cpp @@ -51,12 +51,14 @@ #include "web_engine_settings.h" #include "web_engine_visited_links_manager.h" +#include "components/web_cache/browser/web_cache_manager.h" #include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/public/browser/favicon_status.h" #include "content/public/browser/invalidate_type.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/render_frame_host.h" +#include "content/public/browser/render_process_host.h" #include "content/public/browser/web_contents.h" #include "content/public/common/favicon_url.h" #include "content/public/common/file_chooser_params.h" @@ -315,6 +317,11 @@ void WebContentsDelegateQt::DidNavigateAnyFrame(content::RenderFrameHost* render m_viewClient->browserContextAdapter()->visitedLinksManager()->addUrl(params.url); } +void WebContentsDelegateQt::WasShown() +{ + web_cache::WebCacheManager::GetInstance()->ObserveActivity(web_contents()->GetRenderProcessHost()->GetID()); +} + void WebContentsDelegateQt::RequestToLockMouse(content::WebContents *web_contents, bool user_gesture, bool last_unlocked_by_target) { Q_UNUSED(user_gesture); diff --git a/src/core/web_contents_delegate_qt.h b/src/core/web_contents_delegate_qt.h index abdf75fe5..d3075cfbf 100644 --- a/src/core/web_contents_delegate_qt.h +++ b/src/core/web_contents_delegate_qt.h @@ -44,6 +44,7 @@ #include "base/callback.h" #include "javascript_dialog_manager_qt.h" +#include <QtCore/qvector.h> #include <QtCore/qcompilerdetection.h> QT_FORWARD_DECLARE_CLASS(CertificateErrorController) @@ -104,6 +105,7 @@ public: virtual void DidFinishLoad(content::RenderFrameHost *render_frame_host, const GURL &validated_url) Q_DECL_OVERRIDE; virtual void DidUpdateFaviconURL(const std::vector<content::FaviconURL> &candidates) Q_DECL_OVERRIDE; virtual void DidNavigateAnyFrame(content::RenderFrameHost *render_frame_host, const content::LoadCommittedDetails &details, const content::FrameNavigateParams ¶ms) Q_DECL_OVERRIDE; + virtual void WasShown() Q_DECL_OVERRIDE; void overrideWebPreferences(content::WebContents *, content::WebPreferences*); void allowCertificateError(const QSharedPointer<CertificateErrorController> &) ; @@ -116,7 +118,7 @@ private: WebContentsAdapterClient *m_viewClient; QString m_lastSearchedString; int m_lastReceivedFindReply; - QList<int64> m_loadingErrorFrameList; + QVector<int64> m_loadingErrorFrameList; }; } // namespace QtWebEngineCore diff --git a/src/core/web_engine_context.cpp b/src/core/web_engine_context.cpp index 5be35b348..4d1cbf3d4 100644 --- a/src/core/web_engine_context.cpp +++ b/src/core/web_engine_context.cpp @@ -200,7 +200,7 @@ WebEngineContext::WebEngineContext() , m_browserRunner(content::BrowserMainRunner::Create()) , m_globalQObject(new QObject()) { - QList<QByteArray> args; + QVector<QByteArray> args; Q_FOREACH (const QString& arg, QCoreApplication::arguments()) args << arg.toUtf8(); diff --git a/src/core/web_engine_settings.cpp b/src/core/web_engine_settings.cpp index c8d1cc27f..88d8a0c5c 100644 --- a/src/core/web_engine_settings.cpp +++ b/src/core/web_engine_settings.cpp @@ -46,6 +46,10 @@ namespace QtWebEngineCore { +QHash<WebEngineSettings::Attribute, bool> WebEngineSettings::m_defaultAttributes; +QHash<WebEngineSettings::FontFamily, QString> WebEngineSettings::m_defaultFontFamilies; +QHash<WebEngineSettings::FontSize, int> WebEngineSettings::m_defaultFontSizes; + static const int batchTimerTimeout = 0; class BatchTimer : public QTimer { @@ -132,9 +136,12 @@ bool WebEngineSettings::testAttribute(WebEngineSettings::Attribute attr) const void WebEngineSettings::resetAttribute(WebEngineSettings::Attribute attr) { - if (!parentSettings) // FIXME: Set initial defaults. - return; - m_attributes.remove(attr); + if (!parentSettings) { + Q_ASSERT(m_defaultAttributes.contains(attr)); + m_attributes.insert(attr, m_defaultAttributes.value(attr)); + } else { + m_attributes.remove(attr); + } scheduleApplyRecursively(); } @@ -155,9 +162,12 @@ QString WebEngineSettings::fontFamily(WebEngineSettings::FontFamily which) void WebEngineSettings::resetFontFamily(WebEngineSettings::FontFamily which) { - if (!parentSettings) // FIXME: Set initial defaults. - return; - m_fontFamilies.remove(which); + if (!parentSettings) { + Q_ASSERT(m_defaultFontFamilies.contains(which)); + m_fontFamilies.insert(which, m_defaultFontFamilies.value(which)); + } else { + m_fontFamilies.remove(which); + } scheduleApplyRecursively(); } @@ -178,9 +188,12 @@ int WebEngineSettings::fontSize(WebEngineSettings::FontSize type) const void WebEngineSettings::resetFontSize(WebEngineSettings::FontSize type) { - if (!parentSettings) // FIXME: Set initial defaults. - return; - m_fontSizes.remove(type); + if (!parentSettings) { + Q_ASSERT(m_defaultFontSizes.contains(type)); + m_fontSizes.insert(type, m_defaultFontSizes.value(type)); + } else { + m_fontSizes.remove(type); + } scheduleApplyRecursively(); } @@ -199,46 +212,55 @@ QString WebEngineSettings::defaultTextEncoding() const void WebEngineSettings::initDefaults(bool offTheRecord) { - // Initialize the default settings. - m_attributes.insert(AutoLoadImages, true); - m_attributes.insert(JavascriptEnabled, true); - m_attributes.insert(JavascriptCanOpenWindows, true); - m_attributes.insert(JavascriptCanAccessClipboard, false); - m_attributes.insert(LinksIncludedInFocusChain, true); - m_attributes.insert(LocalStorageEnabled, !offTheRecord); - m_attributes.insert(LocalContentCanAccessRemoteUrls, false); - m_attributes.insert(XSSAuditingEnabled, false); - m_attributes.insert(SpatialNavigationEnabled, false); - m_attributes.insert(LocalContentCanAccessFileUrls, true); - m_attributes.insert(HyperlinkAuditingEnabled, false); - m_attributes.insert(ScrollAnimatorEnabled, false); - m_attributes.insert(ErrorPageEnabled, true); - m_attributes.insert(PluginsEnabled, false); - m_attributes.insert(FullScreenSupportEnabled, false); - m_attributes.insert(ScreenCaptureEnabled, false); - - // Default fonts - QFont defaultFont; - defaultFont.setStyleHint(QFont::Serif); - m_fontFamilies.insert(StandardFont, defaultFont.defaultFamily()); - m_fontFamilies.insert(SerifFont, defaultFont.defaultFamily()); - - defaultFont.setStyleHint(QFont::Fantasy); - m_fontFamilies.insert(FantasyFont, defaultFont.defaultFamily()); - - defaultFont.setStyleHint(QFont::Cursive); - m_fontFamilies.insert(CursiveFont, defaultFont.defaultFamily()); - - defaultFont.setStyleHint(QFont::SansSerif); - m_fontFamilies.insert(SansSerifFont, defaultFont.defaultFamily()); - - defaultFont.setStyleHint(QFont::Monospace); - m_fontFamilies.insert(FixedFont, defaultFont.defaultFamily()); - - m_fontSizes.insert(MinimumFontSize, 0); - m_fontSizes.insert(MinimumLogicalFontSize, 6); - m_fontSizes.insert(DefaultFixedFontSize, 13); - m_fontSizes.insert(DefaultFontSize, 16); + if (m_defaultAttributes.isEmpty()) { + // Initialize the default settings. + m_defaultAttributes.insert(AutoLoadImages, true); + m_defaultAttributes.insert(JavascriptEnabled, true); + m_defaultAttributes.insert(JavascriptCanOpenWindows, true); + m_defaultAttributes.insert(JavascriptCanAccessClipboard, false); + m_defaultAttributes.insert(LinksIncludedInFocusChain, true); + m_defaultAttributes.insert(LocalStorageEnabled, !offTheRecord); + m_defaultAttributes.insert(LocalContentCanAccessRemoteUrls, false); + m_defaultAttributes.insert(XSSAuditingEnabled, false); + m_defaultAttributes.insert(SpatialNavigationEnabled, false); + m_defaultAttributes.insert(LocalContentCanAccessFileUrls, true); + m_defaultAttributes.insert(HyperlinkAuditingEnabled, false); + m_defaultAttributes.insert(ScrollAnimatorEnabled, false); + m_defaultAttributes.insert(ErrorPageEnabled, true); + m_defaultAttributes.insert(PluginsEnabled, false); + m_defaultAttributes.insert(FullScreenSupportEnabled, false); + m_defaultAttributes.insert(ScreenCaptureEnabled, false); + } + m_attributes = m_defaultAttributes; + + if (m_defaultFontFamilies.isEmpty()) { + // Default fonts + QFont defaultFont; + defaultFont.setStyleHint(QFont::Serif); + m_defaultFontFamilies.insert(StandardFont, defaultFont.defaultFamily()); + m_defaultFontFamilies.insert(SerifFont, defaultFont.defaultFamily()); + + defaultFont.setStyleHint(QFont::Fantasy); + m_defaultFontFamilies.insert(FantasyFont, defaultFont.defaultFamily()); + + defaultFont.setStyleHint(QFont::Cursive); + m_defaultFontFamilies.insert(CursiveFont, defaultFont.defaultFamily()); + + defaultFont.setStyleHint(QFont::SansSerif); + m_defaultFontFamilies.insert(SansSerifFont, defaultFont.defaultFamily()); + + defaultFont.setStyleHint(QFont::Monospace); + m_defaultFontFamilies.insert(FixedFont, defaultFont.defaultFamily()); + } + m_fontFamilies = m_defaultFontFamilies; + + if (m_defaultFontSizes.isEmpty()) { + m_defaultFontSizes.insert(MinimumFontSize, 0); + m_defaultFontSizes.insert(MinimumLogicalFontSize, 6); + m_defaultFontSizes.insert(DefaultFixedFontSize, 13); + m_defaultFontSizes.insert(DefaultFontSize, 16); + } + m_fontSizes = m_defaultFontSizes; m_defaultEncoding = QStringLiteral("ISO-8859-1"); } diff --git a/src/core/web_engine_settings.h b/src/core/web_engine_settings.h index d850bd1ef..4104ec67c 100644 --- a/src/core/web_engine_settings.h +++ b/src/core/web_engine_settings.h @@ -137,6 +137,10 @@ private: WebEngineSettings *parentSettings; QSet<WebEngineSettings *> childSettings; + static QHash<Attribute, bool> m_defaultAttributes; + static QHash<FontFamily, QString> m_defaultFontFamilies; + static QHash<FontSize, int> m_defaultFontSizes; + friend class BatchTimer; friend class WebContentsAdapter; }; diff --git a/src/core/yuv_video_node.cpp b/src/core/yuv_video_node.cpp index 815ea7d51..7deeb5802 100644 --- a/src/core/yuv_video_node.cpp +++ b/src/core/yuv_video_node.cpp @@ -40,6 +40,8 @@ #include <QtGui/qopenglfunctions.h> #include <QtQuick/qsgtexture.h> +namespace QtWebEngineCore { + class YUVVideoMaterialShader : public QSGMaterialShader { public: @@ -369,3 +371,5 @@ void YUVVideoNode::setRect(const QRectF &rect) { QSGGeometry::updateTexturedRectGeometry(geometry(), rect, QRectF(0, 0, 1, 1)); } + +} // namespace diff --git a/src/core/yuv_video_node.h b/src/core/yuv_video_node.h index 457c2c7fe..5b13879d3 100644 --- a/src/core/yuv_video_node.h +++ b/src/core/yuv_video_node.h @@ -40,9 +40,9 @@ #include <QtQuick/qsgmaterial.h> #include <QtQuick/qsgnode.h> -QT_BEGIN_NAMESPACE -class QSGTexture; -QT_END_NAMESPACE +QT_FORWARD_DECLARE_CLASS(QSGTexture) + +namespace QtWebEngineCore { // These classes duplicate, QtQuick style, the logic of GLRenderer::DrawYUVVideoQuad. // Their behavior should stay as close as possible to GLRenderer. @@ -59,7 +59,8 @@ public: const QRectF &yaTexCoordRect, const QRectF &uvTexCoordRect, const QSizeF &yaTexSize, const QSizeF &uvTexSize, ColorSpace colorspace); - virtual QSGMaterialType *type() const Q_DECL_OVERRIDE { + virtual QSGMaterialType *type() const Q_DECL_OVERRIDE + { static QSGMaterialType theType; return &theType; } @@ -85,7 +86,8 @@ public: const QRectF &yaTexCoordRect, const QRectF &uvTexCoordRect, const QSizeF &yaTexSize, const QSizeF &uvTexSize, ColorSpace colorspace); - virtual QSGMaterialType *type() const Q_DECL_OVERRIDE{ + virtual QSGMaterialType *type() const Q_DECL_OVERRIDE + { static QSGMaterialType theType; return &theType; } @@ -109,4 +111,6 @@ private: YUVVideoMaterial *m_material; }; +} // namespace + #endif // YUV_VIDEO_NODE_H diff --git a/src/process/main.cpp b/src/process/main.cpp index 446465ef7..8328c0022 100644 --- a/src/process/main.cpp +++ b/src/process/main.cpp @@ -146,8 +146,16 @@ int stat64_proxy(const char *path, struct stat64 *buf) #endif #endif // defined(OS_LINUX) +#ifdef Q_OS_WIN +void initDpiAwareness(); +#endif // defined(Q_OS_WIN) + int main(int argc, const char **argv) { +#ifdef Q_OS_WIN + initDpiAwareness(); +#endif + // QCoreApplication needs a non-const pointer, while the // ContentMain in Chromium needs the pointer to be const. QCoreApplication qtApplication(argc, const_cast<char**>(argv)); diff --git a/src/process/process.pro b/src/process/process.pro index 7bf06a376..6174e53bf 100644 --- a/src/process/process.pro +++ b/src/process/process.pro @@ -8,8 +8,23 @@ load(qt_build_paths) contains(QT_CONFIG, qt_framework) { # Deploy the QtWebEngineProcess app bundle into the QtWebEngineCore framework. DESTDIR = $$MODULE_BASE_OUTDIR/lib/QtWebEngineCore.framework/Versions/5/Helpers - + # FIXME: remove the following workaround with proper rpath handling or + # patching of the installed QtWebEngineProcess binary. + # Since QtWebEngineCore is now built as a framework, we need to pull + # in and fixup its dependencies as well. QT += webenginecore + QMAKE_POST_LINK = \ + "xcrun install_name_tool -change " \ + "`xcrun otool -X -L $(TARGET) | grep QtWebEngineCore | cut -d ' ' -f 1` " \ + "@executable_path/../../../../QtWebEngineCore " \ + "$(TARGET); " + linked_frameworks = QtQuick QtQml QtNetwork QtCore QtGui QtWebChannel + for (current_framework, linked_frameworks) { + QMAKE_POST_LINK += "xcrun install_name_tool -change " \ + "`xcrun otool -X -L $(TARGET) | grep $${current_framework} | cut -d ' ' -f 1` " \ + "@executable_path/../../../../../../../$${current_framework}.framework/$${current_framework} " \ + "$(TARGET);" + } } else { CONFIG -= app_bundle win32: DESTDIR = $$MODULE_BASE_OUTDIR/bin @@ -24,6 +39,11 @@ INCLUDEPATH += ../core SOURCES = main.cpp +win32 { + SOURCES += \ + support_win.cpp +} + contains(QT_CONFIG, qt_framework) { target.path = $$[QT_INSTALL_LIBS]/QtWebEngineCore.framework/Versions/5/Helpers } else { diff --git a/src/process/support_win.cpp b/src/process/support_win.cpp new file mode 100644 index 000000000..4ccd51627 --- /dev/null +++ b/src/process/support_win.cpp @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qlibrary.h> +#include <qsysinfo.h> +#include <qt_windows.h> +#include <Tlhelp32.h> + +class User32DLL { +public: + User32DLL() + : setProcessDPIAware(0) + { + library.setFileName(QStringLiteral("User32")); + if (!library.load()) + return; + setProcessDPIAware = (SetProcessDPIAware)library.resolve("SetProcessDPIAware"); + } + + bool isValid() const + { + return setProcessDPIAware; + } + + typedef BOOL (WINAPI *SetProcessDPIAware)(); + + // Windows Vista onwards + SetProcessDPIAware setProcessDPIAware; + +private: + QLibrary library; +}; + +// This must match PROCESS_DPI_AWARENESS in ShellScalingApi.h +enum DpiAwareness { + PROCESS_PER_UNAWARE = 0, + PROCESS_PER_SYSTEM_DPI_AWARE = 1, + PROCESS_PER_MONITOR_DPI_AWARE = 2 +}; + +// Shell scaling library (Windows 8.1 onwards) +class ShcoreDLL { +public: + ShcoreDLL() + : getProcessDpiAwareness(0), setProcessDpiAwareness(0) + { + if (QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS8_1) + return; + library.setFileName(QStringLiteral("SHCore")); + if (!library.load()) + return; + getProcessDpiAwareness = (GetProcessDpiAwareness)library.resolve("GetProcessDpiAwareness"); + setProcessDpiAwareness = (SetProcessDpiAwareness)library.resolve("SetProcessDpiAwareness"); + } + + bool isValid() const + { + return getProcessDpiAwareness && setProcessDpiAwareness; + } + + typedef HRESULT (WINAPI *GetProcessDpiAwareness)(HANDLE, DpiAwareness *); + typedef HRESULT (WINAPI *SetProcessDpiAwareness)(DpiAwareness); + + GetProcessDpiAwareness getProcessDpiAwareness; + SetProcessDpiAwareness setProcessDpiAwareness; + +private: + QLibrary library; +}; + + +static DWORD getParentProcessId() +{ + HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (hSnapshot == INVALID_HANDLE_VALUE) { + qErrnoWarning(GetLastError(), "CreateToolhelp32Snapshot failed."); + return NULL; + } + + PROCESSENTRY32 pe = {0}; + pe.dwSize = sizeof(PROCESSENTRY32); + + if (!Process32First(hSnapshot, &pe)) { + qWarning("Cannot retrieve parent process handle."); + return NULL; + } + + DWORD parentPid = NULL; + const DWORD pid = GetCurrentProcessId(); + do { + if (pe.th32ProcessID == pid) { + parentPid = pe.th32ParentProcessID; + break; + } + } while (Process32Next(hSnapshot, &pe)); + CloseHandle(hSnapshot); + return parentPid; +} + +void initDpiAwareness() +{ + ShcoreDLL shcore; + if (shcore.isValid()) { + DpiAwareness dpiAwareness = PROCESS_PER_MONITOR_DPI_AWARE; + const DWORD pid = getParentProcessId(); + if (pid) { + HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); + DpiAwareness parentDpiAwareness; + HRESULT hr = shcore.getProcessDpiAwareness(hProcess, &parentDpiAwareness); + CloseHandle(hProcess); + if (hr == S_OK) + dpiAwareness = parentDpiAwareness; + } + if (shcore.setProcessDpiAwareness(dpiAwareness) != S_OK) + qErrnoWarning(GetLastError(), "SetProcessDPIAwareness failed."); + } else { + // Fallback. Use SetProcessDPIAware unconditionally. + User32DLL user32; + if (user32.isValid()) + user32.setProcessDPIAware(); + } +} diff --git a/src/webengine/api/qquickwebenginecertificateerror_p.h b/src/webengine/api/qquickwebenginecertificateerror_p.h index 6f54528d4..7deeac932 100644 --- a/src/webengine/api/qquickwebenginecertificateerror_p.h +++ b/src/webengine/api/qquickwebenginecertificateerror_p.h @@ -62,7 +62,6 @@ class Q_WEBENGINE_EXPORT QQuickWebEngineCertificateError : public QObject { Q_PROPERTY(Error error READ error) Q_PROPERTY(QString description READ description) Q_PROPERTY(bool overridable READ overridable) - Q_ENUMS(Error) public: @@ -82,6 +81,7 @@ public: CertificateWeakKey = -211, CertificateNameConstraintViolation = -212, }; + Q_ENUM(Error) QQuickWebEngineCertificateError(const QSharedPointer<CertificateErrorController> &controller, QObject *parent = 0); ~QQuickWebEngineCertificateError(); diff --git a/src/webengine/api/qquickwebenginedownloaditem_p.h b/src/webengine/api/qquickwebenginedownloaditem_p.h index 9a30eb4ca..d0be2f99a 100644 --- a/src/webengine/api/qquickwebenginedownloaditem_p.h +++ b/src/webengine/api/qquickwebenginedownloaditem_p.h @@ -69,7 +69,7 @@ public: DownloadCancelled, DownloadInterrupted }; - Q_ENUMS(DownloadState) + Q_ENUM(DownloadState) Q_PROPERTY(quint32 id READ id CONSTANT FINAL) Q_PROPERTY(DownloadState state READ state NOTIFY stateChanged) diff --git a/src/webengine/api/qquickwebenginenewviewrequest.cpp b/src/webengine/api/qquickwebenginenewviewrequest.cpp index 893df7f46..6e20c0a46 100644 --- a/src/webengine/api/qquickwebenginenewviewrequest.cpp +++ b/src/webengine/api/qquickwebenginenewviewrequest.cpp @@ -69,7 +69,7 @@ QQuickWebEngineView::NewViewDestination QQuickWebEngineNewViewRequest::destinati } /*! - \qmlproperty bool WebEngineNewViewRequest::isUserInitiated + \qmlproperty bool WebEngineNewViewRequest::userInitiated Whether this window request was directly triggered as the result of a keyboard or mouse event. Use this property to block possibly unwanted \e popups. diff --git a/src/webengine/api/qquickwebengineprofile_p.h b/src/webengine/api/qquickwebengineprofile_p.h index b4e0d173c..1ed15aec2 100644 --- a/src/webengine/api/qquickwebengineprofile_p.h +++ b/src/webengine/api/qquickwebengineprofile_p.h @@ -67,8 +67,6 @@ class QWebEngineCookieStoreClient; class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineProfile : public QObject { Q_OBJECT - Q_ENUMS(HttpCacheType); - Q_ENUMS(PersistentCookiesPolicy); Q_PROPERTY(QString storageName READ storageName WRITE setStorageName NOTIFY storageNameChanged FINAL) Q_PROPERTY(bool offTheRecord READ isOffTheRecord WRITE setOffTheRecord NOTIFY offTheRecordChanged FINAL) Q_PROPERTY(QString persistentStoragePath READ persistentStoragePath WRITE setPersistentStoragePath NOTIFY persistentStoragePathChanged FINAL) @@ -86,12 +84,14 @@ public: MemoryHttpCache, DiskHttpCache }; + Q_ENUM(HttpCacheType) enum PersistentCookiesPolicy { NoPersistentCookies, AllowPersistentCookies, ForcePersistentCookies }; + Q_ENUM(PersistentCookiesPolicy) QString storageName() const; void setStorageName(const QString &name); diff --git a/src/webengine/api/qquickwebenginescript_p.h b/src/webengine/api/qquickwebenginescript_p.h index de91134ef..c9d6f5d26 100644 --- a/src/webengine/api/qquickwebenginescript_p.h +++ b/src/webengine/api/qquickwebenginescript_p.h @@ -59,8 +59,6 @@ class QQuickWebEngineView; class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineScript : public QObject { Q_OBJECT - Q_ENUMS(InjectionPoint) - Q_ENUMS(ScriptWorldId) Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) Q_PROPERTY(QUrl sourceUrl READ sourceUrl WRITE setSourceUrl NOTIFY sourceUrlChanged) Q_PROPERTY(QString sourceCode READ sourceCode WRITE setSourceCode NOTIFY sourceCodeChanged) @@ -75,12 +73,14 @@ public: DocumentReady, DocumentCreation }; + Q_ENUM(InjectionPoint) enum ScriptWorldId { MainWorld = 0, ApplicationWorld, UserWorld }; + Q_ENUM(ScriptWorldId) QQuickWebEngineScript(); ~QQuickWebEngineScript(); diff --git a/src/webengine/api/qquickwebenginesettings_p.h b/src/webengine/api/qquickwebenginesettings_p.h index e82ec6d48..c08a5d897 100644 --- a/src/webengine/api/qquickwebenginesettings_p.h +++ b/src/webengine/api/qquickwebenginesettings_p.h @@ -72,7 +72,8 @@ class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineSettings : public QObject { Q_PROPERTY(bool hyperlinkAuditingEnabled READ hyperlinkAuditingEnabled WRITE setHyperlinkAuditingEnabled NOTIFY hyperlinkAuditingEnabledChanged) Q_PROPERTY(bool errorPageEnabled READ errorPageEnabled WRITE setErrorPageEnabled NOTIFY errorPageEnabledChanged) Q_PROPERTY(bool pluginsEnabled READ pluginsEnabled WRITE setPluginsEnabled NOTIFY pluginsEnabledChanged) - Q_PROPERTY(bool fullScreenSupportEnabled READ fullScreenSupportEnabled WRITE setFullScreenSupportEnabled NOTIFY fullScreenSupportEnabledChanged REVISION 1) + // FIXME(QTBUG-40043): Mark fullScreenSupportEnabled with REVISION 1 + Q_PROPERTY(bool fullScreenSupportEnabled READ fullScreenSupportEnabled WRITE setFullScreenSupportEnabled NOTIFY fullScreenSupportEnabledChanged) // FIXME: add back REVISION when QTBUG-40043 has been fixed. Q_PROPERTY(bool screenCaptureEnabled READ screenCaptureEnabled WRITE setScreenCaptureEnabled NOTIFY screenCaptureEnabledChanged /* REVISION 2 */) Q_PROPERTY(QString defaultTextEncoding READ defaultTextEncoding WRITE setDefaultTextEncoding NOTIFY defaultTextEncodingChanged) @@ -125,7 +126,8 @@ signals: void hyperlinkAuditingEnabledChanged(); void errorPageEnabledChanged(); void pluginsEnabledChanged(); - Q_REVISION(1) void fullScreenSupportEnabledChanged(); + // FIXME(QTBUG-40043): Mark fullScreenSupportEnabledChanged with Q_REVISION(1) + void fullScreenSupportEnabledChanged(); // FIXME: add back Q_REVISION when QTBUG-40043 has been fixed. void screenCaptureEnabledChanged(); void defaultTextEncodingChanged(); diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp index aa450003c..f266fdce6 100644 --- a/src/webengine/api/qquickwebengineview.cpp +++ b/src/webengine/api/qquickwebengineview.cpp @@ -67,6 +67,7 @@ #include <QClipboard> #include <QGuiApplication> +#include <QLoggingCategory> #include <QMimeData> #include <QQmlComponent> #include <QQmlContext> @@ -534,7 +535,29 @@ bool QQuickWebEngineViewPrivate::isFullScreenMode() const void QQuickWebEngineViewPrivate::javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString& message, int lineNumber, const QString& sourceID) { Q_Q(QQuickWebEngineView); - Q_EMIT q->javaScriptConsoleMessage(static_cast<QQuickWebEngineView::JavaScriptConsoleMessageLevel>(level), message, lineNumber, sourceID); + if (q->receivers(SIGNAL(javaScriptConsoleMessage(JavaScriptConsoleMessageLevel,QString,int,QString))) > 0) { + Q_EMIT q->javaScriptConsoleMessage(static_cast<QQuickWebEngineView::JavaScriptConsoleMessageLevel>(level), message, lineNumber, sourceID); + return; + } + + static QLoggingCategory loggingCategory("js", QtWarningMsg); + const QByteArray file = sourceID.toUtf8(); + QMessageLogger logger(file.constData(), lineNumber, nullptr, loggingCategory.categoryName()); + + switch (level) { + case JavaScriptConsoleMessageLevel::Info: + if (loggingCategory.isInfoEnabled()) + logger.info().noquote() << message; + break; + case JavaScriptConsoleMessageLevel::Warning: + if (loggingCategory.isWarningEnabled()) + logger.warning().noquote() << message; + break; + case JavaScriptConsoleMessageLevel::Error: + if (loggingCategory.isCriticalEnabled()) + logger.critical().noquote() << message; + break; + } } void QQuickWebEngineViewPrivate::authenticationRequired(QSharedPointer<AuthenticationDialogController> controller) @@ -656,11 +679,25 @@ void QQuickWebEngineViewPrivate::adoptWebContents(WebContentsAdapter *webContent } Q_Q(QQuickWebEngineView); + + // memorize what webChannel we had for the previous adapter + QQmlWebChannel *qmlWebChannel = NULL; + if (adapter) + qmlWebChannel = qobject_cast<QQmlWebChannel *>(adapter->webChannel()); + // This throws away the WebContentsAdapter that has been used until now. // All its states, particularly the loading URL, are replaced by the adopted WebContentsAdapter. adapter = webContents; adapter->initialize(this); + // associate the webChannel with the new adapter + if (qmlWebChannel) + adapter->setWebChannel(qmlWebChannel); + + // re-bind the userscrips to the new adapter + Q_FOREACH (QQuickWebEngineScript *script, m_userScripts) + script->d_func()->bind(browserContextAdapter()->userScriptController(), adapter.data()); + // Emit signals for values that might be different from the previous WebContentsAdapter. emit q->titleChanged(); emit q->urlChanged(); @@ -1454,5 +1491,3 @@ void QQuickWebEngineViewport::setDevicePixelRatio(qreal devicePixelRatio) QT_END_NAMESPACE -#include "moc_qquickwebengineview_p.cpp" -#include "moc_qquickwebengineview_p_p.cpp" diff --git a/src/webengine/api/qquickwebengineview_p.h b/src/webengine/api/qquickwebengineview_p.h index a17c7bd43..4c4192b4c 100644 --- a/src/webengine/api/qquickwebengineview_p.h +++ b/src/webengine/api/qquickwebengineview_p.h @@ -115,16 +115,7 @@ class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineView : public QQuickItem { Q_PROPERTY(QQuickWebEngineTestSupport *testSupport READ testSupport WRITE setTestSupport FINAL) #endif - Q_ENUMS(NavigationRequestAction); - Q_ENUMS(NavigationType); - Q_ENUMS(LoadStatus); - Q_ENUMS(ErrorDomain); - Q_ENUMS(NewViewDestination); - Q_ENUMS(Feature); - Q_ENUMS(JavaScriptConsoleMessageLevel); - Q_ENUMS(RenderProcessTerminationStatus); Q_FLAGS(FindFlags); - Q_ENUMS(WebAction); public: QQuickWebEngineView(QQuickItem *parent = 0); @@ -155,6 +146,7 @@ public: // we can expose extra actions in experimental. IgnoreRequest = 0xFF }; + Q_ENUM(NavigationRequestAction) // must match WebContentsAdapterClient::NavigationType enum NavigationType { @@ -165,6 +157,7 @@ public: ReloadNavigation, OtherNavigation }; + Q_ENUM(NavigationType) enum LoadStatus { LoadStartedStatus, @@ -172,6 +165,7 @@ public: LoadSucceededStatus, LoadFailedStatus }; + Q_ENUM(LoadStatus) enum ErrorDomain { NoErrorDomain, @@ -182,6 +176,7 @@ public: FtpErrorDomain, DnsErrorDomain }; + Q_ENUM(ErrorDomain) enum NewViewDestination { NewViewInWindow, @@ -189,6 +184,7 @@ public: NewViewInDialog, NewViewInBackgroundTab }; + Q_ENUM(NewViewDestination) enum Feature { MediaAudioCapture, @@ -196,6 +192,7 @@ public: MediaAudioVideoCapture, Geolocation }; + Q_ENUM(Feature) enum WebAction { NoWebAction = - 1, @@ -239,6 +236,7 @@ public: WebActionCount }; + Q_ENUM(WebAction) // must match WebContentsAdapterClient::JavaScriptConsoleMessageLevel enum JavaScriptConsoleMessageLevel { @@ -246,6 +244,7 @@ public: WarningMessageLevel, ErrorMessageLevel }; + Q_ENUM(JavaScriptConsoleMessageLevel) // must match WebContentsAdapterClient::RenderProcessTerminationStatus enum RenderProcessTerminationStatus { @@ -254,6 +253,7 @@ public: CrashedTerminationStatus, KilledTerminationStatus }; + Q_ENUM(RenderProcessTerminationStatus) enum FindFlag { FindBackward = 1, diff --git a/src/webengine/doc/src/external-resources.qdoc b/src/webengine/doc/src/external-resources.qdoc index 34a66291e..2987f1fca 100644 --- a/src/webengine/doc/src/external-resources.qdoc +++ b/src/webengine/doc/src/external-resources.qdoc @@ -35,6 +35,11 @@ \title Chrome DevTools */ +/*! + \externalpage https://developers.google.com/web/tools/javascript/console/console-write + \title Chrome console API +*/ + /* This prevents autolinking of each occurrence of 'WebEngine' To link to the WebEngine QML type, use explicit linking: diff --git a/src/webengine/doc/src/qtwebengine-devtools.qdoc b/src/webengine/doc/src/qtwebengine-debugging.qdoc index ee87214e1..bffcd1669 100644 --- a/src/webengine/doc/src/qtwebengine-devtools.qdoc +++ b/src/webengine/doc/src/qtwebengine-debugging.qdoc @@ -26,8 +26,24 @@ ****************************************************************************/ /*! - \page qtwebengine-devtools.html - \title Qt WebEngine Web Developer Tools + \page qtwebengine-debugging.html + \title Qt WebEngine Debugging and Profiling + + \section1 Console Logging + + JavaScript executed inside Qt WebEngine can use the + \l{Chrome console API} to log information to a console. The logging messages + are forwarded to Qt's logging facilities inside a \c js + \l{QLoggingCategory}{logging category}. However, only warning and fatal + messages are printed by default. To change this, you either have to set custom + rules for the \c js category, or provide custom message handlers + by reimplementing \l{QWebEnginePage::javaScriptConsoleMessage()}, or + connecting to \l{WebEngineView::javaScriptConsoleMessage()}. + + All messages can also be accessed through the Qt WebEngine developer + tools. + + \section1 Qt WebEngine Developer Tools The Qt WebEngine module provides web developer tools that make it easy to inspect and debug layout and performance issues of any web content. diff --git a/src/webengine/doc/src/qtwebengine-index.qdoc b/src/webengine/doc/src/qtwebengine-index.qdoc index e67bd43fd..671425e75 100644 --- a/src/webengine/doc/src/qtwebengine-index.qdoc +++ b/src/webengine/doc/src/qtwebengine-index.qdoc @@ -70,7 +70,7 @@ \list \li \l{Qt WebEngine Overview} \li \l{Qt WebEngine Platform Notes} - \li \l{Qt WebEngine Web Developer Tools} + \li \l{Qt WebEngine Debugging and Profiling} \li \l{Porting from Qt WebKit to Qt WebEngine} \endlist diff --git a/src/webengine/doc/src/qtwebengine-overview.qdoc b/src/webengine/doc/src/qtwebengine-overview.qdoc index 7ab29e324..cfe731c01 100644 --- a/src/webengine/doc/src/qtwebengine-overview.qdoc +++ b/src/webengine/doc/src/qtwebengine-overview.qdoc @@ -67,6 +67,12 @@ specification than Qt WebKit. However, Qt WebEngine is thus heavier than Qt WebKit and does not provide direct access to the network stack and the HTML document through C++ APIs. + Please note that Qt WebEngine is based on Chromium, but does not contain or use any services + or add-ons that might be part of the Chrome browser that is built and delivered by Google. + You can find more detailed information about the differences between Chromium and Chrome in this + \l{https://chromium.googlesource.com/chromium/src/+/master/docs/chromium_browser_vs_google_chrome.md}{overview} + that is part of the documentation in the \l {Chromium Project} upstream source tree. + Chromium is tightly integrated to the \l{Qt Quick Scene Graph}{Qt Quick scene graph}, which is based on OpenGL ES 2.0 or OpenGL 2.0 for its rendering. This provides you with one-pass compositing of web content and all the Qt Quick UI. The integration to Chromium is transparent diff --git a/src/webengine/doc/src/webengineview.qdoc b/src/webengine/doc/src/webengineview.qdoc index f230ba261..d1b4e722b 100644 --- a/src/webengine/doc/src/webengineview.qdoc +++ b/src/webengine/doc/src/webengineview.qdoc @@ -434,7 +434,10 @@ \a level indicates the severity of the event that triggered the message, that is, whether it was triggered by an error or a less severe event. - The corresponding handler is \c onJavaScriptConsoleMessage. + The corresponding handler is \c onJavaScriptConsoleMessage. If no handler is specified, + the view will log the messages into a \c js \l{QLoggingCategory}{logging category}. + + \sa{Console Logging} */ /*! diff --git a/src/webengine/plugin/plugin.cpp b/src/webengine/plugin/plugin.cpp index 2025ce588..c59dfb450 100644 --- a/src/webengine/plugin/plugin.cpp +++ b/src/webengine/plugin/plugin.cpp @@ -79,7 +79,7 @@ public: tr("Cannot create a separate instance of WebEngineDownloadItem")); qmlRegisterUncreatableType<QQuickWebEngineNewViewRequest>(uri, 1, 1, "WebEngineNewViewRequest", tr("Cannot create separate instance of WebEngineNewViewRequest")); qmlRegisterUncreatableType<QQuickWebEngineSettings>(uri, 1, 1, "WebEngineSettings", tr("Cannot create a separate instance of WebEngineSettings")); - qmlRegisterUncreatableType<QQuickWebEngineSettings, 1>(uri, 1, 2, "WebEngineSettings", tr("Cannot create a separate instance of WebEngineSettings")); + // FIXME(QTBUG-40043): qmlRegisterUncreatableType<QQuickWebEngineSettings, 1>(uri, 1, 2, "WebEngineSettings", tr("Cannot create a separate instance of WebEngineSettings")); qmlRegisterSingletonType<QQuickWebEngineSingleton>(uri, 1, 1, "WebEngine", webEngineSingletonProvider); qmlRegisterUncreatableType<QQuickWebEngineHistory>(uri, 1, 1, "NavigationHistory", tr("Cannot create a separate instance of NavigationHistory")); diff --git a/src/webengine/plugin/plugins.qmltypes b/src/webengine/plugin/plugins.qmltypes index 1e577bf51..7a310d268 100644 --- a/src/webengine/plugin/plugins.qmltypes +++ b/src/webengine/plugin/plugins.qmltypes @@ -488,8 +488,10 @@ Module { exports: ["QtWebEngine/FullScreenRequest 1.1"] isCreatable: false exportMetaObjectRevisions: [0] + Property { name: "origin"; type: "QUrl"; isReadonly: true } Property { name: "toggleOn"; type: "bool"; isReadonly: true } Method { name: "accept" } + Method { name: "reject" } } Component { name: "QQuickWebEngineHistory" @@ -609,11 +611,7 @@ Module { name: "downloadFinished" Parameter { name: "download"; type: "QQuickWebEngineDownloadItem"; isPointer: true } } - Method { - name: "setCookieStoreClient" - revision: 1 - Parameter { name: "client"; type: "QWebEngineCookieStoreClient"; isPointer: true } - } + Method { name: "cookieStoreClient"; revision: 1; type: "QWebEngineCookieStoreClient*" } } Component { name: "QQuickWebEngineScript" @@ -832,7 +830,8 @@ Module { "DownloadMediaToDisk": 25, "InspectElement": 26, "ExitFullScreen": 27, - "WebActionCount": 28 + "RequestClose": 28, + "WebActionCount": 29 } } Enum { @@ -953,6 +952,7 @@ Module { Parameter { name: "terminationStatus"; type: "RenderProcessTerminationStatus" } Parameter { name: "exitCode"; type: "int" } } + Signal { name: "windowCloseRequested"; revision: 2 } Method { name: "runJavaScript" Parameter { type: "string" } diff --git a/src/webengine/ui/AuthenticationDialog.qml b/src/webengine/ui/AuthenticationDialog.qml index 46e2e3151..441235980 100644 --- a/src/webengine/ui/AuthenticationDialog.qml +++ b/src/webengine/ui/AuthenticationDialog.qml @@ -35,71 +35,88 @@ ****************************************************************************/ // FIXME: authentication missing in Qt Quick Dialogs atm. Make our own for now. +import QtQuick 2.5 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.0 -import QtQuick 2.5 +import QtQuick.Window 2.2 -ApplicationWindow { +Window { signal accepted(string user, string password); signal rejected; - property alias text: message.text; + property alias text: message.text - width: 350 - height: 100 + title: qsTr("Authentication Required") flags: Qt.Dialog + modality: Qt.WindowModal - title: "Authentication Required" + width: minimumWidth + height: minimumHeight + minimumWidth: rootLayout.implicitWidth + rootLayout.doubleMargins + minimumHeight: rootLayout.implicitHeight + rootLayout.doubleMargins + + SystemPalette { id: palette; colorGroup: SystemPalette.Active } + color: palette.window function open() { show(); } + function acceptDialog() { + accepted(userField.text, passwordField.text); + close(); + } + ColumnLayout { - anchors.fill: parent; - anchors.margins: 4; + id: rootLayout + anchors.fill: parent + anchors.margins: 4 + property int doubleMargins: anchors.margins * 2 Text { id: message; - Layout.fillWidth: true; + color: palette.windowText } - RowLayout { + GridLayout { + columns: 2 Label { - text: "Username:" + text: qsTr("Username:") + color: palette.windowText } TextField { - id: userField; - Layout.fillWidth: true; + id: userField + focus: true + Layout.fillWidth: true + onAccepted: acceptDialog() } - } - RowLayout { Label { - text: "Password:" + text: qsTr("Password:") + color: palette.windowText } TextField { - id: passwordField; - Layout.fillWidth: true; - echoMode: TextInput.Password; + id: passwordField + Layout.fillWidth: true + echoMode: TextInput.Password + onAccepted: acceptDialog() } } + Item { + Layout.fillHeight: true + } RowLayout { Layout.alignment: Qt.AlignRight - spacing: 8; + spacing: 8 Button { - text: "Log In" + id: cancelButton + text: qsTr("&Cancel") onClicked: { - accepted(userField.text, passwordField.text); + rejected(); close(); - destroy(); } } Button { - text: "Cancel" - onClicked: { - rejected(); - close(); - destroy(); - } + text: qsTr("&Log In") + isDefault: true + onClicked: acceptDialog() } } } - } diff --git a/src/webengine/ui_delegates_manager.cpp b/src/webengine/ui_delegates_manager.cpp index f60cfb1a7..2e686b1b1 100644 --- a/src/webengine/ui_delegates_manager.cpp +++ b/src/webengine/ui_delegates_manager.cpp @@ -245,19 +245,19 @@ void UIDelegatesManager::showDialog(QSharedPointer<JavaScriptDialogController> d switch (dialogController->type()) { case WebContentsAdapterClient::AlertDialog: dialogComponentType = AlertDialog; - title = QCoreApplication::translate("UIDelegatesManager", "Javascript Alert - %1").arg(m_view->url().toString()); + title = tr("Javascript Alert - %1").arg(m_view->url().toString()); break; case WebContentsAdapterClient::ConfirmDialog: dialogComponentType = ConfirmDialog; - title = QCoreApplication::translate("UIDelegatesManager", "Javascript Confirm - %1").arg(m_view->url().toString()); + title = tr("Javascript Confirm - %1").arg(m_view->url().toString()); break; case WebContentsAdapterClient::PromptDialog: dialogComponentType = PromptDialog; - title = QCoreApplication::translate("UIDelegatesManager", "Javascript Prompt - %1").arg(m_view->url().toString()); + title = tr("Javascript Prompt - %1").arg(m_view->url().toString()); break; case WebContentsAdapterClient::UnloadDialog: dialogComponentType = ConfirmDialog; - title = QCoreApplication::translate("UIDelegatesManager", "Are you sure you want to leave this page?"); + title = tr("Are you sure you want to leave this page?"); break; case WebContentsAdapterClient::InternalAuthorizationDialog: dialogComponentType = ConfirmDialog; @@ -335,10 +335,10 @@ void UIDelegatesManager::showDialog(QSharedPointer<AuthenticationDialogControlle QString introMessage; if (dialogController->isProxy()) { - introMessage = QObject::tr("Connect to proxy \"%1\" using:"); + introMessage = tr("Connect to proxy \"%1\" using:"); introMessage = introMessage.arg(dialogController->host().toHtmlEscaped()); } else { - introMessage = QObject::tr("Enter username and password for \"%1\" at %2"); + introMessage = tr("Enter username and password for \"%1\" at %2"); introMessage = introMessage.arg(dialogController->realm()).arg(dialogController->url().toString().toHtmlEscaped()); } QQmlProperty textProp(authenticationDialog, QStringLiteral("text")); diff --git a/src/webengine/ui_delegates_manager.h b/src/webengine/ui_delegates_manager.h index fb262aac1..7a87c1eee 100644 --- a/src/webengine/ui_delegates_manager.h +++ b/src/webengine/ui_delegates_manager.h @@ -37,7 +37,12 @@ #ifndef UI_DELEGATES_MANAGER_H #define UI_DELEGATES_MANAGER_H -#include <QObject> +#include "qglobal.h" +#include "web_contents_adapter.h" +#include "web_contents_adapter_client.h" + +#include <QCoreApplication> +#include <QExplicitlySharedDataPointer> #include <QPoint> #include <QSharedPointer> @@ -82,8 +87,9 @@ Q_SIGNALS: void triggered(); }; -class UIDelegatesManager { - +class UIDelegatesManager +{ + Q_DECLARE_TR_FUNCTIONS(UIDelegatesManager) public: enum ComponentType { Invalid = -1, diff --git a/src/webenginewidgets/api/qwebenginedownloaditem.h b/src/webenginewidgets/api/qwebenginedownloaditem.h index 05e0f8765..38b9a4ad8 100644 --- a/src/webenginewidgets/api/qwebenginedownloaditem.h +++ b/src/webenginewidgets/api/qwebenginedownloaditem.h @@ -59,7 +59,7 @@ public: DownloadCancelled, DownloadInterrupted }; - Q_ENUMS(DownloadState) + Q_ENUM(DownloadState) quint32 id() const; DownloadState state() const; diff --git a/src/webenginewidgets/api/qwebenginefullscreenrequest.cpp b/src/webenginewidgets/api/qwebenginefullscreenrequest.cpp index 6223c070d..7db86e6f2 100644 --- a/src/webenginewidgets/api/qwebenginefullscreenrequest.cpp +++ b/src/webenginewidgets/api/qwebenginefullscreenrequest.cpp @@ -39,21 +39,31 @@ QT_BEGIN_NAMESPACE -QWebEngineFullScreenRequest::QWebEngineFullScreenRequest(QWebEnginePagePrivate *pagePrivate, const QUrl &origin, bool fullscreen) - : m_pagePrivate(pagePrivate) +QWebEngineFullScreenRequest::QWebEngineFullScreenRequest(QWebEnginePage *page, const QUrl &origin, bool fullscreen) + : m_page(page) , m_origin(origin) , m_toggleOn(fullscreen) { } -void QWebEngineFullScreenRequest::reject() const +void QWebEngineFullScreenRequest::reject() { - m_pagePrivate->setFullScreenMode(!m_toggleOn); + if (!m_page) { + qWarning("Cannot reject QWebEngineFullScreenRequest: Originating page is already deleted"); + return; + } + + m_page->d_func()->setFullScreenMode(!m_toggleOn); } -void QWebEngineFullScreenRequest::accept() const +void QWebEngineFullScreenRequest::accept() { - m_pagePrivate->setFullScreenMode(m_toggleOn); + if (!m_page) { + qWarning("Cannot accept QWebEngineFullScreenRequest: Originating page is already deleted"); + return; + } + + m_page->d_func()->setFullScreenMode(m_toggleOn); } QT_END_NAMESPACE diff --git a/src/webenginewidgets/api/qwebenginefullscreenrequest.h b/src/webenginewidgets/api/qwebenginefullscreenrequest.h index c6768f4d6..26f7247e0 100644 --- a/src/webenginewidgets/api/qwebenginefullscreenrequest.h +++ b/src/webenginewidgets/api/qwebenginefullscreenrequest.h @@ -38,26 +38,25 @@ #define QWEBENGINEFULLSCREENREQUEST_H #include <qtwebenginewidgetsglobal.h> -#include <qwebenginepage.h> -#include <QtCore/qurl.h> +#include <qurl.h> +#include <qpointer.h> QT_BEGIN_NAMESPACE -class QWebEnginePagePrivate; +class QWebEnginePage; class QWEBENGINEWIDGETS_EXPORT QWebEngineFullScreenRequest { Q_GADGET Q_PROPERTY(bool toggleOn READ toggleOn) Q_PROPERTY(QUrl origin READ origin) public: - Q_INVOKABLE void reject() const; - Q_INVOKABLE void accept() const; + Q_INVOKABLE void reject(); + Q_INVOKABLE void accept(); bool toggleOn() const { return m_toggleOn; } const QUrl &origin() const { return m_origin; } private: - Q_DISABLE_COPY(QWebEngineFullScreenRequest) - QWebEngineFullScreenRequest(QWebEnginePagePrivate *pagePrivate, const QUrl &origin, bool toggleOn); - QWebEnginePagePrivate *m_pagePrivate; + QWebEngineFullScreenRequest(QWebEnginePage *page, const QUrl &origin, bool toggleOn); + QPointer<QWebEnginePage> m_page; const QUrl m_origin; const bool m_toggleOn; friend class QWebEnginePagePrivate; diff --git a/src/webenginewidgets/api/qwebenginehistory.h b/src/webenginewidgets/api/qwebenginehistory.h index 0471e28e6..3dcea9469 100644 --- a/src/webenginewidgets/api/qwebenginehistory.h +++ b/src/webenginewidgets/api/qwebenginehistory.h @@ -65,6 +65,9 @@ public: QUrl iconUrl() const; bool isValid() const; + + void swap(QWebEngineHistoryItem &other) Q_DECL_NOTHROW { qSwap(d, other.d); } + private: QWebEngineHistoryItem(QWebEngineHistoryItemPrivate *priv); Q_DECLARE_PRIVATE_D(d.data(), QWebEngineHistoryItem) @@ -73,6 +76,7 @@ private: friend class QWebEngineHistoryPrivate; }; +Q_DECLARE_SHARED_NOT_MOVABLE_UNTIL_QT6(QWebEngineHistoryItem) class QWebEngineHistoryPrivate; class QWEBENGINEWIDGETS_EXPORT QWebEngineHistory { diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp index dd71db6a0..e85021832 100644 --- a/src/webenginewidgets/api/qwebenginepage.cpp +++ b/src/webenginewidgets/api/qwebenginepage.cpp @@ -55,6 +55,7 @@ #include <QIcon> #include <QInputDialog> #include <QLayout> +#include <QLoggingCategory> #include <QMenu> #include <QMessageBox> #include <QMimeData> @@ -431,7 +432,7 @@ QWebEnginePage::QWebEnginePage(QObject* parent) */ /*! - \fn QWebEnginePage::fullScreenRequested(const QWebEngineFullScreenRequest &request) + \fn QWebEnginePage::fullScreenRequested(QWebEngineFullScreenRequest request) This signal is emitted when the web page issues the request to enter fullscreen mode for a web-element, usually a video element. @@ -877,9 +878,19 @@ bool QWebEnginePage::event(QEvent *e) return QObject::event(e); } +void QWebEnginePagePrivate::wasShown() +{ + adapter->wasShown(); +} + +void QWebEnginePagePrivate::wasHidden() +{ + adapter->wasHidden(); +} + bool QWebEnginePagePrivate::contextMenuRequested(const WebEngineContextMenuData &data) { - if (!view) + if (!view || !view->d_func()->m_pendingContextMenuEvent) return false; m_menuData = WebEngineContextMenuData(); @@ -905,7 +916,6 @@ bool QWebEnginePagePrivate::contextMenuRequested(const WebEngineContextMenuData return false; break; } - Q_ASSERT(view->d_func()->m_pendingContextMenuEvent); view->d_func()->m_pendingContextMenuEvent = false; return true; } @@ -920,7 +930,7 @@ void QWebEnginePagePrivate::navigationRequested(int navigationType, const QUrl & void QWebEnginePagePrivate::requestFullScreenMode(const QUrl &origin, bool fullscreen) { Q_Q(QWebEnginePage); - QWebEngineFullScreenRequest request(this, origin, fullscreen); + QWebEngineFullScreenRequest request(q, origin, fullscreen); Q_EMIT q->fullScreenRequested(request); } @@ -1230,8 +1240,12 @@ void QWebEnginePage::runJavaScript(const QString& scriptSource, const QWebEngine } /*! - Returns the script collection used by this page. - \sa QWebEngineScriptCollection + Returns the collection of scripts that are injected into the page. + + In addition, a page might also execute scripts + added through QWebEngineProfile::scripts(). + + \sa QWebEngineScriptCollection, QWebEngineScript */ QWebEngineScriptCollection &QWebEnginePage::scripts() @@ -1309,10 +1323,24 @@ bool QWebEnginePage::javaScriptPrompt(const QUrl &securityOrigin, const QString void QWebEnginePage::javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString &message, int lineNumber, const QString &sourceID) { - Q_UNUSED(level); - Q_UNUSED(message); - Q_UNUSED(lineNumber); - Q_UNUSED(sourceID); + static QLoggingCategory loggingCategory("js", QtWarningMsg); + static QByteArray file = sourceID.toUtf8(); + QMessageLogger logger(file.constData(), lineNumber, nullptr, loggingCategory.categoryName()); + + switch (level) { + case JavaScriptConsoleMessageLevel::InfoMessageLevel: + if (loggingCategory.isInfoEnabled()) + logger.info().noquote() << message; + break; + case JavaScriptConsoleMessageLevel::WarningMessageLevel: + if (loggingCategory.isWarningEnabled()) + logger.warning().noquote() << message; + break; + case JavaScriptConsoleMessageLevel::ErrorMessageLevel: + if (loggingCategory.isCriticalEnabled()) + logger.critical().noquote() << message; + break; + } } bool QWebEnginePage::certificateError(const QWebEngineCertificateError &) diff --git a/src/webenginewidgets/api/qwebenginepage.h b/src/webenginewidgets/api/qwebenginepage.h index 9740c89c9..69f8822b1 100644 --- a/src/webenginewidgets/api/qwebenginepage.h +++ b/src/webenginewidgets/api/qwebenginepage.h @@ -258,7 +258,7 @@ Q_SIGNALS: void featurePermissionRequested(const QUrl &securityOrigin, QWebEnginePage::Feature feature); void featurePermissionRequestCanceled(const QUrl &securityOrigin, QWebEnginePage::Feature feature); - void fullScreenRequested(const QWebEngineFullScreenRequest &fullScreenRequest); + void fullScreenRequested(QWebEngineFullScreenRequest fullScreenRequest); void authenticationRequired(const QUrl &requestUrl, QAuthenticator *authenticator); void proxyAuthenticationRequired(const QUrl &requestUrl, QAuthenticator *authenticator, const QString &proxyHost); @@ -292,6 +292,7 @@ private: Q_PRIVATE_SLOT(d_func(), void _q_webActionTriggered(bool checked)) #endif + friend class QWebEngineFullScreenRequest; friend class QWebEngineView; friend class QWebEngineViewPrivate; #ifndef QT_NO_ACCESSIBILITY diff --git a/src/webenginewidgets/api/qwebenginepage_p.h b/src/webenginewidgets/api/qwebenginepage_p.h index 66a2cf35b..dd43b08c8 100644 --- a/src/webenginewidgets/api/qwebenginepage_p.h +++ b/src/webenginewidgets/api/qwebenginepage_p.h @@ -131,6 +131,9 @@ public: void updateNavigationActions(); void _q_webActionTriggered(bool checked); + void wasShown(); + void wasHidden(); + QtWebEngineCore::WebContentsAdapter *webContents() { return adapter.data(); } void recreateFromSerializedHistory(QDataStream &input); diff --git a/src/webenginewidgets/api/qwebengineprofile.cpp b/src/webenginewidgets/api/qwebengineprofile.cpp index 2edebdfeb..5fbc4d63c 100644 --- a/src/webenginewidgets/api/qwebengineprofile.cpp +++ b/src/webenginewidgets/api/qwebengineprofile.cpp @@ -199,7 +199,7 @@ void QWebEngineProfilePrivate::downloadUpdated(const DownloadItemInfo &info) */ QWebEngineProfile::QWebEngineProfile(QObject *parent) : QObject(parent) - , d_ptr(new QWebEngineProfilePrivate(new BrowserContextAdapter(false))) + , d_ptr(new QWebEngineProfilePrivate(new BrowserContextAdapter(true))) { d_ptr->q_ptr = this; } @@ -490,8 +490,10 @@ bool QWebEngineProfile::visitedLinksContainsUrl(const QUrl &url) const } /*! - Returns the script collection used by this profile. - \sa QWebEngineScriptCollection + Returns the collection of scripts that are injected into all pages that share + this profile. + + \sa QWebEngineScriptCollection, QWebEngineScript, QWebEnginePage::scripts() */ QWebEngineScriptCollection *QWebEngineProfile::scripts() const { diff --git a/src/webenginewidgets/api/qwebenginescript.cpp b/src/webenginewidgets/api/qwebenginescript.cpp index 1bd56604d..058f58475 100644 --- a/src/webenginewidgets/api/qwebenginescript.cpp +++ b/src/webenginewidgets/api/qwebenginescript.cpp @@ -58,6 +58,9 @@ using QtWebEngineCore::UserScript; not accessible from a different one. ScriptWorldId provides some predefined IDs for this purpose. + Use QWebEnginePage::scripts() and QWebEngineProfile::scripts() to access + the collection of scripts associated with a single page or a + number of pages sharing the same profile. */ /*! \enum QWebEngineScript::InjectionPoint diff --git a/src/webenginewidgets/api/qwebenginescript.h b/src/webenginewidgets/api/qwebenginescript.h index 4cff2631d..29126b110 100644 --- a/src/webenginewidgets/api/qwebenginescript.h +++ b/src/webenginewidgets/api/qwebenginescript.h @@ -99,7 +99,7 @@ private: QSharedDataPointer<QtWebEngineCore::UserScript> d; }; -Q_DECLARE_SHARED(QWebEngineScript) +Q_DECLARE_SHARED_NOT_MOVABLE_UNTIL_QT6(QWebEngineScript) #ifndef QT_NO_DEBUG_STREAM QWEBENGINEWIDGETS_EXPORT QDebug operator<<(QDebug, const QWebEngineScript &); diff --git a/src/webenginewidgets/api/qwebenginescriptcollection.cpp b/src/webenginewidgets/api/qwebenginescriptcollection.cpp index 80a7f9b6e..9967cde85 100644 --- a/src/webenginewidgets/api/qwebenginescriptcollection.cpp +++ b/src/webenginewidgets/api/qwebenginescriptcollection.cpp @@ -47,6 +47,11 @@ using QtWebEngineCore::UserScript; \since 5.5 \brief The QWebEngineScriptCollection class represents a collection of user scripts. + QWebEngineScriptCollection manages a set of user scripts. + + Use QWebEnginePage::scripts() and QWebEngineProfile::scripts() to access + the collection of scripts associated with a single page or a + number of pages sharing the same profile. */ /*! diff --git a/src/webenginewidgets/api/qwebengineview.cpp b/src/webenginewidgets/api/qwebengineview.cpp index 9baa8e34a..362849732 100644 --- a/src/webenginewidgets/api/qwebengineview.cpp +++ b/src/webenginewidgets/api/qwebengineview.cpp @@ -294,6 +294,24 @@ void QWebEngineView::contextMenuEvent(QContextMenuEvent *event) menu->popup(event->globalPos()); } +/*! + * \reimp + */ +void QWebEngineView::showEvent(QShowEvent *event) +{ + QWidget::showEvent(event); + page()->d_ptr->wasShown(); +} + +/*! + * \reimp + */ +void QWebEngineView::hideEvent(QHideEvent *event) +{ + QWidget::hideEvent(event); + page()->d_ptr->wasHidden(); +} + #ifndef QT_NO_ACCESSIBILITY int QWebEngineViewAccessible::childCount() const { diff --git a/src/webenginewidgets/api/qwebengineview.h b/src/webenginewidgets/api/qwebengineview.h index ae38e6c5c..e16bbf4af 100644 --- a/src/webenginewidgets/api/qwebengineview.h +++ b/src/webenginewidgets/api/qwebengineview.h @@ -120,6 +120,8 @@ protected: virtual QWebEngineView *createWindow(QWebEnginePage::WebWindowType type); virtual void contextMenuEvent(QContextMenuEvent*) Q_DECL_OVERRIDE; virtual bool event(QEvent*) Q_DECL_OVERRIDE; + virtual void showEvent(QShowEvent *) Q_DECL_OVERRIDE; + virtual void hideEvent(QHideEvent *) Q_DECL_OVERRIDE; private: Q_DISABLE_COPY(QWebEngineView) diff --git a/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc b/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc index b7b3bf022..17dd15630 100644 --- a/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc +++ b/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc @@ -262,7 +262,10 @@ \a level indicates the severity of the event that triggered the message. That is, whether it was triggered by an error or a less severe event. - The default implementation prints nothing. + Since Qt 5.6, the default implementation logs the messages in a \c js + \l{QLoggingCategory}{logging category}. + + \sa{Console Logging} */ /*! diff --git a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp index 76ca8d354..57631c4cc 100644 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp +++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp @@ -139,14 +139,12 @@ void RenderWidgetHostViewQtDelegateWidget::show() // want to show anything else than popups as top-level. if (parent() || m_isPopup) { QOpenGLWidget::show(); - m_client->notifyShown(); } } void RenderWidgetHostViewQtDelegateWidget::hide() { QOpenGLWidget::hide(); - m_client->notifyHidden(); } bool RenderWidgetHostViewQtDelegateWidget::isVisible() const @@ -257,6 +255,13 @@ void RenderWidgetHostViewQtDelegateWidget::showEvent(QShowEvent *event) m_windowConnections.append(connect(w, SIGNAL(yChanged(int)), SLOT(onWindowPosChanged()))); } m_client->windowChanged(); + m_client->notifyShown(); +} + +void RenderWidgetHostViewQtDelegateWidget::hideEvent(QHideEvent *event) +{ + QOpenGLWidget::hideEvent(event); + m_client->notifyHidden(); } bool RenderWidgetHostViewQtDelegateWidget::event(QEvent *event) diff --git a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h index d228bd487..fddc79c2f 100644 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h +++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h @@ -84,6 +84,7 @@ protected: bool event(QEvent *event) Q_DECL_OVERRIDE; void resizeEvent(QResizeEvent *resizeEvent) Q_DECL_OVERRIDE; void showEvent(QShowEvent *) Q_DECL_OVERRIDE; + void hideEvent(QHideEvent *) Q_DECL_OVERRIDE; void initializeGL() Q_DECL_OVERRIDE; void paintGL() Q_DECL_OVERRIDE; diff --git a/tests/auto/core/core.pro b/tests/auto/core/core.pro index ed0a61532..713c71d14 100644 --- a/tests/auto/core/core.pro +++ b/tests/auto/core/core.pro @@ -1,7 +1,5 @@ TEMPLATE = subdirs -CONFIG += ordered - SUBDIRS += \ qwebenginecookiestoreclient \ qwebengineurlrequestinterceptor \ diff --git a/tests/auto/core/qwebenginecookiestoreclient/tst_qwebenginecookiestoreclient.cpp b/tests/auto/core/qwebenginecookiestoreclient/tst_qwebenginecookiestoreclient.cpp index d78a81c21..ed2a5a55b 100644 --- a/tests/auto/core/qwebenginecookiestoreclient/tst_qwebenginecookiestoreclient.cpp +++ b/tests/auto/core/qwebenginecookiestoreclient/tst_qwebenginecookiestoreclient.cpp @@ -121,6 +121,7 @@ void tst_QWebEngineCookieStoreClient::cookieSignals() void tst_QWebEngineCookieStoreClient::setAndDeleteCookie() { + QTest::qWait(500); // remove, when QTBUG-47946 is fixed! QWebEngineView view; QWebEngineCookieStoreClient *client = view.page()->profile()->cookieStoreClient(); @@ -158,6 +159,7 @@ void tst_QWebEngineCookieStoreClient::setAndDeleteCookie() void tst_QWebEngineCookieStoreClient::batchCookieTasks() { + QTest::qWait(500); // remove, when QTBUG-47946 is fixed! QWebEngineView view; QWebEngineCookieStoreClient *client = view.page()->profile()->cookieStoreClient(); diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp b/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp index 4891cafd0..4a261c46b 100644 --- a/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp +++ b/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp @@ -146,7 +146,6 @@ void tst_QWebEngineUrlRequestInterceptor::interceptRequest() loadSpy.clear(); QCOMPARE(interceptor.observedUrls.count(), 4); - // Make sure that registering an observer does not modify the request. TestRequestInterceptor observer(/* intercept */ false); view.page()->profile()->setRequestInterceptor(&observer); diff --git a/tests/auto/core/tests.pri b/tests/auto/core/tests.pri index cd6ef8615..606ed2a8c 100644 --- a/tests/auto/core/tests.pri +++ b/tests/auto/core/tests.pri @@ -1,8 +1,6 @@ TEMPLATE = app -# FIXME: Re-enable once we want to run tests on the CI -# CONFIG += testcase - +CONFIG += testcase CONFIG += c++11 VPATH += $$_PRO_FILE_PWD_ diff --git a/tests/auto/widgets/positionplugin/plugin.cpp b/tests/auto/widgets/positionplugin/plugin.cpp new file mode 100644 index 000000000..74d30469d --- /dev/null +++ b/tests/auto/widgets/positionplugin/plugin.cpp @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtPositioning/qgeopositioninfosource.h> +#include <QtPositioning/qgeopositioninfosourcefactory.h> +#include <QObject> +#include <QtPlugin> + +class DummySource : public QGeoPositionInfoSource +{ + Q_OBJECT + +public: + DummySource(QObject *parent=0); + + void startUpdates() {} + void stopUpdates() {} + void requestUpdate(int) {} + + QGeoPositionInfo lastKnownPosition(bool fromSatellitePositioningMethodsOnly) const; + PositioningMethods supportedPositioningMethods() const; + + int minimumUpdateInterval() const; + Error error() const; +}; + +DummySource::DummySource(QObject *parent) : + QGeoPositionInfoSource(parent) +{ +} + +QGeoPositionInfoSource::Error DummySource::error() const +{ + return QGeoPositionInfoSource::NoError; +} + +int DummySource::minimumUpdateInterval() const +{ + return 1000; +} + +QGeoPositionInfo DummySource::lastKnownPosition(bool fromSatellitePositioningMethodsOnly) const +{ + Q_UNUSED(fromSatellitePositioningMethodsOnly); + return QGeoPositionInfo(QGeoCoordinate(54.186824, 12.087262), QDateTime::currentDateTime()); +} + +QGeoPositionInfoSource::PositioningMethods DummySource::supportedPositioningMethods() const +{ + return QGeoPositionInfoSource::AllPositioningMethods; +} + + +class QGeoPositionInfoSourceFactoryTest : public QObject, public QGeoPositionInfoSourceFactory +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.qt.position.sourcefactory/5.0" + FILE "plugin.json") + Q_INTERFACES(QGeoPositionInfoSourceFactory) + +public: + QGeoPositionInfoSource *positionInfoSource(QObject *parent); + QGeoSatelliteInfoSource *satelliteInfoSource(QObject *parent); + QGeoAreaMonitorSource *areaMonitor(QObject *parent); +}; + +QGeoPositionInfoSource *QGeoPositionInfoSourceFactoryTest::positionInfoSource(QObject *parent) +{ + return new DummySource(parent); +} + +QGeoSatelliteInfoSource *QGeoPositionInfoSourceFactoryTest::satelliteInfoSource(QObject *) +{ + return 0; +} + +QGeoAreaMonitorSource *QGeoPositionInfoSourceFactoryTest::areaMonitor(QObject* ) +{ + return 0; +} + +#include "plugin.moc" diff --git a/tests/auto/widgets/positionplugin/plugin.json b/tests/auto/widgets/positionplugin/plugin.json new file mode 100644 index 000000000..68acaded3 --- /dev/null +++ b/tests/auto/widgets/positionplugin/plugin.json @@ -0,0 +1,9 @@ +{ + "Keys": ["test.source"], + "Provider": "test.source", + "Position": true, + "Satellite": false, + "Monitor": false, + "Priority": 0, + "Testable": true +} diff --git a/tests/auto/widgets/positionplugin/positionplugin.pro b/tests/auto/widgets/positionplugin/positionplugin.pro new file mode 100644 index 000000000..bca3e5756 --- /dev/null +++ b/tests/auto/widgets/positionplugin/positionplugin.pro @@ -0,0 +1,12 @@ +TARGET = qtwebengine_positioning_testplugin +QT += positioning + +PLUGIN_TYPE = position +PLUGIN_CLASS_NAME = TestPositionPlugin +PLUGIN_EXTENDS = - +load(qt_plugin) + +SOURCES += plugin.cpp + +OTHER_FILES += \ + plugin.json diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp index da19acbf6..50914a920 100644 --- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp +++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp @@ -151,7 +151,6 @@ private Q_SLOTS: void defaultTextEncoding(); void errorPageExtension(); void errorPageExtensionLoadFinished(); - void userAgentApplicationName(); void userAgentNewlineStripping(); void undoActionHaveCustomText(); void renderWidgetHostViewNotShowTopLevel(); @@ -289,6 +288,15 @@ void tst_QWebEnginePage::cleanupFiles() void tst_QWebEnginePage::initTestCase() { cleanupFiles(); // In case there are old files from previous runs + + // Set custom path since the CI doesn't install test plugins. + // Stolen from qtlocation/tests/auto/positionplugintest. + QString searchPath = QCoreApplication::applicationDirPath(); +#ifdef Q_OS_WIN + searchPath += QStringLiteral("/.."); +#endif + searchPath += QStringLiteral("/../../../plugins"); + QCoreApplication::addLibraryPath(searchPath); } void tst_QWebEnginePage::cleanupTestCase() @@ -2790,28 +2798,6 @@ void tst_QWebEnginePage::errorPageExtensionLoadFinished() #endif } -class FriendlyWebPage : public QWebEnginePage -{ -public: - friend class tst_QWebEnginePage; -}; - -void tst_QWebEnginePage::userAgentApplicationName() -{ -#if !defined(QWEBENGINEPAGE_USERAGENTFORURL) - QSKIP("QWEBENGINEPAGE_USERAGENTFORURL"); -#else - const QString oldApplicationName = QCoreApplication::applicationName(); - FriendlyWebPage page; - - const QString applicationNameMarker = QString::fromUtf8("StrangeName\342\210\236"); - QCoreApplication::setApplicationName(applicationNameMarker); - QVERIFY(page.userAgentForUrl(QUrl()).contains(applicationNameMarker)); - - QCoreApplication::setApplicationName(oldApplicationName); -#endif -} - void tst_QWebEnginePage::userAgentNewlineStripping() { QWebEngineProfile profile; @@ -3758,7 +3744,7 @@ void tst_QWebEnginePage::fullScreenRequested() // FullscreenRequest must be a user gesture bool acceptRequest = true; connect(page, &QWebEnginePage::fullScreenRequested, - [&acceptRequest](const QWebEngineFullScreenRequest &request) { + [&acceptRequest](QWebEngineFullScreenRequest request) { if (acceptRequest) request.accept(); else request.reject(); }); diff --git a/tests/auto/widgets/qwebengineprofile/qwebengineprofile.pro b/tests/auto/widgets/qwebengineprofile/qwebengineprofile.pro new file mode 100644 index 000000000..e56bbe8f7 --- /dev/null +++ b/tests/auto/widgets/qwebengineprofile/qwebengineprofile.pro @@ -0,0 +1,3 @@ +include(../tests.pri) +exists($${TARGET}.qrc):RESOURCES += $${TARGET}.qrc +QT *= core-private gui-private diff --git a/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp b/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp new file mode 100644 index 000000000..09929d33f --- /dev/null +++ b/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "../util.h" +#include <QtTest/QtTest> +#include <qwebengineprofile.h> + +class tst_QWebEngineProfile : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void defaultProfile(); + void profileConstructors(); +}; + +void tst_QWebEngineProfile::defaultProfile() +{ + QWebEngineProfile *profile = QWebEngineProfile::defaultProfile(); + QVERIFY(profile); + QVERIFY(!profile->isOffTheRecord()); + QCOMPARE(profile->storageName(), QStringLiteral("Default")); + QCOMPARE(profile->httpCacheType(), QWebEngineProfile::DiskHttpCache); + QCOMPARE(profile->persistentCookiesPolicy(), QWebEngineProfile::AllowPersistentCookies); +} + +void tst_QWebEngineProfile::profileConstructors() +{ + QWebEngineProfile otrProfile; + QWebEngineProfile diskProfile(QStringLiteral("Test")); + + QVERIFY(otrProfile.isOffTheRecord()); + QVERIFY(!diskProfile.isOffTheRecord()); + QCOMPARE(diskProfile.storageName(), QStringLiteral("Test")); + QCOMPARE(otrProfile.httpCacheType(), QWebEngineProfile::MemoryHttpCache); + QCOMPARE(diskProfile.httpCacheType(), QWebEngineProfile::DiskHttpCache); + QCOMPARE(otrProfile.persistentCookiesPolicy(), QWebEngineProfile::NoPersistentCookies); + QCOMPARE(diskProfile.persistentCookiesPolicy(), QWebEngineProfile::AllowPersistentCookies); + +} + +QTEST_MAIN(tst_QWebEngineProfile) +#include "tst_qwebengineprofile.moc" diff --git a/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp b/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp index b29d8fae6..53762f54c 100644 --- a/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp +++ b/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp @@ -25,18 +25,6 @@ #include <qwebengineview.h> #include "../util.h" -//#define DEBUG_SCRIPT_MESSAGES -#ifdef DEBUG_SCRIPT_MESSAGES -class WebEnginePage : public QWebEnginePage { - void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString &message, int lineNumber, const QString &sourceID) { - qDebug() << level << message << lineNumber << sourceID; - } - -}; -#else -typedef QWebEnginePage WebEnginePage; -#endif - class tst_QWebEngineScript: public QObject { Q_OBJECT @@ -49,10 +37,9 @@ private Q_SLOTS: }; - void tst_QWebEngineScript::domEditing() { - WebEnginePage page; + QWebEnginePage page; QWebEngineView view; view.setPage(&page); QWebEngineScript s; @@ -88,7 +75,7 @@ void tst_QWebEngineScript::injectionPoint() s.setSourceCode("var foo = \"foobar\";"); s.setInjectionPoint(static_cast<QWebEngineScript::InjectionPoint>(injectionPoint)); s.setWorldId(QWebEngineScript::MainWorld); - WebEnginePage page; + QWebEnginePage page; page.scripts().insert(s); page.setHtml(QStringLiteral("<html><head><script> var contents;") + testScript + QStringLiteral("document.addEventListener(\"load\", setTimeout(function(event) {\ @@ -96,8 +83,7 @@ void tst_QWebEngineScript::injectionPoint() }, 550));\ </script></head><body></body></html>")); waitForSignal(&page, SIGNAL(loadFinished(bool))); - QTest::qWait(550); - QCOMPARE(evaluateJavaScriptSync(&page, "document.body.innerText"), QVariant::fromValue(QStringLiteral("SUCCESS"))); + QTRY_COMPARE(evaluateJavaScriptSync(&page, "document.body.innerText"), QVariant::fromValue(QStringLiteral("SUCCESS"))); } void tst_QWebEngineScript::injectionPoint_data() @@ -108,9 +94,10 @@ void tst_QWebEngineScript::injectionPoint_data() << QStringLiteral("var contents = (typeof(foo) == \"undefined\")? \"FAILURE\" : \"SUCCESS\";"); QTest::newRow("DocumentReady") << static_cast<int>(QWebEngineScript::DocumentReady) // use a zero timeout to make sure the user script got a chance to run as the order is undefined. - << QStringLiteral("document.addEventListener(\"DOMContentLoaded\", setTimeout(function(event) {\ + << QStringLiteral("document.addEventListener(\"DOMContentLoaded\", function() {\ + setTimeout(function() {\ contents = (typeof(foo) == \"undefined\")? \"FAILURE\" : \"SUCCESS\";\ - }, 0));"); + }, 0)});"); QTest::newRow("Deferred") << static_cast<int>(QWebEngineScript::Deferred) << QStringLiteral("document.addEventListener(\"load\", setTimeout(function(event) {\ contents = (typeof(foo) == \"undefined\")? \"FAILURE\" : \"SUCCESS\";\ @@ -119,7 +106,7 @@ void tst_QWebEngineScript::injectionPoint_data() void tst_QWebEngineScript::scriptWorld() { - WebEnginePage page; + QWebEnginePage page; QWebEngineScript script; script.setInjectionPoint(QWebEngineScript::DocumentCreation); script.setWorldId(QWebEngineScript::MainWorld); @@ -138,7 +125,7 @@ void tst_QWebEngineScript::scriptWorld() void tst_QWebEngineScript::scriptModifications() { - WebEnginePage page; + QWebEnginePage page; QWebEngineScript script; script.setName(QStringLiteral("String1")); script.setInjectionPoint(QWebEngineScript::DocumentCreation); diff --git a/tests/auto/widgets/qwebenginesettings/qwebenginesettings.pro b/tests/auto/widgets/qwebenginesettings/qwebenginesettings.pro new file mode 100644 index 000000000..70786e70f --- /dev/null +++ b/tests/auto/widgets/qwebenginesettings/qwebenginesettings.pro @@ -0,0 +1,2 @@ +include(../tests.pri) +QT *= core-private gui-private diff --git a/tests/auto/widgets/qwebenginesettings/tst_qwebenginesettings.cpp b/tests/auto/widgets/qwebenginesettings/tst_qwebenginesettings.cpp new file mode 100644 index 000000000..0f6a6062e --- /dev/null +++ b/tests/auto/widgets/qwebenginesettings/tst_qwebenginesettings.cpp @@ -0,0 +1,63 @@ +/* + Copyright (C) 2015 The Qt Company Ltd. + + 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 <QtTest/QtTest> + +#include <qwebengineprofile.h> +#include <qwebenginesettings.h> + +class tst_QWebEngineSettings: public QObject { + Q_OBJECT + +private Q_SLOTS: + void resetAttributes(); +}; + +void tst_QWebEngineSettings::resetAttributes() +{ + QWebEngineProfile profile; + QWebEngineSettings *settings = profile.settings(); + + // Attribute + bool defaultValue = settings->testAttribute(QWebEngineSettings::FullScreenSupportEnabled); + settings->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, !defaultValue); + QCOMPARE(!defaultValue, settings->testAttribute(QWebEngineSettings::FullScreenSupportEnabled)); + settings->resetAttribute(QWebEngineSettings::FullScreenSupportEnabled); + QCOMPARE(defaultValue, settings->testAttribute(QWebEngineSettings::FullScreenSupportEnabled)); + + // Font family + QString defaultFamily = settings->fontFamily(QWebEngineSettings::StandardFont); + QString newFontFamily("PugDog"); + settings->setFontFamily(QWebEngineSettings::StandardFont, newFontFamily); + QCOMPARE(newFontFamily, settings->fontFamily(QWebEngineSettings::StandardFont)); + settings->resetFontFamily(QWebEngineSettings::StandardFont); + QCOMPARE(defaultFamily, settings->fontFamily(QWebEngineSettings::StandardFont)); + + // Font size + int defaultSize = settings->fontSize(QWebEngineSettings::MinimumFontSize); + int newSize = defaultSize + 10; + settings->setFontSize(QWebEngineSettings::MinimumFontSize, newSize); + QCOMPARE(newSize, settings->fontSize(QWebEngineSettings::MinimumFontSize)); + settings->resetFontSize(QWebEngineSettings::MinimumFontSize); + QCOMPARE(defaultSize, settings->fontSize(QWebEngineSettings::MinimumFontSize)); +} + +QTEST_MAIN(tst_QWebEngineSettings) + +#include "tst_qwebenginesettings.moc" diff --git a/tests/auto/widgets/widgets.pro b/tests/auto/widgets/widgets.pro index b2df0880d..986d5bbee 100644 --- a/tests/auto/widgets/widgets.pro +++ b/tests/auto/widgets/widgets.pro @@ -1,12 +1,17 @@ TEMPLATE = subdirs -CONFIG += ordered - SUBDIRS += \ qwebengineaccessibility \ qwebenginepage \ - qwebenginehistoryinterface \ - qwebengineview \ qwebenginehistory \ + qwebenginehistoryinterface \ qwebengineinspector \ + qwebengineprofile \ qwebenginescript \ + qwebenginesettings \ + qwebengineview + +qtHaveModule(positioning) { + SUBDIRS += positionplugin + qwebenginepage.depends = positionplugin +} diff --git a/tests/quicktestbrowser/BrowserWindow.qml b/tests/quicktestbrowser/BrowserWindow.qml index ca0b6499b..3fcca4aab 100644 --- a/tests/quicktestbrowser/BrowserWindow.qml +++ b/tests/quicktestbrowser/BrowserWindow.qml @@ -61,8 +61,10 @@ ApplicationWindow { // This is for the case where the system forces us to leave fullscreen. if (currentWebView && !isFullScreen) { currentWebView.state = "" - if (currentWebView.isFullScreen) + if (currentWebView.isFullScreen) { currentWebView.fullScreenCancelled() + fullScreenNotification.hide() + } } } @@ -397,9 +399,11 @@ ApplicationWindow { webEngineView.state = "FullScreen" browserWindow.previousVisibility = browserWindow.visibility browserWindow.showFullScreen() + fullScreenNotification.show() } else { webEngineView.state = "" browserWindow.visibility = browserWindow.previousVisibility + fullScreenNotification.hide() } request.accept() } @@ -502,6 +506,10 @@ ApplicationWindow { } } + FullScreenNotification { + id: fullScreenNotification + } + DownloadView { id: downloadView visible: false diff --git a/tests/quicktestbrowser/FullScreenNotification.qml b/tests/quicktestbrowser/FullScreenNotification.qml new file mode 100644 index 000000000..80a63d479 --- /dev/null +++ b/tests/quicktestbrowser/FullScreenNotification.qml @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * 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. +** * Neither the name of The Qt Company Ltd 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +** OWNER OR 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." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.5 + +Rectangle { + id: fullScreenNotification + width: 500 + height: 40 + color: "white" + radius: 7 + + visible: false + opacity: 0 + + function show() { + visible = true + opacity = 1 + reset.start() + } + + function hide() { + reset.stop() + opacity = 0 + } + + Behavior on opacity { + NumberAnimation { + duration: 750 + onStopped: { + if (opacity == 0) + visible = false + } + } + } + + Timer { + id: reset + interval: 5000 + onTriggered: hide() + } + + anchors.horizontalCenter: parent.horizontalCenter + y: 125 + + Text { + id: message + width: parent.width + + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + + wrapMode: Text.WordWrap + elide: Text.ElideNone + clip: true + + text: qsTr("You are now in fullscreen mode. Press ESC to quit!") + } +} diff --git a/tests/quicktestbrowser/quicktestbrowser.pro b/tests/quicktestbrowser/quicktestbrowser.pro index 7d6dfa6df..996e82a63 100644 --- a/tests/quicktestbrowser/quicktestbrowser.pro +++ b/tests/quicktestbrowser/quicktestbrowser.pro @@ -14,7 +14,8 @@ OTHER_FILES += ApplicationRoot.qml \ ButtonWithMenu.qml \ ContextMenuExtras.qml \ DownloadView.qml \ - FeaturePermissionBar.qml + FeaturePermissionBar.qml \ + FullScreenNotification.qml RESOURCES += resources.qrc diff --git a/tests/quicktestbrowser/resources.qrc b/tests/quicktestbrowser/resources.qrc index 80f1d1543..2dcda4d0d 100644 --- a/tests/quicktestbrowser/resources.qrc +++ b/tests/quicktestbrowser/resources.qrc @@ -5,6 +5,7 @@ <file>BrowserWindow.qml</file> <file>ContextMenuExtras.qml</file> <file>FeaturePermissionBar.qml</file> + <file>FullScreenNotification.qml</file> <file>ButtonWithMenu.qml</file> <file>DownloadView.qml</file> <file>ZoomController.qml</file> diff --git a/tools/qmake/mkspecs/features/configure.prf b/tools/qmake/mkspecs/features/configure.prf index 5799d01ae..7f749146a 100644 --- a/tools/qmake/mkspecs/features/configure.prf +++ b/tools/qmake/mkspecs/features/configure.prf @@ -25,14 +25,11 @@ defineTest(runConfigure) { !config_libcap:skipBuild("libcap development package appears to be missing") !config_khr:skipBuild("khronos development headers appear to be missing (mesa/libegl1-mesa-dev)") - REQUIRED_PACKAGES = dbus-1 fontconfig freetype2 + REQUIRED_PACKAGES = dbus-1 fontconfig contains(QT_CONFIG, xcb): REQUIRED_PACKAGES += libdrm xcomposite xcursor xi xrandr xscrnsaver xtst contains(QT_CONFIG, pulseaudio): REQUIRED_PACKAGES += libpulse contains(QT_CONFIG, system-png): REQUIRED_PACKAGES += libpng - contains(QT_CONFIG, system-harfbuzz)|packagesExist("\'freetype2 >= 2.5.3\'"): { - WEBENGINE_CONFIG += use_system_harfbuzz - REQUIRED_PACKAGES += harfbuzz - } + contains(QT_CONFIG, system-harfbuzz): REQUIRED_PACKAGES += harfbuzz !cross_compile: REQUIRED_PACKAGES += libpci for(package, $$list($$REQUIRED_PACKAGES)) { @@ -55,9 +52,10 @@ defineTest(runConfigure) { config_snappy: WEBENGINE_CONFIG += use_system_snappy else: log("System snappy not found. Using Chromium's copy.$${EOL}") - # Optional dependencies - packagesExist(nss): WEBENGINE_CONFIG += use_nss - else: log("System NSS not found, BoringSSL will be used.$${EOL}") + !cross_compile { + packagesExist(nss): WEBENGINE_CONFIG += use_nss + else: log("System NSS not found, BoringSSL will be used.$${EOL}") + } } isEmpty(skipBuildReason): { diff --git a/tools/qmake/mkspecs/features/functions.prf b/tools/qmake/mkspecs/features/functions.prf index 9f54f4f3c..d5265ab00 100644 --- a/tools/qmake/mkspecs/features/functions.prf +++ b/tools/qmake/mkspecs/features/functions.prf @@ -1,4 +1,8 @@ defineTest(isPlatformSupported) { + !linux-g++*:!linux-clang:!win32-msvc2013*:!win32-msvc2015*:!macx-clang*:!boot2qt { + skipBuild("Qt WebEngine can currently only be built for Linux (GCC/clang), Windows (MSVC 2013 or 2015), OS X (10.9/XCode 5.1+) or Qt for Device Creation.") + return(false) + } !contains(QT_CONFIG, c++11) { skipBuild("C++11 support is required in order to build chromium.") return(false) @@ -22,11 +26,7 @@ defineTest(isPlatformSupported) { linux-g++*:!isGCCVersionSupported(): return(false) !isPythonVersionSupported(): return(false) - linux-g++*|linux-clang|win32-msvc2013*|win32-msvc2015*|macx-clang*: return(true) - boot2qt: return(true) - - skipBuild("Qt WebEngine can currently only be built for Linux (GCC/clang), Windows (MSVC 2013 or 2015), OS X (10.9/XCode 5.1+) or Qt for Device Creation.") - return(false) + return(true) } defineTest(isPythonVersionSupported) { |