diff options
author | Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com> | 2016-02-02 13:13:10 +0100 |
---|---|---|
committer | Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com> | 2016-02-02 13:13:10 +0100 |
commit | ca731a7446f0485886a04474415a21d2f64e3f8b (patch) | |
tree | 9ee153440866fbb28535d204f4dc467f36e867d0 | |
parent | 98f6e0c9d28dbcbecc560abde7606bff7c8e4d99 (diff) | |
parent | 82f4d13a13b40d9cb7710f6dd4190175a272a394 (diff) |
Merge 5.6 into 5.6.0
Change-Id: Ifca953bf6fa663b81dba77a4e825d3917c8e33fc
40 files changed, 1334 insertions, 221 deletions
diff --git a/examples/examples.pro b/examples/examples.pro index fdd25664f..867ce4cc6 100644 --- a/examples/examples.pro +++ b/examples/examples.pro @@ -7,6 +7,7 @@ qtHaveModule(webengine) { qtHaveModule(webenginewidgets) { SUBDIRS += \ webenginewidgets/contentmanipulation \ + webenginewidgets/cookiebrowser \ webenginewidgets/demobrowser \ webenginewidgets/markdowneditor } diff --git a/examples/webenginewidgets/contentmanipulation/doc/images/contentmanipulation-example.png b/examples/webenginewidgets/contentmanipulation/doc/images/contentmanipulation-example.png Binary files differindex 717ac9ddc..ecdbc4c64 100644 --- a/examples/webenginewidgets/contentmanipulation/doc/images/contentmanipulation-example.png +++ b/examples/webenginewidgets/contentmanipulation/doc/images/contentmanipulation-example.png diff --git a/examples/webenginewidgets/contentmanipulation/doc/src/contentmanipulation.qdoc b/examples/webenginewidgets/contentmanipulation/doc/src/contentmanipulation.qdoc index 676173755..f16634d0f 100644 --- a/examples/webenginewidgets/contentmanipulation/doc/src/contentmanipulation.qdoc +++ b/examples/webenginewidgets/contentmanipulation/doc/src/contentmanipulation.qdoc @@ -29,114 +29,143 @@ \example webenginewidgets/contentmanipulation \title WebEngine Content Manipulation Example \ingroup webengine-widgetexamples - \brief Demonstrates how to use browse web and manipulate content - - \brief The Content Manipulation example shows how to use JQuery with QtWebEngine to - create a web browser with special effects and content - manipulation. + \brief Demonstrates how to load and manipulate web content. \image contentmanipulation-example.png - The application makes use of QWebEnginePage::evaluateJavaScript to - evaluate the jQuery JavaScript code. A QMainWindow with a QWebEngineView - as central widget builds up the browser itself. + \e{Content Manipulation} shows how to use JQuery with \l {Qt WebEngine Widgets} to + create a web browser with special effects and content manipulation. + + In the application, we call QWebEnginePage::runJavaScript() to + execute jQuery JavaScript code. We implement a QMainWindow with a QWebEngineView + as a central widget to build up the browser itself. \include examples-run.qdocinc \section1 MainWindow Class Definition The \c MainWindow class inherits QMainWindow. It implements a number of - slots to perform actions on both the application and on the web content. + slots to perform actions on both the application and on the web content: - \snippet webenginewidgets/contentmanipulation/mainwindow.h 1 + \quotefromfile webenginewidgets/contentmanipulation/mainwindow.h + \skipto class MainWindow : + \printuntil /^\}/ - We also declare a QString that contains the jQuery, a QWebView + We also declare a QString that contains the jQuery, a QWebEngineView that displays the web content, and a QLineEdit that acts as the address bar. \section1 MainWindow Class Implementation - We start by implementing the constructor. - - \snippet webenginewidgets/contentmanipulation/mainwindow.cpp 1 + We start by implementing the constructor. The first part of the constructor sets the value of + \c progress to 0. This value will be used later in the code to visualize the loading of a + web page: - The first part of the constructor sets the value of \c progress to - 0. This value will be used later in the code to visualize the - loading of a webpage. + \quotefromfile webenginewidgets/contentmanipulation/mainwindow.cpp + \skipto MainWindow::MainWindow + \printuntil progress - Next, the jQuery library is loaded using a QFile and reading the file + Next, the jQuery library is loaded by using a QFile and reading the file content. The jQuery library is a JavaScript library that provides different - functions for manipulating HTML. + functions for manipulating HTML: + + \printuntil file.close() + + The second part of the constructor creates a QWebEngineView and connects + slots to the view's signals: + + \printuntil SLOT(finishLoading + + Furthermore, we create a QLineEdit as the browser's address bar. We then set the horizontal + QSizePolicy to fill the available area in the browser at all times. We add the + QLineEdit to a QToolBar together with a set of navigation actions from + QWebEngineView::pageAction(): + + \printuntil addWidget(locationEdit) + + The third part of the constructor implements two QMenu widgets and assigns + a set of actions to them: + + \printuntil removeEmbeddedElements - \snippet webenginewidgets/contentmanipulation/mainwindow.cpp 2 + The last line sets the QWebEngineView as the central widget in the QMainWindow: - The second part of the constructor creates a QWebView and connects - slots to the views signals. Furthermore, we create a QLineEdit as - the browsers address bar. We then set the horizontal QSizePolicy - to fill the available area in the browser at all times. We add the - QLineEdit to a QToolbar together with a set of navigation actions - from QWebView::pageAction. + \printuntil } - \snippet webenginewidgets/contentmanipulation/mainwindow.cpp 3 + When the page is loaded, \c adjustLocation() is triggered by the \c loadFinished() signal in + QWebEngineView to update the address bar: - The third and last part of the constructor implements two QMenus and assigns - a set of actions to them. The last line sets the QWebView as the central - widget in the QMainWindow. + \skipto adjustLocation() + \printuntil } - \snippet webenginewidgets/contentmanipulation/mainwindow.cpp 4 + In \c changeLocation(), we create a QUrl object, and then use it to load the page into the + QWebEngineView. When the new web page has finished loading, \c adjustLocation() will be + run once more to update the address bar: - When the page is loaded, \c adjustLocation() updates the address - bar; \c adjustLocation() is triggered by the \c loadFinished() - signal in QWebView. In \c changeLocation() we create a QUrl - object, and then use it to load the page into the QWebView. When - the new web page has finished loading, \c adjustLocation() will be - run once more to update the address bar. + \printuntil } - \snippet webenginewidgets/contentmanipulation/mainwindow.cpp 5 + The \c adjustTitle() method sets the window title and displays the loading progress: - \c adjustTitle() sets the window title and displays the loading - progress. This slot is triggered by the \c titleChanged() signal - in QWebView. + \printuntil } + \printuntil } - \snippet webenginewidgets/contentmanipulation/mainwindow.cpp 6 + This slot is triggered by the \c titleChanged() signal in QWebEngineView. - When a web page has loaded, \c finishLoading() is triggered by the - \c loadFinished() signal in QWebView. \c finishLoading() then updates the - progress in the title bar and calls \c evaluateJavaScript() - to evaluate the jQuery library. This evaluates the JavaScript against the - current web page. What that means is that the JavaScript can be viewed as - part of the content loaded into the QWebView, and therefore needs to be + When a web page has loaded, the \c finishLoading() method is triggered by the + \c loadFinished() signal in QWebEngineView. The method then updates the + progress in the title bar and calls \c runJavaScript() + to evaluate the jQuery library against the current web page: + + \printuntil } + + This means that the JavaScript can be viewed as a + part of the content loaded into the QWebEngineView, and therefore needs to be loaded every time a new page is loaded. Once the jQuery library is loaded, we can start executing the different jQuery functions in the browser. - The rotateImages() function is then called explicitely to make sure + The \c rotateImages() function is then called explicitly to make sure that the images of the newly loaded page respect the state of the toggle action. - \snippet webenginewidgets/contentmanipulation/mainwindow.cpp 7 - The first jQuery-based function, \c highlightAllLinks(), is designed to highlight all links in the current webpage. The JavaScript code looks for web elements named \e {a}, which is the tag for a hyperlink. For each such element, the background color is set to be yellow by - using CSS. + using CSS: - \snippet webenginewidgets/contentmanipulation/mainwindow.cpp 8 + \printuntil } + \printuntil } + + We append \c undefined after the jQuery call to prevent a possible recursion loop + and crash caused by the way the elements returned by the each iterator elements + reference each other, which causes problems upon converting them to QVariant. The \c rotateImages() function rotates the images on the current - web page. This JavaScript code relies on CSS transforms and + web page. This JavaScript code relies on CSS transforms. It looks up all \e {img} elements and rotates the images 180 degrees - and then back again. + and then back again: - \snippet webenginewidgets/contentmanipulation/mainwindow.cpp 9 + \printuntil runJavaScript(code); + \printuntil } - The remaining four methods remove different elements from the current web - page. \c removeGifImages() removes all GIF images on the page by looking up + The remaining methods remove different elements from the current web + page. The \c removeGifImages() removes all GIF images on the page by looking up the \e {src} attribute of all the elements on the web page. Any element with - a \e {gif} file as its source is removed. \c removeInlineFrames() removes all - \e {iframe} or inline elements. \c removeObjectElements() removes all - \e {object} elements, and \c removeEmbeddedElements() removes any elements - such as plugins embedded on the page using the \e {embed} tag. + a \e {gif} file as its source is removed: + + \printuntil } + + The \c removeInlineFrames() method removes all \e {iframe} or inline elements: + + \printuntil } + + The \c removeObjectElements() method removes all \e {object} elements: + + \printuntil } + + The \c removeEmbeddedElements() method removes any elements using the \e {embed} tag, such as + plugins embedded on the page: + \printuntil } */ diff --git a/examples/webenginewidgets/contentmanipulation/mainwindow.cpp b/examples/webenginewidgets/contentmanipulation/mainwindow.cpp index 3dca497a3..d3552ac86 100644 --- a/examples/webenginewidgets/contentmanipulation/mainwindow.cpp +++ b/examples/webenginewidgets/contentmanipulation/mainwindow.cpp @@ -58,8 +58,6 @@ InvokeWrapper<Arg, R, C> invoke(R *receiver, void (C::*memberFun)(Arg)) return wrapper; } -//! [1] - MainWindow::MainWindow(const QUrl& url) { progress = 0; @@ -70,9 +68,7 @@ MainWindow::MainWindow(const QUrl& url) jQuery = file.readAll(); jQuery.append("\nvar qt = { 'jQuery': jQuery.noConflict(true) };"); file.close(); -//! [1] -//! [2] view = new QWebEngineView(this); view->load(url); connect(view, SIGNAL(loadFinished(bool)), SLOT(adjustLocation())); @@ -90,14 +86,12 @@ MainWindow::MainWindow(const QUrl& url) toolBar->addAction(view->pageAction(QWebEnginePage::Reload)); toolBar->addAction(view->pageAction(QWebEnginePage::Stop)); toolBar->addWidget(locationEdit); -//! [2] QMenu *viewMenu = menuBar()->addMenu(tr("&View")); QAction* viewSourceAction = new QAction("Page Source", this); connect(viewSourceAction, SIGNAL(triggered()), SLOT(viewSource())); viewMenu->addAction(viewSourceAction); -//! [3] QMenu *effectMenu = menuBar()->addMenu(tr("&Effect")); effectMenu->addAction("Highlight all links", this, SLOT(highlightAllLinks())); @@ -116,7 +110,6 @@ MainWindow::MainWindow(const QUrl& url) setCentralWidget(view); } -//! [3] void MainWindow::viewSource() { @@ -129,7 +122,6 @@ void MainWindow::viewSource() view->page()->toHtml(invoke(textEdit, &QTextEdit::setPlainText)); } -//! [4] void MainWindow::adjustLocation() { locationEdit->setText(view->url().toString()); @@ -141,9 +133,7 @@ void MainWindow::changeLocation() view->load(url); view->setFocus(); } -//! [4] -//! [5] void MainWindow::adjustTitle() { if (progress <= 0 || progress >= 100) @@ -157,9 +147,7 @@ void MainWindow::setProgress(int p) progress = p; adjustTitle(); } -//! [5] -//! [6] void MainWindow::finishLoading(bool) { progress = 100; @@ -168,36 +156,24 @@ void MainWindow::finishLoading(bool) rotateImages(rotateAction->isChecked()); } -//! [6] -//! [7] void MainWindow::highlightAllLinks() { - // We append '; undefined' after the jQuery call here to prevent a possible recursion loop and crash caused by - // the way the elements returned by the each iterator elements reference each other, which causes problems upon - // converting them to QVariants. QString code = "qt.jQuery('a').each( function () { qt.jQuery(this).css('background-color', 'yellow') } ); undefined"; view->page()->runJavaScript(code); } -//! [7] -//! [8] void MainWindow::rotateImages(bool invert) { QString code; - // We append '; undefined' after each of the jQuery calls here to prevent a possible recursion loop and crash caused by - // the way the elements returned by the each iterator elements reference each other, which causes problems upon - // converting them to QVariants. if (invert) code = "qt.jQuery('img').each( function () { qt.jQuery(this).css('-webkit-transition', '-webkit-transform 2s'); qt.jQuery(this).css('-webkit-transform', 'rotate(180deg)') } ); undefined"; else code = "qt.jQuery('img').each( function () { qt.jQuery(this).css('-webkit-transition', '-webkit-transform 2s'); qt.jQuery(this).css('-webkit-transform', 'rotate(0deg)') } ); undefined"; view->page()->runJavaScript(code); } -//! [8] -//! [9] void MainWindow::removeGifImages() { QString code = "qt.jQuery('[src*=gif]').remove()"; @@ -221,5 +197,3 @@ void MainWindow::removeEmbeddedElements() QString code = "qt.jQuery('embed').remove()"; view->page()->runJavaScript(code); } -//! [9] - diff --git a/examples/webenginewidgets/contentmanipulation/mainwindow.h b/examples/webenginewidgets/contentmanipulation/mainwindow.h index 8e9b12538..06b8aba03 100644 --- a/examples/webenginewidgets/contentmanipulation/mainwindow.h +++ b/examples/webenginewidgets/contentmanipulation/mainwindow.h @@ -45,7 +45,6 @@ class QWebEngineView; class QLineEdit; QT_END_NAMESPACE -//! [1] class MainWindow : public QMainWindow { Q_OBJECT @@ -76,5 +75,4 @@ private: QLineEdit *locationEdit; QAction *rotateAction; int progress; -//! [1] }; diff --git a/examples/webenginewidgets/cookiebrowser/cookiebrowser.pro b/examples/webenginewidgets/cookiebrowser/cookiebrowser.pro new file mode 100644 index 000000000..66ea064ef --- /dev/null +++ b/examples/webenginewidgets/cookiebrowser/cookiebrowser.pro @@ -0,0 +1,19 @@ +QT += core gui webenginewidgets +TARGET = cookiebrowser +TEMPLATE = app +CONFIG += c++11 + +SOURCES += \ + main.cpp\ + mainwindow.cpp + +HEADERS += \ + mainwindow.h + +FORMS += \ + mainwindow.ui \ + cookiedialog.ui \ + cookiewidget.ui + +RESOURCES += \ + cookiebrowser.qrc diff --git a/examples/webenginewidgets/cookiebrowser/cookiebrowser.qrc b/examples/webenginewidgets/cookiebrowser/cookiebrowser.qrc new file mode 100644 index 000000000..8805f2c53 --- /dev/null +++ b/examples/webenginewidgets/cookiebrowser/cookiebrowser.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/"> + <file>view-refresh.png</file> + </qresource> +</RCC> diff --git a/examples/webenginewidgets/cookiebrowser/cookiedialog.ui b/examples/webenginewidgets/cookiebrowser/cookiedialog.ui new file mode 100644 index 000000000..ad6e5cab1 --- /dev/null +++ b/examples/webenginewidgets/cookiebrowser/cookiedialog.ui @@ -0,0 +1,189 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>CookieDialog</class> + <widget class="QDialog" name="CookieDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>245</height> + </rect> + </property> + <property name="windowTitle"> + <string>Cookie</string> + </property> + <layout class="QFormLayout" name="formLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Name</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLineEdit" name="m_nameLineEdit"> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Domain</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="m_domainLineEdit"> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="5" column="0"> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>Path</string> + </property> + </widget> + </item> + <item row="5" column="1"> + <widget class="QLineEdit" name="m_pathLineEdit"> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="6" column="0"> + <widget class="QLabel" name="label_5"> + <property name="text"> + <string>isHttpOnly</string> + </property> + </widget> + </item> + <item row="6" column="1"> + <widget class="QComboBox" name="m_isHttpOnlyComboBox"/> + </item> + <item row="7" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>isSecure</string> + </property> + </widget> + </item> + <item row="8" column="1"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="m_addButton"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string>Add</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="m_cancelButton"> + <property name="text"> + <string>Cancel</string> + </property> + </widget> + </item> + </layout> + </item> + <item row="7" column="1"> + <widget class="QComboBox" name="m_isSecureComboBox"/> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="label_6"> + <property name="text"> + <string>Value</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QLineEdit" name="m_valueLineEdit"> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="4" column="1"> + <widget class="QDateEdit" name="m_dateEdit"> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="4" column="0"> + <widget class="QLabel" name="label_7"> + <property name="text"> + <string>Expires</string> + </property> + </widget> + </item> + </layout> + </widget> + <tabstops> + <tabstop>m_nameLineEdit</tabstop> + <tabstop>m_domainLineEdit</tabstop> + <tabstop>m_valueLineEdit</tabstop> + <tabstop>m_dateEdit</tabstop> + <tabstop>m_pathLineEdit</tabstop> + <tabstop>m_isHttpOnlyComboBox</tabstop> + <tabstop>m_isSecureComboBox</tabstop> + <tabstop>m_addButton</tabstop> + <tabstop>m_cancelButton</tabstop> + </tabstops> + <resources/> + <connections> + <connection> + <sender>m_cancelButton</sender> + <signal>clicked()</signal> + <receiver>CookieDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>350</x> + <y>103</y> + </hint> + <hint type="destinationlabel"> + <x>199</x> + <y>63</y> + </hint> + </hints> + </connection> + <connection> + <sender>m_addButton</sender> + <signal>clicked()</signal> + <receiver>CookieDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>265</x> + <y>112</y> + </hint> + <hint type="destinationlabel"> + <x>199</x> + <y>63</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/examples/webenginewidgets/cookiebrowser/cookiewidget.ui b/examples/webenginewidgets/cookiebrowser/cookiewidget.ui new file mode 100644 index 000000000..816d7473e --- /dev/null +++ b/examples/webenginewidgets/cookiebrowser/cookiewidget.ui @@ -0,0 +1,92 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>CookieWidget</class> + <widget class="QWidget" name="CookieWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>300</width> + <height>71</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>300</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>310</width> + <height>16777215</height> + </size> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout" stretch="3,1"> + <item> + <layout class="QFormLayout" name="formLayout"> + <property name="formAlignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Name:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLabel" name="m_nameLabel"> + <property name="text"> + <string>Empty</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Domain:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLabel" name="m_domainLabel"> + <property name="text"> + <string>Emtpy</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QPushButton" name="m_viewButton"> + <property name="text"> + <string>View</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="m_deleteButton"> + <property name="text"> + <string>Delete</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/examples/webenginewidgets/cookiebrowser/doc/images/cookiebrowser.png b/examples/webenginewidgets/cookiebrowser/doc/images/cookiebrowser.png Binary files differnew file mode 100644 index 000000000..4e76ba6d9 --- /dev/null +++ b/examples/webenginewidgets/cookiebrowser/doc/images/cookiebrowser.png diff --git a/examples/webenginewidgets/cookiebrowser/doc/src/cookiebrowser.qdoc b/examples/webenginewidgets/cookiebrowser/doc/src/cookiebrowser.qdoc new file mode 100644 index 000000000..259de0724 --- /dev/null +++ b/examples/webenginewidgets/cookiebrowser/doc/src/cookiebrowser.qdoc @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** 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/cookiebrowser + \title WebEngine Cookie Browser Example + \ingroup webengine-widgetexamples + \brief A cookie browser based on Qt WebEngine Widgets + + \image cookiebrowser.png + + \e {Cookie Browser} demonstrates how to use the \l{Qt WebEngine Widgets C++ Classes} + {Qt WebEngine C++ classes} to manage cookies. The browser can be used to view cookie content as + well as delete cookies and add new cookies. + + \include examples-run.qdocinc +*/ diff --git a/examples/webenginewidgets/cookiebrowser/main.cpp b/examples/webenginewidgets/cookiebrowser/main.cpp new file mode 100644 index 000000000..c122eb7c3 --- /dev/null +++ b/examples/webenginewidgets/cookiebrowser/main.cpp @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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:BSD$ +** 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 <QApplication> +#include <QUrl> + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + MainWindow window(QUrl("http://qt.io")); + window.show(); + return app.exec(); +} diff --git a/examples/webenginewidgets/cookiebrowser/mainwindow.cpp b/examples/webenginewidgets/cookiebrowser/mainwindow.cpp new file mode 100644 index 000000000..4139153c9 --- /dev/null +++ b/examples/webenginewidgets/cookiebrowser/mainwindow.cpp @@ -0,0 +1,192 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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:BSD$ +** 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 <QWebEngineCookieStore> +#include <QWebEngineProfile> + +CookieDialog::CookieDialog(const QNetworkCookie &cookie, QWidget *parent): QDialog(parent) +{ + setupUi(this); + m_nameLineEdit->setText(cookie.name()); + m_domainLineEdit->setText(cookie.domain()); + m_valueLineEdit->setText(cookie.value()); + m_pathLineEdit->setText(cookie.path()); + m_dateEdit->setDate(cookie.expirationDate().date()); + m_isSecureComboBox->addItem(cookie.isSecure() ? tr("yes") : tr("no")); + m_isHttpOnlyComboBox->addItem(cookie.isHttpOnly() ? tr("yes") : tr("no")); + m_addButton->setVisible(false); + m_cancelButton->setText(tr("Close")); +} + +CookieDialog::CookieDialog(QWidget *parent): QDialog(parent) +{ + setupUi(this); + m_nameLineEdit->setReadOnly(false); + m_domainLineEdit->setReadOnly(false); + m_valueLineEdit->setReadOnly(false); + m_pathLineEdit->setReadOnly(false); + m_dateEdit->setReadOnly(false); + m_dateEdit->setDate(QDateTime::currentDateTime().addYears(1).date()); + m_isSecureComboBox->addItem(tr("no")); + m_isSecureComboBox->addItem(tr("yes")); + m_isHttpOnlyComboBox->addItem(tr("no")); + m_isHttpOnlyComboBox->addItem(tr("yes")); +} + +QNetworkCookie CookieDialog::cookie() +{ + QNetworkCookie cookie; + cookie.setDomain(m_domainLineEdit->text()); + cookie.setName(m_nameLineEdit->text().toLatin1()); + cookie.setValue(m_valueLineEdit->text().toLatin1()); + cookie.setExpirationDate(QDateTime(m_dateEdit->date())); + cookie.setPath(m_pathLineEdit->text()); + cookie.setSecure(m_isSecureComboBox->currentText() == tr("yes")); + cookie.setHttpOnly(m_isHttpOnlyComboBox->currentText() == tr("yes")); + return cookie; +} + +CookieWidget::CookieWidget(const QNetworkCookie &cookie, QWidget *parent): QWidget(parent) +{ + setupUi(this); + setAutoFillBackground(true); + m_nameLabel->setText(cookie.name()); + m_domainLabel->setText(cookie.domain()); + connect(m_viewButton, &QPushButton::clicked, this, &CookieWidget::viewClicked); + connect(m_deleteButton, &QPushButton::clicked, this, &CookieWidget::deleteClicked); +} + +void CookieWidget::setHighlighted(bool enabled) +{ + QPalette p = palette(); + p.setColor(backgroundRole(), enabled ? QColor(0xF0, 0xF8, 0xFF) : Qt::white); + setPalette(p); +} + +MainWindow::MainWindow(const QUrl &url) : + QMainWindow(), + m_store(nullptr), + m_layout(new QVBoxLayout) +{ + setupUi(this); + m_urlLineEdit->setText(url.toString()); + + m_layout->addItem(new QSpacerItem(0,0, QSizePolicy::Minimum, QSizePolicy::Expanding)); + m_layout->setContentsMargins(0, 0, 0, 0); + m_layout->setSpacing(0); + + QWidget *w = new QWidget(); + QPalette p = w->palette(); + p.setColor(widget->backgroundRole(), Qt::white); + w->setPalette(p); + w->setLayout(m_layout); + + m_scrollArea->setWidget(w); + m_scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + m_scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + + connect(m_urlButton, &QPushButton::clicked, this, &MainWindow::handleUrlClicked); + connect(m_deleteAllButton, &QPushButton::clicked, this, &MainWindow::handleDeleteAllClicked); + connect(m_newButton, &QPushButton::clicked, this, &MainWindow::handleNewClicked); + + m_store = m_webview->page()->profile()->cookieStore(); + connect(m_store, &QWebEngineCookieStore::cookieAdded, this, &MainWindow::handleCookieAdded); + m_store->loadAllCookies(); + m_webview->load(url); +} + +bool MainWindow::containsCookie(const QNetworkCookie &cookie) +{ + for (auto c: m_cookies) { + if (c.hasSameIdentifier(cookie)) + return true; + } + return false; +} + +void MainWindow::handleCookieAdded(const QNetworkCookie &cookie) +{ + // only new cookies + if (containsCookie(cookie)) + return; + + CookieWidget *widget = new CookieWidget(cookie); + widget->setHighlighted(m_cookies.count() % 2); + m_cookies.append(cookie); + m_layout->insertWidget(0,widget); + + connect(widget, &CookieWidget::deleteClicked, [this, cookie, widget]() { + m_store->deleteCookie(cookie); + delete widget; + m_cookies.removeOne(cookie); + for (int i = 0; i < m_layout->count() - 1; i++) { + // fix background colors + auto widget = qobject_cast<CookieWidget*>(m_layout->itemAt(i)->widget()); + widget->setHighlighted(i % 2); + } + }); + + connect(widget, &CookieWidget::viewClicked, [cookie]() { + CookieDialog dialog(cookie); + dialog.exec(); + }); +} + +void MainWindow::handleDeleteAllClicked() +{ + m_store->deleteAllCookies(); + for (int i = m_layout->count() - 1; i >= 0; i--) + delete m_layout->itemAt(i)->widget(); + m_cookies.clear(); +} + +void MainWindow::handleNewClicked() +{ + CookieDialog dialog; + if (dialog.exec() == QDialog::Accepted) + m_store->setCookie(dialog.cookie()); +} + +void MainWindow::handleUrlClicked() +{ + m_webview->load(QUrl(m_urlLineEdit->text())); +} diff --git a/examples/webenginewidgets/cookiebrowser/mainwindow.h b/examples/webenginewidgets/cookiebrowser/mainwindow.h new file mode 100644 index 000000000..93d0a5a31 --- /dev/null +++ b/examples/webenginewidgets/cookiebrowser/mainwindow.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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:BSD$ +** 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 "ui_mainwindow.h" +#include "ui_cookiewidget.h" +#include "ui_cookiedialog.h" +#include <QNetworkCookie> +#include <QMainWindow> + +QT_BEGIN_NAMESPACE +class QWebEngineCookieStore; +QT_END_NAMESPACE + +class CookieDialog : public QDialog, public Ui_CookieDialog +{ + Q_OBJECT +public: + CookieDialog(const QNetworkCookie &cookie, QWidget *parent = nullptr); + CookieDialog(QWidget *parent = 0); + QNetworkCookie cookie(); +}; + +class CookieWidget : public QWidget, public Ui_CookieWidget +{ + Q_OBJECT +public: + CookieWidget(const QNetworkCookie &cookie, QWidget *parent = nullptr); + void setHighlighted(bool enabled); +signals: + void deleteClicked(); + void viewClicked(); +}; + +class MainWindow : public QMainWindow, public Ui_MainWindow +{ + Q_OBJECT +public: + explicit MainWindow(const QUrl &url); + +private: + bool containsCookie(const QNetworkCookie &cookie); + +private slots: + void handleCookieAdded(const QNetworkCookie &cookie); + void handleDeleteAllClicked(); + void handleNewClicked(); + void handleUrlClicked(); + +private: + QWebEngineCookieStore *m_store; + QVector<QNetworkCookie> m_cookies; + QVBoxLayout *m_layout; +}; + +#endif // MAINWINDOW_H diff --git a/examples/webenginewidgets/cookiebrowser/mainwindow.ui b/examples/webenginewidgets/cookiebrowser/mainwindow.ui new file mode 100644 index 000000000..78d451396 --- /dev/null +++ b/examples/webenginewidgets/cookiebrowser/mainwindow.ui @@ -0,0 +1,200 @@ +<?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>1400</width> + <height>650</height> + </rect> + </property> + <property name="windowTitle"> + <string>Cookie Manager</string> + </property> + <widget class="QWidget" name="centralWidget"> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QFrame" name="frame"> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QWidget" name="widget" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QLineEdit" name="m_urlLineEdit"/> + </item> + <item> + <widget class="QPushButton" name="m_urlButton"> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset resource="cookiebrowser.qrc"> + <normaloff>:/view-refresh.png</normaloff>:/view-refresh.png</iconset> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QWebEngineView" name="m_webview" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QFrame" name="frame_2"> + <property name="maximumSize"> + <size> + <width>336</width> + <height>16777215</height> + </size> + </property> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Raised</enum> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QWidget" name="widget_2" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout_3"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Cookies:</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>87</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="m_newButton"> + <property name="text"> + <string>New</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="m_deleteAllButton"> + <property name="text"> + <string>Delete All</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QScrollArea" name="m_scrollArea"> + <property name="minimumSize"> + <size> + <width>320</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>320</width> + <height>16777215</height> + </size> + </property> + <property name="widgetResizable"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </widget> + <layoutdefault spacing="6" margin="11"/> + <customwidgets> + <customwidget> + <class>QWebEngineView</class> + <extends>QWidget</extends> + <header>qwebengineview.h</header> + <container>1</container> + </customwidget> + </customwidgets> + <resources> + <include location="cookiebrowser.qrc"/> + </resources> + <connections> + <connection> + <sender>m_urlLineEdit</sender> + <signal>returnPressed()</signal> + <receiver>m_urlButton</receiver> + <slot>click()</slot> + <hints> + <hint type="sourcelabel"> + <x>509</x> + <y>28</y> + </hint> + <hint type="destinationlabel"> + <x>1024</x> + <y>27</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/examples/webenginewidgets/cookiebrowser/view-refresh.png b/examples/webenginewidgets/cookiebrowser/view-refresh.png Binary files differnew file mode 100644 index 000000000..cab4d02c7 --- /dev/null +++ b/examples/webenginewidgets/cookiebrowser/view-refresh.png diff --git a/src/3rdparty b/src/3rdparty -Subproject 77b91185050176b88c446fdb1b33b92dd737dd8 +Subproject 3f655a31b4979b0862e5aec1c8f47b597464749 diff --git a/src/core/api/qwebengineurlrequestjob.h b/src/core/api/qwebengineurlrequestjob.h index 922299fd9..84741b791 100644 --- a/src/core/api/qwebengineurlrequestjob.h +++ b/src/core/api/qwebengineurlrequestjob.h @@ -44,8 +44,8 @@ #include <QtCore/qurl.h> namespace QtWebEngineCore { -class URLRequestCustomJob; class URLRequestCustomJobDelegate; +class URLRequestCustomJobShared; } // namespace QT_BEGIN_NAMESPACE @@ -76,7 +76,7 @@ public: private: QWebEngineUrlRequestJob(QtWebEngineCore::URLRequestCustomJobDelegate *); - friend class QtWebEngineCore::URLRequestCustomJob; + friend class QtWebEngineCore::URLRequestCustomJobShared; QtWebEngineCore::URLRequestCustomJobDelegate* d_ptr; }; diff --git a/src/core/config/common.pri b/src/core/config/common.pri new file mode 100644 index 000000000..c5921a573 --- /dev/null +++ b/src/core/config/common.pri @@ -0,0 +1,10 @@ +# Shared configuration for all our supported platforms + +# Trigger Qt-specific build conditions. +GYP_CONFIG += use_qt=1 +# We do not want to ship more external binary blobs, so let v8 embed its startup data. +GYP_CONFIG += v8_use_external_startup_data=0 +# Disable printing since we don't support it yet +GYP_CONFIG += enable_basic_printing=0 enable_print_preview=0 +# WebSpeech requires Google API keys and adds dependencies on speex and flac. +GYP_CONFIG += enable_web_speech=0 diff --git a/src/core/config/embedded_qnx.pri b/src/core/config/embedded_qnx.pri index 7fd35c976..34470d2d8 100644 --- a/src/core/config/embedded_qnx.pri +++ b/src/core/config/embedded_qnx.pri @@ -1,5 +1,7 @@ GYP_ARGS += "-D qt_os=\"embedded_qnx\" -I config/embedded_qnx.gypi" +include(common.pri) + GYP_CONFIG += \ disable_nacl=1 \ enable_plugins=0 \ diff --git a/src/core/config/linux.pri b/src/core/config/linux.pri index 9868d6848..00e25ec58 100644 --- a/src/core/config/linux.pri +++ b/src/core/config/linux.pri @@ -1,3 +1,5 @@ +include(common.pri) + # linux_use_bundled_gold currently relies on a hardcoded relative path from chromium/src/out/(Release|Debug) # Disable it along with the -Wl,--threads flag just in case gold isn't installed on the system. GYP_CONFIG += \ @@ -34,11 +36,9 @@ 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 use?(system_libxslt): GYP_CONFIG += use_system_libxml=1 -use?(system_flac): GYP_CONFIG += use_system_flac=1 use?(system_jsoncpp): GYP_CONFIG += use_system_jsoncpp=1 use?(system_opus): GYP_CONFIG += use_system_opus=1 use?(system_snappy): GYP_CONFIG += use_system_snappy=1 -use?(system_speex): GYP_CONFIG += use_system_speex=1 use?(system_vpx): GYP_CONFIG += use_system_libvpx=1 use?(system_icu): GYP_CONFIG += use_system_icu=1 use?(system_ffmpeg): GYP_CONFIG += use_system_ffmpeg=1 diff --git a/src/core/config/mac_osx.pri b/src/core/config/mac_osx.pri index 93c77623c..940b47982 100644 --- a/src/core/config/mac_osx.pri +++ b/src/core/config/mac_osx.pri @@ -1,3 +1,5 @@ +include(common.pri) + QMAKE_CLANG_DIR = "/usr" QMAKE_CLANG_PATH = $$eval(QMAKE_MAC_SDK.macx-clang.$${QMAKE_MAC_SDK}.QMAKE_CXX) !isEmpty(QMAKE_CLANG_PATH) { diff --git a/src/core/config/windows.pri b/src/core/config/windows.pri index 1e875f308..760ed5b6f 100644 --- a/src/core/config/windows.pri +++ b/src/core/config/windows.pri @@ -1,5 +1,7 @@ GYP_ARGS += "-D qt_os=\"win32\" -I config/windows.gypi" +include(common.pri) + GYP_CONFIG += \ disable_nacl=1 \ remoting=0 \ diff --git a/src/core/url_request_context_getter_qt.cpp b/src/core/url_request_context_getter_qt.cpp index 618354d1c..20efec295 100644 --- a/src/core/url_request_context_getter_qt.cpp +++ b/src/core/url_request_context_getter_qt.cpp @@ -127,8 +127,9 @@ void URLRequestContextGetterQt::updateStorageSettings() content::BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO), content::BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE) )); - if (m_storage) + if (m_storage) { content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, base::Bind(&URLRequestContextGetterQt::generateStorage, this)); + } } } @@ -283,7 +284,7 @@ void URLRequestContextGetterQt::generateUserAgent() Q_ASSERT(m_urlRequestContext); Q_ASSERT(m_storage); - m_storage->set_http_user_agent_settings(new HttpUserAgentSettingsQt(m_browserContext)); + m_storage->set_http_user_agent_settings(new HttpUserAgentSettingsQt(m_browserContext.constData())); } void URLRequestContextGetterQt::updateHttpCache() diff --git a/src/core/url_request_context_getter_qt.h b/src/core/url_request_context_getter_qt.h index 8740c65a2..555d56784 100644 --- a/src/core/url_request_context_getter_qt.h +++ b/src/core/url_request_context_getter_qt.h @@ -94,7 +94,7 @@ private: bool m_ignoreCertificateErrors; QAtomicInt m_updateCookieStore; QAtomicInt m_updateHttpCache; - BrowserContextAdapter *m_browserContext; + QExplicitlySharedDataPointer<BrowserContextAdapter> m_browserContext; content::ProtocolHandlerMap m_protocolHandlers; QAtomicPointer<net::ProxyConfigService> m_proxyConfigService; diff --git a/src/core/url_request_custom_job.cpp b/src/core/url_request_custom_job.cpp index 907f71c2e..07087c247 100644 --- a/src/core/url_request_custom_job.cpp +++ b/src/core/url_request_custom_job.cpp @@ -56,46 +56,33 @@ namespace QtWebEngineCore { URLRequestCustomJob::URLRequestCustomJob(URLRequest *request, NetworkDelegate *networkDelegate, QWebEngineUrlSchemeHandler *schemeHandler) : URLRequestJob(request, networkDelegate) - , m_device(0) , m_schemeHandler(schemeHandler) - , m_error(0) - , m_started(false) - , m_weakFactoryIO(this) - , m_weakFactoryUI(this) + , m_shared(new URLRequestCustomJobShared(this)) { } URLRequestCustomJob::~URLRequestCustomJob() { - QMutexLocker lock(&m_mutex); - if (m_delegate) { - m_delegate->m_job = 0; - m_delegate->deleteLater(); - } - if (m_device && m_device->isOpen()) - m_device->close(); + if (m_shared) + m_shared->killJob(); +} + +static void startAsync(URLRequestCustomJobShared *shared) +{ + shared->startAsync(); } void URLRequestCustomJob::Start() { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, base::Bind(&URLRequestCustomJob::startAsync, m_weakFactoryIO.GetWeakPtr())); + content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, base::Bind(&startAsync, m_shared)); } void URLRequestCustomJob::Kill() { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - QMutexLocker lock(&m_mutex); - if (m_delegate) { - m_delegate->m_job = 0; - m_delegate->deleteLater(); - } - m_delegate = 0; - if (m_device && m_device->isOpen()) - m_device->close(); - m_device = 0; - m_weakFactoryIO.InvalidateWeakPtrs(); - m_weakFactoryUI.InvalidateWeakPtrs(); + if (m_shared) + m_shared->killJob(); + m_shared = 0; URLRequestJob::Kill(); } @@ -103,8 +90,11 @@ void URLRequestCustomJob::Kill() bool URLRequestCustomJob::GetMimeType(std::string *mimeType) const { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - if (m_mimeType.size() > 0) { - *mimeType = m_mimeType; + if (!m_shared) + return false; + QMutexLocker lock(&m_shared->m_mutex); + if (m_shared->m_mimeType.size() > 0) { + *mimeType = m_shared->m_mimeType; return true; } return false; @@ -113,8 +103,11 @@ bool URLRequestCustomJob::GetMimeType(std::string *mimeType) const bool URLRequestCustomJob::GetCharset(std::string* charset) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - if (m_charset.size() > 0) { - *charset = m_charset; + if (!m_shared) + return false; + QMutexLocker lock(&m_shared->m_mutex); + if (m_shared->m_charset.size() > 0) { + *charset = m_shared->m_charset; return true; } return false; @@ -123,128 +116,223 @@ bool URLRequestCustomJob::GetCharset(std::string* charset) bool URLRequestCustomJob::IsRedirectResponse(GURL* location, int* http_status_code) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - QMutexLocker lock(&m_mutex); - if (m_redirect.is_valid()) { - *location = m_redirect; + if (!m_shared) + return false; + QMutexLocker lock(&m_shared->m_mutex); + if (m_shared->m_redirect.is_valid()) { + *location = m_shared->m_redirect; *http_status_code = 303; return true; } return false; } -void URLRequestCustomJob::setReplyMimeType(const std::string &mimeType) +bool URLRequestCustomJob::ReadRawData(IOBuffer *buf, int bufSize, int *bytesRead) +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + Q_ASSERT(bytesRead); + Q_ASSERT(m_shared); + QMutexLocker lock(&m_shared->m_mutex); + qint64 rv = m_shared->m_device ? m_shared->m_device->read(buf->data(), bufSize) : -1; + if (rv >= 0) { + *bytesRead = static_cast<int>(rv); + return true; + } else { + NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, ERR_FAILED)); + } + return false; +} + +URLRequestCustomJobShared::URLRequestCustomJobShared(URLRequestCustomJob *job) + : m_mutex(QMutex::Recursive) + , m_job(job) + , m_delegate(0) + , m_error(0) + , m_started(false) + , m_asyncInitialized(false) + , m_weakFactory(this) +{ +} + +URLRequestCustomJobShared::~URLRequestCustomJobShared() +{ + Q_ASSERT(!m_job); + Q_ASSERT(!m_delegate); +} + +void URLRequestCustomJobShared::killJob() +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + QMutexLocker lock(&m_mutex); + m_job = 0; + bool doDelete = false; + if (m_delegate) { + m_delegate->deleteLater(); + } else { + // Do not delete yet if startAsync has not yet run. + doDelete = m_asyncInitialized; + } + if (m_device && m_device->isOpen()) + m_device->close(); + m_device = 0; + m_weakFactory.InvalidateWeakPtrs(); + lock.unlock(); + if (doDelete) + delete this; +} + +void URLRequestCustomJobShared::unsetJobDelegate() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + QMutexLocker lock(&m_mutex); + m_delegate = 0; + bool doDelete = false; + if (m_job) + abort(); + else + doDelete = true; + lock.unlock(); + if (doDelete) + delete this; +} + +void URLRequestCustomJobShared::setReplyMimeType(const std::string &mimeType) +{ + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + QMutexLocker lock(&m_mutex); m_mimeType = mimeType; } -void URLRequestCustomJob::setReplyCharset(const std::string &charset) +void URLRequestCustomJobShared::setReplyCharset(const std::string &charset) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + QMutexLocker lock(&m_mutex); m_charset = charset; } -void URLRequestCustomJob::setReplyDevice(QIODevice *device) +void URLRequestCustomJobShared::setReplyDevice(QIODevice *device) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); QMutexLocker lock(&m_mutex); + if (!m_job) + return; m_device = device; if (m_device && !m_device->isReadable()) m_device->open(QIODevice::ReadOnly); if (m_device && m_device->isReadable()) - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, base::Bind(&URLRequestCustomJob::notifyStarted, m_weakFactoryUI.GetWeakPtr())); + content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, base::Bind(&URLRequestCustomJobShared::notifyStarted, m_weakFactory.GetWeakPtr())); else fail(ERR_INVALID_URL); } -bool URLRequestCustomJob::ReadRawData(IOBuffer *buf, int bufSize, int *bytesRead) -{ - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - Q_ASSERT(bytesRead); - QMutexLocker lock(&m_mutex); - qint64 rv = m_device ? m_device->read(buf->data(), bufSize) : -1; - if (rv >= 0) { - *bytesRead = static_cast<int>(rv); - return true; - } else { - NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, ERR_FAILED)); - } - return false; -} - -void URLRequestCustomJob::redirect(const GURL &url) +void URLRequestCustomJobShared::redirect(const GURL &url) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - if (m_device || m_error) - return; QMutexLocker lock(&m_mutex); + if (m_device || m_error) + return; + if (!m_job) + return; m_redirect = url; - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, base::Bind(&URLRequestCustomJob::notifyStarted, m_weakFactoryUI.GetWeakPtr())); + content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, base::Bind(&URLRequestCustomJobShared::notifyStarted, m_weakFactory.GetWeakPtr())); } -void URLRequestCustomJob::abort() +void URLRequestCustomJobShared::abort() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); QMutexLocker lock(&m_mutex); if (m_device && m_device->isOpen()) m_device->close(); m_device = 0; - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, base::Bind(&URLRequestCustomJob::notifyCanceled, m_weakFactoryUI.GetWeakPtr())); + if (!m_job) + return; + content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, base::Bind(&URLRequestCustomJobShared::notifyCanceled, m_weakFactory.GetWeakPtr())); } -void URLRequestCustomJob::notifyCanceled() +void URLRequestCustomJobShared::notifyCanceled() { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + QMutexLocker lock(&m_mutex); + if (!m_job) + return; if (m_started) - NotifyDone(URLRequestStatus(URLRequestStatus::CANCELED, ERR_ABORTED)); + m_job->NotifyDone(URLRequestStatus(URLRequestStatus::CANCELED, ERR_ABORTED)); else - NotifyStartError(URLRequestStatus(URLRequestStatus::CANCELED, ERR_ABORTED)); + m_job->NotifyStartError(URLRequestStatus(URLRequestStatus::CANCELED, ERR_ABORTED)); } -void URLRequestCustomJob::notifyStarted() +void URLRequestCustomJobShared::notifyStarted() { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); + QMutexLocker lock(&m_mutex); + if (!m_job) + return; Q_ASSERT(!m_started); m_started = true; - NotifyHeadersComplete(); + m_job->NotifyHeadersComplete(); } -void URLRequestCustomJob::fail(int error) +void URLRequestCustomJobShared::fail(int error) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); QMutexLocker lock(&m_mutex); m_error = error; - content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, base::Bind(&URLRequestCustomJob::notifyFailure, m_weakFactoryUI.GetWeakPtr())); + if (!m_job) + return; + content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, base::Bind(&URLRequestCustomJobShared::notifyFailure, m_weakFactory.GetWeakPtr())); } -void URLRequestCustomJob::notifyFailure() +void URLRequestCustomJobShared::notifyFailure() { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - m_mutex.lock(); + QMutexLocker lock(&m_mutex); + if (!m_job) + return; if (m_device) m_device->close(); const URLRequestStatus status(URLRequestStatus::FAILED, m_error); const bool started = m_started; - m_mutex.unlock(); if (started) - NotifyDone(status); + m_job->NotifyDone(status); else - NotifyStartError(status); + m_job->NotifyStartError(status); } -void URLRequestCustomJob::startAsync() +GURL URLRequestCustomJobShared::requestUrl() +{ + QMutexLocker lock(&m_mutex); + if (!m_job) + return GURL(); + return m_job->request()->url(); +} + +std::string URLRequestCustomJobShared::requestMethod() +{ + QMutexLocker lock(&m_mutex); + if (!m_job) + return std::string(); + return m_job->request()->method(); +} + +void URLRequestCustomJobShared::startAsync() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); Q_ASSERT(!m_started); Q_ASSERT(!m_delegate); QMutexLocker lock(&m_mutex); + if (!m_job) { + lock.unlock(); + delete this; + return; + } m_delegate = new URLRequestCustomJobDelegate(this); - lock.unlock(); + m_asyncInitialized = true; QWebEngineUrlRequestJob *requestJob = new QWebEngineUrlRequestJob(m_delegate); - m_schemeHandler->requestStarted(requestJob); + if (m_job) + m_job->m_schemeHandler->requestStarted(requestJob); } } // namespace diff --git a/src/core/url_request_custom_job.h b/src/core/url_request_custom_job.h index be5cae43c..eedb41814 100644 --- a/src/core/url_request_custom_job.h +++ b/src/core/url_request_custom_job.h @@ -50,6 +50,7 @@ QT_FORWARD_DECLARE_CLASS(QWebEngineUrlSchemeHandler) namespace QtWebEngineCore { class URLRequestCustomJobDelegate; +class URLRequestCustomJobShared; // A request job that handles reading custom URL schemes class URLRequestCustomJob : public net::URLRequestJob { @@ -62,6 +63,25 @@ public: virtual bool GetCharset(std::string *charset) Q_DECL_OVERRIDE; virtual bool IsRedirectResponse(GURL* location, int* http_status_code) Q_DECL_OVERRIDE; +protected: + virtual ~URLRequestCustomJob(); + +private: + QWebEngineUrlSchemeHandler *m_schemeHandler; + URLRequestCustomJobShared *m_shared; + + friend class URLRequestCustomJobShared; + + DISALLOW_COPY_AND_ASSIGN(URLRequestCustomJob); +}; + +// A shared state between URLRequestCustomJob living on the IO thread +// and URLRequestCustomJobDelegate living on the UI thread. +class URLRequestCustomJobShared { +public: + URLRequestCustomJobShared(URLRequestCustomJob *job); + ~URLRequestCustomJobShared(); + void setReplyMimeType(const std::string &); void setReplyCharset(const std::string &); void setReplyDevice(QIODevice *); @@ -70,29 +90,28 @@ public: void fail(int); void abort(); -protected: - virtual ~URLRequestCustomJob(); + void killJob(); + void unsetJobDelegate(); + void startAsync(); void notifyStarted(); void notifyFailure(); void notifyCanceled(); -private: + GURL requestUrl(); + std::string requestMethod(); + QMutex m_mutex; QPointer<QIODevice> m_device; - QPointer<URLRequestCustomJobDelegate> m_delegate; - QWebEngineUrlSchemeHandler *m_schemeHandler; + URLRequestCustomJob *m_job; + URLRequestCustomJobDelegate *m_delegate; std::string m_mimeType; std::string m_charset; int m_error; GURL m_redirect; bool m_started; - base::WeakPtrFactory<URLRequestCustomJob> m_weakFactoryIO; - base::WeakPtrFactory<URLRequestCustomJob> m_weakFactoryUI; - - friend class URLRequestCustomJobDelegate; - - DISALLOW_COPY_AND_ASSIGN(URLRequestCustomJob); + bool m_asyncInitialized; + base::WeakPtrFactory<URLRequestCustomJobShared> m_weakFactory; }; } // namespace QtWebEngineCore diff --git a/src/core/url_request_custom_job_delegate.cpp b/src/core/url_request_custom_job_delegate.cpp index 0650242c8..1a3e08e52 100644 --- a/src/core/url_request_custom_job_delegate.cpp +++ b/src/core/url_request_custom_job_delegate.cpp @@ -44,39 +44,40 @@ namespace QtWebEngineCore { -URLRequestCustomJobDelegate::URLRequestCustomJobDelegate(URLRequestCustomJob *job) - : m_job(job) +URLRequestCustomJobDelegate::URLRequestCustomJobDelegate(URLRequestCustomJobShared *shared) + : m_shared(shared) { } URLRequestCustomJobDelegate::~URLRequestCustomJobDelegate() { + m_shared->unsetJobDelegate(); } QUrl URLRequestCustomJobDelegate::url() const { - return toQt(m_job->request()->url()); + return toQt(m_shared->requestUrl()); } QByteArray URLRequestCustomJobDelegate::method() const { - return QByteArray::fromStdString(m_job->request()->method()); + return QByteArray::fromStdString(m_shared->requestMethod()); } void URLRequestCustomJobDelegate::setReply(const QByteArray &contentType, QIODevice *device) { - m_job->setReplyMimeType(contentType.toStdString()); - m_job->setReplyDevice(device); + m_shared->setReplyMimeType(contentType.toStdString()); + m_shared->setReplyDevice(device); } void URLRequestCustomJobDelegate::abort() { - m_job->abort(); + m_shared->abort(); } void URLRequestCustomJobDelegate::redirect(const QUrl &url) { - m_job->redirect(toGurl(url)); + m_shared->redirect(toGurl(url)); } void URLRequestCustomJobDelegate::fail(Error error) @@ -102,7 +103,7 @@ void URLRequestCustomJobDelegate::fail(Error error) break; } if (net_error) - m_job->fail(net_error); + m_shared->fail(net_error); } } // namespace diff --git a/src/core/url_request_custom_job_delegate.h b/src/core/url_request_custom_job_delegate.h index 5b6137820..e066e85cc 100644 --- a/src/core/url_request_custom_job_delegate.h +++ b/src/core/url_request_custom_job_delegate.h @@ -46,7 +46,7 @@ QT_FORWARD_DECLARE_CLASS(QIODevice) namespace QtWebEngineCore { -class URLRequestCustomJob; +class URLRequestCustomJobShared; class QWEBENGINE_EXPORT URLRequestCustomJobDelegate : public QObject { Q_OBJECT @@ -72,10 +72,10 @@ public: void fail(Error); private: - URLRequestCustomJobDelegate(URLRequestCustomJob *job); + URLRequestCustomJobDelegate(URLRequestCustomJobShared *shared); - friend class URLRequestCustomJob; - URLRequestCustomJob *m_job; + friend class URLRequestCustomJobShared; + URLRequestCustomJobShared *m_shared; }; } // namespace diff --git a/src/webengine/doc/src/webengineview.qdoc b/src/webengine/doc/src/webengineview.qdoc index a8cd1eb56..1d71a9cd9 100644 --- a/src/webengine/doc/src/webengineview.qdoc +++ b/src/webengine/doc/src/webengineview.qdoc @@ -29,6 +29,22 @@ \inqmlmodule QtWebEngine \since QtWebEngine 1.0 \brief A WebEngineView renders web content within a QML application. + + The WebEngineView type enables QML applications to render regions of dynamic web content. It + may share the screen with other QML types, such as a TabView, or fill the screen, as specified + within the QML application. + + \section1 Rendering to OpenGL Surface + + When using a QQuickRenderControl to render a Qt Quick user interface to an OpenGL surface, the + WebEngineView type is not rendered correctly. The web engine view attempts to use a global + OpenGL context created by \l QtWebEngine::initialize(), but there is no public API for accessing + that context in order to share it with the \c QQuickRenderControl context. + + To have the web engine view rendered correctly, it is possible to manually create a new + offscreen context that is shared with the \c QQuickRenderControl and to call the non-public + function \c qt_gl_set_global_share_context(), rather than calling \c initialize(). + If \c initialize() is called after setting a global context, it will do nothing. */ /*! diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp index aacf6c455..b1bf33067 100644 --- a/src/webenginewidgets/api/qwebenginepage.cpp +++ b/src/webenginewidgets/api/qwebenginepage.cpp @@ -107,6 +107,7 @@ QWebEnginePagePrivate::QWebEnginePagePrivate(QWebEngineProfile *_profile) , m_isBeingAdopted(false) , m_backgroundColor(Qt::white) , fullscreenMode(false) + , webChannel(nullptr) { memset(actions, 0, sizeof(actions)); } @@ -227,6 +228,8 @@ void QWebEnginePagePrivate::adoptNewWindow(WebContentsAdapter *newWebContents, W Q_UNUSED(userGesture); QWebEnginePage *newPage = q->createWindow(toWindowType(disposition)); + if (!newPage) + return; // Mark the new page as being in the process of being adopted, so that a second mouse move event // sent by newWebContents->initialize() gets filtered in RenderWidgetHostViewQt::forwardEvent. @@ -240,7 +243,7 @@ void QWebEnginePagePrivate::adoptNewWindow(WebContentsAdapter *newWebContents, W newPage->d_func()->m_isBeingAdopted = true; // Overwrite the new page's WebContents with ours. - if (newPage && newPage->d_func() != this) { + if (newPage->d_func() != this) { newPage->d_func()->adapter = newWebContents; newWebContents->initialize(newPage->d_func()); if (!initialGeometry.isEmpty()) @@ -405,8 +408,14 @@ void QWebEnginePagePrivate::recreateFromSerializedHistory(QDataStream &input) { QExplicitlySharedDataPointer<WebContentsAdapter> newWebContents = WebContentsAdapter::createFromSerializedNavigationHistory(input, this); if (newWebContents) { + // Keep the old adapter referenced so the user-scripts are not + // unregistered immediately. + QExplicitlySharedDataPointer<WebContentsAdapter> oldWebContents = adapter; adapter = newWebContents.data(); adapter->initialize(this); + if (webChannel) + adapter->setWebChannel(webChannel); + scriptCollection.d->rebindToContents(adapter.data()); } } @@ -517,7 +526,7 @@ QWebEngineSettings *QWebEnginePage::settings() const QWebChannel *QWebEnginePage::webChannel() const { Q_D(const QWebEnginePage); - return d->adapter->webChannel(); + return d->webChannel; } /*! @@ -534,7 +543,10 @@ QWebChannel *QWebEnginePage::webChannel() const void QWebEnginePage::setWebChannel(QWebChannel *channel) { Q_D(QWebEnginePage); - d->adapter->setWebChannel(channel); + if (d->webChannel != channel) { + d->webChannel = channel; + d->adapter->setWebChannel(channel); + } } /*! diff --git a/src/webenginewidgets/api/qwebenginepage_p.h b/src/webenginewidgets/api/qwebenginepage_p.h index 9cc4553d1..18110d923 100644 --- a/src/webenginewidgets/api/qwebenginepage_p.h +++ b/src/webenginewidgets/api/qwebenginepage_p.h @@ -151,6 +151,7 @@ public: bool m_isBeingAdopted; QColor m_backgroundColor; bool fullscreenMode; + QWebChannel *webChannel; mutable QtWebEngineCore::CallbackDirectory m_callbacks; mutable QAction *actions[QWebEnginePage::WebActionCount]; diff --git a/src/webenginewidgets/api/qwebenginescriptcollection.cpp b/src/webenginewidgets/api/qwebenginescriptcollection.cpp index 9967cde85..117c35b5a 100644 --- a/src/webenginewidgets/api/qwebenginescriptcollection.cpp +++ b/src/webenginewidgets/api/qwebenginescriptcollection.cpp @@ -220,3 +220,15 @@ void QWebEngineScriptCollectionPrivate::reserve(int capacity) { m_scriptController->reserve(m_contents, capacity); } + +void QWebEngineScriptCollectionPrivate::rebindToContents(QtWebEngineCore::WebContentsAdapter *page) +{ + Q_ASSERT(m_contents); + Q_ASSERT(page); + Q_ASSERT(m_contents != page); + + Q_FOREACH (const UserScript &script, m_scriptController->registeredScripts(m_contents)) { + m_scriptController->addUserScript(script, page); + } + m_contents = page; +} diff --git a/src/webenginewidgets/api/qwebenginescriptcollection_p.h b/src/webenginewidgets/api/qwebenginescriptcollection_p.h index cc6e88445..b5ae60a2c 100644 --- a/src/webenginewidgets/api/qwebenginescriptcollection_p.h +++ b/src/webenginewidgets/api/qwebenginescriptcollection_p.h @@ -69,6 +69,8 @@ public: QList<QWebEngineScript> toList(const QString &scriptName = QString()) const; QWebEngineScript find(const QString & name) const; + void rebindToContents(QtWebEngineCore::WebContentsAdapter *contents); + void insert(const QWebEngineScript &); bool remove(const QWebEngineScript &); void clear(); diff --git a/tests/auto/quick/qquickwebengineviewgraphics/tst_qquickwebengineviewgraphics.cpp b/tests/auto/quick/qquickwebengineviewgraphics/tst_qquickwebengineviewgraphics.cpp index eacd1f87e..6fd967d5a 100644 --- a/tests/auto/quick/qquickwebengineviewgraphics/tst_qquickwebengineviewgraphics.cpp +++ b/tests/auto/quick/qquickwebengineviewgraphics/tst_qquickwebengineviewgraphics.cpp @@ -191,13 +191,14 @@ void tst_QQuickWebEngineViewGraphics::reparentToOtherWindow() void tst_QQuickWebEngineViewGraphics::setHtml(const QString &html) { QString htmlData = QUrl::toPercentEncoding(html); - QString qmlData = QUrl::toPercentEncoding(QStringLiteral("import QtQuick 2.0; import QtWebEngine 1.2; WebEngineView { width: 150; height: 150; url: loadUrl }")); - m_view->rootContext()->setContextProperty("loadUrl", QUrl(QStringLiteral("data:text/html,%1").arg(htmlData))); + QString qmlData = QUrl::toPercentEncoding(QStringLiteral("import QtQuick 2.0; import QtWebEngine 1.2; WebEngineView { width: 150; height: 150 }")); m_view->setSource(QUrl(QStringLiteral("data:text/plain,%1").arg(qmlData))); m_view->create(); QQuickWebEngineView *webEngineView = static_cast<QQuickWebEngineView *>(m_view->rootObject()); - QVERIFY(waitForSignal(reinterpret_cast<QObject *>(webEngineView->experimental()), SIGNAL(loadVisuallyCommitted()))); + QSignalSpy spy(reinterpret_cast<QObject *>(webEngineView->experimental()), SIGNAL(loadVisuallyCommitted())); + webEngineView->setProperty("url", QUrl(QStringLiteral("data:text/html,%1").arg(htmlData))); + QVERIFY(!spy.isEmpty() || spy.wait()); QCOMPARE(m_view->rootObject()->property("loading"), QVariant(false)); } diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp index 8fd71c701..690cf70e4 100644 --- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp +++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp @@ -33,6 +33,7 @@ #include <QStyle> #include <QtTest/QtTest> #include <QTextCharFormat> +#include <QWebChannel> #include <private/qinputmethod_p.h> #include <qnetworkcookiejar.h> #include <qnetworkreply.h> @@ -42,6 +43,8 @@ #include <qwebenginehistory.h> #include <qwebenginepage.h> #include <qwebengineprofile.h> +#include <qwebenginescript.h> +#include <qwebenginescriptcollection.h> #include <qwebenginesettings.h> #include <qwebengineview.h> #include <qimagewriter.h> @@ -237,6 +240,8 @@ private Q_SLOTS: void loadInSignalHandlers_data(); void loadInSignalHandlers(); + void restoreHistory(); + private: QWebEngineView* m_view; QWebEnginePage* m_page; @@ -5079,5 +5084,36 @@ void tst_QWebEnginePage::loadInSignalHandlers() QCOMPARE(m_page->url(), urlForSetter); } +void tst_QWebEnginePage::restoreHistory() +{ + QWebChannel *channel = new QWebChannel; + QWebEnginePage *page = new QWebEnginePage; + page->setWebChannel(channel); + + QWebEngineScript script; + script.setName(QStringLiteral("script")); + page->scripts().insert(script); + + QSignalSpy spy(page, SIGNAL(loadFinished(bool))); + page->load(QUrl(QStringLiteral("qrc:/resources/test1.html"))); + QTRY_COMPARE(spy.count(), 1); + + QCOMPARE(page->webChannel(), channel); + QVERIFY(page->scripts().contains(script)); + + QByteArray data; + QDataStream out(&data, QIODevice::ReadWrite); + out << *page->history(); + QDataStream in(&data, QIODevice::ReadOnly); + in >> *page->history(); + QTRY_COMPARE(spy.count(), 2); + + QCOMPARE(page->webChannel(), channel); + QVERIFY(page->scripts().contains(script)); + + delete page; + delete channel; +} + QTEST_MAIN(tst_QWebEnginePage) #include "tst_qwebenginepage.moc" diff --git a/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp b/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp index 0ad460634..99182f155 100644 --- a/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp +++ b/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp @@ -146,6 +146,13 @@ void tst_QWebEngineProfile::urlSchemeHandlers() view.load(url); QVERIFY(loadFinishedSpy.wait()); QVERIFY(toPlainTextSync(view.page()) != url.toString()); + + // Install a handler that is owned by the view. Make sure this doesn't crash on shutdown. + profile.installUrlSchemeHandler("aviancarrier", new ReplyingUrlSchemeHandler(&view)); + url = QUrl(QStringLiteral("aviancarrier:inspector.mortensen@politistyrke.dk")); + view.load(url); + QVERIFY(loadFinishedSpy.wait()); + QCOMPARE(toPlainTextSync(view.page()), url.toString()); } class FailingUrlSchemeHandler : public QWebEngineUrlSchemeHandler diff --git a/tools/buildscripts/gyp_qtwebengine b/tools/buildscripts/gyp_qtwebengine index c8e849973..ee09de973 100755 --- a/tools/buildscripts/gyp_qtwebengine +++ b/tools/buildscripts/gyp_qtwebengine @@ -153,11 +153,6 @@ if __name__ == '__main__': args.extend(['-D', 'qtwebengine_root=' + purifyGypVarPath(qtwebengine_root)]) args.extend(['-D', 'chromium_src_dir=' + purifyGypVarPath(chrome_src)]) - args.extend(['-D', 'clang_use_chrome_plugins=0']) - # We do not want to ship more external binary blobs, so let v8 embed its startup data. - args.extend(['-D', 'v8_use_external_startup_data=0']) - # Trigger Qt-specific build conditions. - args.extend(['-D', 'use_qt=1']) # Tweak the output location and format (hardcode ninja for now if not set) args.extend(['--generator-output', '.']) args.extend(['-Goutput_dir='+ os.path.relpath(output_dir, qtwebengine_root)]) diff --git a/tools/qmake/mkspecs/features/configure.prf b/tools/qmake/mkspecs/features/configure.prf index 4be9fac20..4cb4600b6 100644 --- a/tools/qmake/mkspecs/features/configure.prf +++ b/tools/qmake/mkspecs/features/configure.prf @@ -41,7 +41,7 @@ defineTest(runConfigure) { else: log("System libwebp or libwebpdemux not found. Using Chromium's copies.$${EOL}") packagesExist(libxml-2.0,libxslt): WEBENGINE_CONFIG += use_system_libxslt else: log("System libxml2 or libxslt not found. Using Chromium's copies.$${EOL}") - for(package, $$list("libevent flac jsoncpp opus speex")) { + for(package, $$list("libevent jsoncpp opus")) { packagesExist($$package): WEBENGINE_CONFIG += use_system_$$package else: log("System $$package not found. Using Chromium's copy.$${EOL}") } diff --git a/tools/qmake/mkspecs/features/functions.prf b/tools/qmake/mkspecs/features/functions.prf index 2447d8372..2df689bca 100644 --- a/tools/qmake/mkspecs/features/functions.prf +++ b/tools/qmake/mkspecs/features/functions.prf @@ -1,30 +1,48 @@ 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) - } - static { - skipBuild("Static builds of QtWebEngine aren't supported.") - return(false) - } - osx { + linux { + !gcc:!clang { + skipBuild("Qt WebEngine on Linux requires clang or GCC.") + return(false) + } + gcc:!clang:!isGCCVersionSupported(): return(false) + } else:win32 { + winrt { + skipBuild("WinRT is not supported.") + return(false) + } + msvc { + !equals(MSVC_VER, "12.0"):!equals(MSVC_VER, "14.0") { + skipBuild("Qt WebEngine on Windows requires MSVC 2013 or MSVC 2015.") + return(false) + } + } else { + skipBuild("Qt WebEngine on Windows requires MSVC 2013 or MSVC 2015.") + return(false) + } + } else:osx { lessThan(QMAKE_XCODE_VERSION, 5.1) { - skipBuild("Using xcode version $$QMAKE_XCODE_VERSION, but at least version 5.1 is required to build Qt WebEngine.") + skipBuild("Using XCode version $$QMAKE_XCODE_VERSION, but at least version 5.1 is required to build Qt WebEngine.") return(false) } # We require OS X 10.9 (darwin version 13.0.0) or newer darwin_major_version = $$section(QMAKE_HOST.version, ., 0, 0) lessThan(darwin_major_version, 13) { - skipBuild("OS X version 10.9 or newer is required to build Qt WebEngine.") + skipBuild("Qt WebEngine requires OS X version 10.9 or newer.") return(false) } + } else { + skipBuild("Unknown platform. Qt WebEngine only supports Linux, Windows, and OS X.") + return(false) } - linux-g++*:!isGCCVersionSupported(): return(false) + !contains(QT_CONFIG, c++11) { + skipBuild("C++11 support is required in order to build chromium.") + return(false) + } + static { + skipBuild("Static builds of QtWebEngine aren't supported.") + return(false) + } !isPythonVersionSupported(): return(false) return(true) } |