diff options
95 files changed, 4516 insertions, 1220 deletions
diff --git a/.qmake.conf b/.qmake.conf index c60de80a6..0a6b62d97 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -2,4 +2,4 @@ QMAKEPATH += $$PWD/tools/qmake load(qt_build_config) CONFIG += qt_example_installs -MODULE_VERSION = 5.4.1 +MODULE_VERSION = 5.5.0 diff --git a/examples/webengine/quicknanobrowser/quickwindow.qml b/examples/webengine/quicknanobrowser/quickwindow.qml index 610144dca..b954629fb 100644 --- a/examples/webengine/quicknanobrowser/quickwindow.qml +++ b/examples/webengine/quicknanobrowser/quickwindow.qml @@ -93,6 +93,18 @@ ApplicationWindow { tabs.removeTab(tabs.currentIndex) } } + Action { + shortcut: "Ctrl+0" + onTriggered: currentWebView.zoomFactor = 1.0; + } + Action { + shortcut: "Ctrl+-" + onTriggered: currentWebView.zoomFactor -= 0.1; + } + Action { + shortcut: "Ctrl+=" + onTriggered: currentWebView.zoomFactor += 0.1; + } toolBar: ToolBar { id: navigationBar diff --git a/examples/webengine/quicknanobrowser/util.h b/examples/webengine/quicknanobrowser/util.h index bc1cf8beb..ca0f5f1d5 100644 --- a/examples/webengine/quicknanobrowser/util.h +++ b/examples/webengine/quicknanobrowser/util.h @@ -50,7 +50,7 @@ QUrl urlFromUserInput(const QString& userInput) { QFileInfo fileInfo(userInput); if (fileInfo.exists()) - return QUrl(fileInfo.absoluteFilePath()); + return QUrl::fromLocalFile(fileInfo.absoluteFilePath()); return QUrl::fromUserInput(userInput); } diff --git a/examples/webenginewidgets/browser/browserapplication.cpp b/examples/webenginewidgets/browser/browserapplication.cpp index 44713901d..ddcebfb8e 100644 --- a/examples/webenginewidgets/browser/browserapplication.cpp +++ b/examples/webenginewidgets/browser/browserapplication.cpp @@ -66,6 +66,7 @@ #include <QtNetwork/QNetworkProxy> #include <QtNetwork/QSslSocket> +#include <QWebEngineProfile> #include <QWebEngineSettings> #include <QtCore/QDebug> @@ -230,6 +231,8 @@ void BrowserApplication::loadSettings() settings.beginGroup(QLatin1String("websettings")); QWebEngineSettings *defaultSettings = QWebEngineSettings::globalSettings(); + QWebEngineProfile *defaultProfile = QWebEngineProfile::defaultProfile(); + QString standardFontFamily = defaultSettings->fontFamily(QWebEngineSettings::StandardFont); int standardFontSize = defaultSettings->fontSize(QWebEngineSettings::DefaultFontSize); QFont standardFont = QFont(standardFontFamily, standardFontSize); @@ -255,6 +258,14 @@ void BrowserApplication::loadSettings() QUrl url = settings.value(QLatin1String("userStyleSheet")).toUrl(); defaultSettings->setUserStyleSheetUrl(url); #endif + defaultProfile->setHttpUserAgent(settings.value(QLatin1String("httpUserAgent")).toString()); + settings.endGroup(); + settings.beginGroup(QLatin1String("cookies")); + + QWebEngineProfile::PersistentCookiesPolicy persistentCookiesPolicy = QWebEngineProfile::PersistentCookiesPolicy(settings.value(QLatin1String("persistentCookiesPolicy")).toInt()); + defaultProfile->setPersistentCookiesPolicy(persistentCookiesPolicy); + QString pdataPath = settings.value(QLatin1String("persistentDataPath")).toString(); + defaultProfile->setPersistentStoragePath(pdataPath); settings.endGroup(); } diff --git a/examples/webenginewidgets/browser/featurepermissionbar.cpp b/examples/webenginewidgets/browser/featurepermissionbar.cpp index 98f19ad1f..1b6d446cd 100644 --- a/examples/webenginewidgets/browser/featurepermissionbar.cpp +++ b/examples/webenginewidgets/browser/featurepermissionbar.cpp @@ -53,15 +53,17 @@ static QString textForPermissionType(QWebEnginePage::Feature type) { switch (type) { case QWebEnginePage::Notifications: - return QObject::tr("desktop notifications"); + return QObject::tr("use desktop notifications"); case QWebEnginePage::Geolocation: - return QObject::tr("your position"); + return QObject::tr("use your position"); case QWebEnginePage::MediaAudioCapture: - return QObject::tr("your microphone"); + return QObject::tr("use your microphone"); case QWebEnginePage::MediaVideoCapture: - return QObject::tr("your camera"); + return QObject::tr("use your camera"); case QWebEnginePage::MediaAudioVideoCapture: - return QObject::tr("your camera and microphone"); + return QObject::tr("use your camera and microphone"); + case QWebEnginePage::MouseLock: + return QObject::tr("lock your mouse"); default: Q_UNREACHABLE(); } @@ -80,12 +82,13 @@ FeaturePermissionBar::FeaturePermissionBar(QWidget *view) l->addStretch(); QPushButton *allowButton = new QPushButton(tr("Allow"), this); QPushButton *denyButton = new QPushButton(tr("Deny"), this); + QPushButton *discardButton = new QPushButton(QIcon(QStringLiteral(":closetab.png")), QString(), this); connect(allowButton, &QPushButton::clicked, this, &FeaturePermissionBar::permissionGranted); connect(denyButton, &QPushButton::clicked, this, &FeaturePermissionBar::permissionDenied); - QPushButton *discardButton = new QPushButton(QIcon(QStringLiteral(":closetab.png")), QString(), this); - connect(discardButton, &QPushButton::clicked, this, &QObject::deleteLater); + connect(discardButton, &QPushButton::clicked, this, &FeaturePermissionBar::permissionUnknown); connect(allowButton, &QPushButton::clicked, this, &QObject::deleteLater); connect(denyButton, &QPushButton::clicked, this, &QObject::deleteLater); + connect(discardButton, &QPushButton::clicked, this, &QObject::deleteLater); l->addWidget(denyButton); l->addWidget(allowButton); l->addWidget(discardButton); @@ -96,7 +99,7 @@ void FeaturePermissionBar::requestPermission(const QUrl &securityOrigin, QWebEng { m_securityOrigin = securityOrigin; m_feature = feature; - m_messageLabel->setText(tr("%1 wants to use %2.").arg(securityOrigin.host()).arg(textForPermissionType(feature))); + m_messageLabel->setText(tr("%1 wants to %2.").arg(securityOrigin.host()).arg(textForPermissionType(feature))); show(); // Ease in QPropertyAnimation *animation = new QPropertyAnimation(this); @@ -118,3 +121,8 @@ void FeaturePermissionBar::permissionGranted() { emit featurePermissionProvided(m_securityOrigin, m_feature, QWebEnginePage::PermissionGrantedByUser); } + +void FeaturePermissionBar::permissionUnknown() +{ + emit featurePermissionProvided(m_securityOrigin, m_feature, QWebEnginePage::PermissionUnknown); +} diff --git a/examples/webenginewidgets/browser/featurepermissionbar.h b/examples/webenginewidgets/browser/featurepermissionbar.h index 92ca04773..cee5a25b0 100644 --- a/examples/webenginewidgets/browser/featurepermissionbar.h +++ b/examples/webenginewidgets/browser/featurepermissionbar.h @@ -63,6 +63,7 @@ signals: private slots: void permissionDenied(); void permissionGranted(); + void permissionUnknown(); private: QWebEnginePage::Feature m_feature; diff --git a/examples/webenginewidgets/browser/settings.cpp b/examples/webenginewidgets/browser/settings.cpp index 835e7a9b5..753ef033d 100644 --- a/examples/webenginewidgets/browser/settings.cpp +++ b/examples/webenginewidgets/browser/settings.cpp @@ -58,9 +58,7 @@ SettingsDialog::SettingsDialog(QWidget *parent) : QDialog(parent) { setupUi(this); - connect(exceptionsButton, SIGNAL(clicked()), this, SLOT(showExceptions())); connect(setHomeToCurrentPageButton, SIGNAL(clicked()), this, SLOT(setHomeToCurrentPage())); - connect(cookiesButton, SIGNAL(clicked()), this, SLOT(showCookies())); connect(standardFontButton, SIGNAL(clicked()), this, SLOT(chooseFont())); connect(fixedFontButton, SIGNAL(clicked()), this, SLOT(chooseFixedFont())); @@ -89,6 +87,10 @@ void SettingsDialog::loadDefaults() #endif enableScrollAnimator->setChecked(defaultSettings->testAttribute(QWebEngineSettings::ScrollAnimatorEnabled)); + + persistentDataPath->setText(QWebEngineProfile::defaultProfile()->persistentStoragePath()); + sessionCookiesCombo->setCurrentIndex(QWebEngineProfile::defaultProfile()->persistentCookiesPolicy()); + httpUserAgent->setText(QWebEngineProfile::defaultProfile()->httpUserAgent()); } void SettingsDialog::loadFromSettings() @@ -137,47 +139,19 @@ void SettingsDialog::loadFromSettings() enablePlugins->setChecked(settings.value(QLatin1String("enablePlugins"), enablePlugins->isChecked()).toBool()); userStyleSheet->setText(settings.value(QLatin1String("userStyleSheet")).toUrl().toString()); enableScrollAnimator->setChecked(settings.value(QLatin1String("enableScrollAnimator"), enableScrollAnimator->isChecked()).toBool()); + httpUserAgent->setText(settings.value(QLatin1String("httpUserAgent"), httpUserAgent->text()).toString()); settings.endGroup(); -#if defined(QWEBENGINEPAGE_SETNETWORKACCESSMANAGER) // Privacy settings.beginGroup(QLatin1String("cookies")); - QByteArray value = settings.value(QLatin1String("acceptCookies"), QLatin1String("AcceptOnlyFromSitesNavigatedTo")).toByteArray(); - QMetaEnum acceptPolicyEnum = CookieJar::staticMetaObject.enumerator(CookieJar::staticMetaObject.indexOfEnumerator("AcceptPolicy")); - CookieJar::AcceptPolicy acceptCookies = acceptPolicyEnum.keyToValue(value) == -1 ? - CookieJar::AcceptOnlyFromSitesNavigatedTo : - static_cast<CookieJar::AcceptPolicy>(acceptPolicyEnum.keyToValue(value)); - switch (acceptCookies) { - case CookieJar::AcceptAlways: - acceptCombo->setCurrentIndex(0); - break; - case CookieJar::AcceptNever: - acceptCombo->setCurrentIndex(1); - break; - case CookieJar::AcceptOnlyFromSitesNavigatedTo: - acceptCombo->setCurrentIndex(2); - break; - } + int persistentCookiesPolicy = settings.value(QLatin1String("persistentCookiesPolicy"), sessionCookiesCombo->currentIndex()).toInt(); + sessionCookiesCombo->setCurrentIndex(persistentCookiesPolicy); + + QString pdataPath = settings.value(QLatin1String("persistentDataPath"), persistentDataPath->text()).toString(); + persistentDataPath->setText(pdataPath); - value = settings.value(QLatin1String("keepCookiesUntil"), QLatin1String("Expire")).toByteArray(); - QMetaEnum keepPolicyEnum = CookieJar::staticMetaObject.enumerator(CookieJar::staticMetaObject.indexOfEnumerator("KeepPolicy")); - CookieJar::KeepPolicy keepCookies = keepPolicyEnum.keyToValue(value) == -1 ? - CookieJar::KeepUntilExpire : - static_cast<CookieJar::KeepPolicy>(keepPolicyEnum.keyToValue(value)); - switch (keepCookies) { - case CookieJar::KeepUntilExpire: - keepUntilCombo->setCurrentIndex(0); - break; - case CookieJar::KeepUntilExit: - keepUntilCombo->setCurrentIndex(1); - break; - case CookieJar::KeepUntilTimeLimit: - keepUntilCombo->setCurrentIndex(2); - break; - } settings.endGroup(); -#endif // Proxy settings.beginGroup(QLatin1String("proxy")); @@ -227,47 +201,19 @@ void SettingsDialog::saveToSettings() settings.setValue(QLatin1String("userStyleSheet"), QUrl::fromLocalFile(userStyleSheetString)); else settings.setValue(QLatin1String("userStyleSheet"), QUrl(userStyleSheetString)); + settings.setValue(QLatin1String("httpUserAgent"), httpUserAgent->text()); settings.endGroup(); -#if defined(QWEBENGINEPAGE_SETNETWORKACCESSMANAGER) //Privacy settings.beginGroup(QLatin1String("cookies")); - CookieJar::KeepPolicy keepCookies; - switch (acceptCombo->currentIndex()) { - default: - case 0: - keepCookies = CookieJar::KeepUntilExpire; - break; - case 1: - keepCookies = CookieJar::KeepUntilExit; - break; - case 2: - keepCookies = CookieJar::KeepUntilTimeLimit; - break; - } - QMetaEnum acceptPolicyEnum = CookieJar::staticMetaObject.enumerator(CookieJar::staticMetaObject.indexOfEnumerator("AcceptPolicy")); - settings.setValue(QLatin1String("acceptCookies"), QLatin1String(acceptPolicyEnum.valueToKey(keepCookies))); - - CookieJar::KeepPolicy keepPolicy; - switch (keepUntilCombo->currentIndex()) { - default: - case 0: - keepPolicy = CookieJar::KeepUntilExpire; - break; - case 1: - keepPolicy = CookieJar::KeepUntilExit; - break; - case 2: - keepPolicy = CookieJar::KeepUntilTimeLimit; - break; - } + int persistentCookiesPolicy = sessionCookiesCombo->currentIndex(); + settings.setValue(QLatin1String("persistentCookiesPolicy"), persistentCookiesPolicy); - QMetaEnum keepPolicyEnum = CookieJar::staticMetaObject.enumerator(CookieJar::staticMetaObject.indexOfEnumerator("KeepPolicy")); - settings.setValue(QLatin1String("keepCookiesUntil"), QLatin1String(keepPolicyEnum.valueToKey(keepPolicy))); + QString pdataPath = persistentDataPath->text(); + settings.setValue(QLatin1String("persistentDataPath"), pdataPath); settings.endGroup(); -#endif // proxy settings.beginGroup(QLatin1String("proxy")); diff --git a/examples/webenginewidgets/browser/settings.ui b/examples/webenginewidgets/browser/settings.ui index 08374ca7a..7cafdae4b 100644 --- a/examples/webenginewidgets/browser/settings.ui +++ b/examples/webenginewidgets/browser/settings.ui @@ -1,7 +1,8 @@ -<ui version="4.0" > +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> <class>Settings</class> - <widget class="QDialog" name="Settings" > - <property name="geometry" > + <widget class="QDialog" name="Settings"> + <property name="geometry"> <rect> <x>0</x> <y>0</y> @@ -9,64 +10,56 @@ <height>322</height> </rect> </property> - <property name="windowTitle" > + <property name="windowTitle"> <string>Settings</string> </property> - <layout class="QGridLayout" name="gridLayout" > - <item row="2" column="0" > - <widget class="QDialogButtonBox" name="buttonBox" > - <property name="orientation" > + <layout class="QGridLayout" name="gridLayout"> + <item row="2" column="0"> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> <enum>Qt::Horizontal</enum> </property> - <property name="standardButtons" > + <property name="standardButtons"> <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> </property> </widget> </item> - <item row="1" column="0" > - <widget class="QTabWidget" name="tabWidget" > - <property name="currentIndex" > - <number>0</number> + <item row="1" column="0"> + <widget class="QTabWidget" name="tabWidget"> + <property name="currentIndex"> + <number>4</number> </property> - <widget class="QWidget" name="tab" > - <property name="geometry" > - <rect> - <x>0</x> - <y>0</y> - <width>627</width> - <height>243</height> - </rect> - </property> - <attribute name="title" > + <widget class="QWidget" name="tab"> + <attribute name="title"> <string>General</string> </attribute> - <layout class="QGridLayout" name="gridLayout_4" > - <item row="0" column="0" > - <widget class="QLabel" name="label_3" > - <property name="text" > + <layout class="QGridLayout" name="gridLayout_4"> + <item row="0" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> <string>Home:</string> </property> - <property name="alignment" > + <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> </widget> </item> - <item row="0" column="1" colspan="2" > - <widget class="QLineEdit" name="homeLineEdit" /> + <item row="0" column="1" colspan="2"> + <widget class="QLineEdit" name="homeLineEdit"/> </item> - <item row="1" column="1" > - <widget class="QPushButton" name="setHomeToCurrentPageButton" > - <property name="text" > + <item row="1" column="1"> + <widget class="QPushButton" name="setHomeToCurrentPageButton"> + <property name="text"> <string>Set to current page</string> </property> </widget> </item> - <item row="1" column="2" > - <spacer name="horizontalSpacer" > - <property name="orientation" > + <item row="1" column="2"> + <spacer name="horizontalSpacer"> + <property name="orientation"> <enum>Qt::Horizontal</enum> </property> - <property name="sizeHint" stdset="0" > + <property name="sizeHint" stdset="0"> <size> <width>280</width> <height>18</height> @@ -74,103 +67,103 @@ </property> </spacer> </item> - <item row="2" column="0" > - <widget class="QLabel" name="label_4" > - <property name="text" > + <item row="2" column="0"> + <widget class="QLabel" name="label_4"> + <property name="text"> <string>Remove history items:</string> </property> - <property name="alignment" > + <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> </widget> </item> - <item row="2" column="1" colspan="2" > - <widget class="QComboBox" name="expireHistory" > + <item row="2" column="1" colspan="2"> + <widget class="QComboBox" name="expireHistory"> <item> - <property name="text" > + <property name="text"> <string>After one day</string> </property> </item> <item> - <property name="text" > + <property name="text"> <string>After one week</string> </property> </item> <item> - <property name="text" > + <property name="text"> <string>After two weeks</string> </property> </item> <item> - <property name="text" > + <property name="text"> <string>After one month</string> </property> </item> <item> - <property name="text" > + <property name="text"> <string>After one year</string> </property> </item> <item> - <property name="text" > + <property name="text"> <string>Manually</string> </property> </item> </widget> </item> - <item row="3" column="0" > - <widget class="QLabel" name="label_7" > - <property name="text" > + <item row="3" column="0"> + <widget class="QLabel" name="label_7"> + <property name="text"> <string>Save downloads to:</string> </property> - <property name="alignment" > + <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> </widget> </item> - <item row="3" column="1" colspan="2" > - <widget class="QLineEdit" name="downloadsLocation" /> + <item row="3" column="1" colspan="2"> + <widget class="QLineEdit" name="downloadsLocation"/> </item> - <item row="4" column="0" > - <widget class="QLabel" name="label_8" > - <property name="text" > + <item row="4" column="0"> + <widget class="QLabel" name="label_8"> + <property name="text"> <string>Open links from applications:</string> </property> - <property name="alignment" > + <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> </widget> </item> - <item row="4" column="1" colspan="2" > - <widget class="QComboBox" name="openLinksIn" > + <item row="4" column="1" colspan="2"> + <widget class="QComboBox" name="openLinksIn"> <item> - <property name="text" > + <property name="text"> <string>In a tab in the current window</string> </property> </item> <item> - <property name="text" > + <property name="text"> <string>In a new window</string> </property> </item> </widget> </item> <item row="5" column="1" colspan="2"> - <widget class="QCheckBox" name="enableScrollAnimator" > - <property name="text" > - <string>Enable Scroll Animator</string> + <widget class="QCheckBox" name="enableScrollAnimator"> + <property name="text"> + <string>Enable Scroll Animator</string> </property> - <property name="checked" > - <bool>true</bool> + <property name="checked"> + <bool>true</bool> </property> </widget> </item> - <item row="6" column="1" colspan="2" > + <item row="6" column="1" colspan="2"> <spacer> - <property name="orientation" > + <property name="orientation"> <enum>Qt::Vertical</enum> </property> - <property name="sizeHint" stdset="0" > + <property name="sizeHint" stdset="0"> <size> <width>391</width> <height>262</height> @@ -180,91 +173,83 @@ </item> </layout> </widget> - <widget class="QWidget" name="tab_3" > - <property name="geometry" > - <rect> - <x>0</x> - <y>0</y> - <width>627</width> - <height>243</height> - </rect> - </property> - <attribute name="title" > + <widget class="QWidget" name="tab_3"> + <attribute name="title"> <string>Appearance</string> </attribute> - <layout class="QGridLayout" name="gridLayout_3" > - <item row="0" column="0" > - <widget class="QLabel" name="label_5" > - <property name="text" > + <layout class="QGridLayout" name="gridLayout_3"> + <item row="0" column="0"> + <widget class="QLabel" name="label_5"> + <property name="text"> <string>Standard font:</string> </property> - <property name="alignment" > + <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> </widget> </item> - <item row="0" column="1" > - <widget class="QLabel" name="standardLabel" > - <property name="sizePolicy" > - <sizepolicy vsizetype="Preferred" hsizetype="Expanding" > + <item row="0" column="1"> + <widget class="QLabel" name="standardLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> - <property name="frameShape" > + <property name="frameShape"> <enum>QFrame::StyledPanel</enum> </property> - <property name="text" > + <property name="text"> <string>Times 16</string> </property> - <property name="alignment" > + <property name="alignment"> <set>Qt::AlignCenter</set> </property> </widget> </item> - <item row="0" column="2" > - <widget class="QPushButton" name="standardFontButton" > - <property name="text" > + <item row="0" column="2"> + <widget class="QPushButton" name="standardFontButton"> + <property name="text"> <string>Select...</string> </property> </widget> </item> - <item row="1" column="0" > - <widget class="QLabel" name="label_6" > - <property name="text" > + <item row="1" column="0"> + <widget class="QLabel" name="label_6"> + <property name="text"> <string>Fixed-width font:</string> </property> - <property name="alignment" > + <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> </widget> </item> - <item row="1" column="1" > - <widget class="QLabel" name="fixedLabel" > - <property name="frameShape" > + <item row="1" column="1"> + <widget class="QLabel" name="fixedLabel"> + <property name="frameShape"> <enum>QFrame::StyledPanel</enum> </property> - <property name="text" > + <property name="text"> <string>Courier 13</string> </property> - <property name="alignment" > + <property name="alignment"> <set>Qt::AlignCenter</set> </property> </widget> </item> - <item row="1" column="2" > - <widget class="QPushButton" name="fixedFontButton" > - <property name="text" > + <item row="1" column="2"> + <widget class="QPushButton" name="fixedFontButton"> + <property name="text"> <string>Select...</string> </property> </widget> </item> - <item row="2" column="1" > - <spacer name="verticalSpacer" > - <property name="orientation" > + <item row="2" column="1"> + <spacer name="verticalSpacer"> + <property name="orientation"> <enum>Qt::Vertical</enum> </property> - <property name="sizeHint" stdset="0" > + <property name="sizeHint" stdset="0"> <size> <width>20</width> <height>93</height> @@ -274,41 +259,33 @@ </item> </layout> </widget> - <widget class="QWidget" name="tab_2" > - <property name="geometry" > - <rect> - <x>0</x> - <y>0</y> - <width>627</width> - <height>243</height> - </rect> - </property> - <attribute name="title" > + <widget class="QWidget" name="tab_2"> + <attribute name="title"> <string>Privacy</string> </attribute> - <layout class="QVBoxLayout" name="verticalLayout_3" > + <layout class="QVBoxLayout" name="verticalLayout_3"> <item> - <widget class="QGroupBox" name="groupBox" > - <property name="title" > + <widget class="QGroupBox" name="groupBox"> + <property name="title"> <string>Web Content</string> </property> - <layout class="QVBoxLayout" name="verticalLayout_2" > + <layout class="QVBoxLayout" name="verticalLayout_2"> <item> - <widget class="QCheckBox" name="enablePlugins" > - <property name="text" > + <widget class="QCheckBox" name="enablePlugins"> + <property name="text"> <string>Enable Plugins</string> </property> - <property name="checked" > + <property name="checked"> <bool>true</bool> </property> </widget> </item> <item> - <widget class="QCheckBox" name="enableJavascript" > - <property name="text" > + <widget class="QCheckBox" name="enableJavascript"> + <property name="text"> <string>Enable Javascript</string> </property> - <property name="checked" > + <property name="checked"> <bool>true</bool> </property> </widget> @@ -317,186 +294,151 @@ </widget> </item> <item> - <widget class="QGroupBox" name="cookiesGroupBox" > - <property name="title" > + <widget class="QGroupBox" name="cookiesGroupBox"> + <property name="title"> <string>Cookies</string> </property> - <layout class="QGridLayout" > - <item row="0" column="0" > - <widget class="QLabel" name="label_2" > - <property name="text" > - <string>Accept Cookies:</string> + <layout class="QGridLayout"> + <property name="leftMargin"> + <number>9</number> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Persistent Cookie Policy</string> </property> - <property name="alignment" > + <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> </widget> </item> - <item row="0" column="1" > - <widget class="QComboBox" name="acceptCombo" > + <item row="0" column="1"> + <widget class="QComboBox" name="sessionCookiesCombo"> <item> - <property name="text" > - <string>Always</string> + <property name="text"> + <string>Treat all cookies as session cookies</string> </property> </item> <item> - <property name="text" > - <string>Never</string> + <property name="text"> + <string>Allow persistent cookies</string> </property> </item> <item> - <property name="text" > - <string>Only from sites you navigate to</string> + <property name="text"> + <string>Treat all cookies as persistent cookies</string> </property> </item> </widget> </item> - <item row="0" column="2" > - <widget class="QPushButton" name="exceptionsButton" > - <property name="text" > - <string>Exceptions...</string> - </property> - </widget> - </item> - <item row="1" column="0" > - <widget class="QLabel" name="label" > - <property name="text" > - <string>Keep until:</string> + <item row="1" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Persistent Data Path:</string> </property> - <property name="alignment" > + <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> </widget> </item> - <item row="1" column="1" > - <widget class="QComboBox" name="keepUntilCombo" > - <item> - <property name="text" > - <string>They expire</string> - </property> - </item> - <item> - <property name="text" > - <string>I exit the application</string> - </property> - </item> - <item> - <property name="text" > - <string>At most 90 days</string> - </property> - </item> - </widget> - </item> - <item row="1" column="2" > - <widget class="QPushButton" name="cookiesButton" > - <property name="text" > - <string>Cookies...</string> - </property> - </widget> + <item row="1" column="1"> + <widget class="QLineEdit" name="persistentDataPath"/> </item> </layout> </widget> </item> <item> - <spacer> - <property name="orientation" > + <spacer name="verticalSpacer_4"> + <property name="orientation"> <enum>Qt::Vertical</enum> </property> - <property name="sizeHint" stdset="0" > + <property name="sizeHint" stdset="0"> <size> - <width>371</width> - <height>177</height> + <width>20</width> + <height>40</height> </size> </property> </spacer> </item> </layout> </widget> - <widget class="QWidget" name="tab_4" > - <property name="geometry" > - <rect> - <x>0</x> - <y>0</y> - <width>627</width> - <height>243</height> - </rect> - </property> - <attribute name="title" > + <widget class="QWidget" name="tab_4"> + <attribute name="title"> <string>Proxy</string> </attribute> - <layout class="QVBoxLayout" name="verticalLayout" > + <layout class="QVBoxLayout" name="verticalLayout"> <item> - <widget class="QGroupBox" name="proxySupport" > - <property name="title" > + <widget class="QGroupBox" name="proxySupport"> + <property name="title"> <string>Enable proxy</string> </property> - <property name="checkable" > + <property name="checkable"> <bool>true</bool> </property> - <layout class="QGridLayout" name="gridLayout_6" > - <item row="0" column="0" > - <widget class="QLabel" name="label_9" > - <property name="text" > + <layout class="QGridLayout" name="gridLayout_6"> + <item row="0" column="0"> + <widget class="QLabel" name="label_9"> + <property name="text"> <string>Type:</string> </property> - <property name="alignment" > + <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> </widget> </item> - <item row="0" column="1" colspan="2" > - <widget class="QComboBox" name="proxyType" > + <item row="0" column="1" colspan="2"> + <widget class="QComboBox" name="proxyType"> <item> - <property name="text" > + <property name="text"> <string>Socks5</string> </property> </item> <item> - <property name="text" > + <property name="text"> <string>Http</string> </property> </item> </widget> </item> - <item row="1" column="0" > - <widget class="QLabel" name="label_10" > - <property name="text" > + <item row="1" column="0"> + <widget class="QLabel" name="label_10"> + <property name="text"> <string>Host:</string> </property> - <property name="alignment" > + <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> </widget> </item> - <item row="1" column="1" colspan="2" > - <widget class="QLineEdit" name="proxyHostName" /> + <item row="1" column="1" colspan="2"> + <widget class="QLineEdit" name="proxyHostName"/> </item> - <item row="2" column="0" > - <widget class="QLabel" name="label_11" > - <property name="text" > + <item row="2" column="0"> + <widget class="QLabel" name="label_11"> + <property name="text"> <string>Port:</string> </property> - <property name="alignment" > + <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> </widget> </item> - <item row="2" column="1" > - <widget class="QSpinBox" name="proxyPort" > - <property name="maximum" > + <item row="2" column="1"> + <widget class="QSpinBox" name="proxyPort"> + <property name="maximum"> <number>10000</number> </property> - <property name="value" > + <property name="value"> <number>1080</number> </property> </widget> </item> - <item row="2" column="2" > - <spacer name="horizontalSpacer_2" > - <property name="orientation" > + <item row="2" column="2"> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> <enum>Qt::Horizontal</enum> </property> - <property name="sizeHint" stdset="0" > + <property name="sizeHint" stdset="0"> <size> <width>293</width> <height>20</height> @@ -504,42 +446,42 @@ </property> </spacer> </item> - <item row="3" column="0" > - <widget class="QLabel" name="label_12" > - <property name="text" > + <item row="3" column="0"> + <widget class="QLabel" name="label_12"> + <property name="text"> <string>User Name:</string> </property> - <property name="alignment" > + <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> </widget> </item> - <item row="3" column="1" colspan="2" > - <widget class="QLineEdit" name="proxyUserName" /> + <item row="3" column="1" colspan="2"> + <widget class="QLineEdit" name="proxyUserName"/> </item> - <item row="4" column="0" > - <widget class="QLabel" name="label_13" > - <property name="text" > + <item row="4" column="0"> + <widget class="QLabel" name="label_13"> + <property name="text"> <string>Password:</string> </property> - <property name="alignment" > + <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> </widget> </item> - <item row="4" column="1" colspan="2" > - <widget class="QLineEdit" name="proxyPassword" > - <property name="echoMode" > + <item row="4" column="1" colspan="2"> + <widget class="QLineEdit" name="proxyPassword"> + <property name="echoMode"> <enum>QLineEdit::Password</enum> </property> </widget> </item> - <item row="5" column="0" > - <spacer name="verticalSpacer_2" > - <property name="orientation" > + <item row="5" column="0"> + <spacer name="verticalSpacer_2"> + <property name="orientation"> <enum>Qt::Vertical</enum> </property> - <property name="sizeHint" stdset="0" > + <property name="sizeHint" stdset="0"> <size> <width>20</width> <height>8</height> @@ -552,27 +494,27 @@ </item> </layout> </widget> - <widget class="QWidget" name="tab_5" > - <attribute name="title" > + <widget class="QWidget" name="tab_5"> + <attribute name="title"> <string>Advanced</string> </attribute> - <layout class="QGridLayout" name="gridLayout_2" > - <item row="0" column="0" > - <widget class="QLabel" name="label_14" > - <property name="text" > + <layout class="QGridLayout" name="gridLayout_2"> + <item row="0" column="0"> + <widget class="QLabel" name="label_14"> + <property name="text"> <string>Style Sheet:</string> </property> </widget> </item> - <item row="0" column="1" > - <widget class="QLineEdit" name="userStyleSheet" /> + <item row="0" column="1"> + <widget class="QLineEdit" name="userStyleSheet"/> </item> - <item row="1" column="1" > - <spacer name="verticalSpacer_3" > - <property name="orientation" > + <item row="2" column="1"> + <spacer name="verticalSpacer_3"> + <property name="orientation"> <enum>Qt::Vertical</enum> </property> - <property name="sizeHint" stdset="0" > + <property name="sizeHint" stdset="0"> <size> <width>20</width> <height>176</height> @@ -580,6 +522,16 @@ </property> </spacer> </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="httpUserAgent"/> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_15"> + <property name="text"> + <string>HTTP User-Agent:</string> + </property> + </widget> + </item> </layout> </widget> </widget> @@ -594,11 +546,11 @@ <receiver>Settings</receiver> <slot>accept()</slot> <hints> - <hint type="sourcelabel" > + <hint type="sourcelabel"> <x>248</x> <y>254</y> </hint> - <hint type="destinationlabel" > + <hint type="destinationlabel"> <x>157</x> <y>274</y> </hint> @@ -610,11 +562,11 @@ <receiver>Settings</receiver> <slot>reject()</slot> <hints> - <hint type="sourcelabel" > + <hint type="sourcelabel"> <x>316</x> <y>260</y> </hint> - <hint type="destinationlabel" > + <hint type="destinationlabel"> <x>286</x> <y>274</y> </hint> diff --git a/examples/webenginewidgets/browser/webview.cpp b/examples/webenginewidgets/browser/webview.cpp index 5ea273e3a..9b42f2ab2 100644 --- a/examples/webenginewidgets/browser/webview.cpp +++ b/examples/webenginewidgets/browser/webview.cpp @@ -97,37 +97,15 @@ BrowserMainWindow *WebPage::mainWindow() return BrowserApplication::instance()->mainWindow(); } -#if defined(QWEBENGINEPAGE_ACCEPTNAVIGATIONREQUEST) -bool WebPage::acceptNavigationRequest(QWebEngineFrame *frame, const QNetworkRequest &request, NavigationType type) +bool WebPage::acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame) { - // ctrl open in new tab - // ctrl-shift open in new tab and select - // ctrl-alt open in new window - if (type == QWebEnginePage::NavigationTypeLinkClicked - && (m_keyboardModifiers & Qt::ControlModifier - || m_pressedButtons == Qt::MidButton)) { - bool newWindow = (m_keyboardModifiers & Qt::AltModifier); - WebView *webView; - if (newWindow) { - BrowserApplication::instance()->newMainWindow(); - BrowserMainWindow *newMainWindow = BrowserApplication::instance()->mainWindow(); - webView = newMainWindow->currentTab(); - newMainWindow->raise(); - newMainWindow->activateWindow(); - webView->setFocus(); - } else { - bool selectNewTab = (m_keyboardModifiers & Qt::ShiftModifier); - webView = mainWindow()->tabWidget()->newTab(selectNewTab); - } - webView->load(request); - m_keyboardModifiers = Qt::NoModifier; - m_pressedButtons = Qt::NoButton; - return false; + Q_UNUSED(type); + if (isMainFrame) { + m_loadingUrl = url; + emit loadingUrl(m_loadingUrl); } - m_loadingUrl = request.url(); - emit loadingUrl(m_loadingUrl); + return true; } -#endif bool WebPage::certificateError(const QWebEngineCertificateError &error) { diff --git a/examples/webenginewidgets/browser/webview.h b/examples/webenginewidgets/browser/webview.h index 2cedeb79b..5ed674f6a 100644 --- a/examples/webenginewidgets/browser/webview.h +++ b/examples/webenginewidgets/browser/webview.h @@ -65,9 +65,7 @@ public: BrowserMainWindow *mainWindow(); protected: -#if defined(QWEBENGINEPAGE_ACCEPTNAVIGATIONREQUEST) - bool acceptNavigationRequest(QWebEngineFrame *frame, const QNetworkRequest &request, NavigationType type); -#endif + bool acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame); QWebEnginePage *createWindow(QWebEnginePage::WebWindowType type); #if !defined(QT_NO_UITOOLS) QObject *createPlugin(const QString &classId, const QUrl &url, const QStringList ¶mNames, const QStringList ¶mValues); diff --git a/qtwebengine.pro b/qtwebengine.pro index 366446c7a..5156e4620 100644 --- a/qtwebengine.pro +++ b/qtwebengine.pro @@ -1,8 +1,2 @@ load(qt_build_config) - -# As long as we are a module separate from the rest of Qt, we want to unconditionally build examples. -# Once part of Qt 5, this should be removed and we should respect the Qt wide configuration. -QTWEBENGINE_BUILD_PARTS = $$QT_BUILD_PARTS -QTWEBENGINE_BUILD_PARTS *= examples - load(qt_parts) diff --git a/src/core/access_token_store_qt.cpp b/src/core/access_token_store_qt.cpp index 85a91c3f7..791d628ba 100644 --- a/src/core/access_token_store_qt.cpp +++ b/src/core/access_token_store_qt.cpp @@ -34,11 +34,27 @@ ** ****************************************************************************/ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + #include "access_token_store_qt.h" -#include <QDebug> +#include "base/bind.h" +#include "base/message_loop/message_loop.h" +#include "base/strings/utf_string_conversions.h" +#include "content/public/browser/browser_thread.h" + +#include "browser_context_qt.h" +#include "browser_context_adapter.h" +#include "content_browser_client_qt.h" +#include "web_engine_context.h" + +using content::AccessTokenStore; +using content::BrowserThread; AccessTokenStoreQt::AccessTokenStoreQt() + : m_systemRequestContext(0) { } @@ -48,9 +64,23 @@ AccessTokenStoreQt::~AccessTokenStoreQt() void AccessTokenStoreQt::LoadAccessTokens(const LoadAccessTokensCallbackType& callback) { + BrowserThread::PostTaskAndReply(BrowserThread::UI, FROM_HERE + , base::Bind(&AccessTokenStoreQt::performWorkOnUIThread, this) + , base::Bind(&AccessTokenStoreQt::respondOnOriginatingThread, this, callback)); +} + +void AccessTokenStoreQt::performWorkOnUIThread() +{ + m_systemRequestContext = WebEngineContext::current()->defaultBrowserContext()->browserContext()->GetRequestContext(); } -void AccessTokenStoreQt::SaveAccessToken(const GURL& server_url, const base::string16& access_token) +void AccessTokenStoreQt::respondOnOriginatingThread(const LoadAccessTokensCallbackType& callback) { + callback.Run(m_accessTokenSet, m_systemRequestContext); + m_systemRequestContext = 0; } +void AccessTokenStoreQt::SaveAccessToken(const GURL& serverUrl, const base::string16& accessToken) +{ + m_accessTokenSet[serverUrl] = accessToken; +} diff --git a/src/core/access_token_store_qt.h b/src/core/access_token_store_qt.h index 2a76681f0..9493da774 100644 --- a/src/core/access_token_store_qt.h +++ b/src/core/access_token_store_qt.h @@ -37,20 +37,33 @@ #ifndef ACCESS_TOKEN_STORE_QT_H #define ACCESS_TOKEN_STORE_QT_H +#include "base/memory/ref_counted.h" #include "content/public/browser/access_token_store.h" -#include <QtCore/qcompilerdetection.h> // Needed for Q_DECL_OVERRIDE +#include <QtCore/qcompilerdetection.h> +#include <QtCore/QFile> +#include <QtCore/QScopedPointer> -class AccessTokenStoreQt : public content::AccessTokenStore -{ +namespace net { +class URLRequestContextGetter; +} + +class AccessTokenStoreQt : public content::AccessTokenStore { public: AccessTokenStoreQt(); ~AccessTokenStoreQt(); - virtual void LoadAccessTokens(const LoadAccessTokensCallbackType& callback) Q_DECL_OVERRIDE; - virtual void SaveAccessToken(const GURL& server_url, const base::string16& access_token) Q_DECL_OVERRIDE; + virtual void LoadAccessTokens(const LoadAccessTokensCallbackType& request) Q_DECL_OVERRIDE; + virtual void SaveAccessToken(const GURL& serverUrl, const base::string16& accessToken) Q_DECL_OVERRIDE; private: + void performWorkOnUIThread(); + void respondOnOriginatingThread(const LoadAccessTokensCallbackType& callback); + + + net::URLRequestContextGetter *m_systemRequestContext; + AccessTokenSet m_accessTokenSet; + DISALLOW_COPY_AND_ASSIGN(AccessTokenStoreQt); }; diff --git a/src/core/browser_context_adapter.cpp b/src/core/browser_context_adapter.cpp new file mode 100644 index 000000000..95ddc4d87 --- /dev/null +++ b/src/core/browser_context_adapter.cpp @@ -0,0 +1,316 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 "browser_context_adapter.h" + +#include "content/public/browser/browser_thread.h" +#include "browser_context_qt.h" +#include "content_client_qt.h" +#include "download_manager_delegate_qt.h" +#include "web_engine_context.h" +#include "web_engine_visited_links_manager.h" +#include "url_request_context_getter_qt.h" + +#include "net/proxy/proxy_service.h" + +#include <QCoreApplication> +#include <QDir> +#include <QString> +#include <QStringBuilder> +#include <QStandardPaths> + +namespace { +inline QString buildLocationFromStandardPath(const QString &standardPath, const QString &name) { + QString location = standardPath; + if (location.isEmpty()) + location = QDir::homePath() % QLatin1String("/.") % QCoreApplication::applicationName(); + + location.append(QLatin1String("/QtWebEngine/") % name); + return location; +} +} + +BrowserContextAdapter::BrowserContextAdapter(bool offTheRecord) + : m_offTheRecord(offTheRecord) + , m_browserContext(new BrowserContextQt(this)) + , m_httpCacheType(DiskHttpCache) + , m_persistentCookiesPolicy(AllowPersistentCookies) + , m_visitedLinksPolicy(TrackVisitedLinksOnDisk) + , m_client(0) + , m_httpCacheMaxSize(0) +{ +} + +BrowserContextAdapter::BrowserContextAdapter(const QString &storageName) + : m_name(storageName) + , m_offTheRecord(false) + , m_browserContext(new BrowserContextQt(this)) + , m_httpCacheType(DiskHttpCache) + , m_persistentCookiesPolicy(AllowPersistentCookies) + , m_visitedLinksPolicy(TrackVisitedLinksOnDisk) + , m_httpCacheMaxSize(0) +{ +} + +BrowserContextAdapter::~BrowserContextAdapter() +{ + if (m_downloadManagerDelegate) + content::BrowserThread::DeleteSoon(content::BrowserThread::UI, FROM_HERE, m_downloadManagerDelegate.take()); +} + +void BrowserContextAdapter::setStorageName(const QString &storageName) +{ + if (storageName == m_name) + return; + m_name = storageName; + if (m_browserContext->url_request_getter_) + m_browserContext->url_request_getter_->updateStorageSettings(); + m_visitedLinksManager.reset(); +} + +void BrowserContextAdapter::setOffTheRecord(bool offTheRecord) +{ + if (offTheRecord == m_offTheRecord) + return; + m_offTheRecord = offTheRecord; + if (m_browserContext->url_request_getter_) + m_browserContext->url_request_getter_->updateStorageSettings(); + m_visitedLinksManager.reset(); +} + +BrowserContextQt *BrowserContextAdapter::browserContext() +{ + return m_browserContext.data(); +} + +WebEngineVisitedLinksManager *BrowserContextAdapter::visitedLinksManager() +{ + if (!m_visitedLinksManager) + m_visitedLinksManager.reset(new WebEngineVisitedLinksManager(this)); + return m_visitedLinksManager.data(); +} + +DownloadManagerDelegateQt *BrowserContextAdapter::downloadManagerDelegate() +{ + if (!m_downloadManagerDelegate) + m_downloadManagerDelegate.reset(new DownloadManagerDelegateQt(this)); + return m_downloadManagerDelegate.data(); +} + +void BrowserContextAdapter::setClient(BrowserContextAdapterClient *adapterClient) +{ + m_client = adapterClient; +} + +void BrowserContextAdapter::cancelDownload(quint32 downloadId) +{ + downloadManagerDelegate()->cancelDownload(downloadId); +} + +BrowserContextAdapter* BrowserContextAdapter::defaultContext() +{ + return WebEngineContext::current()->defaultBrowserContext(); +} + +BrowserContextAdapter* BrowserContextAdapter::offTheRecordContext() +{ + return WebEngineContext::current()->offTheRecordBrowserContext(); +} + +QString BrowserContextAdapter::dataPath() const +{ + if (m_offTheRecord) + return QString(); + if (!m_dataPath.isEmpty()) + return m_dataPath; + if (!m_name.isNull()) + return buildLocationFromStandardPath(QStandardPaths::writableLocation(QStandardPaths::DataLocation), m_name); + return QString(); +} + +void BrowserContextAdapter::setDataPath(const QString &path) +{ + if (m_dataPath == path) + return; + m_dataPath = path; + if (m_browserContext->url_request_getter_) + m_browserContext->url_request_getter_->updateStorageSettings(); + m_visitedLinksManager.reset(); +} + +QString BrowserContextAdapter::cachePath() const +{ + if (m_offTheRecord) + return QString(); + if (!m_cachePath.isEmpty()) + return m_cachePath; + if (!m_name.isNull()) + return buildLocationFromStandardPath(QStandardPaths::writableLocation(QStandardPaths::CacheLocation), m_name); + return QString(); +} + +void BrowserContextAdapter::setCachePath(const QString &path) +{ + if (m_cachePath == path) + return; + m_cachePath = path; + if (m_browserContext->url_request_getter_) + m_browserContext->url_request_getter_->updateHttpCache(); +} + +QString BrowserContextAdapter::cookiesPath() const +{ + if (m_offTheRecord) + return QString(); + QString basePath = dataPath(); + if (!basePath.isEmpty()) + return basePath % QLatin1String("/Coookies"); + return QString(); +} + +QString BrowserContextAdapter::httpCachePath() const +{ + if (m_offTheRecord) + return QString(); + QString basePath = cachePath(); + if (!basePath.isEmpty()) + return basePath % QLatin1String("/Cache"); + return QString(); +} + +QString BrowserContextAdapter::httpUserAgent() const +{ + if (m_httpUserAgent.isNull()) + return QString::fromStdString(ContentClientQt::getUserAgent()); + return m_httpUserAgent; +} + +void BrowserContextAdapter::setHttpUserAgent(const QString &userAgent) +{ + if (m_httpUserAgent == userAgent) + return; + m_httpUserAgent = userAgent; + if (m_browserContext->url_request_getter_) + m_browserContext->url_request_getter_->updateUserAgent(); +} + +BrowserContextAdapter::HttpCacheType BrowserContextAdapter::httpCacheType() const +{ + if (isOffTheRecord() || httpCachePath().isEmpty()) + return MemoryHttpCache; + return m_httpCacheType; +} + +void BrowserContextAdapter::setHttpCacheType(BrowserContextAdapter::HttpCacheType newhttpCacheType) +{ + BrowserContextAdapter::HttpCacheType oldCacheType = httpCacheType(); + m_httpCacheType = newhttpCacheType; + if (oldCacheType == httpCacheType()) + return; + if (m_browserContext->url_request_getter_) + m_browserContext->url_request_getter_->updateHttpCache(); +} + +BrowserContextAdapter::PersistentCookiesPolicy BrowserContextAdapter::persistentCookiesPolicy() const +{ + if (isOffTheRecord() || cookiesPath().isEmpty()) + return NoPersistentCookies; + return m_persistentCookiesPolicy; +} + +void BrowserContextAdapter::setPersistentCookiesPolicy(BrowserContextAdapter::PersistentCookiesPolicy newPersistentCookiesPolicy) +{ + BrowserContextAdapter::PersistentCookiesPolicy oldPolicy = persistentCookiesPolicy(); + m_persistentCookiesPolicy = newPersistentCookiesPolicy; + if (oldPolicy == persistentCookiesPolicy()) + return; + if (m_browserContext->url_request_getter_) + m_browserContext->url_request_getter_->updateCookieStore(); +} + +BrowserContextAdapter::VisitedLinksPolicy BrowserContextAdapter::visitedLinksPolicy() const +{ + if (isOffTheRecord() || m_visitedLinksPolicy == DoNotTrackVisitedLinks) + return DoNotTrackVisitedLinks; + if (dataPath().isEmpty()) + return TrackVisitedLinksInMemory; + return m_visitedLinksPolicy; +} + +bool BrowserContextAdapter::trackVisitedLinks() const +{ + switch (visitedLinksPolicy()) { + case DoNotTrackVisitedLinks: + return false; + default: + break; + } + return true; +} + +bool BrowserContextAdapter::persistVisitedLinks() const +{ + switch (visitedLinksPolicy()) { + case DoNotTrackVisitedLinks: + case TrackVisitedLinksInMemory: + return false; + default: + break; + } + return true; +} + +void BrowserContextAdapter::setVisitedLinksPolicy(BrowserContextAdapter::VisitedLinksPolicy visitedLinksPolicy) +{ + if (m_visitedLinksPolicy == visitedLinksPolicy) + return; + m_visitedLinksPolicy = visitedLinksPolicy; + m_visitedLinksManager.reset(); +} + +int BrowserContextAdapter::httpCacheMaxSize() const +{ + return m_httpCacheMaxSize; +} + +void BrowserContextAdapter::setHttpCacheMaxSize(int maxSize) +{ + if (m_httpCacheMaxSize == maxSize) + return; + m_httpCacheMaxSize = maxSize; + if (m_browserContext->url_request_getter_) + m_browserContext->url_request_getter_->updateHttpCache(); +} diff --git a/src/core/browser_context_adapter.h b/src/core/browser_context_adapter.h new file mode 100644 index 000000000..1c12c465d --- /dev/null +++ b/src/core/browser_context_adapter.h @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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$ +** +****************************************************************************/ + +#ifndef BROWSER_CONTEXT_ADAPTER_H +#define BROWSER_CONTEXT_ADAPTER_H + +#include "qtwebenginecoreglobal.h" + +#include <QScopedPointer> +#include <QSharedData> +#include <QString> + +class BrowserContextAdapterClient; +class BrowserContextQt; +class DownloadManagerDelegateQt; +class WebEngineVisitedLinksManager; + +class QWEBENGINE_EXPORT BrowserContextAdapter : public QSharedData +{ +public: + explicit BrowserContextAdapter(bool offTheRecord = false); + explicit BrowserContextAdapter(const QString &storagePrefix); + virtual ~BrowserContextAdapter(); + + static BrowserContextAdapter* defaultContext(); + static BrowserContextAdapter* offTheRecordContext(); + + WebEngineVisitedLinksManager *visitedLinksManager(); + DownloadManagerDelegateQt *downloadManagerDelegate(); + + BrowserContextAdapterClient* client() { return m_client; } + + void setClient(BrowserContextAdapterClient *adapterClient); + void cancelDownload(quint32 downloadId); + + BrowserContextQt *browserContext(); + + QString storageName() const { return m_name; } + void setStorageName(const QString &storageName); + + bool isOffTheRecord() const { return m_offTheRecord; } + void setOffTheRecord(bool offTheRecord); + + QString dataPath() const; + void setDataPath(const QString &path); + + QString cachePath() const; + void setCachePath(const QString &path); + + QString httpCachePath() const; + QString cookiesPath() const; + + QString httpUserAgent() const; + void setHttpUserAgent(const QString &userAgent); + + // KEEP IN SYNC with API or add mapping layer + enum HttpCacheType { + MemoryHttpCache = 0, + DiskHttpCache + }; + + enum PersistentCookiesPolicy { + NoPersistentCookies = 0, + AllowPersistentCookies, + ForcePersistentCookies + }; + + enum VisitedLinksPolicy { + DoNotTrackVisitedLinks = 0, + TrackVisitedLinksInMemory, + TrackVisitedLinksOnDisk, + }; + + HttpCacheType httpCacheType() const; + void setHttpCacheType(BrowserContextAdapter::HttpCacheType); + + PersistentCookiesPolicy persistentCookiesPolicy() const; + void setPersistentCookiesPolicy(BrowserContextAdapter::PersistentCookiesPolicy); + + VisitedLinksPolicy visitedLinksPolicy() const; + void setVisitedLinksPolicy(BrowserContextAdapter::VisitedLinksPolicy); + + int httpCacheMaxSize() const; + void setHttpCacheMaxSize(int maxSize); + + bool trackVisitedLinks() const; + bool persistVisitedLinks() const; + +private: + QString m_name; + bool m_offTheRecord; + QScopedPointer<BrowserContextQt> m_browserContext; + QScopedPointer<WebEngineVisitedLinksManager> m_visitedLinksManager; + QScopedPointer<DownloadManagerDelegateQt> m_downloadManagerDelegate; + QString m_dataPath; + QString m_cachePath; + QString m_httpUserAgent; + HttpCacheType m_httpCacheType; + PersistentCookiesPolicy m_persistentCookiesPolicy; + VisitedLinksPolicy m_visitedLinksPolicy; + BrowserContextAdapterClient *m_client; + int m_httpCacheMaxSize; + + Q_DISABLE_COPY(BrowserContextAdapter) +}; + +#endif // BROWSER_CONTEXT_ADAPTER_H diff --git a/src/core/browser_context_adapter_client.h b/src/core/browser_context_adapter_client.h new file mode 100644 index 000000000..2b6b4f434 --- /dev/null +++ b/src/core/browser_context_adapter_client.h @@ -0,0 +1,63 @@ + /**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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$ +** +****************************************************************************/ + +#ifndef BROWSER_CONTEXT_ADAPTER_CLIENT_H +#define BROWSER_CONTEXT_ADAPTER_CLIENT_H + +#include "qtwebenginecoreglobal.h" +#include <QString> + +class QWEBENGINE_EXPORT BrowserContextAdapterClient +{ +public: + // Keep in sync with content::DownloadItem::DownloadState + enum DownloadState { + // Download is actively progressing. + DownloadInProgress = 0, + // Download is completely finished. + DownloadCompleted, + // Download has been cancelled. + DownloadCancelled, + // This state indicates that the download has been interrupted. + DownloadInterrupted + }; + virtual ~BrowserContextAdapterClient() { } + + virtual void downloadRequested(quint32 downloadId, QString &downloadPath, bool &cancelled) = 0; + virtual void downloadUpdated(quint32 downloadId, int downloadState, int percentComplete) = 0; +}; + +#endif // BROWSER_CONTEXT_ADAPTER_CLIENT_H diff --git a/src/core/browser_context_qt.cpp b/src/core/browser_context_qt.cpp index 44b6ca4ef..4661f59fc 100644 --- a/src/core/browser_context_qt.cpp +++ b/src/core/browser_context_qt.cpp @@ -36,27 +36,21 @@ #include "browser_context_qt.h" +#include "browser_context_adapter.h" +#include "download_manager_delegate_qt.h" #include "type_conversion.h" #include "qtwebenginecoreglobal.h" #include "resource_context_qt.h" #include "url_request_context_getter_qt.h" -#include "base/files/scoped_temp_dir.h" #include "base/time/time.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/storage_partition.h" #include "net/proxy/proxy_config_service.h" -#include <QByteArray> -#include <QCoreApplication> -#include <QDir> -#include <QStandardPaths> -#include <QString> -#include <QStringBuilder> - -BrowserContextQt::BrowserContextQt() +BrowserContextQt::BrowserContextQt(BrowserContextAdapter *adapter) + : m_adapter(adapter) { - resourceContext.reset(new ResourceContextQt(this)); } BrowserContextQt::~BrowserContextQt() @@ -67,29 +61,17 @@ BrowserContextQt::~BrowserContextQt() base::FilePath BrowserContextQt::GetPath() const { - QString dataLocation = QStandardPaths::writableLocation(QStandardPaths::DataLocation); - if (dataLocation.isEmpty()) - dataLocation = QDir::homePath() % QDir::separator() % QChar::fromLatin1('.') % QCoreApplication::applicationName(); - - dataLocation.append(QDir::separator() % QLatin1String("QtWebEngine")); - dataLocation.append(QDir::separator() % QLatin1String("Default")); - return base::FilePath(toFilePathString(dataLocation)); + return toFilePath(m_adapter->dataPath()); } base::FilePath BrowserContextQt::GetCachePath() const { - QString cacheLocation = QStandardPaths::writableLocation(QStandardPaths::CacheLocation); - if (cacheLocation.isEmpty()) - cacheLocation = QDir::homePath() % QDir::separator() % QChar::fromLatin1('.') % QCoreApplication::applicationName(); - - cacheLocation.append(QDir::separator() % QLatin1String("QtWebEngine")); - cacheLocation.append(QDir::separator() % QLatin1String("Default")); - return base::FilePath(toFilePathString(cacheLocation)); + return toFilePath(m_adapter->cachePath()); } bool BrowserContextQt::IsOffTheRecord() const { - return false; + return m_adapter->isOffTheRecord(); } net::URLRequestContextGetter *BrowserContextQt::GetRequestContext() @@ -119,12 +101,14 @@ net::URLRequestContextGetter *BrowserContextQt::GetMediaRequestContextForStorage content::ResourceContext *BrowserContextQt::GetResourceContext() { + if (!resourceContext) + resourceContext.reset(new ResourceContextQt(this)); return resourceContext.get(); } content::DownloadManagerDelegate *BrowserContextQt::GetDownloadManagerDelegate() { - return downloadManagerDelegate.get(); + return m_adapter->downloadManagerDelegate(); } content::BrowserPluginGuestManager *BrowserContextQt::GetGuestManager() @@ -145,7 +129,7 @@ content::PushMessagingService *BrowserContextQt::GetPushMessagingService() net::URLRequestContextGetter *BrowserContextQt::CreateRequestContext(content::ProtocolHandlerMap *protocol_handlers) { - url_request_getter_ = new URLRequestContextGetterQt(GetPath(), GetCachePath(), protocol_handlers); - static_cast<ResourceContextQt*>(resourceContext.get())->set_url_request_context_getter(url_request_getter_.get()); + url_request_getter_ = new URLRequestContextGetterQt(m_adapter, protocol_handlers); + static_cast<ResourceContextQt*>(GetResourceContext())->set_url_request_context_getter(url_request_getter_.get()); return url_request_getter_.get(); } diff --git a/src/core/browser_context_qt.h b/src/core/browser_context_qt.h index 125c0fc46..8ab6024ae 100644 --- a/src/core/browser_context_qt.h +++ b/src/core/browser_context_qt.h @@ -41,12 +41,16 @@ #include "content/public/browser/content_browser_client.h" #include "content/public/browser/resource_context.h" #include "net/url_request/url_request_context.h" -#include "download_manager_delegate_qt.h" + +#include <QtCore/qcompilerdetection.h> // Needed for Q_DECL_OVERRIDE + +class BrowserContextAdapter; +class URLRequestContextGetterQt; class BrowserContextQt : public content::BrowserContext { public: - explicit BrowserContextQt(); + explicit BrowserContextQt(BrowserContextAdapter *); virtual ~BrowserContextQt(); @@ -68,8 +72,9 @@ public: private: scoped_ptr<content::ResourceContext> resourceContext; - scoped_refptr<net::URLRequestContextGetter> url_request_getter_; - scoped_ptr<DownloadManagerDelegateQt> downloadManagerDelegate; + scoped_refptr<URLRequestContextGetterQt> url_request_getter_; + BrowserContextAdapter *m_adapter; + friend class BrowserContextAdapter; DISALLOW_COPY_AND_ASSIGN(BrowserContextQt); }; diff --git a/src/core/content_browser_client_qt.cpp b/src/core/content_browser_client_qt.cpp index 4948d1d8d..6dfaa64c7 100644 --- a/src/core/content_browser_client_qt.cpp +++ b/src/core/content_browser_client_qt.cpp @@ -55,17 +55,22 @@ #include "ui/gl/gl_implementation.h" #include "ui/gl/gl_share_group.h" +#include "access_token_store_qt.h" #include "browser_context_qt.h" #include "certificate_error_controller.h" #include "certificate_error_controller_p.h" #include "desktop_screen_qt.h" #include "dev_tools_http_handler_delegate_qt.h" +#ifdef QT_USE_POSITIONING +#include "location_provider_qt.h" +#endif #include "media_capture_devices_dispatcher.h" #include "resource_dispatcher_host_delegate_qt.h" #include "web_contents_delegate_qt.h" #include "access_token_store_qt.h" #include <QGuiApplication> +#include <QLocale> #include <QOpenGLContext> #include <qpa/qplatformnativeinterface.h> @@ -203,12 +208,10 @@ public: void PreMainMessageLoopRun() Q_DECL_OVERRIDE { - m_browserContext.reset(new BrowserContextQt()); } void PostMainMessageLoopRun() { - m_browserContext.reset(); } int PreCreateThreads() Q_DECL_OVERRIDE @@ -219,13 +222,7 @@ public: return 0; } - BrowserContextQt* browser_context() const { - return m_browserContext.get(); - } - private: - scoped_ptr<BrowserContextQt> m_browserContext; - DISALLOW_COPY_AND_ASSIGN(BrowserMainPartsQt); }; @@ -246,7 +243,7 @@ public: m_handle = pni->nativeResourceForContext(QByteArrayLiteral("cglcontextobj"), qtContext); else if (platform == QLatin1String("qnx")) m_handle = pni->nativeResourceForContext(QByteArrayLiteral("eglcontext"), qtContext); - else if (platform == QLatin1String("eglfs")) + else if (platform == QLatin1String("eglfs") || platform == QLatin1String("wayland")) m_handle = pni->nativeResourceForContext(QByteArrayLiteral("eglcontext"), qtContext); else if (platform == QLatin1String("windows")) { if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2) @@ -364,22 +361,15 @@ content::AccessTokenStore *ContentBrowserClientQt::CreateAccessTokenStore() return new AccessTokenStoreQt; } -BrowserContextQt* ContentBrowserClientQt::browser_context() { - Q_ASSERT(m_browserMainParts); - return static_cast<BrowserMainPartsQt*>(m_browserMainParts)->browser_context(); -} - -net::URLRequestContextGetter* ContentBrowserClientQt::CreateRequestContext(content::BrowserContext* content_browser_context, content::ProtocolHandlerMap* protocol_handlers, content::URLRequestInterceptorScopedVector request_interceptors) +net::URLRequestContextGetter* ContentBrowserClientQt::CreateRequestContext(content::BrowserContext* browser_context, content::ProtocolHandlerMap* protocol_handlers, content::URLRequestInterceptorScopedVector request_interceptors) { - if (content_browser_context != browser_context()) - fprintf(stderr, "Warning: off the record browser context not implemented !\n"); - return static_cast<BrowserContextQt*>(browser_context())->CreateRequestContext(protocol_handlers); + return static_cast<BrowserContextQt*>(browser_context)->CreateRequestContext(protocol_handlers); } -void ContentBrowserClientQt::enableInspector(bool enable) +void ContentBrowserClientQt::enableInspector(bool enable, content::BrowserContext* browser_context) { if (enable && !m_devtools) { - m_devtools.reset(new DevToolsHttpHandlerDelegateQt(browser_context())); + m_devtools.reset(new DevToolsHttpHandlerDelegateQt(browser_context)); } else if (!enable && m_devtools) { m_devtools.reset(); } @@ -409,19 +399,28 @@ void ContentBrowserClientQt::AllowCertificateError(int render_process_id, int re contentsDelegate->allowCertificateError(errorController); } -void ContentBrowserClientQt::RequestGeolocationPermission(content::WebContents *webContents, - int bridge_id, - const GURL &requesting_frame, - bool user_gesture, - base::Callback<void(bool)> result_callback, - base::Closure *cancel_callback) +void ContentBrowserClientQt::RequestGeolocationPermission(content::WebContents *webContents, int /*bridgeId*/, const GURL &requestingFrameOrigin, bool /*userGesture*/, base::Callback<void (bool)> resultCallback, base::Closure *cancelCallback) +{ + WebContentsDelegateQt* contentsDelegate = static_cast<WebContentsDelegateQt*>(webContents->GetDelegate()); + Q_ASSERT(contentsDelegate); + contentsDelegate->requestGeolocationPermission(requestingFrameOrigin, resultCallback, cancelCallback); +} + +blink::WebNotificationPresenter::Permission ContentBrowserClientQt::CheckDesktopNotificationPermission(const GURL&, content::ResourceContext *, int ) +{ + return blink::WebNotificationPresenter::PermissionDenied; +} + +content::LocationProvider *ContentBrowserClientQt::OverrideSystemLocationProvider() +{ +#ifdef QT_USE_POSITIONING + return new LocationProviderQt; +#else + return 0; // Leave it up to Chromium to figure something out. +#endif +} + +std::string ContentBrowserClientQt::GetApplicationLocale() { - Q_UNUSED(webContents); - Q_UNUSED(bridge_id); - Q_UNUSED(requesting_frame); - Q_UNUSED(user_gesture); - Q_UNUSED(cancel_callback); - - // TODO: Add geolocation support - result_callback.Run(false); + return QLocale().name().toStdString(); } diff --git a/src/core/content_browser_client_qt.h b/src/core/content_browser_client_qt.h index f1ecf5825..d5b49e835 100644 --- a/src/core/content_browser_client_qt.h +++ b/src/core/content_browser_client_qt.h @@ -52,6 +52,7 @@ class BrowserContext; class BrowserMainParts; class RenderProcessHost; class RenderViewHostDelegateView; +class ResourceContext; class WebContentsViewPort; class WebContents; struct MainFunctionParams; @@ -78,9 +79,9 @@ public: virtual void ResourceDispatcherHostCreated() Q_DECL_OVERRIDE; virtual gfx::GLShareGroup* GetInProcessGpuShareGroup() Q_DECL_OVERRIDE; virtual content::MediaObserver* GetMediaObserver() Q_DECL_OVERRIDE; - virtual void OverrideWebkitPrefs(content::RenderViewHost *, const GURL &, WebPreferences *) Q_DECL_OVERRIDE; - virtual content::AccessTokenStore *CreateAccessTokenStore() Q_DECL_OVERRIDE; + virtual content::AccessTokenStore* CreateAccessTokenStore() Q_DECL_OVERRIDE; virtual content::QuotaPermissionContext *CreateQuotaPermissionContext() Q_DECL_OVERRIDE; + virtual void OverrideWebkitPrefs(content::RenderViewHost *, const GURL &, WebPreferences *) Q_DECL_OVERRIDE; virtual void AllowCertificateError( int render_process_id, int render_frame_id, @@ -92,19 +93,18 @@ public: bool strict_enforcement, const base::Callback<void(bool)>& callback, content::CertificateRequestResultType* result) Q_DECL_OVERRIDE; - virtual void RequestGeolocationPermission( - content::WebContents *webContents, - int bridge_id, - const GURL &requesting_frame, - bool user_gesture, - base::Callback<void(bool)> result_callback, - base::Closure *cancel_callback) Q_DECL_OVERRIDE; + void RequestGeolocationPermission(content::WebContents* web_contents, int, const GURL& requesting_frame + , bool, base::Callback<void(bool)> resultCallback + , base::Closure* cancelCallback) Q_DECL_OVERRIDE; + content::LocationProvider* OverrideSystemLocationProvider() Q_DECL_OVERRIDE; + + virtual net::URLRequestContextGetter *CreateRequestContext(content::BrowserContext *browser_context, content::ProtocolHandlerMap *protocol_handlers, content::URLRequestInterceptorScopedVector request_interceptorss) Q_DECL_OVERRIDE; - BrowserContextQt* browser_context(); + virtual blink::WebNotificationPresenter::Permission CheckDesktopNotificationPermission(const GURL& source_origin, content::ResourceContext* context, int render_process_id) Q_DECL_OVERRIDE; - virtual net::URLRequestContextGetter *CreateRequestContext(content::BrowserContext *content_browser_context, content::ProtocolHandlerMap *protocol_handlers, content::URLRequestInterceptorScopedVector request_interceptorss) Q_DECL_OVERRIDE; + virtual std::string GetApplicationLocale() Q_DECL_OVERRIDE; - void enableInspector(bool); + void enableInspector(bool enable, content::BrowserContext *browser_context); private: BrowserMainPartsQt* m_browserMainParts; diff --git a/src/core/content_main_delegate_qt.cpp b/src/core/content_main_delegate_qt.cpp index e41888976..44dc0b8bd 100644 --- a/src/core/content_main_delegate_qt.cpp +++ b/src/core/content_main_delegate_qt.cpp @@ -52,6 +52,8 @@ #include "renderer/content_renderer_client_qt.h" #include "web_engine_library_info.h" +#include <QLocale> + static base::StringPiece PlatformResourceProvider(int key) { if (key == IDR_DIR_HEADER_HTML) { base::StringPiece html_data = ui::ResourceBundle::GetSharedInstance().GetRawDataResource(IDR_DIR_HEADER_HTML); @@ -63,7 +65,7 @@ static base::StringPiece PlatformResourceProvider(int key) { void ContentMainDelegateQt::PreSandboxStartup() { net::NetModule::SetResourceProvider(PlatformResourceProvider); - ui::ResourceBundle::InitSharedInstanceWithLocale(l10n_util::GetApplicationLocale(std::string("en-US")), 0); + ui::ResourceBundle::InitSharedInstanceWithLocale(QLocale().name().toStdString(), 0); // Suppress info, warning and error messages per default. int logLevel = logging::LOG_FATAL; diff --git a/src/core/core_gyp_generator.pro b/src/core/core_gyp_generator.pro index 3817c334b..ae2422957 100644 --- a/src/core/core_gyp_generator.pro +++ b/src/core/core_gyp_generator.pro @@ -11,7 +11,7 @@ TEMPLATE = lib # gyp/ninja will take care of the compilation, qmake/make will finish with linking and install. TARGET = QtWebEngineCore QT += qml quick -QT_PRIVATE += gui-private +QT_PRIVATE += quick-private gui-private core-private # Defining keywords such as 'signal' clashes with the chromium code base. DEFINES += QT_NO_KEYWORDS \ @@ -35,6 +35,7 @@ SOURCES = \ access_token_store_qt.cpp \ browser_accessibility_manager_qt.cpp \ browser_accessibility_qt.cpp \ + browser_context_adapter.cpp \ browser_context_qt.cpp \ certificate_error_controller.cpp \ chromium_gpu_helper.cpp \ @@ -83,6 +84,8 @@ HEADERS = \ access_token_store_qt.h \ browser_accessibility_manager_qt.h \ browser_accessibility_qt.h \ + browser_context_adapter.h \ + browser_context_adapter_client.h \ browser_context_qt.h \ certificate_error_controller_p.h \ certificate_error_controller.h \ @@ -116,6 +119,7 @@ HEADERS = \ resource_dispatcher_host_delegate_qt.h \ stream_video_node.h \ surface_factory_qt.h \ + type_conversion.h \ url_request_context_getter_qt.h \ url_request_qrc_job_qt.h \ web_contents_adapter.h \ @@ -130,3 +134,10 @@ HEADERS = \ web_engine_visited_links_manager.h \ web_event_factory.h \ yuv_video_node.h + +qtHaveModule(positioning) { + SOURCES += location_provider_qt.cpp + HEADERS += location_provider_qt.h + DEFINES += QT_USE_POSITIONING=1 + QT += positioning +} diff --git a/src/core/core_module.pro b/src/core/core_module.pro index 8e445bd3a..e6933cc4b 100644 --- a/src/core/core_module.pro +++ b/src/core/core_module.pro @@ -1,8 +1,9 @@ MODULE = webenginecore TARGET = QtWebEngineCore +qtHaveModule(positioning):QT += positioning QT += qml quick -QT_PRIVATE += gui-private +QT_PRIVATE += quick-private gui-private core-private # Needed to set a CFBundleIdentifier QMAKE_INFO_PLIST = Info_mac.plist diff --git a/src/core/delegated_frame_node.cpp b/src/core/delegated_frame_node.cpp index e12873c81..8d09794be 100644 --- a/src/core/delegated_frame_node.cpp +++ b/src/core/delegated_frame_node.cpp @@ -55,6 +55,7 @@ #include "base/bind.h" #include "cc/output/delegated_frame_data.h" #include "cc/quads/checkerboard_draw_quad.h" +#include "cc/quads/debug_border_draw_quad.h" #include "cc/quads/draw_quad.h" #include "cc/quads/render_pass_draw_quad.h" #include "cc/quads/solid_color_draw_quad.h" @@ -62,80 +63,60 @@ #include "cc/quads/texture_draw_quad.h" #include "cc/quads/tile_draw_quad.h" #include "cc/quads/yuv_video_draw_quad.h" +#include "content/common/host_shared_bitmap_manager.h" #include <QOpenGLContext> -#include <QOpenGLFramebufferObject> #include <QOpenGLFunctions> -#include <QSGAbstractRenderer> -#include <QSGEngine> #include <QSGSimpleRectNode> #include <QSGSimpleTextureNode> #include <QSGTexture> +#include <private/qsgadaptationlayer_p.h> #if !defined(QT_NO_EGL) #include <EGL/egl.h> #include <EGL/eglext.h> #endif -class RenderPassTexture : public QSGTexture, protected QOpenGLFunctions -{ -public: - RenderPassTexture(const cc::RenderPass::Id &id); - - const cc::RenderPass::Id &id() const { return m_id; } - void bind(); - - int textureId() const { return m_fbo ? m_fbo->texture() : 0; } - QSize textureSize() const { return m_rect.size(); } - bool hasAlphaChannel() const { return m_format != GL_RGB; } - bool hasMipmaps() const { return false; } - - void setRect(const QRect &rect) { m_rect = rect; } - void setFormat(GLenum format) { m_format = format; } - QSGNode *rootNode() { return m_rootNode.data(); } - - void grab(); - -private: - cc::RenderPass::Id m_id; - QRect m_rect; - GLenum m_format; - - QScopedPointer<QSGEngine> m_sgEngine; - QScopedPointer<QSGRootNode> m_rootNode; - QScopedPointer<QSGAbstractRenderer> m_renderer; - QScopedPointer<QOpenGLFramebufferObject> m_fbo; -}; - class MailboxTexture : public QSGTexture, protected QOpenGLFunctions { public: - MailboxTexture(const cc::TransferableResource &resource); + MailboxTexture(const gpu::MailboxHolder &mailboxHolder, const QSize textureSize); virtual int textureId() const Q_DECL_OVERRIDE { return m_textureId; } - void setTextureSize(const QSize& size) { m_textureSize = size; } virtual QSize textureSize() const Q_DECL_OVERRIDE { return m_textureSize; } virtual bool hasAlphaChannel() const Q_DECL_OVERRIDE { return m_hasAlpha; } void setHasAlphaChannel(bool hasAlpha) { m_hasAlpha = hasAlpha; } virtual bool hasMipmaps() const Q_DECL_OVERRIDE { return false; } virtual void bind() Q_DECL_OVERRIDE; - bool needsToFetch() const { return !m_textureId; } - cc::TransferableResource &resource() { return m_resource; } - cc::ReturnedResource returnResource(); + gpu::MailboxHolder &mailboxHolder() { return m_mailboxHolder; } void fetchTexture(gpu::gles2::MailboxManager *mailboxManager); void setTarget(GLenum target); - void incImportCount() { ++m_importCount; } private: - cc::TransferableResource m_resource; + gpu::MailboxHolder m_mailboxHolder; int m_textureId; QSize m_textureSize; bool m_hasAlpha; GLenum m_target; - int m_importCount; #ifdef Q_OS_QNX EGLStreamData m_eglStreamData; #endif }; +class ResourceHolder { +public: + ResourceHolder(const cc::TransferableResource &resource); + QSharedPointer<QSGTexture> initTexture(bool quadIsAllOpaque, RenderWidgetHostViewQtDelegate *apiDelegate = 0); + QSGTexture *texture() const { return m_texture.data(); } + cc::TransferableResource &transferableResource() { return m_resource; } + cc::ReturnedResource returnResource(); + void incImportCount() { ++m_importCount; } + bool needsToFetch() const { return !m_resource.is_software && m_texture && !m_texture.data()->textureId(); } + +private: + QWeakPointer<QSGTexture> m_texture; + cc::TransferableResource m_resource; + int m_importCount; +}; + class RectClipNode : public QSGClipNode { public: @@ -144,23 +125,13 @@ private: QSGGeometry m_geometry; }; -static inline QSharedPointer<RenderPassTexture> findRenderPassTexture(const cc::RenderPass::Id &id, const QList<QSharedPointer<RenderPassTexture> > &list) -{ - Q_FOREACH (const QSharedPointer<RenderPassTexture> &texture, list) - if (texture->id() == id) - return texture; - return QSharedPointer<RenderPassTexture>(); -} - -static inline QSharedPointer<MailboxTexture> &findMailboxTexture(unsigned resourceId - , QHash<unsigned, QSharedPointer<MailboxTexture> > &usedTextures - , QHash<unsigned, QSharedPointer<MailboxTexture> > &candidateTextures) +static inline QSharedPointer<QSGLayer> findRenderPassLayer(const cc::RenderPass::Id &id, const QList<QPair<cc::RenderPass::Id, QSharedPointer<QSGLayer> > > &list) { - QSharedPointer<MailboxTexture> &texture = usedTextures[resourceId]; - if (!texture) - texture = candidateTextures.take(resourceId); - Q_ASSERT(texture); - return texture; + typedef QPair<cc::RenderPass::Id, QSharedPointer<QSGLayer> > Pair; + Q_FOREACH (const Pair &pair, list) + if (pair.first == id) + return pair.second; + return QSharedPointer<QSGLayer>(); } static QSGNode *buildRenderPassChain(QSGNode *chainParent) @@ -294,59 +265,20 @@ static void deleteChromiumSync(gfx::TransferableFence *sync) Q_ASSERT(!*sync); } -RenderPassTexture::RenderPassTexture(const cc::RenderPass::Id &id) - : QSGTexture() - , m_id(id) - , m_format(GL_RGBA) - , m_sgEngine(new QSGEngine) - , m_rootNode(new QSGRootNode) -{ - initializeOpenGLFunctions(); -} - -void RenderPassTexture::bind() -{ - glBindTexture(GL_TEXTURE_2D, m_fbo ? m_fbo->texture() : 0); - updateBindOptions(); -} - -void RenderPassTexture::grab() -{ - if (!m_renderer) { - m_sgEngine->initialize(QOpenGLContext::currentContext()); - m_renderer.reset(m_sgEngine->createRenderer()); - m_renderer->setRootNode(m_rootNode.data()); - } - - if (!m_fbo || m_fbo->size() != m_rect.size() || m_fbo->format().internalTextureFormat() != m_format) - { - QOpenGLFramebufferObjectFormat format; - format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); - format.setInternalTextureFormat(m_format); - - m_fbo.reset(new QOpenGLFramebufferObject(m_rect.size(), format)); - glBindTexture(GL_TEXTURE_2D, m_fbo->texture()); - updateBindOptions(true); - } - - m_renderer->setDeviceRect(m_rect.size()); - m_renderer->setViewportRect(m_rect.size()); - QRectF mirrored(m_rect.left(), m_rect.bottom(), m_rect.width(), -m_rect.height()); - m_renderer->setProjectionMatrixToRect(mirrored); - m_renderer->setClearColor(Qt::transparent); - - m_renderer->renderScene(m_fbo->handle()); -} - -MailboxTexture::MailboxTexture(const cc::TransferableResource &resource) - : m_resource(resource) +MailboxTexture::MailboxTexture(const gpu::MailboxHolder &mailboxHolder, const QSize textureSize) + : m_mailboxHolder(mailboxHolder) , m_textureId(0) - , m_textureSize(toQt(resource.size)) + , m_textureSize(textureSize) , m_hasAlpha(false) , m_target(GL_TEXTURE_2D) - , m_importCount(1) { initializeOpenGLFunctions(); + + // Assume that resources without a size will be used with a full source rect. + // Setting a size of 1x1 will let any texture node compute a normalized source + // rect of (0, 0) to (1, 1) while an empty texture size would set (0, 0) on all corners. + if (m_textureSize.isEmpty()) + m_textureSize = QSize(1, 1); } void MailboxTexture::bind() @@ -373,7 +305,55 @@ void MailboxTexture::setTarget(GLenum target) m_target = target; } -cc::ReturnedResource MailboxTexture::returnResource() +void MailboxTexture::fetchTexture(gpu::gles2::MailboxManager *mailboxManager) +{ + gpu::gles2::Texture *tex = ConsumeTexture(mailboxManager, m_target, m_mailboxHolder.mailbox); + + // The texture might already have been deleted (e.g. when navigating away from a page). + if (tex) { + m_textureId = service_id(tex); +#ifdef Q_OS_QNX + if (m_target == GL_TEXTURE_EXTERNAL_OES) { + m_eglStreamData = eglstream_connect_consumer(tex); + } +#endif + } +} + +ResourceHolder::ResourceHolder(const cc::TransferableResource &resource) + : m_resource(resource) + , m_importCount(1) +{ +} + +QSharedPointer<QSGTexture> ResourceHolder::initTexture(bool quadNeedsBlending, RenderWidgetHostViewQtDelegate *apiDelegate) +{ + QSharedPointer<QSGTexture> texture = m_texture.toStrongRef(); + if (!texture) { + if (m_resource.is_software) { + Q_ASSERT(apiDelegate); + scoped_ptr<cc::SharedBitmap> sharedBitmap = content::HostSharedBitmapManager::current()->GetSharedBitmapFromId(m_resource.size, m_resource.mailbox_holder.mailbox); + // QSG interprets QImage::hasAlphaChannel meaning that a node should enable blending + // to draw it but Chromium keeps this information in the quads. + // The input format is currently always Format_ARGB32_Premultiplied, so assume that all + // alpha bytes are 0xff if quads aren't requesting blending and avoid the conversion + // from Format_ARGB32_Premultiplied to Format_RGB32 just to get hasAlphaChannel to + // return false. + QImage::Format format = quadNeedsBlending ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32; + QImage image(sharedBitmap->pixels(), m_resource.size.width(), m_resource.size.height(), format); + texture.reset(apiDelegate->createTextureFromImage(image.copy())); + } else { + texture.reset(new MailboxTexture(m_resource.mailbox_holder, toQt(m_resource.size))); + static_cast<MailboxTexture *>(texture.data())->setHasAlphaChannel(quadNeedsBlending); + } + m_texture = texture; + } + // All quads using a resource should request the same blending state. + Q_ASSERT(texture->hasAlphaChannel() || !quadNeedsBlending); + return texture; +} + +cc::ReturnedResource ResourceHolder::returnResource() { cc::ReturnedResource returned; // The ResourceProvider ensures that the resource isn't used by the parent compositor's GL @@ -389,20 +369,6 @@ cc::ReturnedResource MailboxTexture::returnResource() return returned; } -void MailboxTexture::fetchTexture(gpu::gles2::MailboxManager *mailboxManager) -{ - gpu::gles2::Texture *tex = ConsumeTexture(mailboxManager, m_target, m_resource.mailbox_holder.mailbox); - - // The texture might already have been deleted (e.g. when navigating away from a page). - if (tex) { - m_textureId = service_id(tex); -#ifdef Q_OS_QNX - if (m_target == GL_TEXTURE_EXTERNAL_OES) { - m_eglStreamData = eglstream_connect_consumer(tex); - } -#endif - } -} RectClipNode::RectClipNode(const QRectF &rect) : m_geometry(QSGGeometry::defaultAttributes_Point2D(), 4) @@ -429,9 +395,12 @@ void DelegatedFrameNode::preprocess() // We can now wait for the Chromium GPU thread to produce textures that will be // rendered on our quads and fetch the IDs from the mailboxes we were given. QList<MailboxTexture *> mailboxesToFetch; - Q_FOREACH (const QSharedPointer<MailboxTexture> &mailboxTexture, m_data->mailboxTextures.values()) - if (mailboxTexture->needsToFetch()) - mailboxesToFetch.append(mailboxTexture.data()); + typedef QHash<unsigned, QSharedPointer<ResourceHolder> >::const_iterator ResourceHolderIterator; + ResourceHolderIterator end = m_chromiumCompositorData->resourceHolders.constEnd(); + for (ResourceHolderIterator it = m_chromiumCompositorData->resourceHolders.constBegin(); it != end ; ++it) { + if ((*it)->needsToFetch()) + mailboxesToFetch.append(static_cast<MailboxTexture *>((*it)->texture())); + } if (!mailboxesToFetch.isEmpty()) { QMap<uint32, gfx::TransferableFence> transferredFences; @@ -442,7 +411,7 @@ void DelegatedFrameNode::preprocess() Q_FOREACH (MailboxTexture *mailboxTexture, mailboxesToFetch) { m_numPendingSyncPoints++; - AddSyncPointCallbackOnGpuThread(gpuMessageLoop, syncPointManager, mailboxTexture->resource().mailbox_holder.sync_point, base::Bind(&DelegatedFrameNode::syncPointRetired, this, &mailboxesToFetch)); + AddSyncPointCallbackOnGpuThread(gpuMessageLoop, syncPointManager, mailboxTexture->mailboxHolder().sync_point, base::Bind(&DelegatedFrameNode::syncPointRetired, this, &mailboxesToFetch)); } m_mailboxesFetchedWaitCond.wait(&m_mutex); @@ -452,7 +421,7 @@ void DelegatedFrameNode::preprocess() // Tell GL to wait until Chromium is done generating resource textures on the GPU thread // for each mailbox. We can safely start referencing those textures onto geometries afterward. Q_FOREACH (MailboxTexture *mailboxTexture, mailboxesToFetch) { - gfx::TransferableFence fence = transferredFences.take(mailboxTexture->resource().mailbox_holder.sync_point); + gfx::TransferableFence fence = transferredFences.take(mailboxTexture->mailboxHolder().sync_point); waitChromiumSync(&fence); deleteChromiumSync(&fence); } @@ -464,14 +433,19 @@ void DelegatedFrameNode::preprocess() } // Then render any intermediate RenderPass in order. - Q_FOREACH (const QSharedPointer<RenderPassTexture> &renderPass, m_renderPassTextures) - renderPass->grab(); + typedef QPair<cc::RenderPass::Id, QSharedPointer<QSGLayer> > Pair; + Q_FOREACH (const Pair &pair, m_sgObjects.renderPassLayers) { + // The layer is non-live, request a one-time update here. + pair.second->scheduleUpdate(); + // Proceed with the actual update. + pair.second->updateTexture(); + } } -void DelegatedFrameNode::commit(DelegatedFrameNodeData* data, cc::ReturnedResourceArray *resourcesToRelease) +void DelegatedFrameNode::commit(ChromiumCompositorData *chromiumCompositorData, cc::ReturnedResourceArray *resourcesToRelease, RenderWidgetHostViewQtDelegate *apiDelegate) { - m_data = data; - cc::DelegatedFrameData* frameData = m_data->frameData.get(); + m_chromiumCompositorData = chromiumCompositorData; + cc::DelegatedFrameData* frameData = m_chromiumCompositorData->frameData.get(); if (!frameData) return; @@ -479,14 +453,15 @@ void DelegatedFrameNode::commit(DelegatedFrameNodeData* data, cc::ReturnedResour // countering the scale of devicePixel-scaled tiles when rendering them // to the final surface. QMatrix4x4 matrix; - matrix.scale(1 / m_data->frameDevicePixelRatio, 1 / m_data->frameDevicePixelRatio); + matrix.scale(1 / m_chromiumCompositorData->frameDevicePixelRatio, 1 / m_chromiumCompositorData->frameDevicePixelRatio); setMatrix(matrix); - // Keep the old texture lists around to find the ones we can re-use. - QList<QSharedPointer<RenderPassTexture> > oldRenderPassTextures; - m_renderPassTextures.swap(oldRenderPassTextures); - QHash<unsigned, QSharedPointer<MailboxTexture> > mailboxTextureCandidates; - m_data->mailboxTextures.swap(mailboxTextureCandidates); + // Keep the old objects in scope to hold a ref on layers, resources and textures + // that we can re-use. Destroy the remaining objects before returning. + SGObjects previousSGObjects; + qSwap(m_sgObjects, previousSGObjects); + QHash<unsigned, QSharedPointer<ResourceHolder> > resourceCandidates; + qSwap(m_chromiumCompositorData->resourceHolders, resourceCandidates); // A frame's resource_list only contains the new resources to be added to the scene. Quads can // still reference resources that were added in previous frames. Add them to the list of @@ -494,14 +469,21 @@ void DelegatedFrameNode::commit(DelegatedFrameNodeData* data, cc::ReturnedResour // to the producing child compositor. for (unsigned i = 0; i < frameData->resource_list.size(); ++i) { const cc::TransferableResource &res = frameData->resource_list.at(i); - if (QSharedPointer<MailboxTexture> texture = mailboxTextureCandidates.value(res.id)) - texture->incImportCount(); + if (QSharedPointer<ResourceHolder> resource = resourceCandidates.value(res.id)) + resource->incImportCount(); else - mailboxTextureCandidates[res.id] = QSharedPointer<MailboxTexture>(new MailboxTexture(res)); + resourceCandidates[res.id] = QSharedPointer<ResourceHolder>(new ResourceHolder(res)); } frameData->resource_list.clear(); + // There is currently no way to know which and how quads changed since the last frame. + // We have to reconstruct the node chain with their geometries on every update. + // Intermediate render pass node chains are going to be destroyed when previousSGObjects + // goes out of scope together with any QSGLayer that could reference them. + while (QSGNode *oldChain = firstChild()) + delete oldChain; + // The RenderPasses list is actually a tree where a parent RenderPass is connected // to its dependencies through a RenderPass::Id reference in one or more RenderPassQuads. // The list is already ordered with intermediate RenderPasses placed before their @@ -515,21 +497,24 @@ void DelegatedFrameNode::commit(DelegatedFrameNodeData* data, cc::ReturnedResour QSGNode *renderPassParent = 0; if (pass != rootRenderPass) { - QSharedPointer<RenderPassTexture> rpTexture = findRenderPassTexture(pass->id, oldRenderPassTextures); - if (!rpTexture) - rpTexture = QSharedPointer<RenderPassTexture>(new RenderPassTexture(pass->id)); - m_renderPassTextures.append(rpTexture); - rpTexture->setRect(toQt(pass->output_rect)); - rpTexture->setFormat(pass->has_transparent_background ? GL_RGBA : GL_RGB); - renderPassParent = rpTexture->rootNode(); + QSharedPointer<QSGLayer> rpLayer = findRenderPassLayer(pass->id, previousSGObjects.renderPassLayers); + if (!rpLayer) { + rpLayer = QSharedPointer<QSGLayer>(apiDelegate->createLayer()); + // Avoid any premature texture update since we need to wait + // for the GPU thread to produce the dependent resources first. + rpLayer->setLive(false); + } + QSharedPointer<QSGRootNode> rootNode(new QSGRootNode); + rpLayer->setRect(toQt(pass->output_rect)); + rpLayer->setSize(toQt(pass->output_rect.size())); + rpLayer->setFormat(pass->has_transparent_background ? GL_RGBA : GL_RGB); + rpLayer->setItem(rootNode.data()); + m_sgObjects.renderPassLayers.append(QPair<cc::RenderPass::Id, QSharedPointer<QSGLayer> >(pass->id, rpLayer)); + m_sgObjects.renderPassRootNodes.append(rootNode); + renderPassParent = rootNode.data(); } else renderPassParent = this; - // There is currently no way to know which and how quads changed since the last frame. - // We have to reconstruct the node chain with their geometries on every update. - while (QSGNode *oldChain = renderPassParent->firstChild()) - delete oldChain; - QSGNode *renderPassChain = buildRenderPassChain(renderPassParent); const cc::SharedQuadState *currentLayerState = 0; QSGNode *currentLayerChain = 0; @@ -555,37 +540,28 @@ void DelegatedFrameNode::commit(DelegatedFrameNodeData* data, cc::ReturnedResour break; } case cc::DrawQuad::RENDER_PASS: { const cc::RenderPassDrawQuad *renderPassQuad = cc::RenderPassDrawQuad::MaterialCast(quad); - QSGTexture *texture = findRenderPassTexture(renderPassQuad->render_pass_id, m_renderPassTextures).data(); + QSGTexture *layer = findRenderPassLayer(renderPassQuad->render_pass_id, m_sgObjects.renderPassLayers).data(); // cc::GLRenderer::DrawRenderPassQuad silently ignores missing render passes. - if (!texture) + if (!layer) continue; - QSGSimpleTextureNode *textureNode = new QSGSimpleTextureNode; - textureNode->setRect(toQt(quad->rect)); - textureNode->setTexture(texture); - currentLayerChain->appendChildNode(textureNode); + // Only QSGImageNode currently supports QSGLayer textures. + QSGImageNode *imageNode = apiDelegate->createImageNode(); + imageNode->setTargetRect(toQt(quad->rect)); + imageNode->setInnerTargetRect(toQt(quad->rect)); + imageNode->setTexture(layer); + imageNode->update(); + currentLayerChain->appendChildNode(imageNode); break; } case cc::DrawQuad::TEXTURE_CONTENT: { const cc::TextureDrawQuad *tquad = cc::TextureDrawQuad::MaterialCast(quad); - QSharedPointer<MailboxTexture> &texture = findMailboxTexture(tquad->resource_id, m_data->mailboxTextures, mailboxTextureCandidates); - - // FIXME: TransferableResource::size isn't always set properly for TextureDrawQuads, use the size of its DrawQuad::rect instead. - texture->setTextureSize(toQt(quad->rect.size())); - - // TransferableResource::format seems to always be GL_BGRA even though it might not - // contain any pixel with alpha < 1.0. The information about if they need blending - // for the contents itself is actually stored in quads. - // Tell the scene graph to enable blending for a texture only when at least one quad asks for it. - // Do not rely on DrawQuad::ShouldDrawWithBlending() since the shared_quad_state->opacity - // case will be handled by QtQuick by fetching this information from QSGOpacityNodes. - if (!quad->visible_rect.IsEmpty() && !quad->opaque_rect.Contains(quad->visible_rect)) - texture->setHasAlphaChannel(true); + ResourceHolder *resource = findAndHoldResource(tquad->resource_id, resourceCandidates); QSGSimpleTextureNode *textureNode = new QSGSimpleTextureNode; textureNode->setTextureCoordinatesTransform(tquad->flipped ? QSGSimpleTextureNode::MirrorVertically : QSGSimpleTextureNode::NoTransform); textureNode->setRect(toQt(quad->rect)); - textureNode->setFiltering(texture->resource().filter == GL_LINEAR ? QSGTexture::Linear : QSGTexture::Nearest); - textureNode->setTexture(texture.data()); + textureNode->setFiltering(resource->transferableResource().filter == GL_LINEAR ? QSGTexture::Linear : QSGTexture::Nearest); + textureNode->setTexture(initAndHoldTexture(resource, quad->ShouldDrawWithBlending(), apiDelegate)); currentLayerChain->appendChildNode(textureNode); break; } case cc::DrawQuad::SOLID_COLOR: { @@ -601,46 +577,67 @@ void DelegatedFrameNode::commit(DelegatedFrameNodeData* data, cc::ReturnedResour rectangleNode->setColor(toQt(scquad->color)); currentLayerChain->appendChildNode(rectangleNode); break; + } case cc::DrawQuad::DEBUG_BORDER: { + const cc::DebugBorderDrawQuad *dbquad = cc::DebugBorderDrawQuad::MaterialCast(quad); + QSGGeometryNode *geometryNode = new QSGGeometryNode; + + QSGGeometry *geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 4); + geometry->setDrawingMode(GL_LINE_LOOP); + geometry->setLineWidth(dbquad->width); + // QSGGeometry::updateRectGeometry would actually set the corners in the following order: + // top-left, bottom-left, top-right, bottom-right, leading to a nice criss cross, instead + // of having a closed loop. + const gfx::Rect &r(dbquad->rect); + geometry->vertexDataAsPoint2D()[0].set(r.x(), r.y()); + geometry->vertexDataAsPoint2D()[1].set(r.x() + r.width(), r.y()); + geometry->vertexDataAsPoint2D()[2].set(r.x() + r.width(), r.y() + r.height()); + geometry->vertexDataAsPoint2D()[3].set(r.x(), r.y() + r.height()); + geometryNode->setGeometry(geometry); + + QSGFlatColorMaterial *material = new QSGFlatColorMaterial; + material->setColor(toQt(dbquad->color)); + geometryNode->setMaterial(material); + + geometryNode->setFlags(QSGNode::OwnsGeometry | QSGNode::OwnsMaterial); + currentLayerChain->appendChildNode(geometryNode); + break; } case cc::DrawQuad::TILED_CONTENT: { const cc::TileDrawQuad *tquad = cc::TileDrawQuad::MaterialCast(quad); - QSharedPointer<MailboxTexture> &texture = findMailboxTexture(tquad->resource_id, m_data->mailboxTextures, mailboxTextureCandidates); - - if (!quad->visible_rect.IsEmpty() && !quad->opaque_rect.Contains(quad->visible_rect)) - texture->setHasAlphaChannel(true); + ResourceHolder *resource = findAndHoldResource(tquad->resource_id, resourceCandidates); QSGSimpleTextureNode *textureNode = new QSGSimpleTextureNode; textureNode->setRect(toQt(quad->rect)); - textureNode->setFiltering(texture->resource().filter == GL_LINEAR ? QSGTexture::Linear : QSGTexture::Nearest); - textureNode->setTexture(texture.data()); - - // FIXME: Find out if we can implement a QSGSimpleTextureNode::setSourceRect instead of this hack. - // This has to be done at the end since many QSGSimpleTextureNode methods would overwrite this. - QSGGeometry::updateTexturedRectGeometry(textureNode->geometry(), textureNode->rect(), textureNode->texture()->convertToNormalizedSourceRect(toQt(tquad->tex_coord_rect))); + textureNode->setSourceRect(toQt(tquad->tex_coord_rect)); + textureNode->setFiltering(resource->transferableResource().filter == GL_LINEAR ? QSGTexture::Linear : QSGTexture::Nearest); + textureNode->setTexture(initAndHoldTexture(resource, quad->ShouldDrawWithBlending(), apiDelegate)); currentLayerChain->appendChildNode(textureNode); break; } case cc::DrawQuad::YUV_VIDEO_CONTENT: { const cc::YUVVideoDrawQuad *vquad = cc::YUVVideoDrawQuad::MaterialCast(quad); - QSharedPointer<MailboxTexture> &yTexture = findMailboxTexture(vquad->y_plane_resource_id, m_data->mailboxTextures, mailboxTextureCandidates); - QSharedPointer<MailboxTexture> &uTexture = findMailboxTexture(vquad->u_plane_resource_id, m_data->mailboxTextures, mailboxTextureCandidates); - QSharedPointer<MailboxTexture> &vTexture = findMailboxTexture(vquad->v_plane_resource_id, m_data->mailboxTextures, mailboxTextureCandidates); - - // Do not use a reference for this one, it might be null. - QSharedPointer<MailboxTexture> aTexture; + ResourceHolder *yResource = findAndHoldResource(vquad->y_plane_resource_id, resourceCandidates); + ResourceHolder *uResource = findAndHoldResource(vquad->u_plane_resource_id, resourceCandidates); + ResourceHolder *vResource = findAndHoldResource(vquad->v_plane_resource_id, resourceCandidates); + ResourceHolder *aResource = 0; // This currently requires --enable-vp8-alpha-playback and needs a video with alpha data to be triggered. if (vquad->a_plane_resource_id) - aTexture = findMailboxTexture(vquad->a_plane_resource_id, m_data->mailboxTextures, mailboxTextureCandidates); + aResource = findAndHoldResource(vquad->a_plane_resource_id, resourceCandidates); - YUVVideoNode *videoNode = new YUVVideoNode(yTexture.data(), uTexture.data(), vTexture.data(), aTexture.data(), toQt(vquad->tex_coord_rect)); + YUVVideoNode *videoNode = new YUVVideoNode( + initAndHoldTexture(yResource, quad->ShouldDrawWithBlending()), + initAndHoldTexture(uResource, quad->ShouldDrawWithBlending()), + initAndHoldTexture(vResource, quad->ShouldDrawWithBlending()), + aResource ? initAndHoldTexture(aResource, quad->ShouldDrawWithBlending()) : 0, toQt(vquad->tex_coord_rect)); videoNode->setRect(toQt(quad->rect)); currentLayerChain->appendChildNode(videoNode); break; #ifdef GL_OES_EGL_image_external } case cc::DrawQuad::STREAM_VIDEO_CONTENT: { const cc::StreamVideoDrawQuad *squad = cc::StreamVideoDrawQuad::MaterialCast(quad); - QSharedPointer<MailboxTexture> &texture = findMailboxTexture(squad->resource_id, m_data->mailboxTextures, mailboxTextureCandidates); + ResourceHolder *resource = findAndHoldResource(squad->resource_id, resourceCandidates); + 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.data()); + StreamVideoNode *svideoNode = new StreamVideoNode(texture); svideoNode->setRect(toQt(squad->rect)); svideoNode->setTextureMatrix(toQt(squad->matrix.matrix())); currentLayerChain->appendChildNode(svideoNode); @@ -653,8 +650,30 @@ void DelegatedFrameNode::commit(DelegatedFrameNodeData* data, cc::ReturnedResour } // Send resources of remaining candidates back to the child compositors so that they can be freed or reused. - Q_FOREACH (const QSharedPointer<MailboxTexture> &mailboxTexture, mailboxTextureCandidates.values()) - resourcesToRelease->push_back(mailboxTexture->returnResource()); + typedef QHash<unsigned, QSharedPointer<ResourceHolder> >::const_iterator ResourceHolderIterator; + ResourceHolderIterator end = resourceCandidates.constEnd(); + for (ResourceHolderIterator it = resourceCandidates.constBegin(); it != end ; ++it) + resourcesToRelease->push_back((*it)->returnResource()); +} + +ResourceHolder *DelegatedFrameNode::findAndHoldResource(unsigned resourceId, QHash<unsigned, QSharedPointer<ResourceHolder> > &candidates) +{ + // ResourceHolders must survive when the scene graph destroys our node branch + QSharedPointer<ResourceHolder> &resource = m_chromiumCompositorData->resourceHolders[resourceId]; + if (!resource) + resource = candidates.take(resourceId); + Q_ASSERT(resource); + return resource.data(); +} + +QSGTexture *DelegatedFrameNode::initAndHoldTexture(ResourceHolder *resource, bool quadIsAllOpaque, RenderWidgetHostViewQtDelegate *apiDelegate) +{ + // QSGTextures must be destroyed in the scene graph thread as part of the QSGNode tree, + // so we can't store them with the ResourceHolder in m_chromiumCompositorData. + // Hold them through a QSharedPointer solely on the root DelegatedFrameNode of the web view + // and access them through a QWeakPointer from the resource holder to find them later. + m_sgObjects.textureStrongRefs.append(resource->initTexture(quadIsAllOpaque, apiDelegate)); + return m_sgObjects.textureStrongRefs.last().data(); } void DelegatedFrameNode::fetchTexturesAndUnlockQt(DelegatedFrameNode *frameNode, QList<MailboxTexture *> *mailboxesToFetch) diff --git a/src/core/delegated_frame_node.h b/src/core/delegated_frame_node.h index a031a464f..b866c94b4 100644 --- a/src/core/delegated_frame_node.h +++ b/src/core/delegated_frame_node.h @@ -38,6 +38,7 @@ #define DELEGATED_FRAME_NODE_H #include "base/memory/scoped_ptr.h" +#include "cc/quads/render_pass.h" #include "cc/resources/transferable_resource.h" #include <QMutex> #include <QSGNode> @@ -46,20 +47,25 @@ #include <QWaitCondition> #include "chromium_gpu_helper.h" +#include "render_widget_host_view_qt_delegate.h" + +QT_BEGIN_NAMESPACE +class QSGLayer; +QT_END_NAMESPACE namespace cc { class DelegatedFrameData; } class MailboxTexture; -class RenderPassTexture; +class ResourceHolder; // Separating this data allows another DelegatedFrameNode to reconstruct the QSGNode tree from the mailbox textures // and render pass information. -class DelegatedFrameNodeData : public QSharedData { +class ChromiumCompositorData : public QSharedData { public: - DelegatedFrameNodeData() : frameDevicePixelRatio(1) { } - QHash<unsigned, QSharedPointer<MailboxTexture> > mailboxTextures; + ChromiumCompositorData() : frameDevicePixelRatio(1) { } + QHash<unsigned, QSharedPointer<ResourceHolder> > resourceHolders; scoped_ptr<cc::DelegatedFrameData> frameData; qreal frameDevicePixelRatio; }; @@ -69,20 +75,27 @@ public: DelegatedFrameNode(); ~DelegatedFrameNode(); void preprocess(); - void commit(DelegatedFrameNodeData* data, cc::ReturnedResourceArray *resourcesToRelease); + void commit(ChromiumCompositorData *chromiumCompositorData, cc::ReturnedResourceArray *resourcesToRelease, RenderWidgetHostViewQtDelegate *apiDelegate); private: - QExplicitlySharedDataPointer<DelegatedFrameNodeData> m_data; - QList<QSharedPointer<RenderPassTexture> > m_renderPassTextures; - int m_numPendingSyncPoints; - QMap<uint32, gfx::TransferableFence> m_mailboxGLFences; - QWaitCondition m_mailboxesFetchedWaitCond; - QMutex m_mutex; - // Making those callbacks static bypasses base::Bind's ref-counting requirement // of the this pointer when the callback is a method. static void fetchTexturesAndUnlockQt(DelegatedFrameNode *frameNode, QList<MailboxTexture *> *mailboxesToFetch); static void syncPointRetired(DelegatedFrameNode *frameNode, QList<MailboxTexture *> *mailboxesToFetch); + + ResourceHolder *findAndHoldResource(unsigned resourceId, QHash<unsigned, QSharedPointer<ResourceHolder> > &candidates); + QSGTexture *initAndHoldTexture(ResourceHolder *resource, bool quadIsAllOpaque, RenderWidgetHostViewQtDelegate *apiDelegate = 0); + + QExplicitlySharedDataPointer<ChromiumCompositorData> m_chromiumCompositorData; + struct SGObjects { + QList<QPair<cc::RenderPass::Id, QSharedPointer<QSGLayer> > > renderPassLayers; + QList<QSharedPointer<QSGRootNode> > renderPassRootNodes; + QList<QSharedPointer<QSGTexture> > textureStrongRefs; + } m_sgObjects; + int m_numPendingSyncPoints; + QMap<uint32, gfx::TransferableFence> m_mailboxGLFences; + QWaitCondition m_mailboxesFetchedWaitCond; + QMutex m_mutex; }; #endif // DELEGATED_FRAME_NODE_H diff --git a/src/core/dev_tools_http_handler_delegate_qt.cpp b/src/core/dev_tools_http_handler_delegate_qt.cpp index 4f8992dab..1bb8ec1f1 100644 --- a/src/core/dev_tools_http_handler_delegate_qt.cpp +++ b/src/core/dev_tools_http_handler_delegate_qt.cpp @@ -34,6 +34,10 @@ ** ****************************************************************************/ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + #include "dev_tools_http_handler_delegate_qt.h" #include <QByteArray> @@ -42,16 +46,90 @@ #include "base/command_line.h" #include "base/files/file_path.h" #include "base/strings/string_number_conversions.h" +#include "base/strings/utf_string_conversions.h" #include "content/public/browser/devtools_agent_host.h" #include "content/public/browser/devtools_http_handler.h" #include "content/public/browser/devtools_target.h" +#include "content/public/browser/favicon_status.h" +#include "content/public/browser/navigation_entry.h" +#include "content/public/browser/render_view_host.h" #include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_delegate.h" #include "content/public/common/content_switches.h" #include "net/socket/stream_listen_socket.h" #include "net/socket/tcp_listen_socket.h" using namespace content; +namespace { + +const char kTargetTypePage[] = "page"; + +class Target : public content::DevToolsTarget { +public: + explicit Target(WebContents* web_contents); + + virtual std::string GetId() const OVERRIDE { return id_; } + virtual std::string GetParentId() const OVERRIDE { return std::string(); } + virtual std::string GetType() const OVERRIDE { return kTargetTypePage; } + virtual std::string GetTitle() const OVERRIDE { return title_; } + virtual std::string GetDescription() const OVERRIDE { return std::string(); } + virtual GURL GetURL() const OVERRIDE { return url_; } + virtual GURL GetFaviconURL() const OVERRIDE { return favicon_url_; } + virtual base::TimeTicks GetLastActivityTime() const OVERRIDE { + return last_activity_time_; + } + virtual bool IsAttached() const OVERRIDE { + return agent_host_->IsAttached(); + } + virtual scoped_refptr<DevToolsAgentHost> GetAgentHost() const OVERRIDE { + return agent_host_; + } + virtual bool Activate() const OVERRIDE; + virtual bool Close() const OVERRIDE; + +private: + scoped_refptr<DevToolsAgentHost> agent_host_; + std::string id_; + std::string title_; + GURL url_; + GURL favicon_url_; + base::TimeTicks last_activity_time_; +}; + +Target::Target(WebContents* web_contents) { + agent_host_ = DevToolsAgentHost::GetOrCreateFor(web_contents->GetRenderViewHost()); + id_ = agent_host_->GetId(); + title_ = base::UTF16ToUTF8(web_contents->GetTitle()); + url_ = web_contents->GetURL(); + content::NavigationController& controller = web_contents->GetController(); + content::NavigationEntry* entry = controller.GetActiveEntry(); + if (entry != NULL && entry->GetURL().is_valid()) + favicon_url_ = entry->GetFavicon().url; + last_activity_time_ = web_contents->GetLastActiveTime(); +} + +bool Target::Activate() const { + RenderViewHost* rvh = agent_host_->GetRenderViewHost(); + if (!rvh) + return false; + WebContents* web_contents = WebContents::FromRenderViewHost(rvh); + if (!web_contents) + return false; + web_contents->GetDelegate()->ActivateContents(web_contents); + return true; +} + +bool Target::Close() const { + RenderViewHost* rvh = agent_host_->GetRenderViewHost(); + if (!rvh) + return false; + rvh->ClosePage(); + return true; +} + +} // namespace + DevToolsHttpHandlerDelegateQt::DevToolsHttpHandlerDelegateQt(BrowserContext* browser_context) : m_browserContext(browser_context) { @@ -107,7 +185,14 @@ scoped_ptr<DevToolsTarget> DevToolsHttpHandlerDelegateQt::CreateNewTarget(const void DevToolsHttpHandlerDelegateQt::EnumerateTargets(TargetCallback callback) { - callback.Run(TargetList()); + TargetList targets; + std::vector<RenderViewHost*> rvh_list = content::DevToolsAgentHost::GetValidRenderViewHosts(); + for (std::vector<RenderViewHost*>::iterator it = rvh_list.begin(); it != rvh_list.end(); ++it) { + WebContents* web_contents = WebContents::FromRenderViewHost(*it); + if (web_contents) + targets.push_back(new Target(web_contents)); + } + callback.Run(targets); } scoped_ptr<net::StreamListenSocket> DevToolsHttpHandlerDelegateQt::CreateSocketForTethering(net::StreamListenSocket::Delegate* delegate, std::string* name) diff --git a/src/core/download_manager_delegate_qt.cpp b/src/core/download_manager_delegate_qt.cpp index 3df03ffa3..3f6ec7bcc 100644 --- a/src/core/download_manager_delegate_qt.cpp +++ b/src/core/download_manager_delegate_qt.cpp @@ -36,6 +36,7 @@ #include "download_manager_delegate_qt.h" +#include "content/public/browser/download_manager.h" #include "content/public/browser/download_item.h" #include "content/public/browser/save_page_type.h" #include "content/public/browser/web_contents.h" @@ -46,115 +47,21 @@ #include <QMap> #include <QStandardPaths> +#include "browser_context_adapter.h" +#include "browser_context_adapter_client.h" +#include "browser_context_qt.h" #include "type_conversion.h" #include "qtwebenginecoreglobal.h" -// Helper class to track currently ongoing downloads to prevent file name -// clashes / overwriting of files. -class DownloadTargetHelper : public content::DownloadItem::Observer { -public: - DownloadTargetHelper() - : m_defaultDownloadDirectory(QStandardPaths::writableLocation(QStandardPaths::DownloadLocation)) - { - - } - virtual ~DownloadTargetHelper() {} - - bool determineDownloadTarget(content::DownloadItem *item, const content::DownloadTargetCallback &callback); - - virtual void OnDownloadUpdated(content::DownloadItem *download) Q_DECL_OVERRIDE; - virtual void OnDownloadDestroyed(content::DownloadItem *download) Q_DECL_OVERRIDE; -private: - bool isPathAvailable(const QString& path); - - QDir m_defaultDownloadDirectory; - QMap<content::DownloadItem*, QString> m_ongoingDownloads; -}; - -bool DownloadTargetHelper::isPathAvailable(const QString& path) -{ - return !m_ongoingDownloads.values().contains(path) && !QFile::exists(path); -} - -bool DownloadTargetHelper::determineDownloadTarget(content::DownloadItem *item, const content::DownloadTargetCallback &callback) -{ - std::string suggestedFilename = item->GetSuggestedFilename(); - - if (suggestedFilename.empty()) - suggestedFilename = item->GetTargetFilePath().AsUTF8Unsafe(); - - if (suggestedFilename.empty()) - suggestedFilename = item->GetURL().ExtractFileName(); - - if (suggestedFilename.empty()) - suggestedFilename = "qwe_download"; - - if (!m_defaultDownloadDirectory.exists() && !m_defaultDownloadDirectory.mkpath(m_defaultDownloadDirectory.absolutePath())) - return false; - - QString suggestedFilePath = m_defaultDownloadDirectory.absoluteFilePath(QString::fromStdString(suggestedFilename)); - if (!isPathAvailable(suggestedFilePath)) { - int i = 1; - for (; i < 99; i++) { - QFileInfo tmpFile(suggestedFilePath); - QString tmpFilePath = QString("%1%2%3(%4).%5").arg(tmpFile.absolutePath()).arg(QDir::separator()).arg(tmpFile.baseName()).arg(i).arg(tmpFile.completeSuffix()); - if (isPathAvailable(tmpFilePath)) { - suggestedFilePath = tmpFilePath; - break; - } - } - if (i >= 99) { - callback.Run(base::FilePath(), content::DownloadItem::TARGET_DISPOSITION_PROMPT, content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT, base::FilePath()); - return false; - } - } - - m_ongoingDownloads.insert(item, suggestedFilePath); - item->AddObserver(this); - - base::FilePath filePathForCallback(toFilePathString(suggestedFilePath)); - callback.Run(filePathForCallback, content::DownloadItem::TARGET_DISPOSITION_OVERWRITE, - content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT, filePathForCallback.AddExtension(toFilePathString("download"))); - return true; -} - -void DownloadTargetHelper::OnDownloadUpdated(content::DownloadItem *download) +DownloadManagerDelegateQt::DownloadManagerDelegateQt(BrowserContextAdapter *contextAdapter) + : m_currentId(0) + , m_contextAdapter(contextAdapter) { - switch (download->GetState()) { - case content::DownloadItem::COMPLETE: - case content::DownloadItem::CANCELLED: - case content::DownloadItem::INTERRUPTED: - download->RemoveObserver(this); - m_ongoingDownloads.remove(download); - break; - case content::DownloadItem::IN_PROGRESS: - default: - break; - } -} - -void DownloadTargetHelper::OnDownloadDestroyed(content::DownloadItem *download) -{ - download->RemoveObserver(this); - m_ongoingDownloads.remove(download); -} - -DownloadManagerDelegateQt::DownloadManagerDelegateQt() - : m_targetHelper(new DownloadTargetHelper()) - , m_currentId(0) -{ - + Q_ASSERT(m_contextAdapter); } DownloadManagerDelegateQt::~DownloadManagerDelegateQt() { - delete m_targetHelper; -} - - -void DownloadManagerDelegateQt::Shutdown() -{ - QT_NOT_YET_IMPLEMENTED } void DownloadManagerDelegateQt::GetNextId(const content::DownloadIdCallback& callback) @@ -162,24 +69,17 @@ void DownloadManagerDelegateQt::GetNextId(const content::DownloadIdCallback& cal callback.Run(++m_currentId); } -bool DownloadManagerDelegateQt::ShouldOpenFileBasedOnExtension(const base::FilePath& path) -{ - QT_NOT_YET_IMPLEMENTED - return false; -} - -bool DownloadManagerDelegateQt::ShouldCompleteDownload(content::DownloadItem* item, - const base::Closure& complete_callback) +void DownloadManagerDelegateQt::cancelDownload(const content::DownloadTargetCallback& callback) { - QT_NOT_YET_IMPLEMENTED - return true; + callback.Run(base::FilePath(), content::DownloadItem::TARGET_DISPOSITION_PROMPT, content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT, base::FilePath()); } -bool DownloadManagerDelegateQt::ShouldOpenDownload(content::DownloadItem* item, - const content::DownloadOpenDelayedCallback& callback) +void DownloadManagerDelegateQt::cancelDownload(quint32 downloadId) { - QT_NOT_YET_IMPLEMENTED - return false; + content::DownloadManager* dlm = content::BrowserContext::GetDownloadManager(m_contextAdapter->browserContext()); + content::DownloadItem *download = dlm->GetDownload(downloadId); + if (download) + download->Cancel(/* user_cancel */ true); } bool DownloadManagerDelegateQt::DetermineDownloadTarget(content::DownloadItem* item, @@ -194,41 +94,55 @@ bool DownloadManagerDelegateQt::DetermineDownloadTarget(content::DownloadItem* i return true; } - // Let the target helper determine the download target path. - return m_targetHelper->determineDownloadTarget(item, callback); -} + std::string suggestedFilename = item->GetSuggestedFilename(); -bool DownloadManagerDelegateQt::GenerateFileHash() -{ - QT_NOT_YET_IMPLEMENTED - return false; -} + if (suggestedFilename.empty()) + suggestedFilename = item->GetTargetFilePath().AsUTF8Unsafe(); -void DownloadManagerDelegateQt::ChooseSavePath( - content::WebContents* web_contents, - const base::FilePath& suggested_path, - const base::FilePath::StringType& default_extension, - bool can_save_as_complete, - const content::SavePackagePathPickedCallback& callback) -{ - QT_NOT_YET_IMPLEMENTED -} + if (suggestedFilename.empty()) + suggestedFilename = item->GetURL().ExtractFileName(); -void DownloadManagerDelegateQt::OpenDownload(content::DownloadItem* download) -{ - QT_NOT_YET_IMPLEMENTED -} + if (suggestedFilename.empty()) + suggestedFilename = "qwe_download"; -void DownloadManagerDelegateQt::ShowDownloadInShell(content::DownloadItem* download) -{ - QT_NOT_YET_IMPLEMENTED -} + QDir defaultDownloadDirectory = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation); -void DownloadManagerDelegateQt::CheckForFileExistence( - content::DownloadItem* download, - const content::CheckForFileExistenceCallback& callback) -{ - QT_NOT_YET_IMPLEMENTED + QFileInfo suggestedFile(defaultDownloadDirectory.absoluteFilePath(QString::fromStdString(suggestedFilename))); + QString suggestedFilePath = suggestedFile.absoluteFilePath(); + QString tmpFileBase = QString("%1%2%3").arg(suggestedFile.absolutePath()).arg(QDir::separator()).arg(suggestedFile.baseName()); + + for (int i = 1; QFileInfo::exists(suggestedFilePath); ++i) { + suggestedFilePath = QString("%1(%2).%3").arg(tmpFileBase).arg(i).arg(suggestedFile.completeSuffix()); + if (i >= 99) { + suggestedFilePath = suggestedFile.absoluteFilePath(); + break; + } + } + + item->AddObserver(this); + quint32 downloadId = item->GetId(); + if (m_contextAdapter->client()) { + bool cancelled = false; + m_contextAdapter->client()->downloadRequested(downloadId, suggestedFilePath, cancelled); + suggestedFile.setFile(suggestedFilePath); + + if (!cancelled && !suggestedFile.absoluteDir().mkpath(suggestedFile.absolutePath())) { + qWarning("Creating download path failed, download cancelled: %s", suggestedFile.absolutePath().toUtf8().data()); + cancelled = true; + } + + if (cancelled) { + cancelDownload(callback); + return true; + } + + base::FilePath filePathForCallback(toFilePathString(suggestedFile.absoluteFilePath())); + callback.Run(filePathForCallback, content::DownloadItem::TARGET_DISPOSITION_OVERWRITE, + content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT, filePathForCallback.AddExtension(toFilePathString("download"))); + } else + cancelDownload(callback); + + return true; } void DownloadManagerDelegateQt::GetSaveDir(content::BrowserContext* browser_context, @@ -242,4 +156,16 @@ void DownloadManagerDelegateQt::GetSaveDir(content::BrowserContext* browser_cont *skip_dir_check = true; } +void DownloadManagerDelegateQt::OnDownloadUpdated(content::DownloadItem *download) +{ + const quint32 downloadId = download->GetId(); + + if (m_contextAdapter->client()) + m_contextAdapter->client()->downloadUpdated(downloadId, download->GetState(), download->PercentComplete()); +} +void DownloadManagerDelegateQt::OnDownloadDestroyed(content::DownloadItem *download) +{ + download->RemoveObserver(this); + download->Cancel(/* user_cancel */ false); +} diff --git a/src/core/download_manager_delegate_qt.h b/src/core/download_manager_delegate_qt.h index 4c838363f..007f2e580 100644 --- a/src/core/download_manager_delegate_qt.h +++ b/src/core/download_manager_delegate_qt.h @@ -39,7 +39,7 @@ #include "content/public/browser/download_manager_delegate.h" -#include <qglobal.h> +#include <QtCore/qcompilerdetection.h> // Needed for Q_DECL_OVERRIDE namespace base { class FilePath; @@ -51,46 +51,38 @@ class DownloadItem; class WebContents; } -class DownloadTargetHelper; - -class DownloadManagerDelegateQt : public content::DownloadManagerDelegate +class BrowserContextAdapter; +class DownloadManagerDelegateInstance; +class DownloadManagerDelegateQt + : public content::DownloadManagerDelegate + , public content::DownloadItem::Observer { public: - DownloadManagerDelegateQt(); - virtual ~DownloadManagerDelegateQt(); - - void Shutdown() Q_DECL_OVERRIDE; + DownloadManagerDelegateQt(BrowserContextAdapter *contextAdapter); + ~DownloadManagerDelegateQt(); void GetNextId(const content::DownloadIdCallback& callback) Q_DECL_OVERRIDE; - bool ShouldOpenFileBasedOnExtension(const base::FilePath& path) Q_DECL_OVERRIDE; - bool ShouldCompleteDownload(content::DownloadItem* item, - const base::Closure& complete_callback) Q_DECL_OVERRIDE; - - bool ShouldOpenDownload(content::DownloadItem* item, - const content::DownloadOpenDelayedCallback& callback) Q_DECL_OVERRIDE; bool DetermineDownloadTarget(content::DownloadItem* item, const content::DownloadTargetCallback& callback) Q_DECL_OVERRIDE; - bool GenerateFileHash() Q_DECL_OVERRIDE; - void ChooseSavePath(content::WebContents* web_contents, - const base::FilePath& suggested_path, - const base::FilePath::StringType& default_extension, - bool can_save_as_complete, - const content::SavePackagePathPickedCallback& callback) Q_DECL_OVERRIDE; - - void OpenDownload(content::DownloadItem* download) Q_DECL_OVERRIDE; - void ShowDownloadInShell(content::DownloadItem* download) Q_DECL_OVERRIDE; - void CheckForFileExistence(content::DownloadItem* download, - const content::CheckForFileExistenceCallback& callback) Q_DECL_OVERRIDE; - void GetSaveDir(content::BrowserContext* browser_context, base::FilePath* website_save_dir, base::FilePath* download_save_dir, bool* skip_dir_check) Q_DECL_OVERRIDE; + void cancelDownload(quint32 downloadId); + + // Inherited from content::DownloadItem::Observer + void OnDownloadUpdated(content::DownloadItem *download) Q_DECL_OVERRIDE; + void OnDownloadDestroyed(content::DownloadItem *download) Q_DECL_OVERRIDE; + private: - DownloadTargetHelper* m_targetHelper; + void cancelDownload(const content::DownloadTargetCallback& callback); + BrowserContextAdapter *m_contextAdapter; + uint64 m_currentId; + + friend class DownloadManagerDelegateInstance; DISALLOW_COPY_AND_ASSIGN(DownloadManagerDelegateQt); }; diff --git a/src/core/location_provider_qt.cpp b/src/core/location_provider_qt.cpp new file mode 100644 index 000000000..cdc9f1a44 --- /dev/null +++ b/src/core/location_provider_qt.cpp @@ -0,0 +1,248 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 "location_provider_qt.h" + +#include <math.h> + +#include "type_conversion.h" + +#include <QtCore/QCoreApplication> +#include <QtCore/QThread> +#include <QtPositioning/QGeoPositionInfoSource> + +#include "base/message_loop/message_loop.h" +#include "base/bind.h" +#include "content/browser/geolocation/geolocation_provider_impl.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/geolocation_provider.h" + +using content::BrowserThread; + +class QtPositioningHelper : public QObject { + Q_OBJECT +public: + QtPositioningHelper(LocationProviderQt *provider); + ~QtPositioningHelper(); + + bool start(bool highAccuracy); + void stop(); + void refresh(); + +private Q_SLOTS: + void updatePosition(const QGeoPositionInfo &); + void error(QGeoPositionInfoSource::Error positioningError); + void timeout(); + +private: + LocationProviderQt *m_locationProvider; + QGeoPositionInfoSource *m_positionInfoSource; + + void postToLocationProvider(const base::Closure &task); +}; + +QtPositioningHelper::QtPositioningHelper(LocationProviderQt *provider) + : m_locationProvider(provider) + , m_positionInfoSource(0) +{ + Q_ASSERT(provider); +} + +QtPositioningHelper::~QtPositioningHelper() +{ + m_locationProvider->m_positioningHelper = 0; +} + +bool 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) + return false; + + 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) + , this, &QtPositioningHelper::error); + connect(m_positionInfoSource, &QGeoPositionInfoSource::updateTimeout, this, &QtPositioningHelper::timeout); + + m_positionInfoSource->startUpdates(); + return true; +} + +void QtPositioningHelper::stop() +{ + DCHECK_CURRENTLY_ON(BrowserThread::UI); + if (!m_positionInfoSource) + return; + m_positionInfoSource->stopUpdates(); +} + +void QtPositioningHelper::refresh() +{ + DCHECK_CURRENTLY_ON(BrowserThread::UI); + if (!m_positionInfoSource) + return; + m_positionInfoSource->stopUpdates(); +} + +void QtPositioningHelper::updatePosition(const QGeoPositionInfo &pos) +{ + if (!pos.isValid()) + return; + Q_ASSERT(m_positionInfoSource->error() == QGeoPositionInfoSource::NoError); + content::Geoposition newPos; + newPos.error_code = content::Geoposition::ERROR_CODE_NONE; + newPos.error_message.clear(); + + newPos.timestamp = toTime(pos.timestamp()); + newPos.latitude = pos.coordinate().latitude(); + newPos.longitude = pos.coordinate().longitude(); + + const double altitude = pos.coordinate().altitude(); + if (!qIsNaN(altitude)) + newPos.altitude = altitude; + + // Chromium's geoposition needs a valid (as in >=0.) accuracy field. + // try and get an accuracy estimate from QGeoPositionInfo. + // If we don't have any accuracy info, 100m seems a pesimistic enough default. + if (!pos.hasAttribute(QGeoPositionInfo::VerticalAccuracy) && !pos.hasAttribute(QGeoPositionInfo::HorizontalAccuracy)) + newPos.accuracy = 100; + else { + const double vAccuracy = pos.hasAttribute(QGeoPositionInfo::VerticalAccuracy) ? pos.attribute(QGeoPositionInfo::VerticalAccuracy) : 0; + const double hAccuracy = pos.hasAttribute(QGeoPositionInfo::HorizontalAccuracy) ? pos.attribute(QGeoPositionInfo::HorizontalAccuracy) : 0; + newPos.accuracy = sqrt(vAccuracy * vAccuracy + hAccuracy * hAccuracy); + } + + // And now the "nice to have" fields (-1 means invalid). + newPos.speed = pos.hasAttribute(QGeoPositionInfo::GroundSpeed) ? pos.attribute(QGeoPositionInfo::GroundSpeed) : -1; + newPos.heading = pos.hasAttribute(QGeoPositionInfo::Direction) ? pos.attribute(QGeoPositionInfo::Direction) : -1; + + postToLocationProvider(base::Bind(&LocationProviderQt::updatePosition, base::Unretained(m_locationProvider), newPos)); +} + +void QtPositioningHelper::error(QGeoPositionInfoSource::Error positioningError) +{ + Q_ASSERT(positioningError != QGeoPositionInfoSource::NoError); + content::Geoposition newPos; + switch (positioningError) { + case QGeoPositionInfoSource::AccessError: + newPos.error_code = content::Geoposition::ERROR_CODE_PERMISSION_DENIED; + break; + case QGeoPositionInfoSource::ClosedError: + case QGeoPositionInfoSource::UnknownSourceError: // position unavailable is as good as it gets in Geoposition + default: + newPos.error_code = content::Geoposition::ERROR_CODE_POSITION_UNAVAILABLE; + break; + } + postToLocationProvider(base::Bind(&LocationProviderQt::updatePosition, base::Unretained(m_locationProvider), newPos)); +} + +void QtPositioningHelper::timeout() +{ + content::Geoposition newPos; + // content::Geoposition::ERROR_CODE_TIMEOUT is not handled properly in the renderer process, and the timeout + // argument used in JS never comes all the way to the browser process. + // Let's just treat it like any other error where the position is unavailable. + newPos.error_code = content::Geoposition::ERROR_CODE_POSITION_UNAVAILABLE; + postToLocationProvider(base::Bind(&LocationProviderQt::updatePosition, base::Unretained(m_locationProvider), newPos)); +} + +inline void QtPositioningHelper::postToLocationProvider(const base::Closure &task) +{ + LocationProviderQt::messageLoop()->PostTask(FROM_HERE, task); +} + +#include "location_provider_qt.moc" + +LocationProviderQt::LocationProviderQt() + : m_positioningHelper(0) +{ +} + +LocationProviderQt::~LocationProviderQt() +{ + m_positioningHelper->deleteLater(); +} + +bool LocationProviderQt::StartProvider(bool highAccuracy) +{ + DCHECK(base::MessageLoop::current() == messageLoop()); + QThread *guiThread = qApp->thread(); + if (!m_positioningHelper) { + m_positioningHelper = new QtPositioningHelper(this); + m_positioningHelper->moveToThread(guiThread); + } + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(base::IgnoreResult(&QtPositioningHelper::start) + , base::Unretained(m_positioningHelper), highAccuracy)); + return true; +} + +void LocationProviderQt::StopProvider() +{ + DCHECK(base::MessageLoop::current() == messageLoop()); + if (m_positioningHelper) + BrowserThread::PostTask(BrowserThread::UI,FROM_HERE, base::Bind(&QtPositioningHelper::stop + , base::Unretained(m_positioningHelper))); +} + +void LocationProviderQt::RequestRefresh() +{ + DCHECK(base::MessageLoop::current() == messageLoop()); + if (m_positioningHelper) + BrowserThread::PostTask(BrowserThread::UI,FROM_HERE, base::Bind(&QtPositioningHelper::refresh + , base::Unretained(m_positioningHelper))); +} + +void LocationProviderQt::OnPermissionGranted() +{ + RequestRefresh(); +} + +void LocationProviderQt::updatePosition(const content::Geoposition &position) +{ + DCHECK(base::MessageLoop::current() == messageLoop()); + m_lastKnownPosition = position; + NotifyCallback(position); +} + +base::MessageLoop *LocationProviderQt::messageLoop() +{ + return static_cast<content::GeolocationProviderImpl*>(content::GeolocationProvider::GetInstance())->message_loop(); +} diff --git a/src/core/location_provider_qt.h b/src/core/location_provider_qt.h new file mode 100644 index 000000000..c3e462092 --- /dev/null +++ b/src/core/location_provider_qt.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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$ +** +****************************************************************************/ + +#ifndef LOCATION_PROVIDER_QT_H +#define LOCATION_PROVIDER_QT_H + +#include <QtCore/qcompilerdetection.h> + +#include "content/browser/geolocation/location_provider_base.h" +#include "content/public/common/geoposition.h" + +QT_FORWARD_DECLARE_CLASS(QThread) +class QtPositioningHelper; + +namespace base { +class MessageLoop; +} + +class LocationProviderQt : public content::LocationProviderBase +{ +public: + LocationProviderQt(); + virtual ~LocationProviderQt(); + + // LocationProviderBase + virtual bool StartProvider(bool highAccuracy) Q_DECL_OVERRIDE; + virtual void StopProvider() Q_DECL_OVERRIDE; + virtual void GetPosition(content::Geoposition *position) Q_DECL_OVERRIDE { *position = m_lastKnownPosition; } + virtual void RequestRefresh() Q_DECL_OVERRIDE; + virtual void OnPermissionGranted() Q_DECL_OVERRIDE; + +private: + friend class QtPositioningHelper; + + static base::MessageLoop *messageLoop(); + void updatePosition(const content::Geoposition &); + + content::Geoposition m_lastKnownPosition; + QtPositioningHelper *m_positioningHelper; +}; +//#define QT_USE_POSITIONING 1 + +#endif // LOCATION_PROVIDER_QT_H diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp index c221e94e3..a94ae6995 100644 --- a/src/core/render_widget_host_view_qt.cpp +++ b/src/core/render_widget_host_view_qt.cpp @@ -189,7 +189,7 @@ RenderWidgetHostViewQt::RenderWidgetHostViewQt(content::RenderWidgetHost* widget : m_host(content::RenderWidgetHostImpl::From(widget)) , m_gestureProvider(QtGestureProviderConfig(), this) , m_sendMotionActionDown(false) - , m_frameNodeData(new DelegatedFrameNodeData) + , m_chromiumCompositorData(new ChromiumCompositorData) , m_needsDelegatedFrameAck(false) , m_didFirstVisuallyNonEmptyLayout(false) , m_adapterClient(0) @@ -352,12 +352,19 @@ gfx::Rect RenderWidgetHostViewQt::GetViewBounds() const // Return value indicates whether the mouse is locked successfully or not. bool RenderWidgetHostViewQt::LockMouse() { - QT_NOT_USED - return false; + mouse_locked_ = true; + m_lockedMousePosition = QCursor::pos(); + m_delegate->lockMouse(); + qApp->setOverrideCursor(Qt::BlankCursor); + return true; } + void RenderWidgetHostViewQt::UnlockMouse() { - QT_NOT_USED + mouse_locked_ = false; + m_delegate->unlockMouse(); + qApp->restoreOverrideCursor(); + m_host->LostMouseLock(); } void RenderWidgetHostViewQt::WasShown() @@ -594,14 +601,14 @@ void RenderWidgetHostViewQt::OnSwapCompositorFrame(uint32 output_surface_id, sco m_needsDelegatedFrameAck = true; m_pendingOutputSurfaceId = output_surface_id; Q_ASSERT(frame->delegated_frame_data); - Q_ASSERT(!m_frameNodeData->frameData || m_frameNodeData->frameData->resource_list.empty()); - m_frameNodeData->frameData = frame->delegated_frame_data.Pass(); - m_frameNodeData->frameDevicePixelRatio = frame->metadata.device_scale_factor; + Q_ASSERT(!m_chromiumCompositorData->frameData || m_chromiumCompositorData->frameData->resource_list.empty()); + m_chromiumCompositorData->frameData = frame->delegated_frame_data.Pass(); + m_chromiumCompositorData->frameDevicePixelRatio = frame->metadata.device_scale_factor; // Support experimental.viewport.devicePixelRatio, see GetScreenInfo implementation below. float dpiScale = this->dpiScale(); if (dpiScale != 0 && dpiScale != 1) - m_frameNodeData->frameDevicePixelRatio /= dpiScale; + m_chromiumCompositorData->frameDevicePixelRatio /= dpiScale; m_delegate->update(); @@ -661,7 +668,7 @@ QSGNode *RenderWidgetHostViewQt::updatePaintNode(QSGNode *oldNode) if (!frameNode) frameNode = new DelegatedFrameNode; - frameNode->commit(m_frameNodeData.data(), &m_resourcesToRelease); + frameNode->commit(m_chromiumCompositorData.data(), &m_resourcesToRelease, m_delegate.get()); // This is possibly called from the Qt render thread, post the ack back to the UI // to tell the child compositors to release resources and trigger a new frame. @@ -833,11 +840,20 @@ void RenderWidgetHostViewQt::handleMouseEvent(QMouseEvent* event) m_clickHelper.lastPressPosition = QPointF(event->pos()).toPoint(); } + if (IsMouseLocked()) { + webEvent.movementX = -(m_lockedMousePosition.x() - event->globalX()); + webEvent.movementY = -(m_lockedMousePosition.y() - event->globalY()); + QCursor::setPos(m_lockedMousePosition); + } + m_host->ForwardMouseEvent(webEvent); } void RenderWidgetHostViewQt::handleKeyEvent(QKeyEvent *ev) { + if (IsMouseLocked() && ev->key() == Qt::Key_Escape && ev->type() == QEvent::KeyRelease) + UnlockMouse(); + content::NativeWebKeyboardEvent webEvent = WebEventFactory::toWebKeyboardEvent(ev); m_host->ForwardKeyboardEvent(webEvent); if (webEvent.type == blink::WebInputEvent::RawKeyDown && !ev->text().isEmpty()) { diff --git a/src/core/render_widget_host_view_qt.h b/src/core/render_widget_host_view_qt.h index d4a3ff248..6ba95213b 100644 --- a/src/core/render_widget_host_view_qt.h +++ b/src/core/render_widget_host_view_qt.h @@ -235,7 +235,7 @@ private: QMap<int, int> m_touchIdMapping; scoped_ptr<RenderWidgetHostViewQtDelegate> m_delegate; - QExplicitlySharedDataPointer<DelegatedFrameNodeData> m_frameNodeData; + QExplicitlySharedDataPointer<ChromiumCompositorData> m_chromiumCompositorData; cc::ReturnedResourceArray m_resourcesToRelease; bool m_needsDelegatedFrameAck; bool m_didFirstVisuallyNonEmptyLayout; @@ -248,6 +248,7 @@ private: QRect m_cursorRect; size_t m_anchorPositionWithinSelection; size_t m_cursorPositionWithinSelection; + QPoint m_lockedMousePosition; bool m_initPending; }; diff --git a/src/core/render_widget_host_view_qt_delegate.h b/src/core/render_widget_host_view_qt_delegate.h index 3f6d9caac..018a914d8 100644 --- a/src/core/render_widget_host_view_qt_delegate.h +++ b/src/core/render_widget_host_view_qt_delegate.h @@ -46,7 +46,10 @@ QT_BEGIN_NAMESPACE class QCursor; class QEvent; class QPainter; +class QSGImageNode; +class QSGLayer; class QSGNode; +class QSGTexture; class QVariant; class QWindow; class QInputMethodEvent; @@ -74,10 +77,15 @@ public: virtual QRectF contentsRect() const = 0; virtual void setKeyboardFocus() = 0; virtual bool hasKeyboardFocus() = 0; + virtual void lockMouse() = 0; + virtual void unlockMouse() = 0; virtual void show() = 0; virtual void hide() = 0; virtual bool isVisible() const = 0; virtual QWindow* window() const = 0; + virtual QSGTexture *createTextureFromImage(const QImage &) = 0; + virtual QSGLayer *createLayer() = 0; + virtual QSGImageNode *createImageNode() = 0; virtual void update() = 0; virtual void updateCursor(const QCursor &) = 0; virtual void resize(int width, int height) = 0; diff --git a/src/core/resources/devtools_discovery_page.html b/src/core/resources/devtools_discovery_page.html index 79463cc16..7aac74932 100644 --- a/src/core/resources/devtools_discovery_page.html +++ b/src/core/resources/devtools_discovery_page.html @@ -1,18 +1,55 @@ -<!-- -Copyright (c) 2013 BlackBerry Limited. All rights reserved. ---> <html> <head> -<title>QtWebEngine remote debugging</title> +<title>QtWebEngine Remote Debugging</title> <style> +body { + background-color: rgb(245, 245, 245); + font-family: Helvetica, Arial, sans-serif; + 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; + height: 20px; + text-align: left; +} + +#items { + margin-left: 60px; + margin-right: 60px; + -webkit-box-orient: horizontal; + -webkit-box-lines: multiple; +} + +.frontend_ref { + color: black; + text-decoration: initial; +} + +.text { + background: no-repeat 0; + background-size: 16px; + font-size: 12px; + margin: 4px 0px 0px 4px; + overflow: hidden; + padding: 2px 0px 0px 20px; + text-align: left; + text-overflow: ellipsis; + white-space: nowrap; +} </style> <script> + function onLoad() { - var tabs_list_request = new XMLHttpRequest(); - tabs_list_request.open('GET', '/json/list?t=' + new Date().getTime(), true); - tabs_list_request.onreadystatechange = onReady; - tabs_list_request.send(); + var tabsListRequest = new XMLHttpRequest(); + tabsListRequest.open('GET', '/json/list', true); + tabsListRequest.onreadystatechange = onReady; + tabsListRequest.send(); } function onReady() { @@ -24,23 +61,35 @@ function onReady() { } } +function overrideFrontendUrl(item) { + if (window.location.hash) { + var overridden_url = window.location.hash.substr(1); + var ws_suffix = item.webSocketDebuggerUrl.replace('ws://', 'ws='); + if (overridden_url.indexOf('?') == -1) + return overridden_url + '?' + ws_suffix; + else + return overridden_url + '&' + ws_suffix; + } + return item.devtoolsFrontendUrl; +} + function appendItem(item_object) { var frontend_ref; if (item_object.devtoolsFrontendUrl) { frontend_ref = document.createElement('a'); - frontend_ref.href = item_object.devtoolsFrontendUrl; + frontend_ref.href = overrideFrontendUrl(item_object); frontend_ref.title = item_object.title; } else { frontend_ref = document.createElement('div'); - frontend_ref.title = 'The tab already has active debugging session'; + frontend_ref.title = 'The tab already has an active debug session'; } + frontend_ref.className = 'frontend_ref'; var text = document.createElement('div'); - if (item_object.title) - text.innerText = item_object.title; - else - text.innerText = '(untitled tab)'; - text.style.cssText = 'background-image:url(' + item_object.faviconUrl + ')'; + 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 item = document.createElement('p'); @@ -51,7 +100,9 @@ function appendItem(item_object) { </script> </head> <body onload='onLoad()'> - <div id='caption'>Inspectable WebContents</div> - <div id='items'></div> + <div id='caption'>Inspectable pages</div> + <div id='items'> + </div> + <hr> </body> </html> diff --git a/src/core/type_conversion.h b/src/core/type_conversion.h index 9d9cdd675..781023b7c 100644 --- a/src/core/type_conversion.h +++ b/src/core/type_conversion.h @@ -39,6 +39,7 @@ #include <QColor> #include <QDateTime> +#include <QDir> #include <QMatrix4x4> #include <QRect> #include <QString> @@ -135,10 +136,14 @@ inline QDateTime toQt(base::Time time) return QDateTime::fromMSecsSinceEpoch(time.ToJavaTime()); } +inline base::Time toTime(const QDateTime &dateTime) { + return base::Time::FromInternalValue(dateTime.toMSecsSinceEpoch()); +} + inline base::FilePath::StringType toFilePathString(const QString &str) { #if defined(OS_WIN) - return str.toStdWString(); + return QDir::toNativeSeparators(str).toStdWString(); #else return str.toStdString(); #endif @@ -150,7 +155,7 @@ inline base::FilePath toFilePath(const QString &str) } template <typename T> -inline T fileListingHelper(const QString &) {qFatal("Specialization missing for %s.", Q_FUNC_INFO);} +inline T fileListingHelper(const QString &) {qFatal("Specialization missing for %s.", Q_FUNC_INFO); return T(); } template <> inline ui::SelectedFileInfo fileListingHelper<ui::SelectedFileInfo>(const QString &file) diff --git a/src/core/url_request_context_getter_qt.cpp b/src/core/url_request_context_getter_qt.cpp index 8ec600a85..5d32ef470 100644 --- a/src/core/url_request_context_getter_qt.cpp +++ b/src/core/url_request_context_getter_qt.cpp @@ -61,125 +61,229 @@ #include "net/url_request/ftp_protocol_handler.h" #include "net/ftp/ftp_network_layer.h" -#include "network_delegate_qt.h" +#include "browser_context_adapter.h" #include "content_client_qt.h" +#include "network_delegate_qt.h" #include "qrc_protocol_handler_qt.h" +#include "type_conversion.h" static const char kQrcSchemeQt[] = "qrc"; using content::BrowserThread; -URLRequestContextGetterQt::URLRequestContextGetterQt(const base::FilePath &dataPath, const base::FilePath &cachePath, content::ProtocolHandlerMap *protocolHandlers) +URLRequestContextGetterQt::URLRequestContextGetterQt(BrowserContextAdapter *browserContext, content::ProtocolHandlerMap *protocolHandlers) : m_ignoreCertificateErrors(false) - , m_dataPath(dataPath) - , m_cachePath(cachePath) + , m_updateStorageSettings(false) + , m_updateCookieStore(false) + , m_updateHttpCache(false) + , m_browserContext(browserContext) { std::swap(m_protocolHandlers, *protocolHandlers); - // We must create the proxy config service on the UI loop on Linux because it - // must synchronously run on the glib message loop. This will be passed to - // the URLRequestContextStorage on the IO thread in GetURLRequestContext(). -//#ifdef Q_OS_LINUX - m_proxyConfigService.reset(net::ProxyService::CreateSystemProxyConfigService(BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::IO)->message_loop_proxy() - , BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::FILE))); -//#endif + updateStorageSettings(); } net::URLRequestContext *URLRequestContextGetterQt::GetURLRequestContext() { if (!m_urlRequestContext) { - m_urlRequestContext.reset(new net::URLRequestContext()); - m_networkDelegate.reset(new NetworkDelegateQt); + m_networkDelegate.reset(new NetworkDelegateQt); m_urlRequestContext->set_network_delegate(m_networkDelegate.get()); - base::FilePath cookiesPath = m_dataPath.Append(FILE_PATH_LITERAL("Cookies")); - content::CookieStoreConfig cookieStoreConfig(cookiesPath, content::CookieStoreConfig::PERSISTANT_SESSION_COOKIES, NULL, NULL); - scoped_refptr<net::CookieStore> cookieStore = content::CreateCookieStore(cookieStoreConfig); + generateStorage(); + generateJobFactory(); + } + + return m_urlRequestContext.get(); +} + +void URLRequestContextGetterQt::updateStorageSettings() +{ + Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + if (!m_proxyConfigService) { + // We must create the proxy config service on the UI loop on Linux because it + // must synchronously run on the glib message loop. This will be passed to + // the URLRequestContextStorage on the IO thread in GetURLRequestContext(). + m_proxyConfigService.reset(net::ProxyService::CreateSystemProxyConfigService( + BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::IO)->message_loop_proxy(), + BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::FILE)) + ); + } + if (m_storage && !m_updateStorageSettings) { + m_updateStorageSettings = true; + content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, base::Bind(&URLRequestContextGetterQt::generateStorage, this)); + } +} + +void URLRequestContextGetterQt::generateStorage() +{ + Q_ASSERT(m_urlRequestContext); + Q_ASSERT(m_proxyConfigService); + m_updateStorageSettings = false; + + m_storage.reset(new net::URLRequestContextStorage(m_urlRequestContext.get())); + + generateCookieStore(); + generateUserAgent(); + + m_storage->set_server_bound_cert_service(new net::ServerBoundCertService( + new net::DefaultServerBoundCertStore(NULL), + base::WorkerPool::GetTaskRunner(true))); + + m_storage->set_cert_verifier(net::CertVerifier::CreateDefault()); + m_storage->set_proxy_service(net::ProxyService::CreateUsingSystemProxyResolver( + m_proxyConfigService.release(), 0, NULL)); + m_storage->set_ssl_config_service(new net::SSLConfigServiceDefaults); + m_storage->set_transport_security_state(new net::TransportSecurityState()); + + scoped_ptr<net::HostResolver> host_resolver(net::HostResolver::CreateDefaultResolver(NULL)); + m_storage->set_http_auth_handler_factory(net::HttpAuthHandlerFactory::CreateDefault(host_resolver.get())); + m_storage->set_http_server_properties(scoped_ptr<net::HttpServerProperties>(new net::HttpServerPropertiesImpl)); + + // Give |m_storage| ownership at the end in case it's |mapped_host_resolver|. + m_storage->set_host_resolver(host_resolver.Pass()); + + generateHttpCache(); +} + +void URLRequestContextGetterQt::updateCookieStore() +{ + if (m_urlRequestContext && !m_updateCookieStore && !m_updateStorageSettings) { + m_updateCookieStore = true; + content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, base::Bind(&URLRequestContextGetterQt::generateCookieStore, this)); + } +} - m_storage.reset(new net::URLRequestContextStorage(m_urlRequestContext.get())); - m_storage->set_cookie_store(cookieStore.get()); - m_storage->set_server_bound_cert_service(new net::ServerBoundCertService( - new net::DefaultServerBoundCertStore(NULL), - base::WorkerPool::GetTaskRunner(true))); - m_storage->set_http_user_agent_settings( - new net::StaticHttpUserAgentSettings("en-us,en", ContentClientQt::getUserAgent())); +void URLRequestContextGetterQt::generateCookieStore() +{ + Q_ASSERT(m_urlRequestContext); + Q_ASSERT(m_storage); + m_updateCookieStore = false; - scoped_ptr<net::HostResolver> host_resolver( - net::HostResolver::CreateDefaultResolver(NULL)); + // Unset it first to get a chance to destroy and flush the old cookie store before before opening a new on possibly the same file. + m_storage->set_cookie_store(0); - m_storage->set_cert_verifier(net::CertVerifier::CreateDefault()); + net::CookieStore* cookieStore = 0; + switch (m_browserContext->persistentCookiesPolicy()) { + case BrowserContextAdapter::NoPersistentCookies: + cookieStore = + content::CreateCookieStore(content::CookieStoreConfig( + base::FilePath(), + content::CookieStoreConfig::EPHEMERAL_SESSION_COOKIES, + NULL, NULL) + ); + break; + case BrowserContextAdapter::AllowPersistentCookies: + cookieStore = + content::CreateCookieStore(content::CookieStoreConfig( + toFilePath(m_browserContext->cookiesPath()), + content::CookieStoreConfig::PERSISTANT_SESSION_COOKIES, + NULL, NULL) + ); + break; + case BrowserContextAdapter::ForcePersistentCookies: + cookieStore = + content::CreateCookieStore(content::CookieStoreConfig( + toFilePath(m_browserContext->cookiesPath()), + content::CookieStoreConfig::RESTORED_SESSION_COOKIES, + NULL, NULL) + ); + break; + } + m_storage->set_cookie_store(cookieStore); +} - m_storage->set_proxy_service(net::ProxyService::CreateUsingSystemProxyResolver(m_proxyConfigService.release(), 0, NULL)); +void URLRequestContextGetterQt::updateUserAgent() +{ + if (m_urlRequestContext && !m_updateStorageSettings) + content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, base::Bind(&URLRequestContextGetterQt::generateUserAgent, this)); +} - m_storage->set_ssl_config_service(new net::SSLConfigServiceDefaults); - m_storage->set_transport_security_state(new net::TransportSecurityState()); +void URLRequestContextGetterQt::generateUserAgent() +{ + Q_ASSERT(m_urlRequestContext); + Q_ASSERT(m_storage); - m_storage->set_http_auth_handler_factory( - net::HttpAuthHandlerFactory::CreateDefault(host_resolver.get())); - m_storage->set_http_server_properties(scoped_ptr<net::HttpServerProperties>(new net::HttpServerPropertiesImpl)); + m_storage->set_http_user_agent_settings( + new net::StaticHttpUserAgentSettings("en-us,en", m_browserContext->httpUserAgent().toStdString())); +} - base::FilePath cache_path = m_cachePath.Append(FILE_PATH_LITERAL("Cache")); - net::HttpCache::DefaultBackend* main_backend = +void URLRequestContextGetterQt::updateHttpCache() +{ + if (m_urlRequestContext && !m_updateHttpCache && !m_updateStorageSettings) { + m_updateHttpCache = true; + content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE, base::Bind(&URLRequestContextGetterQt::generateHttpCache, this)); + } +} + +void URLRequestContextGetterQt::generateHttpCache() +{ + Q_ASSERT(m_urlRequestContext); + Q_ASSERT(m_storage); + m_updateHttpCache = false; + + net::HttpCache::DefaultBackend* main_backend = 0; + switch (m_browserContext->httpCacheType()) { + case BrowserContextAdapter::MemoryHttpCache: + main_backend = + new net::HttpCache::DefaultBackend( + net::MEMORY_CACHE, + net::CACHE_BACKEND_DEFAULT, + base::FilePath(), + m_browserContext->httpCacheMaxSize(), + BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE) + ); + break; + case BrowserContextAdapter::DiskHttpCache: + main_backend = new net::HttpCache::DefaultBackend( net::DISK_CACHE, net::CACHE_BACKEND_DEFAULT, - cache_path, - 0, - BrowserThread::GetMessageLoopProxyForThread( - BrowserThread::CACHE)); - - net::HttpNetworkSession::Params network_session_params; - network_session_params.transport_security_state = - m_urlRequestContext->transport_security_state(); - network_session_params.cert_verifier = - m_urlRequestContext->cert_verifier(); - network_session_params.server_bound_cert_service = - m_urlRequestContext->server_bound_cert_service(); - network_session_params.proxy_service = - m_urlRequestContext->proxy_service(); - network_session_params.ssl_config_service = - m_urlRequestContext->ssl_config_service(); - network_session_params.http_auth_handler_factory = - m_urlRequestContext->http_auth_handler_factory(); - network_session_params.network_delegate = - m_networkDelegate.get(); - network_session_params.http_server_properties = - m_urlRequestContext->http_server_properties(); - network_session_params.ignore_certificate_errors = - m_ignoreCertificateErrors; - - // Give |m_storage| ownership at the end in case it's |mapped_host_resolver|. - m_storage->set_host_resolver(host_resolver.Pass()); - network_session_params.host_resolver = - m_urlRequestContext->host_resolver(); - - net::HttpCache* main_cache = new net::HttpCache( - network_session_params, main_backend); - m_storage->set_http_transaction_factory(main_cache); - - - m_jobFactory.reset(new net::URLRequestJobFactoryImpl()); - - // Chromium has a few protocol handlers ready for us, only pick blob: and throw away the rest. - content::ProtocolHandlerMap::iterator it = m_protocolHandlers.find(url::kBlobScheme); - Q_ASSERT(it != m_protocolHandlers.end()); - m_jobFactory->SetProtocolHandler(it->first, it->second.release()); - m_protocolHandlers.clear(); - - m_jobFactory->SetProtocolHandler(url::kDataScheme, new net::DataProtocolHandler()); - m_jobFactory->SetProtocolHandler(url::kFileScheme, new net::FileProtocolHandler( - content::BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior(base::SequencedWorkerPool::SKIP_ON_SHUTDOWN))); - m_jobFactory->SetProtocolHandler(kQrcSchemeQt, new QrcProtocolHandlerQt()); - m_jobFactory->SetProtocolHandler(url::kFtpScheme, new net::FtpProtocolHandler( - new net::FtpNetworkLayer(m_urlRequestContext->host_resolver()))); - m_urlRequestContext->set_job_factory(m_jobFactory.get()); + toFilePath(m_browserContext->httpCachePath()), + m_browserContext->httpCacheMaxSize(), + BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE) + ); + break; } - return m_urlRequestContext.get(); + net::HttpNetworkSession::Params network_session_params; + network_session_params.transport_security_state = m_urlRequestContext->transport_security_state(); + network_session_params.cert_verifier = m_urlRequestContext->cert_verifier(); + network_session_params.server_bound_cert_service = m_urlRequestContext->server_bound_cert_service(); + network_session_params.proxy_service = m_urlRequestContext->proxy_service(); + network_session_params.ssl_config_service = m_urlRequestContext->ssl_config_service(); + network_session_params.http_auth_handler_factory = m_urlRequestContext->http_auth_handler_factory(); + network_session_params.network_delegate = m_networkDelegate.get(); + network_session_params.http_server_properties = m_urlRequestContext->http_server_properties(); + network_session_params.ignore_certificate_errors = m_ignoreCertificateErrors; + network_session_params.host_resolver = m_urlRequestContext->host_resolver(); + + m_storage->set_http_transaction_factory(new net::HttpCache(network_session_params, main_backend)); } +void URLRequestContextGetterQt::generateJobFactory() +{ + Q_ASSERT(m_urlRequestContext); + Q_ASSERT(!m_jobFactory); + m_jobFactory.reset(new net::URLRequestJobFactoryImpl()); + + // Chromium has a few protocol handlers ready for us, only pick blob: and throw away the rest. + content::ProtocolHandlerMap::iterator it = m_protocolHandlers.find(url::kBlobScheme); + Q_ASSERT(it != m_protocolHandlers.end()); + m_jobFactory->SetProtocolHandler(it->first, it->second.release()); + m_protocolHandlers.clear(); + + m_jobFactory->SetProtocolHandler(url::kDataScheme, new net::DataProtocolHandler()); + m_jobFactory->SetProtocolHandler(url::kFileScheme, new net::FileProtocolHandler( + content::BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior( + base::SequencedWorkerPool::SKIP_ON_SHUTDOWN))); + m_jobFactory->SetProtocolHandler(kQrcSchemeQt, new QrcProtocolHandlerQt()); + m_jobFactory->SetProtocolHandler(url::kFtpScheme, + new net::FtpProtocolHandler(new net::FtpNetworkLayer(m_urlRequestContext->host_resolver()))); + + m_urlRequestContext->set_job_factory(m_jobFactory.get()); +} scoped_refptr<base::SingleThreadTaskRunner> URLRequestContextGetterQt::GetNetworkTaskRunner() const { diff --git a/src/core/url_request_context_getter_qt.h b/src/core/url_request_context_getter_qt.h index 6c9ac6d59..5f6048403 100644 --- a/src/core/url_request_context_getter_qt.h +++ b/src/core/url_request_context_getter_qt.h @@ -40,6 +40,7 @@ #include "net/url_request/url_request_context_getter.h" #include "base/files/file_path.h" +#include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/single_thread_task_runner.h" #include "content/public/browser/content_browser_client.h" @@ -50,25 +51,41 @@ #include "qglobal.h" namespace net { -class HostResolver; class MappedHostResolver; class NetworkDelegate; class ProxyConfigService; } +class BrowserContextAdapter; + class URLRequestContextGetterQt : public net::URLRequestContextGetter { public: - explicit URLRequestContextGetterQt(const base::FilePath &, const base::FilePath &, content::ProtocolHandlerMap *protocolHandlers); + explicit URLRequestContextGetterQt(BrowserContextAdapter *browserContext, content::ProtocolHandlerMap *protocolHandlers); virtual net::URLRequestContext *GetURLRequestContext() Q_DECL_OVERRIDE; virtual scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner() const Q_DECL_OVERRIDE; + // Called on the UI thread: + void updateStorageSettings(); + void updateUserAgent(); + void updateCookieStore(); + void updateHttpCache(); + private: virtual ~URLRequestContextGetterQt() {} + // Called on the IO thread: + void generateStorage(); + void generateCookieStore(); + void generateHttpCache(); + void generateUserAgent(); + void generateJobFactory(); + bool m_ignoreCertificateErrors; - base::FilePath m_dataPath; - base::FilePath m_cachePath; + volatile bool m_updateStorageSettings; + volatile bool m_updateCookieStore; + volatile bool m_updateHttpCache; + BrowserContextAdapter *m_browserContext; content::ProtocolHandlerMap m_protocolHandlers; scoped_ptr<net::ProxyConfigService> m_proxyConfigService; diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp index 3f223f733..9398046d0 100644 --- a/src/core/web_contents_adapter.cpp +++ b/src/core/web_contents_adapter.cpp @@ -41,6 +41,7 @@ #include "web_contents_adapter.h" #include "web_contents_adapter_p.h" +#include "browser_context_adapter.h" #include "browser_context_qt.h" #include "content_browser_client_qt.h" #include "javascript_dialog_manager_qt.h" @@ -175,9 +176,8 @@ static QStringList listRecursively(const QDir& dir) { return ret; } -static content::WebContents *createBlankWebContents(WebContentsAdapterClient *adapterClient) +static content::WebContents *createBlankWebContents(WebContentsAdapterClient *adapterClient, content::BrowserContext *browserContext) { - content::BrowserContext* browserContext = ContentBrowserClientQt::Get()->browser_context(); content::WebContents::CreateParams create_params(browserContext, NULL); create_params.routing_id = MSG_ROUTING_NONE; create_params.initial_size = gfx::Size(kTestWindowWidth, kTestWindowHeight); @@ -222,7 +222,7 @@ static void serializeNavigationHistory(const content::NavigationController &cont } } -void deserializeNavigationHistory(QDataStream &input, int *currentIndex, std::vector<content::NavigationEntry*> *entries) +static void deserializeNavigationHistory(QDataStream &input, int *currentIndex, std::vector<content::NavigationEntry*> *entries, content::BrowserContext *browserContext) { int version; input >> version; @@ -278,7 +278,7 @@ void deserializeNavigationHistory(QDataStream &input, int *currentIndex, std::ve false, // The extra headers are not sync'ed across sessions. std::string(), - ContentBrowserClientQt::Get()->browser_context()); + browserContext); entry->SetTitle(toString16(title)); entry->SetPageState(content::PageState::CreateFromEncodedData(std::string(pageState.data(), pageState.size()))); @@ -292,6 +292,30 @@ void deserializeNavigationHistory(QDataStream &input, int *currentIndex, std::ve } } +namespace { +static QList<WebContentsAdapter *> recursive_guard_loading_adapters; + +class LoadRecursionGuard { + public: + static bool isGuarded(WebContentsAdapter *adapter) + { + return recursive_guard_loading_adapters.contains(adapter); + } + LoadRecursionGuard(WebContentsAdapter *adapter) + : m_adapter(adapter) + { + recursive_guard_loading_adapters.append(adapter); + } + + ~LoadRecursionGuard() { + recursive_guard_loading_adapters.removeOne(m_adapter); + } + + private: + WebContentsAdapter *m_adapter; +}; +} // Anonymous namespace + WebContentsAdapterPrivate::WebContentsAdapterPrivate() // This has to be the first thing we create, and the last we destroy. : engineContext(WebEngineContext::current()) @@ -308,13 +332,13 @@ QExplicitlySharedDataPointer<WebContentsAdapter> WebContentsAdapter::createFromS { int currentIndex; std::vector<content::NavigationEntry*> entries; - deserializeNavigationHistory(input, ¤tIndex, &entries); + deserializeNavigationHistory(input, ¤tIndex, &entries, adapterClient->browserContextAdapter()->browserContext()); if (currentIndex == -1) return QExplicitlySharedDataPointer<WebContentsAdapter>(); // Unlike WebCore, Chromium only supports Restoring to a new WebContents instance. - content::WebContents* newWebContents = createBlankWebContents(adapterClient); + content::WebContents* newWebContents = createBlankWebContents(adapterClient, adapterClient->browserContextAdapter()->browserContext()); content::NavigationController &controller = newWebContents->GetController(); controller.Restore(currentIndex, content::NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY, &entries); @@ -347,10 +371,13 @@ void WebContentsAdapter::initialize(WebContentsAdapterClient *adapterClient) { Q_D(WebContentsAdapter); d->adapterClient = adapterClient; + // We keep a reference to browserContextAdapter to keep it alive as long as we use it. + // This is needed in case the QML WebEngineProfile is garbage collected before the WebEnginePage. + d->browserContextAdapter = adapterClient->browserContextAdapter(); // Create our own if a WebContents wasn't provided at construction. if (!d->webContents) - d->webContents.reset(createBlankWebContents(adapterClient)); + d->webContents.reset(createBlankWebContents(adapterClient, d->browserContextAdapter->browserContext())); // This might replace any adapter that has been initialized with this WebEngineSettings. adapterClient->webEngineSettings()->setWebContentsAdapter(this); @@ -421,6 +448,19 @@ void WebContentsAdapter::reload() void WebContentsAdapter::load(const QUrl &url) { + // The situation can occur when relying on the editingFinished signal in QML to set the url + // of the WebView. + // When enter is pressed, onEditingFinished fires and the url of the webview is set, which + // calls into this and focuses the webview, taking the focus from the TextField/TextInput, + // which in turn leads to editingFinished firing again. This scenario would cause a crash + // down the line when unwinding as the first RenderWidgetHostViewQtDelegateQuick instance is + // a dangling pointer by that time. + + if (LoadRecursionGuard::isGuarded(this)) + return; + LoadRecursionGuard guard(this); + Q_UNUSED(guard); + Q_D(WebContentsAdapter); content::NavigationController::LoadURLParams params(toGurl(url)); params.transition_type = content::PageTransitionFromInt(content::PAGE_TRANSITION_TYPED | content::PAGE_TRANSITION_FROM_ADDRESS_BAR); @@ -625,7 +665,13 @@ qreal WebContentsAdapter::currentZoomFactor() const void WebContentsAdapter::enableInspector(bool enable) { - ContentBrowserClientQt::Get()->enableInspector(enable); + ContentBrowserClientQt::Get()->enableInspector(enable, browserContext()); +} + +BrowserContextQt* WebContentsAdapter::browserContext() +{ + Q_D(WebContentsAdapter); + return d->browserContextAdapter->browserContext(); } QAccessibleInterface *WebContentsAdapter::browserAccessible() @@ -724,6 +770,26 @@ void WebContentsAdapter::grantMediaAccessPermission(const QUrl &securityOrigin, MediaCaptureDevicesDispatcher::GetInstance()->handleMediaAccessPermissionResponse(d->webContents.get(), securityOrigin, flags); } +void WebContentsAdapter::runGeolocationRequestCallback(const QUrl &securityOrigin, bool allowed) +{ + Q_D(WebContentsAdapter); + d->webContentsDelegate->m_lastGeolocationRequestCallbacks.first.Run(allowed); +} + +void WebContentsAdapter::grantMouseLockPermission(bool granted) +{ + Q_D(WebContentsAdapter); + + if (granted) { + if (RenderWidgetHostViewQt *rwhv = static_cast<RenderWidgetHostViewQt *>(d->webContents->GetRenderWidgetHostView())) + rwhv->Focus(); + else + granted = false; + } + + d->webContents->GotResponseToLockMouseRequest(granted); +} + void WebContentsAdapter::dpiScaleChanged() { Q_D(WebContentsAdapter); diff --git a/src/core/web_contents_adapter.h b/src/core/web_contents_adapter.h index 6bec50316..432380be2 100644 --- a/src/core/web_contents_adapter.h +++ b/src/core/web_contents_adapter.h @@ -48,6 +48,7 @@ namespace content { class WebContents; } +class BrowserContextQt; class WebContentsAdapterPrivate; struct WebPreferences; @@ -108,14 +109,18 @@ public: void wasShown(); void wasHidden(); void grantMediaAccessPermission(const QUrl &securityOrigin, WebContentsAdapterClient::MediaRequestFlags flags); + void runGeolocationRequestCallback(const QUrl &securityOrigin, bool allowed); + void grantMouseLockPermission(bool granted); void dpiScaleChanged(); QAccessibleInterface *browserAccessible(); + BrowserContextQt* browserContext(); private: Q_DISABLE_COPY(WebContentsAdapter); Q_DECLARE_PRIVATE(WebContentsAdapter); QScopedPointer<WebContentsAdapterPrivate> d_ptr; + friend class WebContentsDelegateQt; }; #endif // WEB_CONTENTS_ADAPTER_H diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h index 8fd401fe4..f4e2c658f 100644 --- a/src/core/web_contents_adapter_client.h +++ b/src/core/web_contents_adapter_client.h @@ -48,6 +48,7 @@ QT_FORWARD_DECLARE_CLASS(QVariant) +class BrowserContextAdapter; class CertificateErrorController; class JavaScriptDialogController; class RenderWidgetHostViewQt; @@ -171,11 +172,15 @@ public: virtual QObject *accessibilityParentObject() = 0; virtual void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString& message, int lineNumber, const QString& sourceID) = 0; virtual void authenticationRequired(const QUrl &requestUrl, const QString &realm, bool isProxy, const QString &challengingHost, QString *outUser, QString *outPassword) = 0; + virtual void runGeolocationPermissionRequest(const QUrl &securityOrigin) = 0; virtual void runMediaAccessPermissionRequest(const QUrl &securityOrigin, MediaRequestFlags requestFlags) = 0; + virtual void runMouseLockPermissionRequest(const QUrl &securityOrigin) = 0; virtual WebEngineSettings *webEngineSettings() const = 0; virtual void allowCertificateError(const QExplicitlySharedDataPointer<CertificateErrorController> &errorController) = 0; + virtual BrowserContextAdapter* browserContextAdapter() = 0; + }; #endif // WEB_CONTENTS_ADAPTER_CLIENT_H diff --git a/src/core/web_contents_adapter_p.h b/src/core/web_contents_adapter_p.h index 28df0113a..f47c05de0 100644 --- a/src/core/web_contents_adapter_p.h +++ b/src/core/web_contents_adapter_p.h @@ -42,6 +42,9 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" +#include <QExplicitlySharedDataPointer> + +class BrowserContextAdapter; class QtRenderViewObserverHost; class WebContentsAdapterClient; class WebContentsDelegateQt; @@ -52,6 +55,7 @@ public: WebContentsAdapterPrivate(); ~WebContentsAdapterPrivate(); scoped_refptr<WebEngineContext> engineContext; + QExplicitlySharedDataPointer<BrowserContextAdapter> browserContextAdapter; scoped_ptr<content::WebContents> webContents; scoped_ptr<WebContentsDelegateQt> webContentsDelegate; scoped_ptr<QtRenderViewObserverHost> renderViewObserverHost; diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp index c2cccfedb..d64584c47 100644 --- a/src/core/web_contents_delegate_qt.cpp +++ b/src/core/web_contents_delegate_qt.cpp @@ -40,6 +40,7 @@ #include "web_contents_delegate_qt.h" +#include "browser_context_adapter.h" #include "media_capture_devices_dispatcher.h" #include "type_conversion.h" #include "web_contents_adapter_client.h" @@ -268,11 +269,21 @@ void WebContentsDelegateQt::UpdateTargetURL(content::WebContents *source, int32 void WebContentsDelegateQt::DidNavigateAnyFrame(const content::LoadCommittedDetails &, const content::FrameNavigateParams ¶ms) { - if (!params.should_update_history) + // VisistedLinksMaster asserts !IsOffTheRecord(). + if (!params.should_update_history || !m_viewClient->browserContextAdapter()->trackVisitedLinks()) return; - WebEngineContext::current()->visitedLinksManager()->addUrl(params.url); + m_viewClient->browserContextAdapter()->visitedLinksManager()->addUrl(params.url); } +void WebContentsDelegateQt::RequestToLockMouse(content::WebContents *web_contents, bool user_gesture, bool last_unlocked_by_target) +{ + Q_UNUSED(user_gesture); + + if (last_unlocked_by_target) + web_contents->GotResponseToLockMouseRequest(true); + else + m_viewClient->runMouseLockPermissionRequest(toQt(web_contents->GetVisibleURL())); +} void WebContentsDelegateQt::overrideWebPreferences(content::WebContents *, WebPreferences *webPreferences) { @@ -300,3 +311,9 @@ void WebContentsDelegateQt::allowCertificateError(const QExplicitlySharedDataPoi { m_viewClient->allowCertificateError(errorController); } + +void WebContentsDelegateQt::requestGeolocationPermission(const GURL &requestingFrameOrigin, base::Callback<void (bool)> resultCallback, base::Closure *cancelCallback) +{ + m_lastGeolocationRequestCallbacks = qMakePair(resultCallback, cancelCallback); + m_viewClient->runGeolocationPermissionRequest(toQt(requestingFrameOrigin)); +} diff --git a/src/core/web_contents_delegate_qt.h b/src/core/web_contents_delegate_qt.h index 2ab5fc8cd..aa97b52cc 100644 --- a/src/core/web_contents_delegate_qt.h +++ b/src/core/web_contents_delegate_qt.h @@ -40,6 +40,8 @@ #include "content/public/browser/web_contents_delegate.h" #include "content/public/browser/web_contents_observer.h" +#include "base/callback.h" + #include "javascript_dialog_manager_qt.h" #include <QtCore/qcompilerdetection.h> @@ -85,10 +87,13 @@ public: virtual void RequestMediaAccessPermission(content::WebContents* web_contents, const content::MediaStreamRequest& request, const content::MediaResponseCallback& callback) Q_DECL_OVERRIDE; virtual void UpdateTargetURL(content::WebContents *source, int32 page_id, const GURL &url) Q_DECL_OVERRIDE; virtual void DidNavigateAnyFrame(const content::LoadCommittedDetails&, const content::FrameNavigateParams& params) Q_DECL_OVERRIDE; + virtual void RequestToLockMouse(content::WebContents *web_contents, bool user_gesture, bool last_unlocked_by_target) Q_DECL_OVERRIDE; void overrideWebPreferences(content::WebContents *, WebPreferences*); void allowCertificateError(const QExplicitlySharedDataPointer<CertificateErrorController> &) ; + void requestGeolocationPermission(const GURL &requestingFrameOrigin, base::Callback<void (bool)> resultCallback, base::Closure *cancelCallback); + QPair<base::Callback<void (bool)>, base::Closure*> m_lastGeolocationRequestCallbacks; private: WebContentsAdapter *createWindow(content::WebContents *new_contents, WindowOpenDisposition disposition, const gfx::Rect& initial_pos, bool user_gesture); diff --git a/src/core/web_engine_context.cpp b/src/core/web_engine_context.cpp index 446f0e92c..85c1136d9 100644 --- a/src/core/web_engine_context.cpp +++ b/src/core/web_engine_context.cpp @@ -66,6 +66,7 @@ #include "content/public/app/startup_helper_win.h" #endif // OS_WIN +#include "browser_context_adapter.h" #include "content_browser_client_qt.h" #include "content_client_qt.h" #include "content_main_delegate_qt.h" @@ -74,7 +75,7 @@ #include "type_conversion.h" #include "surface_factory_qt.h" #include "web_engine_library_info.h" -#include "web_engine_visited_links_manager.h" +#include <QFileInfo> #include <QGuiApplication> #include <QOpenGLContext> #include <QStringList> @@ -90,6 +91,46 @@ void destroyContext() sContext = 0; } +bool usingANGLE() +{ +#if defined(Q_OS_WIN) + return QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES; +#else + return false; +#endif +} + +bool usingSoftwareDynamicGL() +{ +#if defined(Q_OS_WIN) + HMODULE handle = static_cast<HMODULE>(QOpenGLContext::openGLModuleHandle()); + wchar_t path[MAX_PATH]; + DWORD size = GetModuleFileName(handle, path, MAX_PATH); + QFileInfo openGLModule(QString::fromWCharArray(path, size)); + return openGLModule.fileName() == QLatin1String("opengl32sw.dll"); +#else + return false; +#endif +} + +bool usingQtQuick2DRenderer() +{ + const QStringList args = QGuiApplication::arguments(); + QString device; + for (int index = 0; index < args.count(); ++index) { + if (args.at(index).startsWith(QLatin1String("--device="))) { + device = args.at(index).mid(9); + break; + } + } + + if (device.isEmpty()) + device = QString::fromLocal8Bit(qgetenv("QMLSCENE_DEVICE")); + + // This assumes that the plugin is installed and is going to be used by QtQuick. + return device == QLatin1String("softwarecontext"); +} + } // namespace WebEngineContext::~WebEngineContext() @@ -111,9 +152,18 @@ scoped_refptr<WebEngineContext> WebEngineContext::current() return sContext; } -WebEngineVisitedLinksManager *WebEngineContext::visitedLinksManager() +BrowserContextAdapter* WebEngineContext::defaultBrowserContext() { - return m_visitedLinksManager.get(); + if (!m_defaultBrowserContext) + m_defaultBrowserContext = new BrowserContextAdapter(QStringLiteral("Default")); + return m_defaultBrowserContext.data(); +} + +BrowserContextAdapter* WebEngineContext::offTheRecordBrowserContext() +{ + if (!m_offTheRecordBrowserContext) + m_offTheRecordBrowserContext = new BrowserContextAdapter(true); + return m_offTheRecordBrowserContext.data(); } #ifndef CHROMIUM_VERSION @@ -180,16 +230,20 @@ WebEngineContext::WebEngineContext() GLContextHelper::initialize(); - const char *glType; - switch (QOpenGLContext::currentContext()->openGLModuleType()) { - case QOpenGLContext::LibGL: - glType = gfx::kGLImplementationDesktopName; - break; - case QOpenGLContext::LibGLES: - glType = gfx::kGLImplementationEGLName; - break; + if (usingANGLE() || usingSoftwareDynamicGL() || usingQtQuick2DRenderer()) { + parsedCommandLine->AppendSwitch(switches::kDisableGpu); + } else { + const char *glType; + switch (QOpenGLContext::openGLModuleType()) { + case QOpenGLContext::LibGL: + glType = gfx::kGLImplementationDesktopName; + break; + case QOpenGLContext::LibGLES: + glType = gfx::kGLImplementationEGLName; + break; + } + parsedCommandLine->AppendSwitchASCII(switches::kUseGL, glType); } - parsedCommandLine->AppendSwitchASCII(switches::kUseGL, glType); content::UtilityProcessHostImpl::RegisterUtilityMainThreadFactory(content::CreateInProcessUtilityThread); content::RenderProcessHostImpl::RegisterRendererMainThreadFactory(content::CreateInProcessRendererThread); @@ -213,7 +267,4 @@ WebEngineContext::WebEngineContext() // thread to avoid a thread check assertion in its constructor when it // first gets referenced on the IO thread. MediaCaptureDevicesDispatcher::GetInstance(); - - // Ensure we have a VisitedLinksMaster instance up and running - m_visitedLinksManager.reset(new WebEngineVisitedLinksManager); } diff --git a/src/core/web_engine_context.h b/src/core/web_engine_context.h index d1cd9a7a5..a44a48d3a 100644 --- a/src/core/web_engine_context.h +++ b/src/core/web_engine_context.h @@ -40,6 +40,8 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" +#include <QExplicitlySharedDataPointer> + namespace base { class RunLoop; } @@ -49,15 +51,16 @@ class BrowserMainRunner; class ContentMainRunner; } +class BrowserContextAdapter; class ContentMainDelegateQt; class SurfaceFactoryQt; -class WebEngineVisitedLinksManager; class WebEngineContext : public base::RefCounted<WebEngineContext> { public: static scoped_refptr<WebEngineContext> current(); - WebEngineVisitedLinksManager *visitedLinksManager(); + BrowserContextAdapter *defaultBrowserContext(); + BrowserContextAdapter *offTheRecordBrowserContext(); private: friend class base::RefCounted<WebEngineContext>; @@ -71,7 +74,8 @@ private: #if defined(OS_ANDROID) scoped_ptr<SurfaceFactoryQt> m_surfaceFactory; #endif - scoped_ptr<WebEngineVisitedLinksManager> m_visitedLinksManager; + QExplicitlySharedDataPointer<BrowserContextAdapter> m_defaultBrowserContext; + QExplicitlySharedDataPointer<BrowserContextAdapter> m_offTheRecordBrowserContext; }; #endif // WEB_ENGINE_CONTEXT_H diff --git a/src/core/web_engine_library_info.cpp b/src/core/web_engine_library_info.cpp index 2d72dd5a2..452eee306 100644 --- a/src/core/web_engine_library_info.cpp +++ b/src/core/web_engine_library_info.cpp @@ -78,7 +78,7 @@ QString location(QLibraryInfo::LibraryLocation path) switch (path) { case QLibraryInfo::TranslationsPath: if (!webEnginePath.isEmpty()) - return webEnginePath % QDir::separator() % QLatin1String("translations"); + return webEnginePath % QLatin1String("/translations"); break; case QLibraryInfo::DataPath: if (!webEnginePath.isEmpty()) @@ -148,7 +148,7 @@ QString subProcessPath() % QStringLiteral("/Helpers/" QTWEBENGINEPROCESS_NAME ".app/Contents/MacOS/" QTWEBENGINEPROCESS_NAME)); #else static QString processPath (location(QLibraryInfo::LibraryExecutablesPath) - % QDir::separator() % processBinary); + % QLatin1Char('/') % processBinary); #endif if (!initialized) { // Allow overriding at runtime for the time being. @@ -157,7 +157,7 @@ QString subProcessPath() processPath = QString::fromLatin1(fromEnv); if (!QFileInfo(processPath).exists()) { qWarning("QtWebEngineProcess not found at location %s. Trying fallback path...", qPrintable(processPath)); - processPath = QCoreApplication::applicationDirPath() % QDir::separator() % processBinary; + processPath = QCoreApplication::applicationDirPath() % QLatin1Char('/') % processBinary; } if (!QFileInfo(processPath).exists()) qFatal("QtWebEngineProcess not found at location %s. Try setting the QTWEBENGINEPROCESS_PATH environment variable.", qPrintable(processPath)); @@ -172,7 +172,7 @@ QString pluginsPath() #if defined(OS_MACOSX) && defined(QT_MAC_FRAMEWORK_BUILD) return getPath(frameworkBundle()) % QLatin1String("/Libraries"); #else - return location(QLibraryInfo::PluginsPath) % QDir::separator() % QLatin1String("qtwebengine"); + return location(QLibraryInfo::PluginsPath) % QLatin1String("/qtwebengine"); #endif } @@ -186,7 +186,7 @@ QString localesPath() } QString fallbackDir() { - static QString directory = QDir::homePath() % QDir::separator() % QChar::fromLatin1('.') % QCoreApplication::applicationName(); + static QString directory = QDir::homePath() % QLatin1String("/.") % QCoreApplication::applicationName(); return directory; } diff --git a/src/core/web_engine_visited_links_manager.cpp b/src/core/web_engine_visited_links_manager.cpp index 36467ca21..c5ed54f3e 100644 --- a/src/core/web_engine_visited_links_manager.cpp +++ b/src/core/web_engine_visited_links_manager.cpp @@ -36,8 +36,9 @@ #include "web_engine_visited_links_manager.h" -#include "content_browser_client_qt.h" +#include "browser_context_adapter.h" #include "browser_context_qt.h" +#include "content_browser_client_qt.h" #include "type_conversion.h" #include "base/memory/scoped_ptr.h" @@ -80,12 +81,17 @@ void WebEngineVisitedLinksManager::deleteVisitedLinkDataForUrls(const QList<QUrl m_visitedLinkMaster->DeleteURLs(&iterator); } -WebEngineVisitedLinksManager::WebEngineVisitedLinksManager() +bool WebEngineVisitedLinksManager::containsUrl(const QUrl &url) const +{ + return m_visitedLinkMaster->IsVisited(toGurl(url)); +} + +WebEngineVisitedLinksManager::WebEngineVisitedLinksManager(BrowserContextAdapter *adapter) : m_delegate(new VisitedLinkDelegateQt) { - Q_ASSERT(ContentBrowserClientQt::Get() && ContentBrowserClientQt::Get()->browser_context()); - BrowserContextQt *browserContext = ContentBrowserClientQt::Get()->browser_context(); - m_visitedLinkMaster.reset(new visitedlink::VisitedLinkMaster(browserContext, m_delegate.data(), /* persist to disk = */true)); + Q_ASSERT(adapter && adapter->browserContext()); + BrowserContextQt *browserContext = adapter->browserContext(); + m_visitedLinkMaster.reset(new visitedlink::VisitedLinkMaster(browserContext, m_delegate.data(), adapter->persistVisitedLinks())); m_visitedLinkMaster->Init(); } diff --git a/src/core/web_engine_visited_links_manager.h b/src/core/web_engine_visited_links_manager.h index aa44dd9cf..dc2a4bff2 100644 --- a/src/core/web_engine_visited_links_manager.h +++ b/src/core/web_engine_visited_links_manager.h @@ -49,6 +49,7 @@ namespace visitedlink { class VisitedLinkMaster; } +class BrowserContextAdapter; class VisitedLinkDelegateQt; class GURL; @@ -57,11 +58,13 @@ class QWEBENGINE_EXPORT WebEngineVisitedLinksManager { public: virtual~WebEngineVisitedLinksManager(); - WebEngineVisitedLinksManager(); + WebEngineVisitedLinksManager(BrowserContextAdapter*); void deleteAllVisitedLinkData(); void deleteVisitedLinkDataForUrls(const QList<QUrl> &); + bool containsUrl(const QUrl &) const; + private: void addUrl(const GURL &); friend class WebContentsDelegateQt; diff --git a/src/webengine/api/qquickwebenginedownloaditem.cpp b/src/webengine/api/qquickwebenginedownloaditem.cpp new file mode 100644 index 000000000..729cb0d3f --- /dev/null +++ b/src/webengine/api/qquickwebenginedownloaditem.cpp @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 "qquickwebenginedownloaditem_p.h" +#include "qquickwebenginedownloaditem_p_p.h" + +QT_BEGIN_NAMESPACE + +QQuickWebEngineDownloadItemPrivate::QQuickWebEngineDownloadItemPrivate(QQuickWebEngineProfilePrivate *p) + : profile(p) + , downloadStarted(false) + , downloadId(-1) + , downloadState(QQuickWebEngineDownloadItem::DownloadCancelled) + , downloadProgress(0) +{ +} + +QQuickWebEngineDownloadItemPrivate::~QQuickWebEngineDownloadItemPrivate() +{ + Q_Q(QQuickWebEngineDownloadItem); + q->cancel(); +} + +void QQuickWebEngineDownloadItemPrivate::update(QQuickWebEngineDownloadItem::DownloadState state, int progress) +{ + Q_Q(QQuickWebEngineDownloadItem); + if (state != downloadState) { + downloadState = state; + Q_EMIT q->stateChanged(); + } + if (progress != downloadProgress) { + downloadProgress = progress; + Q_EMIT q->progressChanged(); + } +} + +void QQuickWebEngineDownloadItem::cancel() +{ + Q_D(QQuickWebEngineDownloadItem); + + if (d->downloadState == QQuickWebEngineDownloadItem::DownloadCompleted + || d->downloadState == QQuickWebEngineDownloadItem::DownloadCancelled) + return; + + d->update(QQuickWebEngineDownloadItem::DownloadCancelled, d->downloadProgress); + + // We directly cancel the download if the user cancels before + // it even started, so no need to notify the profile here. + if (d->downloadStarted) + d->profile->cancelDownload(d->downloadId); +} + +quint32 QQuickWebEngineDownloadItem::id() +{ + Q_D(QQuickWebEngineDownloadItem); + return d->downloadId; +} + +QQuickWebEngineDownloadItem::DownloadState QQuickWebEngineDownloadItem::state() +{ + Q_D(QQuickWebEngineDownloadItem); + return d->downloadState; +} + +int QQuickWebEngineDownloadItem::progress() +{ + Q_D(QQuickWebEngineDownloadItem); + return d->downloadProgress; +} + +QString QQuickWebEngineDownloadItem::path() +{ + Q_D(QQuickWebEngineDownloadItem); + return d->downloadPath; +} + +void QQuickWebEngineDownloadItem::setPath(QString path) +{ + Q_D(QQuickWebEngineDownloadItem); + if (d->downloadStarted) { + qWarning("Setting the download path is not allowed after the download has been started."); + return; + } + if (d->downloadPath != path) { + d->downloadPath = path; + Q_EMIT pathChanged(); + } +} + +QQuickWebEngineDownloadItem::QQuickWebEngineDownloadItem(QQuickWebEngineDownloadItemPrivate *p, QObject *parent) + : QObject(parent) + , d_ptr(p) +{ + p->q_ptr = this; +} + +QQuickWebEngineDownloadItem::~QQuickWebEngineDownloadItem() +{ +} + +QT_END_NAMESPACE diff --git a/src/webengine/api/qquickwebenginedownloaditem_p.h b/src/webengine/api/qquickwebenginedownloaditem_p.h new file mode 100644 index 000000000..8ea9f0850 --- /dev/null +++ b/src/webengine/api/qquickwebenginedownloaditem_p.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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$ +** +****************************************************************************/ + +#ifndef QQUICKWEBENGINEDOWNLOADITEM_P_H +#define QQUICKWEBENGINEDOWNLOADITEM_P_H + +#include <qtwebengineglobal_p.h> +#include <QObject> +#include <QScopedPointer> +#include <QString> + +QT_BEGIN_NAMESPACE + +class QQuickWebEngineDownloadItemPrivate; +class QQuickWebEngineProfilePrivate; + +class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineDownloadItem: public QObject { + Q_OBJECT +public: + ~QQuickWebEngineDownloadItem(); + enum DownloadState { + DownloadInProgress, + DownloadCompleted, + DownloadCancelled, + DownloadInterrupted + }; + Q_ENUMS(DownloadState) + + Q_PROPERTY(quint32 id READ id() CONSTANT FINAL) + Q_PROPERTY(DownloadState state READ state NOTIFY stateChanged) + Q_PROPERTY(int progress READ progress NOTIFY progressChanged) + Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged) + + Q_INVOKABLE void cancel(); + + quint32 id(); + DownloadState state(); + int progress(); + QString path(); + void setPath(QString path); + +Q_SIGNALS: + void stateChanged(); + void progressChanged(); + void pathChanged(); + +private: + QQuickWebEngineDownloadItem(QQuickWebEngineDownloadItemPrivate*, QObject *parent = 0); + Q_DISABLE_COPY(QQuickWebEngineDownloadItem) + Q_DECLARE_PRIVATE(QQuickWebEngineDownloadItem) + friend class QQuickWebEngineProfilePrivate; + + QScopedPointer<QQuickWebEngineDownloadItemPrivate> d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QQUICKWEBENGINEDOWNLOADITEM_P_H diff --git a/src/webengine/api/qquickwebenginedownloaditem_p_p.h b/src/webengine/api/qquickwebenginedownloaditem_p_p.h new file mode 100644 index 000000000..6b724b4c9 --- /dev/null +++ b/src/webengine/api/qquickwebenginedownloaditem_p_p.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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$ +** +****************************************************************************/ + +#ifndef QQUICKWEBENGINEDOWNLOADITEM_P_P_H +#define QQUICKWEBENGINEDOWNLOADITEM_P_P_H + +#include "qquickwebenginedownloaditem_p.h" +#include "qquickwebengineprofile_p_p.h" +#include <private/qtwebengineglobal_p.h> +#include <QString> + +QT_BEGIN_NAMESPACE + +class QQuickWebEngineDownloadItemPrivate { + QQuickWebEngineDownloadItem *q_ptr; + QQuickWebEngineProfilePrivate* profile; + friend class QQuickWebEngineProfilePrivate; +public: + Q_DECLARE_PUBLIC(QQuickWebEngineDownloadItem) + QQuickWebEngineDownloadItemPrivate(QQuickWebEngineProfilePrivate *p); + ~QQuickWebEngineDownloadItemPrivate(); + + bool downloadStarted; + quint32 downloadId; + QQuickWebEngineDownloadItem::DownloadState downloadState; + int downloadProgress; + QString downloadPath; + + void update(QQuickWebEngineDownloadItem::DownloadState state, int progress); +}; + +QT_END_NAMESPACE + +#endif // QQUICKWEBENGINEDOWNLOADITEM_P_P_H diff --git a/src/webengine/api/qquickwebengineprofile.cpp b/src/webengine/api/qquickwebengineprofile.cpp new file mode 100644 index 000000000..9eecae073 --- /dev/null +++ b/src/webengine/api/qquickwebengineprofile.cpp @@ -0,0 +1,293 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 "qquickwebengineprofile_p.h" + +#include "qquickwebenginedownloaditem_p.h" +#include "qquickwebenginedownloaditem_p_p.h" +#include "qquickwebengineprofile_p_p.h" +#include <QQmlEngine> + +#include "browser_context_adapter.h" + +QT_BEGIN_NAMESPACE + +static inline QQuickWebEngineDownloadItem::DownloadState toDownloadState(int state) { + switch (state) { + case BrowserContextAdapterClient::DownloadInProgress: + return QQuickWebEngineDownloadItem::DownloadInProgress; + case BrowserContextAdapterClient::DownloadCompleted: + return QQuickWebEngineDownloadItem::DownloadCompleted; + case BrowserContextAdapterClient::DownloadCancelled: + return QQuickWebEngineDownloadItem::DownloadCancelled; + case BrowserContextAdapterClient::DownloadInterrupted: + return QQuickWebEngineDownloadItem::DownloadInterrupted; + default: + Q_UNREACHABLE(); + return QQuickWebEngineDownloadItem::DownloadCancelled; + } +} + +QQuickWebEngineProfilePrivate::QQuickWebEngineProfilePrivate(BrowserContextAdapter* browserContext, bool ownsContext) + : m_browserContext(browserContext) +{ + if (ownsContext) + m_browserContextRef = browserContext; + + m_browserContext->setClient(this); +} + +QQuickWebEngineProfilePrivate::~QQuickWebEngineProfilePrivate() +{ + m_browserContext->setClient(0); + + Q_FOREACH (QQuickWebEngineDownloadItem* download, m_ongoingDownloads) { + if (download) + download->cancel(); + } + + m_ongoingDownloads.clear(); +} + +void QQuickWebEngineProfilePrivate::cancelDownload(quint32 downloadId) +{ + m_browserContext->cancelDownload(downloadId); +} + +void QQuickWebEngineProfilePrivate::downloadDestroyed(quint32 downloadId) +{ + m_ongoingDownloads.remove(downloadId); +} + +void QQuickWebEngineProfilePrivate::downloadRequested(quint32 downloadId, QString &downloadPath, bool &cancelled) +{ + Q_Q(QQuickWebEngineProfile); + + Q_ASSERT(!m_ongoingDownloads.contains(downloadId)); + QQuickWebEngineDownloadItemPrivate *itemPrivate = new QQuickWebEngineDownloadItemPrivate(this); + itemPrivate->downloadId = downloadId; + itemPrivate->downloadState = QQuickWebEngineDownloadItem::DownloadInProgress; + itemPrivate->downloadPath = downloadPath; + + QQuickWebEngineDownloadItem *download = new QQuickWebEngineDownloadItem(itemPrivate, q); + + m_ongoingDownloads.insert(downloadId, download); + + QQmlEngine::setObjectOwnership(download, QQmlEngine::JavaScriptOwnership); + Q_EMIT q->downloadStarted(download); + download->d_func()->downloadStarted = true; + + downloadPath = download->path(); + cancelled = download->state() == QQuickWebEngineDownloadItem::DownloadCancelled; +} + +void QQuickWebEngineProfilePrivate::downloadUpdated(quint32 downloadId, int downloadState, int percentComplete) +{ + Q_Q(QQuickWebEngineProfile); + + Q_ASSERT(m_ongoingDownloads.contains(downloadId)); + QQuickWebEngineDownloadItem* download = m_ongoingDownloads.value(downloadId).data(); + + if (!download) { + cancelDownload(downloadId); + return; + } + + download->d_func()->update(toDownloadState(downloadState), percentComplete); + + if (downloadState != BrowserContextAdapterClient::DownloadInProgress) { + Q_EMIT q->downloadFinished(download); + m_ongoingDownloads.remove(downloadId); + } +} + +QQuickWebEngineProfile::QQuickWebEngineProfile() + : d_ptr(new QQuickWebEngineProfilePrivate(new BrowserContextAdapter(false), true)) +{ + d_ptr->q_ptr = this; +} + +QQuickWebEngineProfile::QQuickWebEngineProfile(QQuickWebEngineProfilePrivate *privatePtr) + : d_ptr(privatePtr) +{ + d_ptr->q_ptr = this; +} + +QQuickWebEngineProfile::~QQuickWebEngineProfile() +{ +} + +QString QQuickWebEngineProfile::storageName() const +{ + const Q_D(QQuickWebEngineProfile); + return d->browserContext()->storageName(); +} + +void QQuickWebEngineProfile::setStorageName(const QString &name) +{ + Q_D(QQuickWebEngineProfile); + if (d->browserContext()->storageName() == name) + return; + BrowserContextAdapter::HttpCacheType oldCacheType = d->browserContext()->httpCacheType(); + BrowserContextAdapter::PersistentCookiesPolicy oldPolicy = d->browserContext()->persistentCookiesPolicy(); + d->browserContext()->setStorageName(name); + emit storageNameChanged(); + emit persistentStoragePathChanged(); + emit cachePathChanged(); + if (d->browserContext()->httpCacheType() != oldCacheType) + emit httpCacheTypeChanged(); + if (d->browserContext()->persistentCookiesPolicy() != oldPolicy) + emit persistentCookiesPolicyChanged(); +} + +bool QQuickWebEngineProfile::isOffTheRecord() const +{ + const Q_D(QQuickWebEngineProfile); + return d->browserContext()->isOffTheRecord(); +} + +void QQuickWebEngineProfile::setOffTheRecord(bool offTheRecord) +{ + Q_D(QQuickWebEngineProfile); + if (d->browserContext()->isOffTheRecord() == offTheRecord) + return; + BrowserContextAdapter::HttpCacheType oldCacheType = d->browserContext()->httpCacheType(); + BrowserContextAdapter::PersistentCookiesPolicy oldPolicy = d->browserContext()->persistentCookiesPolicy(); + d->browserContext()->setOffTheRecord(offTheRecord); + emit offTheRecordChanged(); + if (d->browserContext()->httpCacheType() != oldCacheType) + emit httpCacheTypeChanged(); + if (d->browserContext()->persistentCookiesPolicy() != oldPolicy) + emit persistentCookiesPolicyChanged(); +} + +QString QQuickWebEngineProfile::persistentStoragePath() const +{ + const Q_D(QQuickWebEngineProfile); + return d->browserContext()->dataPath(); +} + +void QQuickWebEngineProfile::setPersistentStoragePath(const QString &path) +{ + Q_D(QQuickWebEngineProfile); + if (persistentStoragePath() == path) + return; + d->browserContext()->setDataPath(path); + emit persistentStoragePathChanged(); +} + +QString QQuickWebEngineProfile::cachePath() const +{ + const Q_D(QQuickWebEngineProfile); + return d->browserContext()->cachePath(); +} + +void QQuickWebEngineProfile::setCachePath(const QString &path) +{ + Q_D(QQuickWebEngineProfile); + if (cachePath() == path) + return; + d->browserContext()->setCachePath(path); + emit cachePathChanged(); +} + +QString QQuickWebEngineProfile::httpUserAgent() const +{ + const Q_D(QQuickWebEngineProfile); + return d->browserContext()->httpUserAgent(); +} + +void QQuickWebEngineProfile::setHttpUserAgent(const QString &userAgent) +{ + Q_D(QQuickWebEngineProfile); + if (d->browserContext()->httpUserAgent() == userAgent) + return; + d->browserContext()->setHttpUserAgent(userAgent); + emit httpUserAgentChanged(); +} + +QQuickWebEngineProfile::HttpCacheType QQuickWebEngineProfile::httpCacheType() const +{ + const Q_D(QQuickWebEngineProfile); + return QQuickWebEngineProfile::HttpCacheType(d->browserContext()->httpCacheType()); +} + +void QQuickWebEngineProfile::setHttpCacheType(QQuickWebEngineProfile::HttpCacheType httpCacheType) +{ + Q_D(QQuickWebEngineProfile); + BrowserContextAdapter::HttpCacheType oldCacheType = d->browserContext()->httpCacheType(); + d->browserContext()->setHttpCacheType(BrowserContextAdapter::HttpCacheType(httpCacheType)); + if (d->browserContext()->httpCacheType() != oldCacheType) + emit httpCacheTypeChanged(); +} + +QQuickWebEngineProfile::PersistentCookiesPolicy QQuickWebEngineProfile::persistentCookiesPolicy() const +{ + const Q_D(QQuickWebEngineProfile); + return QQuickWebEngineProfile::PersistentCookiesPolicy(d->browserContext()->persistentCookiesPolicy()); +} + +void QQuickWebEngineProfile::setPersistentCookiesPolicy(QQuickWebEngineProfile::PersistentCookiesPolicy newPersistentCookiesPolicy) +{ + Q_D(QQuickWebEngineProfile); + BrowserContextAdapter::PersistentCookiesPolicy oldPolicy = d->browserContext()->persistentCookiesPolicy(); + d->browserContext()->setPersistentCookiesPolicy(BrowserContextAdapter::PersistentCookiesPolicy(newPersistentCookiesPolicy)); + if (d->browserContext()->persistentCookiesPolicy() != oldPolicy) + emit persistentCookiesPolicyChanged(); +} + +int QQuickWebEngineProfile::httpCacheMaxSize() const +{ + const Q_D(QQuickWebEngineProfile); + return d->browserContext()->httpCacheMaxSize(); +} + +void QQuickWebEngineProfile::setHttpCacheMaxSize(int maxSize) +{ + Q_D(QQuickWebEngineProfile); + if (d->browserContext()->httpCacheMaxSize() == maxSize) + return; + d->browserContext()->setHttpCacheMaxSize(maxSize); + emit httpCacheMaxSizeChanged(); +} + +QQuickWebEngineProfile *QQuickWebEngineProfile::defaultProfile() +{ + static QQuickWebEngineProfile profile(new QQuickWebEngineProfilePrivate(BrowserContextAdapter::defaultContext(), false)); + return &profile; +} + +QT_END_NAMESPACE diff --git a/src/webengine/api/qquickwebengineprofile_p.h b/src/webengine/api/qquickwebengineprofile_p.h new file mode 100644 index 000000000..b8d7c8652 --- /dev/null +++ b/src/webengine/api/qquickwebengineprofile_p.h @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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$ +** +****************************************************************************/ + +#ifndef QQUICKWEBENGINEPROFILE_P_H +#define QQUICKWEBENGINEPROFILE_P_H + +#include <private/qtwebengineglobal_p.h> + +#include <QObject> +#include <QScopedPointer> +#include <QString> + +QT_BEGIN_NAMESPACE + +class QQuickWebEngineDownloadItem; +class QQuickWebEngineProfilePrivate; + +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) + Q_PROPERTY(QString cachePath READ cachePath WRITE setCachePath NOTIFY cachePathChanged FINAL) + Q_PROPERTY(QString httpUserAgent READ httpUserAgent WRITE setHttpUserAgent NOTIFY httpUserAgentChanged FINAL) + Q_PROPERTY(HttpCacheType httpCacheType READ httpCacheType WRITE setHttpCacheType NOTIFY httpCacheTypeChanged FINAL) + Q_PROPERTY(PersistentCookiesPolicy persistentCookiesPolicy READ persistentCookiesPolicy WRITE setPersistentCookiesPolicy NOTIFY persistentCookiesPolicyChanged FINAL) + Q_PROPERTY(int httpCacheMaxSize READ httpCacheMaxSize WRITE setHttpCacheMaxSize NOTIFY httpCacheMaxSizeChanged FINAL) +public: + QQuickWebEngineProfile(); + ~QQuickWebEngineProfile(); + + enum HttpCacheType { + MemoryHttpCache, + DiskHttpCache + }; + + enum PersistentCookiesPolicy { + NoPersistentCookies, + AllowPersistentCookies, + ForcePersistentCookies + }; + + QString storageName() const; + void setStorageName(const QString &name); + + bool isOffTheRecord() const; + void setOffTheRecord(bool offTheRecord); + + QString persistentStoragePath() const; + void setPersistentStoragePath(const QString &path); + + QString cachePath() const; + void setCachePath(const QString &path); + + QString httpUserAgent() const; + void setHttpUserAgent(const QString &userAgent); + + HttpCacheType httpCacheType() const; + void setHttpCacheType(QQuickWebEngineProfile::HttpCacheType); + + PersistentCookiesPolicy persistentCookiesPolicy() const; + void setPersistentCookiesPolicy(QQuickWebEngineProfile::PersistentCookiesPolicy); + + int httpCacheMaxSize() const; + void setHttpCacheMaxSize(int maxSize); + + static QQuickWebEngineProfile *defaultProfile(); + +signals: + void storageNameChanged(); + void offTheRecordChanged(); + void persistentStoragePathChanged(); + void cachePathChanged(); + void httpUserAgentChanged(); + void httpCacheTypeChanged(); + void persistentCookiesPolicyChanged(); + void httpCacheMaxSizeChanged(); + + void downloadStarted(QQuickWebEngineDownloadItem *download); + void downloadFinished(QQuickWebEngineDownloadItem *download); + +private: + Q_DECLARE_PRIVATE(QQuickWebEngineProfile); + QQuickWebEngineProfile(QQuickWebEngineProfilePrivate *); + + friend class QQuickWebEngineViewPrivate; + QScopedPointer<QQuickWebEngineProfilePrivate> d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QQUICKWEBENGINEPROFILE_P_H diff --git a/src/webengine/api/qquickwebengineprofile_p_p.h b/src/webengine/api/qquickwebengineprofile_p_p.h new file mode 100644 index 000000000..18ccfc467 --- /dev/null +++ b/src/webengine/api/qquickwebengineprofile_p_p.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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$ +** +****************************************************************************/ + +#ifndef QQUICKWEBENGINEPROFILE_P_P_H +#define QQUICKWEBENGINEPROFILE_P_P_H + +class BrowserContextAdapter; + +#include "browser_context_adapter_client.h" +#include "qquickwebengineprofile_p.h" + +#include <QExplicitlySharedDataPointer> +#include <QMap> +#include <QPointer> + +QT_BEGIN_NAMESPACE +class QQuickWebEngineDownloadItem; +class QQuickWebEngineProfilePrivate + : public BrowserContextAdapterClient +{ +public: + Q_DECLARE_PUBLIC(QQuickWebEngineProfile) + QQuickWebEngineProfilePrivate(BrowserContextAdapter* browserContext, bool ownsContext); + ~QQuickWebEngineProfilePrivate(); + + BrowserContextAdapter *browserContext() const { return m_browserContext; } + + void cancelDownload(quint32 downloadId); + void downloadDestroyed(quint32 downloadId); + + void downloadRequested(quint32 downloadId, QString &downloadPath, bool &cancelled) Q_DECL_OVERRIDE; + void downloadUpdated(quint32 downloadId, int downloadState, int percentComplete) Q_DECL_OVERRIDE; + +private: + friend class QQuickWebEngineViewPrivate; + QQuickWebEngineProfile *q_ptr; + BrowserContextAdapter *m_browserContext; + QExplicitlySharedDataPointer<BrowserContextAdapter> m_browserContextRef; + QMap<quint32, QPointer<QQuickWebEngineDownloadItem> > m_ongoingDownloads; +}; + +QT_END_NAMESPACE + +#endif // QQUICKWEBENGINEPROFILE_P_P_H diff --git a/src/webengine/api/qquickwebenginesettings.cpp b/src/webengine/api/qquickwebenginesettings.cpp index 743d22d81..e46b1a80d 100644 --- a/src/webengine/api/qquickwebenginesettings.cpp +++ b/src/webengine/api/qquickwebenginesettings.cpp @@ -43,6 +43,20 @@ QT_BEGIN_NAMESPACE Q_GLOBAL_STATIC(QList<QQuickWebEngineSettingsPrivate*>, allSettings) +class QQuickWebEngineGlobalSettings { + QQuickWebEngineSettings globalSettings; +public: + QQuickWebEngineGlobalSettings() { + // globalSettings shouldn't be in that list. + allSettings->removeAll(globalSettings.d_func()); + globalSettings.d_func()->coreSettings->initDefaults(); + } + + QQuickWebEngineSettings *data() { return &globalSettings; } +}; + +Q_GLOBAL_STATIC(QQuickWebEngineGlobalSettings, globalInstance) + QQuickWebEngineSettingsPrivate::QQuickWebEngineSettingsPrivate() : coreSettings(new WebEngineSettings(this)) { @@ -64,16 +78,9 @@ WebEngineSettings *QQuickWebEngineSettingsPrivate::fallbackSettings() const return QQuickWebEngineSettings::globalSettings()->d_func()->coreSettings.data(); } - QQuickWebEngineSettings *QQuickWebEngineSettings::globalSettings() { - static QQuickWebEngineSettings *globals = 0; - if (!globals) { - globals = new QQuickWebEngineSettings; - allSettings->removeAll(globals->d_func()); - globals->d_func()->coreSettings->initDefaults(); - } - return globals; + return globalInstance()->data(); } QQuickWebEngineSettings::~QQuickWebEngineSettings() @@ -161,7 +168,7 @@ void QQuickWebEngineSettings::setAutoLoadImages(bool on) // could be from the fallback and is prone to changing later on. d->coreSettings->setAttribute(WebEngineSettings::AutoLoadImages, on); if (wasOn ^ on) - Q_EMIT autoLoadImagesChanged(on); + Q_EMIT autoLoadImagesChanged(); } void QQuickWebEngineSettings::setJavascriptEnabled(bool on) @@ -170,7 +177,7 @@ void QQuickWebEngineSettings::setJavascriptEnabled(bool on) bool wasOn = d->coreSettings->testAttribute(WebEngineSettings::JavascriptEnabled); d->coreSettings->setAttribute(WebEngineSettings::JavascriptEnabled, on); if (wasOn ^ on) - Q_EMIT javascriptEnabledChanged(on); + Q_EMIT javascriptEnabledChanged(); } void QQuickWebEngineSettings::setJavascriptCanOpenWindows(bool on) @@ -179,7 +186,7 @@ void QQuickWebEngineSettings::setJavascriptCanOpenWindows(bool on) bool wasOn = d->coreSettings->testAttribute(WebEngineSettings::JavascriptCanOpenWindows); d->coreSettings->setAttribute(WebEngineSettings::JavascriptCanOpenWindows, on); if (wasOn ^ on) - Q_EMIT javascriptCanOpenWindowsChanged(on); + Q_EMIT javascriptCanOpenWindowsChanged(); } void QQuickWebEngineSettings::setJavascriptCanAccessClipboard(bool on) @@ -188,7 +195,7 @@ void QQuickWebEngineSettings::setJavascriptCanAccessClipboard(bool on) bool wasOn = d->coreSettings->testAttribute(WebEngineSettings::JavascriptCanAccessClipboard); d->coreSettings->setAttribute(WebEngineSettings::JavascriptCanAccessClipboard, on); if (wasOn ^ on) - Q_EMIT javascriptCanAccessClipboardChanged(on); + Q_EMIT javascriptCanAccessClipboardChanged(); } void QQuickWebEngineSettings::setLinksIncludedInFocusChain(bool on) @@ -197,7 +204,7 @@ void QQuickWebEngineSettings::setLinksIncludedInFocusChain(bool on) bool wasOn = d->coreSettings->testAttribute(WebEngineSettings::LinksIncludedInFocusChain); d->coreSettings->setAttribute(WebEngineSettings::LinksIncludedInFocusChain, on); if (wasOn ^ on) - Q_EMIT linksIncludedInFocusChainChanged(on); + Q_EMIT linksIncludedInFocusChainChanged(); } void QQuickWebEngineSettings::setLocalStorageEnabled(bool on) @@ -206,7 +213,7 @@ void QQuickWebEngineSettings::setLocalStorageEnabled(bool on) bool wasOn = d->coreSettings->testAttribute(WebEngineSettings::LocalStorageEnabled); d->coreSettings->setAttribute(WebEngineSettings::LocalStorageEnabled, on); if (wasOn ^ on) - Q_EMIT localStorageEnabledChanged(on); + Q_EMIT localStorageEnabledChanged(); } void QQuickWebEngineSettings::setLocalContentCanAccessRemoteUrls(bool on) @@ -215,7 +222,7 @@ void QQuickWebEngineSettings::setLocalContentCanAccessRemoteUrls(bool on) bool wasOn = d->coreSettings->testAttribute(WebEngineSettings::LocalContentCanAccessRemoteUrls); d->coreSettings->setAttribute(WebEngineSettings::LocalContentCanAccessRemoteUrls, on); if (wasOn ^ on) - Q_EMIT localContentCanAccessRemoteUrlsChanged(on); + Q_EMIT localContentCanAccessRemoteUrlsChanged(); } @@ -225,7 +232,7 @@ void QQuickWebEngineSettings::setSpatialNavigationEnabled(bool on) bool wasOn = d->coreSettings->testAttribute(WebEngineSettings::SpatialNavigationEnabled); d->coreSettings->setAttribute(WebEngineSettings::SpatialNavigationEnabled, on); if (wasOn ^ on) - Q_EMIT spatialNavigationEnabledChanged(on); + Q_EMIT spatialNavigationEnabledChanged(); } void QQuickWebEngineSettings::setLocalContentCanAccessFileUrls(bool on) @@ -234,7 +241,7 @@ void QQuickWebEngineSettings::setLocalContentCanAccessFileUrls(bool on) bool wasOn = d->coreSettings->testAttribute(WebEngineSettings::LocalContentCanAccessFileUrls); d->coreSettings->setAttribute(WebEngineSettings::LocalContentCanAccessFileUrls, on); if (wasOn ^ on) - Q_EMIT localContentCanAccessFileUrlsChanged(on); + Q_EMIT localContentCanAccessFileUrlsChanged(); } void QQuickWebEngineSettings::setHyperlinkAuditingEnabled(bool on) @@ -243,7 +250,7 @@ void QQuickWebEngineSettings::setHyperlinkAuditingEnabled(bool on) bool wasOn = d->coreSettings->testAttribute(WebEngineSettings::HyperlinkAuditingEnabled); d->coreSettings->setAttribute(WebEngineSettings::HyperlinkAuditingEnabled, on); if (wasOn ^ on) - Q_EMIT hyperlinkAuditingEnabledChanged(on); + Q_EMIT hyperlinkAuditingEnabledChanged(); } void QQuickWebEngineSettings::setErrorPageEnabled(bool on) @@ -252,7 +259,7 @@ void QQuickWebEngineSettings::setErrorPageEnabled(bool on) bool wasOn = d->coreSettings->testAttribute(WebEngineSettings::ErrorPageEnabled); d->coreSettings->setAttribute(WebEngineSettings::ErrorPageEnabled, on); if (wasOn ^ on) - Q_EMIT errorPageEnabledChanged(on); + Q_EMIT errorPageEnabledChanged(); } void QQuickWebEngineSettings::setDefaultTextEncoding(QString encoding) @@ -261,7 +268,7 @@ void QQuickWebEngineSettings::setDefaultTextEncoding(QString encoding) const QString oldDefaultTextEncoding = d->coreSettings->defaultTextEncoding(); d->coreSettings->setDefaultTextEncoding(encoding); if (oldDefaultTextEncoding.compare(encoding)) - Q_EMIT defaultTextEncodingChanged(encoding); + Q_EMIT defaultTextEncodingChanged(); } QQuickWebEngineSettings::QQuickWebEngineSettings() diff --git a/src/webengine/api/qquickwebenginesettings_p.h b/src/webengine/api/qquickwebenginesettings_p.h index 4a7c2f834..040a5f5fb 100644 --- a/src/webengine/api/qquickwebenginesettings_p.h +++ b/src/webengine/api/qquickwebenginesettings_p.h @@ -44,6 +44,7 @@ QT_BEGIN_NAMESPACE class QQuickWebEngineSettingsPrivate; +class QQuickWebEngineGlobalSettings; class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineSettings : public QObject { Q_OBJECT @@ -92,24 +93,25 @@ public: void setDefaultTextEncoding(QString encoding); signals: - void autoLoadImagesChanged(bool on); - void javascriptEnabledChanged(bool on); - void javascriptCanOpenWindowsChanged(bool on); - void javascriptCanAccessClipboardChanged(bool on); - void linksIncludedInFocusChainChanged(bool on); - void localStorageEnabledChanged(bool on); - void localContentCanAccessRemoteUrlsChanged(bool on); - void spatialNavigationEnabledChanged(bool on); - void localContentCanAccessFileUrlsChanged(bool on); - void hyperlinkAuditingEnabledChanged(bool on); - void errorPageEnabledChanged(bool on); - void defaultTextEncodingChanged(QString encoding); + void autoLoadImagesChanged(); + void javascriptEnabledChanged(); + void javascriptCanOpenWindowsChanged(); + void javascriptCanAccessClipboardChanged(); + void linksIncludedInFocusChainChanged(); + void localStorageEnabledChanged(); + void localContentCanAccessRemoteUrlsChanged(); + void spatialNavigationEnabledChanged(); + void localContentCanAccessFileUrlsChanged(); + void hyperlinkAuditingEnabledChanged(); + void errorPageEnabledChanged(); + void defaultTextEncodingChanged(); private: QQuickWebEngineSettings(); Q_DISABLE_COPY(QQuickWebEngineSettings) Q_DECLARE_PRIVATE(QQuickWebEngineSettings) friend class QQuickWebEngineViewPrivate; + friend class QQuickWebEngineGlobalSettings; QScopedPointer<QQuickWebEngineSettingsPrivate> d_ptr; }; diff --git a/src/webengine/api/qquickwebenginesettings_p_p.h b/src/webengine/api/qquickwebenginesettings_p_p.h index 8f3e95eea..05a163b92 100644 --- a/src/webengine/api/qquickwebenginesettings_p_p.h +++ b/src/webengine/api/qquickwebenginesettings_p_p.h @@ -44,7 +44,6 @@ QT_BEGIN_NAMESPACE class QQuickWebEngineSettingsPrivate : public WebEngineSettingsDelegate { public: QQuickWebEngineSettingsPrivate(); - QQuickWebEngineSettingsPrivate(WebContentsAdapter *adapter); void apply() Q_DECL_OVERRIDE; WebEngineSettings *fallbackSettings() const Q_DECL_OVERRIDE; diff --git a/src/webengine/api/qquickwebenginesingleton.cpp b/src/webengine/api/qquickwebenginesingleton.cpp index bf4951f3b..280f5b913 100644 --- a/src/webengine/api/qquickwebenginesingleton.cpp +++ b/src/webengine/api/qquickwebenginesingleton.cpp @@ -37,6 +37,7 @@ #include "qquickwebenginesingleton_p.h" #include "qquickwebenginesettings_p.h" +#include "qquickwebengineprofile_p.h" QT_BEGIN_NAMESPACE @@ -45,4 +46,9 @@ QQuickWebEngineSettings *QQuickWebEngineSingleton::settings() const return QQuickWebEngineSettings::globalSettings(); } +QQuickWebEngineProfile *QQuickWebEngineSingleton::defaultProfile() const +{ + return QQuickWebEngineProfile::defaultProfile(); +} + QT_END_NAMESPACE diff --git a/src/webengine/api/qquickwebenginesingleton_p.h b/src/webengine/api/qquickwebenginesingleton_p.h index 23205e2df..f983d0ffb 100644 --- a/src/webengine/api/qquickwebenginesingleton_p.h +++ b/src/webengine/api/qquickwebenginesingleton_p.h @@ -41,14 +41,16 @@ #include <qtwebengineglobal_p.h> QT_BEGIN_NAMESPACE +class QQuickWebEngineProfile; class QQuickWebEngineSettings; - class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineSingleton : public QObject { Q_OBJECT Q_PROPERTY(QQuickWebEngineSettings* settings READ settings CONSTANT FINAL) + Q_PROPERTY(QQuickWebEngineProfile* defaultProfile READ defaultProfile CONSTANT FINAL REVISION 1) public: QQuickWebEngineSettings *settings() const; + QQuickWebEngineProfile *defaultProfile() const; }; QT_END_NAMESPACE diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp index 3497c16ad..1b95f86b4 100644 --- a/src/webengine/api/qquickwebengineview.cpp +++ b/src/webengine/api/qquickwebengineview.cpp @@ -37,12 +37,15 @@ #include "qquickwebengineview_p.h" #include "qquickwebengineview_p_p.h" +#include "browser_context_adapter.h" #include "certificate_error_controller.h" #include "javascript_dialog_controller.h" #include "qquickwebenginehistory_p.h" #include "qquickwebengineloadrequest_p.h" #include "qquickwebenginenavigationrequest_p.h" #include "qquickwebenginenewviewrequest_p.h" +#include "qquickwebengineprofile_p.h" +#include "qquickwebengineprofile_p_p.h" #include "qquickwebenginesettings_p.h" #include "qquickwebenginesettings_p_p.h" #include "render_widget_host_view_qt_delegate_quick.h" @@ -73,10 +76,11 @@ static QAccessibleInterface *webAccessibleFactory(const QString &, QObject *obje } QQuickWebEngineViewPrivate::QQuickWebEngineViewPrivate() - : adapter(new WebContentsAdapter) + : adapter(0) , e(new QQuickWebEngineViewExperimental(this)) , v(new QQuickWebEngineViewport(this)) , m_history(new QQuickWebEngineHistory(this)) + , m_profile(QQuickWebEngineProfile::defaultProfile()) , m_settings(new QQuickWebEngineSettings) , contextMenuExtraItems(0) , loadProgress(0) @@ -217,6 +221,11 @@ void QQuickWebEngineViewPrivate::allowCertificateError(const QExplicitlySharedDa Q_UNUSED(errorController); } +void QQuickWebEngineViewPrivate::runGeolocationPermissionRequest(const QUrl &url) +{ + Q_EMIT e->featurePermissionRequested(url, QQuickWebEngineViewExperimental::Geolocation); +} + void QQuickWebEngineViewPrivate::runFileChooser(FileChooserMode mode, const QString &defaultFileName, const QStringList &acceptedMimeTypes) { ui()->showFilePicker(mode, defaultFileName, acceptedMimeTypes, adapter); @@ -343,9 +352,11 @@ void QQuickWebEngineViewPrivate::adoptNewWindow(WebContentsAdapter *newWebConten switch (disposition) { case WebContentsAdapterClient::NewForegroundTabDisposition: - case WebContentsAdapterClient::NewBackgroundTabDisposition: request.m_destination = QQuickWebEngineView::NewViewInTab; break; + case WebContentsAdapterClient::NewBackgroundTabDisposition: + request.m_destination = QQuickWebEngineView::NewViewInBackgroundTab; + break; case WebContentsAdapterClient::NewPopupDisposition: request.m_destination = QQuickWebEngineView::NewViewInDialog; break; @@ -356,7 +367,7 @@ void QQuickWebEngineViewPrivate::adoptNewWindow(WebContentsAdapter *newWebConten Q_UNREACHABLE(); } - emit e->newViewRequested(&request); + Q_EMIT e->newViewRequested(&request); } void QQuickWebEngineViewPrivate::close() @@ -387,20 +398,34 @@ void QQuickWebEngineViewPrivate::runMediaAccessPermissionRequest(const QUrl &sec return; QQuickWebEngineViewExperimental::Feature feature; if (requestFlags.testFlag(WebContentsAdapterClient::MediaAudioCapture) && requestFlags.testFlag(WebContentsAdapterClient::MediaVideoCapture)) - feature = QQuickWebEngineViewExperimental::MediaAudioVideoDevices; + feature = QQuickWebEngineViewExperimental::MediaAudioVideoCapture; else if (requestFlags.testFlag(WebContentsAdapterClient::MediaAudioCapture)) - feature = QQuickWebEngineViewExperimental::MediaAudioDevices; + feature = QQuickWebEngineViewExperimental::MediaAudioCapture; else // WebContentsAdapterClient::MediaVideoCapture - feature = QQuickWebEngineViewExperimental::MediaVideoDevices; + feature = QQuickWebEngineViewExperimental::MediaVideoCapture; Q_EMIT e->featurePermissionRequested(securityOrigin, feature); } +void QQuickWebEngineViewPrivate::runMouseLockPermissionRequest(const QUrl &securityOrigin) +{ + + Q_UNUSED(securityOrigin); + + // TODO: Add mouse lock support + adapter->grantMouseLockPermission(false); +} + QObject *QQuickWebEngineViewPrivate::accessibilityParentObject() { Q_Q(QQuickWebEngineView); return q; } +BrowserContextAdapter *QQuickWebEngineViewPrivate::browserContextAdapter() +{ + return m_profile->d_ptr->browserContext(); +} + WebEngineSettings *QQuickWebEngineViewPrivate::webEngineSettings() const { return m_settings->d_func()->coreSettings.data(); @@ -493,7 +518,6 @@ QQuickWebEngineView::QQuickWebEngineView(QQuickItem *parent) { Q_D(QQuickWebEngineView); d->e->q_ptr = d->q_ptr = this; - d->adapter->initialize(d); this->setActiveFocusOnTab(true); this->setFlag(QQuickItem::ItemIsFocusScope); @@ -505,10 +529,21 @@ QQuickWebEngineView::~QQuickWebEngineView() { } +void QQuickWebEngineViewPrivate::ensureContentsAdapter() +{ + if (!adapter) { + adapter = new WebContentsAdapter(); + adapter->initialize(this); + adapter->enableInspector(inspectable); + if (explicitUrl.isValid()) + adapter->load(explicitUrl); + } +} + QUrl QQuickWebEngineView::url() const { Q_D(const QQuickWebEngineView); - return d->explicitUrl.isValid() ? d->explicitUrl : d->adapter->activeUrl(); + return d->explicitUrl.isValid() ? d->explicitUrl : (d->adapter ? d->adapter->activeUrl() : QUrl()); } void QQuickWebEngineView::setUrl(const QUrl& url) @@ -518,7 +553,10 @@ void QQuickWebEngineView::setUrl(const QUrl& url) Q_D(QQuickWebEngineView); d->explicitUrl = url; - d->adapter->load(url); + if (d->adapter) + d->adapter->load(url); + if (!qmlEngine(this)) + d->ensureContentsAdapter(); } QUrl QQuickWebEngineView::icon() const @@ -530,33 +568,83 @@ QUrl QQuickWebEngineView::icon() const void QQuickWebEngineView::loadHtml(const QString &html, const QUrl &baseUrl) { Q_D(QQuickWebEngineView); - d->adapter->setContent(html.toUtf8(), QStringLiteral("text/html;charset=UTF-8"), baseUrl); + d->explicitUrl = QUrl(); + if (!qmlEngine(this)) + d->ensureContentsAdapter(); + if (d->adapter) + d->adapter->setContent(html.toUtf8(), QStringLiteral("text/html;charset=UTF-8"), baseUrl); } void QQuickWebEngineView::goBack() { Q_D(QQuickWebEngineView); + if (!d->adapter) + return; d->adapter->navigateToOffset(-1); } void QQuickWebEngineView::goForward() { Q_D(QQuickWebEngineView); + if (!d->adapter) + return; d->adapter->navigateToOffset(1); } void QQuickWebEngineView::reload() { Q_D(QQuickWebEngineView); + if (!d->adapter) + return; d->adapter->reload(); } void QQuickWebEngineView::stop() { Q_D(QQuickWebEngineView); + if (!d->adapter) + return; d->adapter->stop(); } +void QQuickWebEngineView::setZoomFactor(qreal arg) +{ + Q_D(QQuickWebEngineView); + if (!d->adapter) + return; + qreal oldFactor = d->adapter->currentZoomFactor(); + d->adapter->setZoomFactor(arg); + if (qFuzzyCompare(oldFactor, d->adapter->currentZoomFactor())) + return; + + emit zoomFactorChanged(arg); +} + +QQuickWebEngineProfile *QQuickWebEngineView::profile() const +{ + Q_D(const QQuickWebEngineView); + return d->m_profile; +} + +void QQuickWebEngineView::setProfile(QQuickWebEngineProfile *profile) +{ + Q_D(QQuickWebEngineView); + d->setProfile(profile); +} + +void QQuickWebEngineViewPrivate::setProfile(QQuickWebEngineProfile *profile) +{ + m_profile = profile; + if (adapter && adapter->browserContext() != browserContextAdapter()->browserContext()) { + // When the profile changes we need to create a new WebContentAdapter and reload the active URL. + QUrl activeUrl = adapter->activeUrl(); + adapter = 0; + ensureContentsAdapter(); + if (!explicitUrl.isValid() && activeUrl.isValid()) + adapter->load(activeUrl); + } +} + void QQuickWebEngineViewPrivate::didRunJavaScript(quint64 requestId, const QVariant &result) { Q_Q(QQuickWebEngineView); @@ -589,24 +677,32 @@ int QQuickWebEngineView::loadProgress() const QString QQuickWebEngineView::title() const { Q_D(const QQuickWebEngineView); + if (!d->adapter) + return QString(); return d->adapter->pageTitle(); } bool QQuickWebEngineView::canGoBack() const { Q_D(const QQuickWebEngineView); + if (!d->adapter) + return false; return d->adapter->canGoBack(); } bool QQuickWebEngineView::canGoForward() const { Q_D(const QQuickWebEngineView); + if (!d->adapter) + return false; return d->adapter->canGoForward(); } void QQuickWebEngineView::runJavaScript(const QString &script, const QJSValue &callback) { Q_D(QQuickWebEngineView); + if (!d->adapter) + return; if (!callback.isUndefined()) { quint64 requestId = d_ptr->adapter->runJavaScriptCallbackResult(script); d->m_callbacks.insert(requestId, callback); @@ -620,6 +716,14 @@ QQuickWebEngineViewExperimental *QQuickWebEngineView::experimental() const return d->e.data(); } +qreal QQuickWebEngineView::zoomFactor() const +{ + Q_D(const QQuickWebEngineView); + if (!d->adapter) + return 1.0; + return d->adapter->currentZoomFactor(); +} + bool QQuickWebEngineViewExperimental::inspectable() const { Q_D(const QQuickWebEngineView); @@ -630,6 +734,8 @@ void QQuickWebEngineViewExperimental::setInspectable(bool enable) { Q_D(QQuickWebEngineView); d->inspectable = enable; + if (!d->adapter) + return; d->adapter->enableInspector(enable); } @@ -664,17 +770,20 @@ QQuickWebEngineSettings *QQuickWebEngineViewExperimental::settings() const void QQuickWebEngineViewExperimental::findText(const QString &subString, FindFlags options, const QJSValue &callback) { + Q_D(QQuickWebEngineView); + if (!d->adapter) + return; if (subString.isEmpty()) { - d_ptr->adapter->stopFinding(); + d->adapter->stopFinding(); if (!callback.isUndefined()) { QJSValueList args; args.append(QJSValue(0)); const_cast<QJSValue&>(callback).call(args); } } else { - quint64 requestId = d_ptr->adapter->findText(subString, options & FindCaseSensitively, options & FindBackward); + quint64 requestId = d->adapter->findText(subString, options & FindCaseSensitively, options & FindBackward); if (!callback.isUndefined()) - d_ptr->m_callbacks.insert(requestId, callback); + d->m_callbacks.insert(requestId, callback); } } @@ -685,27 +794,35 @@ QQuickWebEngineHistory *QQuickWebEngineViewExperimental::navigationHistory() con void QQuickWebEngineViewExperimental::grantFeaturePermission(const QUrl &securityOrigin, QQuickWebEngineViewExperimental::Feature feature, bool granted) { - if (!granted && feature >= MediaAudioDevices && feature <= MediaAudioVideoDevices) { + if (!d_ptr->adapter) + return; + if (!granted && feature >= MediaAudioCapture && feature <= MediaAudioVideoCapture) { d_ptr->adapter->grantMediaAccessPermission(securityOrigin, WebContentsAdapterClient::MediaNone); return; } switch (feature) { - case MediaAudioDevices: + case MediaAudioCapture: d_ptr->adapter->grantMediaAccessPermission(securityOrigin, WebContentsAdapterClient::MediaAudioCapture); break; - case MediaVideoDevices: + case MediaVideoCapture: d_ptr->adapter->grantMediaAccessPermission(securityOrigin, WebContentsAdapterClient::MediaVideoCapture); break; - case MediaAudioVideoDevices: - d_ptr->adapter->grantMediaAccessPermission(securityOrigin, WebContentsAdapterClient::MediaRequestFlags(WebContentsAdapterClient::MediaAudioCapture - | WebContentsAdapterClient::MediaVideoCapture)); + case MediaAudioVideoCapture: + d_ptr->adapter->grantMediaAccessPermission(securityOrigin, WebContentsAdapterClient::MediaRequestFlags(WebContentsAdapterClient::MediaAudioCapture | WebContentsAdapterClient::MediaVideoCapture)); + break; + case Geolocation: + d_ptr->adapter->runGeolocationRequestCallback(securityOrigin, granted); break; + default: + Q_UNREACHABLE(); } } void QQuickWebEngineViewExperimental::goBackTo(int index) { + if (!d_ptr->adapter) + return; int count = d_ptr->adapter->currentNavigationEntryIndex(); if (index < 0 || index >= count) return; @@ -715,6 +832,8 @@ void QQuickWebEngineViewExperimental::goBackTo(int index) void QQuickWebEngineViewExperimental::goForwardTo(int index) { + if (!d_ptr->adapter) + return; int count = d_ptr->adapter->navigationEntryCount() - d_ptr->adapter->currentNavigationEntryIndex() - 1; if (index < 0 || index >= count) return; @@ -734,7 +853,7 @@ void QQuickWebEngineView::geometryChanged(const QRectF &newGeometry, const QRect void QQuickWebEngineView::itemChange(ItemChange change, const ItemChangeData &value) { Q_D(QQuickWebEngineView); - if (change == ItemSceneChange || change == ItemVisibleHasChanged) { + if (d->adapter && (change == ItemSceneChange || change == ItemVisibleHasChanged)) { if (window() && isVisible()) d->adapter->wasShown(); else @@ -743,6 +862,13 @@ void QQuickWebEngineView::itemChange(ItemChange change, const ItemChangeData &va QQuickItem::itemChange(change, value); } +void QQuickWebEngineView::componentComplete() +{ + Q_D(QQuickWebEngineView); + QQuickItem::componentComplete(); + d->ensureContentsAdapter(); +} + QQuickWebEngineViewExperimental::QQuickWebEngineViewExperimental(QQuickWebEngineViewPrivate *viewPrivate) : q_ptr(0) , d_ptr(viewPrivate) @@ -774,6 +900,8 @@ void QQuickWebEngineViewport::setDevicePixelRatio(qreal devicePixelRatio) if (d->devicePixelRatio == devicePixelRatio) return; d->setDevicePixelRatio(devicePixelRatio); + if (!d->adapter) + return; d->adapter->dpiScaleChanged(); Q_EMIT devicePixelRatioChanged(); } diff --git a/src/webengine/api/qquickwebengineview_p.h b/src/webengine/api/qquickwebengineview_p.h index 22713ee22..f3ef133ae 100644 --- a/src/webengine/api/qquickwebengineview_p.h +++ b/src/webengine/api/qquickwebengineview_p.h @@ -42,10 +42,11 @@ QT_BEGIN_NAMESPACE -class QQuickWebEngineViewExperimental; -class QQuickWebEngineViewPrivate; class QQuickWebEngineLoadRequest; class QQuickWebEngineNavigationRequest; +class QQuickWebEngineProfile; +class QQuickWebEngineViewExperimental; +class QQuickWebEngineViewPrivate; class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineView : public QQuickItem { Q_OBJECT @@ -56,6 +57,8 @@ class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineView : public QQuickItem { Q_PROPERTY(QString title READ title NOTIFY titleChanged) Q_PROPERTY(bool canGoBack READ canGoBack NOTIFY urlChanged) Q_PROPERTY(bool canGoForward READ canGoForward NOTIFY urlChanged) + Q_PROPERTY(qreal zoomFactor READ zoomFactor WRITE setZoomFactor NOTIFY zoomFactorChanged) + Q_PROPERTY(QQuickWebEngineProfile *profile READ profile WRITE setProfile FINAL) Q_ENUMS(NavigationRequestAction); Q_ENUMS(NavigationType); Q_ENUMS(LoadStatus); @@ -75,6 +78,7 @@ public: QString title() const; bool canGoBack() const; bool canGoForward() const; + qreal zoomFactor() const; QQuickWebEngineViewExperimental *experimental() const; @@ -116,7 +120,8 @@ public: enum NewViewDestination { NewViewInWindow, NewViewInTab, - NewViewInDialog + NewViewInDialog, + NewViewInBackgroundTab }; // must match WebContentsAdapterClient::JavaScriptConsoleMessageLevel @@ -126,6 +131,12 @@ public: ErrorMessageLevel }; + // QmlParserStatus + virtual void componentComplete() Q_DECL_OVERRIDE; + + QQuickWebEngineProfile *profile() const; + void setProfile(QQuickWebEngineProfile *); + public Q_SLOTS: void runJavaScript(const QString&, const QJSValue & = QJSValue()); void loadHtml(const QString &html, const QUrl &baseUrl = QUrl()); @@ -133,6 +144,7 @@ public Q_SLOTS: void goForward(); void reload(); void stop(); + void setZoomFactor(qreal arg); Q_SIGNALS: void titleChanged(); @@ -143,6 +155,7 @@ Q_SIGNALS: void linkHovered(const QUrl &hoveredUrl); void navigationRequested(QQuickWebEngineNavigationRequest *request); void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString &message, int lineNumber, const QString &sourceID); + void zoomFactorChanged(qreal arg); protected: void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry); diff --git a/src/webengine/api/qquickwebengineview_p_p.h b/src/webengine/api/qquickwebengineview_p_p.h index 6662f1f02..f773b3d28 100644 --- a/src/webengine/api/qquickwebengineview_p_p.h +++ b/src/webengine/api/qquickwebengineview_p_p.h @@ -88,9 +88,10 @@ class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineViewExperimental : public QObjec public: enum Feature { - MediaAudioDevices, - MediaVideoDevices, - MediaAudioVideoDevices + MediaAudioCapture, + MediaVideoCapture, + MediaAudioVideoCapture, + Geolocation }; enum FindFlag { @@ -175,17 +176,24 @@ public: virtual void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString& message, int lineNumber, const QString& sourceID) Q_DECL_OVERRIDE; virtual void authenticationRequired(const QUrl&, const QString&, bool, const QString&, QString*, QString*) Q_DECL_OVERRIDE { } virtual void runMediaAccessPermissionRequest(const QUrl &securityOrigin, MediaRequestFlags requestFlags) Q_DECL_OVERRIDE; + virtual void runMouseLockPermissionRequest(const QUrl &securityOrigin) Q_DECL_OVERRIDE; virtual QObject *accessibilityParentObject() Q_DECL_OVERRIDE; virtual WebEngineSettings *webEngineSettings() const Q_DECL_OVERRIDE; virtual void allowCertificateError(const QExplicitlySharedDataPointer<CertificateErrorController> &errorController); + virtual void runGeolocationPermissionRequest(QUrl const&) Q_DECL_OVERRIDE; + + virtual BrowserContextAdapter *browserContextAdapter() Q_DECL_OVERRIDE; void setDevicePixelRatio(qreal); void adoptWebContents(WebContentsAdapter *webContents); + void setProfile(QQuickWebEngineProfile *profile); + void ensureContentsAdapter(); QExplicitlySharedDataPointer<WebContentsAdapter> adapter; QScopedPointer<QQuickWebEngineViewExperimental> e; QScopedPointer<QQuickWebEngineViewport> v; QScopedPointer<QQuickWebEngineHistory> m_history; + QQuickWebEngineProfile *m_profile; QScopedPointer<QQuickWebEngineSettings> m_settings; QQmlComponent *contextMenuExtraItems; QUrl explicitUrl; diff --git a/src/webengine/plugin/experimental/plugin.cpp b/src/webengine/plugin/experimental/plugin.cpp index 883ebc598..93f0cb7f0 100644 --- a/src/webengine/plugin/experimental/plugin.cpp +++ b/src/webengine/plugin/experimental/plugin.cpp @@ -36,6 +36,7 @@ #include <QtQml/qqmlextensionplugin.h> +#include "qquickwebenginedownloaditem_p.h" #include "qquickwebenginehistory_p.h" #include "qquickwebenginesettings_p.h" #include "qquickwebenginesingleton_p.h" @@ -80,6 +81,8 @@ public: QObject::tr("Cannot create a separate instance of NavigationHistory")); qmlRegisterUncreatableType<QQuickWebEngineSettings>(uri, 1, 0, "WebEngineSettings", QObject::tr("Cannot create a separate instance of WebEngineSettings")); + qmlRegisterUncreatableType<QQuickWebEngineDownloadItem>(uri, 1, 0, "WebEngineDownloadItem", + QObject::tr("Cannot create a separate instance of WebEngineDownloadItem")); qmlRegisterSingletonType<QQuickWebEngineSingleton>(uri, 1, 0, "WebEngine", webEngineSingletonProvider); } }; diff --git a/src/webengine/plugin/plugin.cpp b/src/webengine/plugin/plugin.cpp index 60e401301..5d7bf2d36 100644 --- a/src/webengine/plugin/plugin.cpp +++ b/src/webengine/plugin/plugin.cpp @@ -39,6 +39,7 @@ #include "qquickwebengineloadrequest_p.h" #include "qquickwebenginenavigationrequest_p.h" #include "qquickwebenginenewviewrequest_p.h" +#include "qquickwebengineprofile_p.h" #include "qquickwebengineview_p.h" #include "qtwebengineversion.h" @@ -58,6 +59,7 @@ public: Q_ASSERT(QLatin1String(uri) == QLatin1String("QtWebEngine")); qmlRegisterType<QQuickWebEngineView>(uri, 1, 0, "WebEngineView"); + qmlRegisterType<QQuickWebEngineProfile>(uri, 1, 1, "WebEngineProfile"); qmlRegisterUncreatableType<QQuickWebEngineLoadRequest>(uri, 1, 0, "WebEngineLoadRequest", QObject::tr("Cannot create separate instance of WebEngineLoadRequest")); qmlRegisterUncreatableType<QQuickWebEngineNewViewRequest>(uri, 1, 0, "WebEngineNewViewRequest", QObject::tr("Cannot create separate instance of WebEngineNewViewRequest")); qmlRegisterUncreatableType<QQuickWebEngineNavigationRequest>(uri, 1, 0, "WebEngineNavigationRequest", QObject::tr("Cannot create separate instance of WebEngineNavigationRequest")); diff --git a/src/webengine/render_widget_host_view_qt_delegate_quick.cpp b/src/webengine/render_widget_host_view_qt_delegate_quick.cpp index 7c04cb8c0..663232eda 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quick.cpp +++ b/src/webengine/render_widget_host_view_qt_delegate_quick.cpp @@ -43,6 +43,8 @@ #include <QQuickWindow> #include <QVariant> #include <QWindow> +#include <private/qquickwindow_p.h> +#include <private/qsgcontext_p.h> RenderWidgetHostViewQtDelegateQuick::RenderWidgetHostViewQtDelegateQuick(RenderWidgetHostViewQtDelegateClient *client, bool isPopup) : m_client(client) @@ -103,6 +105,16 @@ bool RenderWidgetHostViewQtDelegateQuick::hasKeyboardFocus() return hasFocus(); } +void RenderWidgetHostViewQtDelegateQuick::lockMouse() +{ + grabMouse(); +} + +void RenderWidgetHostViewQtDelegateQuick::unlockMouse() +{ + ungrabMouse(); +} + void RenderWidgetHostViewQtDelegateQuick::show() { setVisible(true); @@ -123,6 +135,23 @@ QWindow* RenderWidgetHostViewQtDelegateQuick::window() const return QQuickItem::window(); } +QSGTexture *RenderWidgetHostViewQtDelegateQuick::createTextureFromImage(const QImage &image) +{ + return QQuickItem::window()->createTextureFromImage(image, QQuickWindow::TextureCanUseAtlas); +} + +QSGLayer *RenderWidgetHostViewQtDelegateQuick::createLayer() +{ + QSGRenderContext *renderContext = QQuickWindowPrivate::get(QQuickItem::window())->context; + return renderContext->sceneGraphContext()->createLayer(renderContext); +} + +QSGImageNode *RenderWidgetHostViewQtDelegateQuick::createImageNode() +{ + QSGRenderContext *renderContext = QQuickWindowPrivate::get(QQuickItem::window())->context; + return renderContext->sceneGraphContext()->createImageNode(); +} + void RenderWidgetHostViewQtDelegateQuick::update() { QQuickItem::update(); diff --git a/src/webengine/render_widget_host_view_qt_delegate_quick.h b/src/webengine/render_widget_host_view_qt_delegate_quick.h index ddc581289..305c14957 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quick.h +++ b/src/webengine/render_widget_host_view_qt_delegate_quick.h @@ -53,10 +53,15 @@ public: virtual QRectF contentsRect() const Q_DECL_OVERRIDE; virtual void setKeyboardFocus() Q_DECL_OVERRIDE; virtual bool hasKeyboardFocus() Q_DECL_OVERRIDE; + virtual void lockMouse() Q_DECL_OVERRIDE; + virtual void unlockMouse() Q_DECL_OVERRIDE; virtual void show() Q_DECL_OVERRIDE; virtual void hide() Q_DECL_OVERRIDE; virtual bool isVisible() const Q_DECL_OVERRIDE; virtual QWindow* window() const Q_DECL_OVERRIDE; + virtual QSGTexture *createTextureFromImage(const QImage &) Q_DECL_OVERRIDE; + virtual QSGLayer *createLayer() Q_DECL_OVERRIDE; + virtual QSGImageNode *createImageNode() Q_DECL_OVERRIDE; virtual void update() Q_DECL_OVERRIDE; virtual void updateCursor(const QCursor &) Q_DECL_OVERRIDE; virtual void resize(int width, int height) Q_DECL_OVERRIDE; diff --git a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp index da8d3d806..6a0e416e0 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp +++ b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp @@ -95,6 +95,21 @@ QWindow *RenderWidgetHostViewQtDelegateQuickWindow::window() const return const_cast<RenderWidgetHostViewQtDelegateQuickWindow*>(this); } +QSGTexture *RenderWidgetHostViewQtDelegateQuickWindow::createTextureFromImage(const QImage &image) +{ + return m_realDelegate->createTextureFromImage(image); +} + +QSGLayer *RenderWidgetHostViewQtDelegateQuickWindow::createLayer() +{ + return m_realDelegate->createLayer(); +} + +QSGImageNode *RenderWidgetHostViewQtDelegateQuickWindow::createImageNode() +{ + return m_realDelegate->createImageNode(); +} + void RenderWidgetHostViewQtDelegateQuickWindow::update() { QQuickWindow::update(); diff --git a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h index eeab4a79a..d3e81e497 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h +++ b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h @@ -56,10 +56,15 @@ public: virtual QRectF contentsRect() const Q_DECL_OVERRIDE; virtual void setKeyboardFocus() Q_DECL_OVERRIDE {} virtual bool hasKeyboardFocus() Q_DECL_OVERRIDE { return false; } + virtual void lockMouse() Q_DECL_OVERRIDE {} + virtual void unlockMouse() Q_DECL_OVERRIDE {} virtual void show() Q_DECL_OVERRIDE; virtual void hide() Q_DECL_OVERRIDE; virtual bool isVisible() const Q_DECL_OVERRIDE; virtual QWindow* window() const Q_DECL_OVERRIDE; + virtual QSGTexture *createTextureFromImage(const QImage &) Q_DECL_OVERRIDE; + virtual QSGLayer *createLayer() Q_DECL_OVERRIDE; + virtual QSGImageNode *createImageNode() Q_DECL_OVERRIDE; virtual void update() Q_DECL_OVERRIDE; virtual void updateCursor(const QCursor &) Q_DECL_OVERRIDE; virtual void resize(int width, int height) Q_DECL_OVERRIDE; diff --git a/src/webengine/webengine.pro b/src/webengine/webengine.pro index 4c4606690..15514e457 100644 --- a/src/webengine/webengine.pro +++ b/src/webengine/webengine.pro @@ -4,17 +4,19 @@ TARGET = QtWebEngine DEFINES += QT_BUILD_WEBENGINE_LIB QT += qml quick -QT_PRIVATE += webenginecore quick-private +QT_PRIVATE += webenginecore quick-private gui-private core-private QMAKE_DOCS = $$PWD/doc/qtwebengine.qdocconf INCLUDEPATH += $$PWD api ../core SOURCES = \ + api/qquickwebenginedownloaditem.cpp \ api/qquickwebenginehistory.cpp \ api/qquickwebengineloadrequest.cpp \ api/qquickwebenginenavigationrequest.cpp \ api/qquickwebenginenewviewrequest.cpp \ + api/qquickwebengineprofile.cpp \ api/qquickwebenginesettings.cpp \ api/qquickwebenginesingleton.cpp \ api/qquickwebengineview.cpp \ @@ -26,10 +28,14 @@ SOURCES = \ HEADERS = \ api/qtwebengineglobal.h \ api/qtwebengineglobal_p.h \ + api/qquickwebenginedownloaditem_p.h \ + api/qquickwebenginedownloaditem_p_p.h \ api/qquickwebenginehistory_p.h \ api/qquickwebengineloadrequest_p.h \ api/qquickwebenginenavigationrequest_p.h \ api/qquickwebenginenewviewrequest_p.h \ + api/qquickwebengineprofile_p.h \ + api/qquickwebengineprofile_p_p.h \ api/qquickwebenginesettings_p.h \ api/qquickwebenginesettings_p_p.h \ api/qquickwebenginesingleton_p.h \ diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp index 72b16f28b..eafcf114c 100644 --- a/src/webenginewidgets/api/qwebenginepage.cpp +++ b/src/webenginewidgets/api/qwebenginepage.cpp @@ -23,10 +23,13 @@ #include "qwebenginepage.h" #include "qwebenginepage_p.h" +#include "browser_context_adapter.h" #include "certificate_error_controller.h" #include "javascript_dialog_controller.h" #include "qwebenginehistory.h" #include "qwebenginehistory_p.h" +#include "qwebengineprofile.h" +#include "qwebengineprofile_p.h" #include "qwebenginesettings.h" #include "qwebenginesettings_p.h" #include "qwebengineview.h" @@ -166,9 +169,10 @@ void CallbackDirectory::CallbackSharedDataPointer::doDeref() } } -QWebEnginePagePrivate::QWebEnginePagePrivate() +QWebEnginePagePrivate::QWebEnginePagePrivate(QWebEngineProfile *_profile) : adapter(new WebContentsAdapter) , history(new QWebEngineHistory(new QWebEngineHistoryPrivate(this))) + , profile(_profile ? _profile : QWebEngineProfile::defaultProfile()) , settings(new QWebEngineSettings) , view(0) , isLoading(false) @@ -342,6 +346,18 @@ void QWebEnginePagePrivate::runMediaAccessPermissionRequest(const QUrl &security Q_EMIT q->featurePermissionRequested(securityOrigin, requestedFeature); } +void QWebEnginePagePrivate::runGeolocationPermissionRequest(const QUrl &securityOrigin) +{ + Q_Q(QWebEnginePage); + Q_EMIT q->featurePermissionRequested(securityOrigin, QWebEnginePage::Geolocation); +} + +void QWebEnginePagePrivate::runMouseLockPermissionRequest(const QUrl &securityOrigin) +{ + Q_Q(QWebEnginePage); + Q_EMIT q->featurePermissionRequested(securityOrigin, QWebEnginePage::MouseLock); +} + QObject *QWebEnginePagePrivate::accessibilityParentObject() { return view; @@ -410,9 +426,31 @@ void QWebEnginePagePrivate::recreateFromSerializedHistory(QDataStream &input) } } +BrowserContextAdapter *QWebEnginePagePrivate::browserContextAdapter() +{ + return profile->d_ptr->browserContext(); +} + QWebEnginePage::QWebEnginePage(QObject* parent) : QObject(parent) - , d_ptr(new QWebEnginePagePrivate) + , d_ptr(new QWebEnginePagePrivate()) +{ + Q_D(QWebEnginePage); + d->q_ptr = this; + d->adapter->initialize(d); +} + +/*! + Constructs an empty QWebEnginePage in the QWebEngineProfile \a profile with parent \a parent. + + If the profile is not the default profile the caller must ensure the profile is alive for as + long as the page is. + + \since 5.5 +*/ +QWebEnginePage::QWebEnginePage(QWebEngineProfile *profile, QObject* parent) + : QObject(parent) + , d_ptr(new QWebEnginePagePrivate(profile)) { Q_D(QWebEnginePage); d->q_ptr = this; @@ -448,6 +486,16 @@ QWidget *QWebEnginePage::view() const return d->view; } +/*! + Returns the QWebEngineProfile the page belongs to. + \since 5.5 +*/ +QWebEngineProfile *QWebEnginePage::profile() const +{ + Q_D(const QWebEnginePage); + return d->profile; +} + bool QWebEnginePage::hasSelection() const { return !selectedText().isEmpty(); @@ -624,6 +672,13 @@ bool QWebEnginePagePrivate::contextMenuRequested(const WebEngineContextMenuData return true; } +void QWebEnginePagePrivate::navigationRequested(int navigationType, const QUrl &url, int &navigationRequestAction, bool isMainFrame) +{ + Q_Q(QWebEnginePage); + bool accepted = q->acceptNavigationRequest(url, static_cast<QWebEnginePage::NavigationType>(navigationType), isMainFrame); + navigationRequestAction = accepted ? WebContentsAdapterClient::AcceptRequest : WebContentsAdapterClient::IgnoreRequest; +} + void QWebEnginePagePrivate::javascriptDialog(QSharedPointer<JavaScriptDialogController> controller) { Q_Q(QWebEnginePage); @@ -743,6 +798,8 @@ QMenu *QWebEnginePage::createStandardContextMenu() void QWebEnginePage::setFeaturePermission(const QUrl &securityOrigin, QWebEnginePage::Feature feature, QWebEnginePage::PermissionPolicy policy) { Q_D(QWebEnginePage); + if (policy == PermissionUnknown) + return; WebContentsAdapterClient::MediaRequestFlags flags = WebContentsAdapterClient::MediaNone; switch (feature) { case MediaAudioVideoCapture: @@ -761,6 +818,16 @@ void QWebEnginePage::setFeaturePermission(const QUrl &securityOrigin, QWebEngine } d->adapter->grantMediaAccessPermission(securityOrigin, flags); } + d->adapter->grantMediaAccessPermission(securityOrigin, flags); + break; + case QWebEnginePage::Geolocation: + d->adapter->runGeolocationRequestCallback(securityOrigin, (policy == PermissionGrantedByUser) ? true : false); + break; + case MouseLock: + if (policy == PermissionGrantedByUser) + d->adapter->grantMouseLockPermission(true); + else + d->adapter->grantMouseLockPermission(false); break; default: break; @@ -945,6 +1012,14 @@ bool QWebEnginePage::certificateError(const QWebEngineCertificateError &) return false; } +bool QWebEnginePage::acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame) +{ + Q_UNUSED(url); + Q_UNUSED(type); + Q_UNUSED(isMainFrame); + return true; +} + QT_END_NAMESPACE #include "moc_qwebenginepage.cpp" diff --git a/src/webenginewidgets/api/qwebenginepage.h b/src/webenginewidgets/api/qwebenginepage.h index 7856b8243..4b9208117 100644 --- a/src/webenginewidgets/api/qwebenginepage.h +++ b/src/webenginewidgets/api/qwebenginepage.h @@ -50,8 +50,9 @@ QT_BEGIN_NAMESPACE class QMenu; class QWebEngineHistory; class QWebEnginePage; -class QWebEngineSettings; class QWebEnginePagePrivate; +class QWebEngineProfile; +class QWebEngineSettings; namespace QtWebEnginePrivate { @@ -136,6 +137,16 @@ public: PermissionDeniedByUser }; + // must match WebContentsAdapterClient::NavigationType + enum NavigationType { + NavigationTypeLinkClicked, + NavigationTypeTyped, + NavigationTypeFormSubmitted, + NavigationTypeBackForward, + NavigationTypeReload, + NavigationTypeOther + }; + enum Feature { #ifndef Q_QDOC Notifications = 0, @@ -143,7 +154,8 @@ public: #endif MediaAudioCapture = 2, MediaVideoCapture, - MediaAudioVideoCapture + MediaAudioVideoCapture, + MouseLock }; // Ex-QWebFrame enum @@ -161,6 +173,7 @@ public: }; explicit QWebEnginePage(QObject *parent = 0); + QWebEnginePage(QWebEngineProfile *profile, QObject *parent = 0); ~QWebEnginePage(); QWebEngineHistory *history() const; @@ -170,6 +183,8 @@ public: bool hasSelection() const; QString selectedText() const; + QWebEngineProfile *profile() const; + #ifndef QT_NO_ACTION QAction *action(WebAction action) const; #endif @@ -248,6 +263,7 @@ protected: virtual bool javaScriptPrompt(const QUrl &securityOrigin, const QString& msg, const QString& defaultValue, QString* result); virtual void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString& message, int lineNumber, const QString& sourceID); virtual bool certificateError(const QWebEngineCertificateError &certificateError); + virtual bool acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame); private: Q_DECLARE_PRIVATE(QWebEnginePage); diff --git a/src/webenginewidgets/api/qwebenginepage_p.h b/src/webenginewidgets/api/qwebenginepage_p.h index 54129229f..a11c44ded 100644 --- a/src/webenginewidgets/api/qwebenginepage_p.h +++ b/src/webenginewidgets/api/qwebenginepage_p.h @@ -49,6 +49,7 @@ class WebContentsAdapter; QT_BEGIN_NAMESPACE class QWebEngineHistory; class QWebEnginePage; +class QWebEngineProfile; class QWebEngineSettings; class QWebEngineView; @@ -101,7 +102,7 @@ public: Q_DECLARE_PUBLIC(QWebEnginePage) QWebEnginePage *q_ptr; - QWebEnginePagePrivate(); + QWebEnginePagePrivate(QWebEngineProfile *profile = 0); ~QWebEnginePagePrivate(); virtual RenderWidgetHostViewQtDelegate* CreateRenderWidgetHostViewQtDelegate(RenderWidgetHostViewQtDelegateClient *client) Q_DECL_OVERRIDE; @@ -122,7 +123,7 @@ public: virtual void adoptNewWindow(WebContentsAdapter *newWebContents, WindowOpenDisposition disposition, bool userGesture, const QRect &initialGeometry) Q_DECL_OVERRIDE; virtual void close() Q_DECL_OVERRIDE; virtual bool contextMenuRequested(const WebEngineContextMenuData &data) Q_DECL_OVERRIDE; - virtual void navigationRequested(int, const QUrl &, int &, bool) Q_DECL_OVERRIDE { } + virtual void navigationRequested(int navigationType, const QUrl &url, int &navigationRequestAction, bool isMainFrame) Q_DECL_OVERRIDE; virtual void requestFullScreen(bool) Q_DECL_OVERRIDE { } virtual bool isFullScreen() const Q_DECL_OVERRIDE { return false; } virtual void javascriptDialog(QSharedPointer<JavaScriptDialogController>) Q_DECL_OVERRIDE; @@ -135,10 +136,14 @@ public: virtual void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString& message, int lineNumber, const QString& sourceID) Q_DECL_OVERRIDE; virtual void authenticationRequired(const QUrl &requestUrl, const QString &realm, bool isProxy, const QString &challengingHost, QString *outUser, QString *outPassword) Q_DECL_OVERRIDE; virtual void runMediaAccessPermissionRequest(const QUrl &securityOrigin, MediaRequestFlags requestFlags) Q_DECL_OVERRIDE; + virtual void runGeolocationPermissionRequest(const QUrl &securityOrigin) Q_DECL_OVERRIDE; + virtual void runMouseLockPermissionRequest(const QUrl &securityOrigin) Q_DECL_OVERRIDE; virtual QObject *accessibilityParentObject() Q_DECL_OVERRIDE; virtual WebEngineSettings *webEngineSettings() const Q_DECL_OVERRIDE; virtual void allowCertificateError(const QExplicitlySharedDataPointer<CertificateErrorController> &controller) Q_DECL_OVERRIDE; + virtual BrowserContextAdapter *browserContextAdapter() Q_DECL_OVERRIDE; + void updateAction(QWebEnginePage::WebAction) const; void updateNavigationActions(); void _q_webActionTriggered(bool checked); @@ -148,6 +153,7 @@ public: QExplicitlySharedDataPointer<WebContentsAdapter> adapter; QWebEngineHistory *history; + QWebEngineProfile *profile; QWebEngineSettings *settings; QWebEngineView *view; QSize viewportSize; diff --git a/src/webenginewidgets/api/qwebengineprofile.cpp b/src/webenginewidgets/api/qwebengineprofile.cpp new file mode 100644 index 000000000..9929ee657 --- /dev/null +++ b/src/webenginewidgets/api/qwebengineprofile.cpp @@ -0,0 +1,352 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 "qwebengineprofile.h" + +#include "qwebenginepage.h" +#include "qwebengineprofile_p.h" + +#include "browser_context_adapter.h" +#include "web_engine_visited_links_manager.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QWebEngineProfile + \brief The QWebEngineProfile class provides a web-engine profile shared by multiple pages. + \since 5.5 + + \inmodule QtWebEngineWidgets + + QWebEngineProfile contains settings and history shared by all QWebEnginePages that belong + to the profile. + + A default profile is built-in that all web pages not specifically created with another profile + belongs to. +*/ + +/*! + \enum QWebEngineProfile::HttpCacheType + + This enum describes the HTTP cache types QtWebEngine can be configured to use. + + \value MemoryHttpCache Use a in-memory cache. This is the only setting possible if off-the-record is set or no cache path is available. + \value DiskHttpCache Use a disk cache. This is the default. +*/ + +/*! + \enum QWebEngineProfile::PersistentCookiesPolicy + + This enum describes policy for cookie persistency. + + \value NoPersistentCookies Both session and persistent cookies are stored in memory. This is the only setting possible if off-the-record is set or no persistent data path is available. + \value AllowPersistentCookies Cookies marked persistent are save and restored from disk, session cookies are only stored to disk for crash recovery. This is the default setting. + \value ForcePersistentCookies Both session and persistent cookies are save and restored from disk. +*/ + +QWebEngineProfilePrivate::QWebEngineProfilePrivate(BrowserContextAdapter* browserContext, bool ownsContext) + : m_browserContext(browserContext) +{ + if (ownsContext) + m_browserContextRef = browserContext; +} + +QWebEngineProfilePrivate::~QWebEngineProfilePrivate() +{ +} + +/*! + Constructs a new off-the-record profile. + + An off-the-record profile leaves no record on the local machine, and has no persistent data or cache. + Thus, the HTTP cache can only be in memory and the cookies only be non-persistent, trying to change + these settings will have no effect. + + \sa isOffTheRecord() +*/ +QWebEngineProfile::QWebEngineProfile(QObject *parent) + : QObject(parent) + , d_ptr(new QWebEngineProfilePrivate(new BrowserContextAdapter(true), true)) +{ +} + +/*! + Constructs a new profile with storage name \a storageName. + + The storage name must be unique. + + A disk-based QWebEngineProfile should be destroyed on or before application exit, otherwise the cache + and persistent data may not be fully flushed to disk. + + \sa storageName() +*/ +QWebEngineProfile::QWebEngineProfile(const QString &storageName, QObject *parent) + : QObject(parent) + , d_ptr(new QWebEngineProfilePrivate(new BrowserContextAdapter(storageName), true)) +{ +} + +/*! \internal +*/ +QWebEngineProfile::QWebEngineProfile(QWebEngineProfilePrivate *privatePtr) + : d_ptr(privatePtr) +{ +} + +/*! \internal +*/ +QWebEngineProfile::~QWebEngineProfile() +{ +} + +/*! + Returns the storage name for the profile. + + The storage name is used to give each profile that uses the disk separate subdirectories for persistent data and cache. +*/ +QString QWebEngineProfile::storageName() const +{ + const Q_D(QWebEngineProfile); + return d->browserContext()->storageName(); +} + +/*! + Returns true if this is an off-the-record profile that leaves no record on the computer. + + This will force cookies and HTTP cache to be in memory, but also force all other normally + persistent data to be stored in memory. +*/ +bool QWebEngineProfile::isOffTheRecord() const +{ + const Q_D(QWebEngineProfile); + return d->browserContext()->isOffTheRecord(); +} + +/*! + Returns the path used to store persistent data for the browser and web content. + + Persistent data includes persistent cookies, HTML5 local storage and visited links. + + By default this is below QStandardPaths::writableLocation(QStandardPaths::DataLocation) in a storage name specific directory. + + \sa setPersistentStoragePath(), storageName(), QStandardPaths::writableLocation() +*/ +QString QWebEngineProfile::persistentStoragePath() const +{ + const Q_D(QWebEngineProfile); + return d->browserContext()->dataPath(); +} + +/*! + Overrides the default path used to store persistent web engine data. + + If set to the null string, the default path is restored. + + \sa persistentStoragePath() +*/ +void QWebEngineProfile::setPersistentStoragePath(const QString &path) +{ + const Q_D(QWebEngineProfile); + d->browserContext()->setDataPath(path); +} + +/*! + Returns the path used for caches. + + By default this is below QStandardPaths::writableLocation(QStandardPaths::CacheLocation) in a storage name specific directory. + + \sa setCachePath(), storageName(), QStandardPaths::writableLocation() +*/ +QString QWebEngineProfile::cachePath() const +{ + const Q_D(QWebEngineProfile); + return d->browserContext()->cachePath(); +} + +/*! + Overrides the default path used for disk caches. + + If set to the null string, the default path is restored. + + \sa cachePath() +*/ +void QWebEngineProfile::setCachePath(const QString &path) +{ + Q_D(QWebEngineProfile); + d->browserContext()->setCachePath(path); +} + +/*! + Returns the user-agent string send with HTTP to identify the browser. + + \sa setHttpUserAgent() +*/ +QString QWebEngineProfile::httpUserAgent() const +{ + const Q_D(QWebEngineProfile); + return d->browserContext()->httpUserAgent(); +} + +/*! + Overrides the default user-agent string, setting it to \a userAgent. + + \sa httpUserAgent() +*/ +void QWebEngineProfile::setHttpUserAgent(const QString &userAgent) +{ + Q_D(QWebEngineProfile); + d->browserContext()->setHttpUserAgent(userAgent); +} + +/*! + Returns the type of HTTP cache used. + + If the profile is off-the-record MemoryHttpCache is returned. + + \sa setHttpCacheType(), cachePath() +*/ +QWebEngineProfile::HttpCacheType QWebEngineProfile::httpCacheType() const +{ + const Q_D(QWebEngineProfile); + return QWebEngineProfile::HttpCacheType(d->browserContext()->httpCacheType()); +} + +/*! + Sets the HTTP cache type to \a httpCacheType. + + \sa httpCacheType(), setCachePath() +*/ +void QWebEngineProfile::setHttpCacheType(QWebEngineProfile::HttpCacheType httpCacheType) +{ + Q_D(QWebEngineProfile); + d->browserContext()->setHttpCacheType(BrowserContextAdapter::HttpCacheType(httpCacheType)); +} + +/*! + Returns the current policy for persistent cookies. + + If the profile is off-the-record NoPersistentCookies is returned. + + \sa setPersistentCookiesPolicy() +*/ +QWebEngineProfile::PersistentCookiesPolicy QWebEngineProfile::persistentCookiesPolicy() const +{ + const Q_D(QWebEngineProfile); + return QWebEngineProfile::PersistentCookiesPolicy(d->browserContext()->persistentCookiesPolicy()); +} + +/*! + Sets the policy for persistent cookies to \a newPersistentCookiesPolicy. + + \sa persistentCookiesPolicy() +*/ +void QWebEngineProfile::setPersistentCookiesPolicy(QWebEngineProfile::PersistentCookiesPolicy newPersistentCookiesPolicy) +{ + Q_D(QWebEngineProfile); + d->browserContext()->setPersistentCookiesPolicy(BrowserContextAdapter::PersistentCookiesPolicy(newPersistentCookiesPolicy)); +} + +/*! + Returns the maximum size of the HTTP size. + + Will return 0 if the size is automatically controlled by QtWebEngine. + + \sa setHttpCacheMaximumSize(), httpCacheType() +*/ +int QWebEngineProfile::httpCacheMaximumSize() const +{ + const Q_D(QWebEngineProfile); + return d->browserContext()->httpCacheMaxSize(); +} + +/*! + Sets the maximum size of the HTTP cache to \a maxSize. + + Setting it to 0 means the size will be controlled automatically by QtWebEngine. + + \sa httpCacheMaximumSize(), setHttpCacheType() +*/ +void QWebEngineProfile::setHttpCacheMaximumSize(int maxSize) +{ + Q_D(QWebEngineProfile); + d->browserContext()->setHttpCacheMaxSize(maxSize); +} + +/*! + Clears all links from the visited links database. + + \sa clearVisitedLinks() +*/ +void QWebEngineProfile::clearAllVisitedLinks() +{ + Q_D(QWebEngineProfile); + d->browserContext()->visitedLinksManager()->deleteAllVisitedLinkData(); +} + +/*! + Clears the links in \a urls from the visited links database. + + \sa clearAllVisitedLinks() +*/ +void QWebEngineProfile::clearVisitedLinks(const QList<QUrl> &urls) +{ + Q_D(QWebEngineProfile); + d->browserContext()->visitedLinksManager()->deleteVisitedLinkDataForUrls(urls); +} + +/*! + Returns true if \a url is considered a visited link by this profile. +*/ +bool QWebEngineProfile::visitedLinksContainsUrl(const QUrl &url) const +{ + Q_D(const QWebEngineProfile); + return d->browserContext()->visitedLinksManager()->containsUrl(url); +} + +/*! + Returns the default profile. + + The default profile uses the storage name "Default". + + \sa storageName() +*/ +QWebEngineProfile *QWebEngineProfile::defaultProfile() +{ + static QWebEngineProfile profile(new QWebEngineProfilePrivate(BrowserContextAdapter::defaultContext(), false)); + return &profile; +} + +QT_END_NAMESPACE diff --git a/src/webenginewidgets/api/qwebengineprofile.h b/src/webenginewidgets/api/qwebengineprofile.h new file mode 100644 index 000000000..0536d711f --- /dev/null +++ b/src/webenginewidgets/api/qwebengineprofile.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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$ +** +****************************************************************************/ + +#ifndef QWEBENGINEPROFILE_H +#define QWEBENGINEPROFILE_H + +#include "qtwebenginewidgetsglobal.h" + +#include <QObject> +#include <QScopedPointer> +#include <QString> + +QT_BEGIN_NAMESPACE + +class QObject; +class QUrl; +class QWebEnginePage; +class QWebEnginePagePrivate; +class QWebEngineProfilePrivate; + +class QWEBENGINEWIDGETS_EXPORT QWebEngineProfile : public QObject { + Q_OBJECT +public: + explicit QWebEngineProfile(QObject *parent = 0); + explicit QWebEngineProfile(const QString &name, QObject *parent = 0); + virtual ~QWebEngineProfile(); + + enum HttpCacheType { + MemoryHttpCache, + DiskHttpCache + }; + + enum PersistentCookiesPolicy { + NoPersistentCookies, + AllowPersistentCookies, + ForcePersistentCookies + }; + + QString storageName() const; + bool isOffTheRecord() const; + + QString persistentStoragePath() const; + void setPersistentStoragePath(const QString &path); + + QString cachePath() const; + void setCachePath(const QString &path); + + QString httpUserAgent() const; + void setHttpUserAgent(const QString &userAgent); + + HttpCacheType httpCacheType() const; + void setHttpCacheType(QWebEngineProfile::HttpCacheType); + + PersistentCookiesPolicy persistentCookiesPolicy() const; + void setPersistentCookiesPolicy(QWebEngineProfile::PersistentCookiesPolicy); + + int httpCacheMaximumSize() const; + void setHttpCacheMaximumSize(int maxSize); + + void clearAllVisitedLinks(); + void clearVisitedLinks(const QList<QUrl> &urls); + bool visitedLinksContainsUrl(const QUrl &url) const; + + static QWebEngineProfile *defaultProfile(); + +private: + Q_DECLARE_PRIVATE(QWebEngineProfile); + QWebEngineProfile(QWebEngineProfilePrivate *); + + friend class QWebEnginePagePrivate; + QScopedPointer<QWebEngineProfilePrivate> d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QWEBENGINEPROFILE_H diff --git a/src/webenginewidgets/api/qwebengineprofile_p.h b/src/webenginewidgets/api/qwebengineprofile_p.h new file mode 100644 index 000000000..3a08b6b1e --- /dev/null +++ b/src/webenginewidgets/api/qwebengineprofile_p.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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$ +** +****************************************************************************/ + +#ifndef QWEBENGINEPROFILE_P_H +#define QWEBENGINEPROFILE_P_H + +class BrowserContextAdapter; + +QT_BEGIN_NAMESPACE + +class QWebEngineSettings; + +class QWebEngineProfilePrivate { +public: + QWebEngineProfilePrivate(BrowserContextAdapter* browserContext, bool ownsContext); + ~QWebEngineProfilePrivate(); + + BrowserContextAdapter *browserContext() const { return m_browserContext; } + +private: + BrowserContextAdapter *m_browserContext; + QExplicitlySharedDataPointer<BrowserContextAdapter> m_browserContextRef; +}; + +QT_END_NAMESPACE + +#endif // QWEBENGINEPROFILE_P_H diff --git a/src/webenginewidgets/api/qwebenginesettings.cpp b/src/webenginewidgets/api/qwebenginesettings.cpp index 729a09f56..3a0f4fced 100644 --- a/src/webenginewidgets/api/qwebenginesettings.cpp +++ b/src/webenginewidgets/api/qwebenginesettings.cpp @@ -39,7 +39,7 @@ #include <QDebug> -QT_USE_NAMESPACE +QT_BEGIN_NAMESPACE static WebEngineSettings::Attribute toWebEngineAttribute(QWebEngineSettings::WebAttribute attribute) { switch (attribute) { @@ -74,7 +74,21 @@ static WebEngineSettings::Attribute toWebEngineAttribute(QWebEngineSettings::Web } } -Q_GLOBAL_STATIC(QList<QWebEngineSettingsPrivate*>, allSettings); +Q_GLOBAL_STATIC(QList<QWebEngineSettingsPrivate*>, allSettings) + +class QWebEngineGlobalSettings { + QWebEngineSettings globalSettings; +public: + QWebEngineGlobalSettings() { + // globalSettings shouldn't be in that list. + allSettings->removeAll(globalSettings.d_func()); + globalSettings.d_func()->coreSettings->initDefaults(); + } + + QWebEngineSettings *data() { return &globalSettings; } +}; + +Q_GLOBAL_STATIC(QWebEngineGlobalSettings, globalInstance) QWebEngineSettingsPrivate::QWebEngineSettingsPrivate() : coreSettings(new WebEngineSettings(this)) @@ -92,25 +106,13 @@ void QWebEngineSettingsPrivate::apply() } } -void QWebEngineSettingsPrivate::initDefaults() -{ - coreSettings->initDefaults(); -} - WebEngineSettings *QWebEngineSettingsPrivate::fallbackSettings() const { return QWebEngineSettings::globalSettings()->d_func()->coreSettings.data(); } QWebEngineSettings *QWebEngineSettings::globalSettings() { - static QWebEngineSettings* globalSettings = 0; - if (!globalSettings) { - globalSettings = new QWebEngineSettings; - // globalSettings shouldn't be in that list. - allSettings->removeAll(globalSettings->d_func()); - globalSettings->d_func()->initDefaults(); - } - return globalSettings; + return globalInstance()->data(); } Q_STATIC_ASSERT_X(static_cast<int>(WebEngineSettings::StandardFont) == static_cast<int>(QWebEngineSettings::StandardFont), "The enum values must match"); @@ -215,3 +217,5 @@ void QWebEngineSettings::resetAttribute(QWebEngineSettings::WebAttribute attr) { setAttribute(attr, globalSettings()->testAttribute(attr)); } + +QT_END_NAMESPACE diff --git a/src/webenginewidgets/api/qwebenginesettings.h b/src/webenginewidgets/api/qwebenginesettings.h index d9f57a935..29825f5a4 100644 --- a/src/webenginewidgets/api/qwebenginesettings.h +++ b/src/webenginewidgets/api/qwebenginesettings.h @@ -31,6 +31,7 @@ class QIcon; class QPixmap; class QUrl; class QWebEngineSettingsPrivate; +class QWebEngineGlobalSettings; class QWEBENGINEWIDGETS_EXPORT QWebEngineSettings { public: @@ -87,6 +88,7 @@ private: Q_DECLARE_PRIVATE(QWebEngineSettings); QScopedPointer<QWebEngineSettingsPrivate> d_ptr; friend class QWebEnginePagePrivate; + friend class QWebEngineGlobalSettings; QWebEngineSettings(); ~QWebEngineSettings(); diff --git a/src/webenginewidgets/api/qwebenginesettings_p.h b/src/webenginewidgets/api/qwebenginesettings_p.h index 830e8b360..12464fa02 100644 --- a/src/webenginewidgets/api/qwebenginesettings_p.h +++ b/src/webenginewidgets/api/qwebenginesettings_p.h @@ -48,7 +48,6 @@ class QWebEngineSettingsPrivate : public WebEngineSettingsDelegate { public: QWebEngineSettingsPrivate(); - void initDefaults(); void apply() Q_DECL_OVERRIDE; WebEngineSettings *fallbackSettings() const Q_DECL_OVERRIDE; diff --git a/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc b/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc index e89b10ab8..af435d170 100644 --- a/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc +++ b/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc @@ -147,6 +147,21 @@ */ /*! + \enum QWebEnginePage::NavigationType + + This enum describes the type of a navigation request. + + \value NavigationTypeLinkClicked The navigation request resulted from a clicked link. + \value NavigationTypeTyped The navigation request resulted from an explicitly loaded url. + \value NavigationTypeFormSubmitted The navigation request resulted from a form submission. + \value NavigationTypeBackForward The navigation request resulted from a back/forward action. + \value NavigationTypeReload The navigation request resulted from a reload action. + \value NavigationTypeOther The navigation request was triggered by other means not covered by the above. + + \sa acceptNavigationRequest() +*/ + +/*! \enum QWebEnginePage::Feature This enum describes the platform feature access categories that the user may be asked to grant or deny access to. @@ -209,6 +224,15 @@ */ /*! + \fn bool acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame) + This function is called whenever there is a request to navigate to a specified \a url by means of the specified navigation type \atype. + The \a isMainFrame argument marks if the request corresponds to the main frame, or a sub frame. + If the request is accepted Chromium will continue to load the page, else the request will be ignored. + The default implementation accepts the navigation request. +*/ + + +/*! \fn void QWebEnginePage::javaScriptAlert(const QUrl &securityOrigin, const QString& msg) This function is called whenever a JavaScript program running in a frame affiliated with \a securityOrigin calls the alert() function with the message \a msg. 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 c4a32d685..3880e4197 100644 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp +++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp @@ -44,9 +44,11 @@ #include <QOpenGLContext> #include <QResizeEvent> #include <QSGAbstractRenderer> -#include <QSGEngine> #include <QSGNode> #include <QWindow> +#include <private/qsgcontext_p.h> +#include <private/qsgengine_p.h> + static const int MaxTooltipLength = 1024; @@ -119,6 +121,16 @@ bool RenderWidgetHostViewQtDelegateWidget::hasKeyboardFocus() return hasFocus(); } +void RenderWidgetHostViewQtDelegateWidget::lockMouse() +{ + grabMouse(); +} + +void RenderWidgetHostViewQtDelegateWidget::unlockMouse() +{ + releaseMouse(); +} + void RenderWidgetHostViewQtDelegateWidget::show() { // Check if we're attached to a QWebEngineView, we don't @@ -143,6 +155,22 @@ QWindow* RenderWidgetHostViewQtDelegateWidget::window() const return root ? root->windowHandle() : 0; } +QSGTexture *RenderWidgetHostViewQtDelegateWidget::createTextureFromImage(const QImage &image) +{ + return m_sgEngine->createTextureFromImage(image, QSGEngine::TextureCanUseAtlas); +} + +QSGLayer *RenderWidgetHostViewQtDelegateWidget::createLayer() +{ + QSGEnginePrivate *enginePrivate = QSGEnginePrivate::get(m_sgEngine.data()); + return enginePrivate->sgContext->createLayer(enginePrivate->sgRenderContext.data()); +} + +QSGImageNode *RenderWidgetHostViewQtDelegateWidget::createImageNode() +{ + return QSGEnginePrivate::get(m_sgEngine.data())->sgContext->createImageNode(); +} + void RenderWidgetHostViewQtDelegateWidget::update() { #if (QT_VERSION < QT_VERSION_CHECK(5, 4, 0)) 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 0b553d8eb..8fc189124 100644 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h +++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h @@ -61,10 +61,15 @@ public: virtual QRectF contentsRect() const Q_DECL_OVERRIDE; virtual void setKeyboardFocus() Q_DECL_OVERRIDE; virtual bool hasKeyboardFocus() Q_DECL_OVERRIDE; + virtual void lockMouse() Q_DECL_OVERRIDE; + virtual void unlockMouse() Q_DECL_OVERRIDE; virtual void show() Q_DECL_OVERRIDE; virtual void hide() Q_DECL_OVERRIDE; virtual bool isVisible() const Q_DECL_OVERRIDE; virtual QWindow* window() const Q_DECL_OVERRIDE; + virtual QSGTexture *createTextureFromImage(const QImage &) Q_DECL_OVERRIDE; + virtual QSGLayer *createLayer() Q_DECL_OVERRIDE; + virtual QSGImageNode *createImageNode() Q_DECL_OVERRIDE; virtual void update() Q_DECL_OVERRIDE; virtual void updateCursor(const QCursor &) Q_DECL_OVERRIDE; virtual void resize(int width, int height) Q_DECL_OVERRIDE; diff --git a/src/webenginewidgets/webenginewidgets.pro b/src/webenginewidgets/webenginewidgets.pro index 4da888baa..638535bbc 100644 --- a/src/webenginewidgets/webenginewidgets.pro +++ b/src/webenginewidgets/webenginewidgets.pro @@ -4,7 +4,7 @@ TARGET = QtWebEngineWidgets DEFINES += QT_BUILD_WEBENGINEWIDGETS_LIB QT += webengine widgets network quick -QT_PRIVATE += webenginecore +QT_PRIVATE += webenginecore quick-private gui-private core-private QMAKE_DOCS = $$PWD/doc/qtwebenginewidgets.qdocconf @@ -15,8 +15,9 @@ SOURCES = \ api/qwebenginecertificateerror.cpp \ api/qwebenginehistory.cpp \ api/qwebenginepage.cpp \ + api/qwebengineprofile.cpp \ api/qwebenginesettings.cpp \ - api/qwebengineview.cpp\ + api/qwebengineview.cpp \ render_widget_host_view_qt_delegate_widget.cpp HEADERS = \ @@ -25,6 +26,8 @@ HEADERS = \ api/qwebenginehistory.h \ api/qwebenginepage.h \ api/qwebenginepage_p.h \ + api/qwebengineprofile.h \ + api/qwebengineprofile_p.h \ api/qwebenginesettings.h \ api/qwebenginesettings_p.h \ api/qwebengineview.h \ diff --git a/tests/auto/quick/publicapi/tst_publicapi.cpp b/tests/auto/quick/publicapi/tst_publicapi.cpp index f7cffb8b1..28a837260 100644 --- a/tests/auto/quick/publicapi/tst_publicapi.cpp +++ b/tests/auto/quick/publicapi/tst_publicapi.cpp @@ -48,6 +48,7 @@ #include <private/qquickwebengineview_p.h> #include <private/qquickwebengineloadrequest_p.h> #include <private/qquickwebenginenavigationrequest_p.h> +#include <private/qquickwebengineprofile_p.h> class tst_publicapi : public QObject { Q_OBJECT @@ -59,6 +60,7 @@ static QList<const QMetaObject *> typesToCheck = QList<const QMetaObject *>() << &QQuickWebEngineView::staticMetaObject << &QQuickWebEngineLoadRequest::staticMetaObject << &QQuickWebEngineNavigationRequest::staticMetaObject + << &QQuickWebEngineProfile::staticMetaObject ; static QList<const char *> knownEnumNames = QList<const char *>(); @@ -90,6 +92,7 @@ static QStringList expectedAPI = QStringList() << "QQuickWebEngineView.NewViewInWindow --> NewViewDestination" << "QQuickWebEngineView.NewViewInTab --> NewViewDestination" << "QQuickWebEngineView.NewViewInDialog --> NewViewDestination" + << "QQuickWebEngineView.NewViewInBackgroundTab --> NewViewDestination" << "QQuickWebEngineView.InfoMessageLevel --> JavaScriptConsoleMessageLevel" << "QQuickWebEngineView.WarningMessageLevel --> JavaScriptConsoleMessageLevel" << "QQuickWebEngineView.ErrorMessageLevel --> JavaScriptConsoleMessageLevel" @@ -117,6 +120,10 @@ static QStringList expectedAPI = QStringList() << "QQuickWebEngineView.goForward() --> void" << "QQuickWebEngineView.stop() --> void" << "QQuickWebEngineView.reload() --> void" + << "QQuickWebEngineView.zoomFactor --> double" + << "QQuickWebEngineView.zoomFactorChanged(double) --> void" + << "QQuickWebEngineView.setZoomFactor(double) --> void" + << "QQuickWebEngineView.profile --> QQuickWebEngineProfile*" << "QQuickWebEngineLoadRequest.url --> QUrl" << "QQuickWebEngineLoadRequest.status --> QQuickWebEngineView::LoadStatus" << "QQuickWebEngineLoadRequest.errorString --> QString" @@ -127,6 +134,27 @@ static QStringList expectedAPI = QStringList() << "QQuickWebEngineNavigationRequest.action --> QQuickWebEngineView::NavigationRequestAction" << "QQuickWebEngineNavigationRequest.navigationType --> QQuickWebEngineView::NavigationType" << "QQuickWebEngineNavigationRequest.actionChanged() --> void" + << "QQuickWebEngineProfile.MemoryHttpCache --> HttpCacheType" + << "QQuickWebEngineProfile.DiskHttpCache --> HttpCacheType" + << "QQuickWebEngineProfile.NoPersistentCookies --> PersistentCookiesPolicy" + << "QQuickWebEngineProfile.AllowPersistentCookies --> PersistentCookiesPolicy" + << "QQuickWebEngineProfile.ForcePersistentCookies --> PersistentCookiesPolicy" + << "QQuickWebEngineProfile.storageName --> QString" + << "QQuickWebEngineProfile.offTheRecord --> bool" + << "QQuickWebEngineProfile.persistentStoragePath --> QString" + << "QQuickWebEngineProfile.cachePath --> QString" + << "QQuickWebEngineProfile.httpUserAgent --> QString" + << "QQuickWebEngineProfile.httpCacheType --> HttpCacheType" + << "QQuickWebEngineProfile.persistentCookiesPolicy --> PersistentCookiesPolicy" + << "QQuickWebEngineProfile.httpCacheMaxSize --> int" + << "QQuickWebEngineProfile.storageNameChanged() --> void" + << "QQuickWebEngineProfile.offTheRecordChanged() --> void" + << "QQuickWebEngineProfile.persistentStoragePathChanged() --> void" + << "QQuickWebEngineProfile.cachePathChanged() --> void" + << "QQuickWebEngineProfile.httpUserAgentChanged() --> void" + << "QQuickWebEngineProfile.httpCacheTypeChanged() --> void" + << "QQuickWebEngineProfile.persistentCookiesPolicyChanged() --> void" + << "QQuickWebEngineProfile.httpCacheMaxSizeChanged() --> void" ; static bool isCheckedEnum(const QByteArray &typeName) diff --git a/tests/auto/quick/qmltests/data/tst_loadRecursionCrash.qml b/tests/auto/quick/qmltests/data/tst_loadRecursionCrash.qml new file mode 100644 index 000000000..f9b95ac19 --- /dev/null +++ b/tests/auto/quick/qmltests/data/tst_loadRecursionCrash.qml @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt 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$ +** +****************************************************************************/ + +import QtQuick 2.3 +import QtTest 1.0 +import QtWebEngine 1.0 + +Item { +width: 300 +height: 400 + TextInput { + id: textInput + anchors { + top: parent.top + left: parent.left + right: parent.right + } + focus: true + text: Qt.resolvedUrl("test1.html") + onEditingFinished: webEngineView.url = text + } + + TestWebEngineView { + id: webEngineView + anchors { + top: textInput.bottom + left: parent.left + right: parent.right + bottom: parent.bottom + } + + TestCase { + name: "WebEngineViewLoadRecursionCrash" + when:windowShown + + function test_QTBUG_42929() { + textInput.forceActiveFocus() + keyClick(Qt.Key_Return) + verify(webEngineView.waitForLoadSucceeded()) + textInput.text = "about:blank" + textInput.forceActiveFocus() + keyClick(Qt.Key_Return) + verify(webEngineView.waitForLoadSucceeded()) + textInput.text = Qt.resolvedUrl("test4.html") + textInput.forceActiveFocus() + // Don't crash now + keyClick(Qt.Key_Return) + verify(webEngineView.waitForLoadSucceeded()) + } + } + } +} diff --git a/tests/auto/quick/qmltests/qmltests.pro b/tests/auto/quick/qmltests/qmltests.pro index b40ef3b8c..33a864cf1 100644 --- a/tests/auto/quick/qmltests/qmltests.pro +++ b/tests/auto/quick/qmltests/qmltests.pro @@ -23,6 +23,7 @@ OTHER_FILES += \ $$PWD/data/tst_loadHtml.qml \ $$PWD/data/tst_loadProgress.qml \ $$PWD/data/tst_loadProgressSignal.qml \ + $$PWD/data/tst_loadRecursionCrash.qml \ $$PWD/data/tst_loadUrl.qml \ $$PWD/data/tst_navigationHistory.qml \ $$PWD/data/tst_navigationRequested.qml \ diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp index 6fb46057d..85939a686 100644 --- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp +++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp @@ -107,11 +107,11 @@ private Q_SLOTS: void contextMenuCopy(); void contextMenuPopulatedOnce(); void acceptNavigationRequest(); + void acceptNavigationRequestNavigationType(); void geolocationRequestJS(); void loadFinished(); void actionStates(); void popupFormSubmission(); - void acceptNavigationRequestWithNewWindow(); void userStyleSheet(); void userStyleSheetFromLocalFileUrl(); void userStyleSheetFromQrcUrl(); @@ -133,8 +133,6 @@ private Q_SLOTS: void textEditing(); void backActionUpdate(); void frameAt(); - void requestCache(); - void loadCachedPage(); void protectBindingsRuntimeObjectsFromCollector(); void localURLSchemes(); void testOptionalJSObjects(); @@ -240,7 +238,6 @@ void tst_QWebEnginePage::cleanupTestCase() cleanupFiles(); // Be nice } -#if defined(QWEBENGINEPAGE_ACCEPTNAVIGATIONREQUEST) class NavigationRequestOverride : public QWebEnginePage { public: @@ -248,21 +245,18 @@ public: bool m_acceptNavigationRequest; protected: - virtual bool acceptNavigationRequest(QWebEngineFrame* frame, const QNetworkRequest &request, QWebEnginePage::NavigationType type) { - Q_UNUSED(frame); - Q_UNUSED(request); + virtual bool acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame) + { + Q_UNUSED(url); Q_UNUSED(type); + Q_UNUSED(isMainFrame); return m_acceptNavigationRequest; } }; -#endif void tst_QWebEnginePage::acceptNavigationRequest() { -#if !defined(QWEBENGINEPAGE_ACCEPTNAVIGATIONREQUEST) - QSKIP("QWEBENGINEPAGE_ACCEPTNAVIGATIONREQUEST"); -#else QSignalSpy loadSpy(m_view, SIGNAL(loadFinished(bool))); NavigationRequestOverride* newPage = new NavigationRequestOverride(m_view, false); @@ -278,11 +272,10 @@ void tst_QWebEnginePage::acceptNavigationRequest() evaluateJavaScriptSync(m_view->page(), "tstform.submit();"); QTRY_COMPARE(loadSpy.count(), 2); - QCOMPARE(m_view->page()->toPlainText(), QString("foo?")); + QCOMPARE(toPlainTextSync(m_view->page()), QString("foo?")); // Restore default page m_view->setPage(0); -#endif } #if defined(QWEBENGINEPAGE_SETFEATUREPERMISSION) @@ -439,23 +432,22 @@ public: connect(this, SIGNAL(geometryChangeRequested(QRect)), this, SLOT(slotGeometryChangeRequested(QRect))); } -#if defined(QWEBENGINEPAGE_ACCEPTNAVIGATIONREQUEST) struct Navigation { - QWebEngineFrame *frame; - QNetworkRequest request; NavigationType type; + QUrl url; + bool isMainFrame; }; QList<Navigation> navigations; - virtual bool acceptNavigationRequest(QWebEngineFrame* frame, const QNetworkRequest &request, NavigationType type) { + virtual bool acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame) + { Navigation n; - n.frame = frame; - n.request = request; + n.url = url; n.type = type; + n.isMainFrame = isMainFrame; navigations.append(n); return true; } -#endif QList<TestPage*> createdWindows; virtual QWebEnginePage* createWindow(WebWindowType) { @@ -471,6 +463,42 @@ private Q_SLOTS: } }; +void tst_QWebEnginePage::acceptNavigationRequestNavigationType() +{ + + TestPage page; + QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool))); + + page.load(QUrl("qrc:///resources/script.html")); + QTRY_COMPARE(loadSpy.count(), 1); + QTRY_COMPARE(page.navigations.count(), 1); + + page.load(QUrl("qrc:///resources/content.html")); + QTRY_COMPARE(loadSpy.count(), 2); + QTRY_COMPARE(page.navigations.count(), 2); + + page.triggerAction(QWebEnginePage::Stop); + QVERIFY(page.history()->canGoBack()); + page.triggerAction(QWebEnginePage::Back); + + QTRY_COMPARE(loadSpy.count(), 3); + QTRY_COMPARE(page.navigations.count(), 3); + + page.triggerAction(QWebEnginePage::Reload); + QTRY_COMPARE(loadSpy.count(), 4); + QTRY_COMPARE(page.navigations.count(), 4); + + QList<QWebEnginePage::NavigationType> expectedList; + expectedList << QWebEnginePage::NavigationTypeTyped + << QWebEnginePage::NavigationTypeTyped + << QWebEnginePage::NavigationTypeBackForward + << QWebEnginePage::NavigationTypeReload; + QVERIFY(expectedList.count() == page.navigations.count()); + for (int i = 0; i < expectedList.count(); ++i) { + QCOMPARE(page.navigations[i].type, expectedList[i]); + } +} + void tst_QWebEnginePage::popupFormSubmission() { TestPage page; @@ -491,38 +519,6 @@ void tst_QWebEnginePage::popupFormSubmission() QVERIFY(url.contains("?foo=bar")); } -void tst_QWebEnginePage::acceptNavigationRequestWithNewWindow() -{ -#if !defined(QWEBENGINESETTINGS) - QSKIP("QWEBENGINESETTINGS"); -#else - TestPage* page = new TestPage(m_view); - page->settings()->setAttribute(QWebEngineSettings::LinksIncludedInFocusChain, true); - m_page = page; - m_view->setPage(m_page); - - m_view->setUrl(QString("data:text/html,<a href=\"data:text/html,Reached\" target=\"_blank\">Click me</a>")); - QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); - - QFocusEvent fe(QEvent::FocusIn); - m_page->event(&fe); - - QVERIFY(m_page->focusNextPrevChild(/*next*/ true)); - - QKeyEvent keyEnter(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier); - m_page->event(&keyEnter); - - QCOMPARE(page->navigations.count(), 2); - - TestPage::Navigation n = page->navigations.at(1); - QVERIFY(!n.frame); - QCOMPARE(n.request.url().toString(), QString("data:text/html,Reached")); - QVERIFY(n.type == QWebEnginePage::NavigationTypeLinkClicked); - - QCOMPARE(page->createdWindows.count(), 1); -#endif -} - class TestNetworkManager : public QNetworkAccessManager { public: @@ -1606,72 +1602,6 @@ void tst_QWebEnginePage::textEditing() #endif } -void tst_QWebEnginePage::requestCache() -{ -#if !defined(ACCEPTNAVIGATIONREQUEST) - QSKIP("ACCEPTNAVIGATIONREQUEST"); -#else - TestPage page; - QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool))); - - page.setUrl(QString("data:text/html,<a href=\"data:text/html,Reached\" target=\"_blank\">Click me</a>")); - QTRY_COMPARE(loadSpy.count(), 1); - QTRY_COMPARE(page.navigations.count(), 1); - - page.setUrl(QString("data:text/html,<a href=\"data:text/html,Reached\" target=\"_blank\">Click me2</a>")); - QTRY_COMPARE(loadSpy.count(), 2); - QTRY_COMPARE(page.navigations.count(), 2); - - page.triggerAction(QWebEnginePage::Stop); - QVERIFY(page.history()->canGoBack()); - page.triggerAction(QWebEnginePage::Back); - - QTRY_COMPARE(loadSpy.count(), 3); - QTRY_COMPARE(page.navigations.count(), 3); - QCOMPARE(page.navigations.at(0).request.attribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork).toInt(), - (int)QNetworkRequest::PreferNetwork); - QCOMPARE(page.navigations.at(1).request.attribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork).toInt(), - (int)QNetworkRequest::PreferNetwork); - QCOMPARE(page.navigations.at(2).request.attribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork).toInt(), - (int)QNetworkRequest::PreferCache); -#endif -} - -void tst_QWebEnginePage::loadCachedPage() -{ -#if !defined(QWEBENGINESETTINGS) - QSKIP("QWEBENGINESETTINGS"); -#else - TestPage page; - QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool))); - page.settings()->setMaximumPagesInCache(3); - - page.load(QUrl("data:text/html,This is first page")); - - QTRY_COMPARE(loadSpy.count(), 1); - QTRY_COMPARE(page.navigations.count(), 1); - - QUrl firstPageUrl = page.url(); - page.load(QUrl("data:text/html,This is second page")); - - QTRY_COMPARE(loadSpy.count(), 2); - QTRY_COMPARE(page.navigations.count(), 2); - - page.triggerAction(QWebEnginePage::Stop); - QVERIFY(page.history()->canGoBack()); - - QSignalSpy urlSpy(&page, SIGNAL(urlChanged(QUrl))); - QVERIFY(urlSpy.isValid()); - - page.triggerAction(QWebEnginePage::Back); - ::waitForSignal(&page, SIGNAL(urlChanged(QUrl))); - QCOMPARE(urlSpy.size(), 1); - - QList<QVariant> arguments1 = urlSpy.takeFirst(); - QCOMPARE(arguments1.at(0).toUrl(), firstPageUrl); -#endif -} - void tst_QWebEnginePage::backActionUpdate() { QWebEngineView view; diff --git a/tests/quicktestbrowser/DownloadView.qml b/tests/quicktestbrowser/DownloadView.qml new file mode 100644 index 000000000..4475e183f --- /dev/null +++ b/tests/quicktestbrowser/DownloadView.qml @@ -0,0 +1,165 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia Plc and its Subsidiary(-ies) 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.1 +import QtQuick.Controls 1.0 +import QtQuick.Controls.Styles 1.0 +import QtWebEngine 1.0 +import QtWebEngine.experimental 1.0 +import QtQuick.Layouts 1.0 + +Rectangle { + id: downloadView + color: "lightgray" + + ListModel { + id: downloadModel + property var downloads: [] + } + + function append(download) { + downloadModel.append(download) + downloadModel.downloads.push(download) + } + + Component { + id: downloadItemDelegate + + Rectangle { + width: listView.width + height: childrenRect.height + anchors.margins: 10 + radius: 3 + color: "transparent" + border.color: "black" + Rectangle { + id: progressBar + + property int progress: downloadModel.downloads[index] ? downloadModel.downloads[index].progress : 0 + + radius: 3 + color: width == listView.width ? "green" : "#2b74c7" + width: listView.width / 100 * progress + height: cancelButton.height + + Behavior on width { + SmoothedAnimation { duration: 100 } + } + } + Rectangle { + anchors { + left: parent.left + right: parent.right + leftMargin: 20 + } + Label { + id: label + text: path + anchors { + verticalCenter: cancelButton.verticalCenter + left: parent.left + right: cancelButton.left + } + } + Button { + id: cancelButton + anchors.right: parent.right + iconSource: "icons/process-stop.png" + onClicked: { + var download = downloadModel.downloads[index] + + download.cancel() + + downloadModel.downloads = downloadModel.downloads.filter(function (el) { + return el.id !== download.id; + }); + downloadModel.remove(index) + } + } + } + } + + } + ListView { + id: listView + anchors { + topMargin: 10 + top: parent.top + bottom: parent.bottom + horizontalCenter: parent.horizontalCenter + } + width: parent.width - 20 + spacing: 5 + + model: downloadModel + delegate: downloadItemDelegate + + Text { + visible: !listView.count + horizontalAlignment: Text.AlignHCenter + height: 30 + anchors { + top: parent.top + left: parent.left + right: parent.right + } + font.pixelSize: 20 + text: "No active downloads." + } + + Rectangle { + color: "gray" + anchors { + bottom: parent.bottom + left: parent.left + right: parent.right + } + height: 30 + Button { + id: okButton + text: "OK" + anchors.centerIn: parent + onClicked: { + downloadView.visible = false + } + } + } + } +} diff --git a/tests/quicktestbrowser/FeaturePermissionBar.qml b/tests/quicktestbrowser/FeaturePermissionBar.qml index dd2e0f714..68ad43195 100644 --- a/tests/quicktestbrowser/FeaturePermissionBar.qml +++ b/tests/quicktestbrowser/FeaturePermissionBar.qml @@ -69,12 +69,14 @@ Rectangle { Layout.fillWidth: true function textForFeature(feature) { - if (feature === WebEngineViewExperimental.MediaAudioDevices) + if (feature === WebEngineViewExperimental.MediaAudioCapture) return "your microphone" - if (feature === WebEngineViewExperimental.MediaVideoDevices) + if (feature === WebEngineViewExperimental.MediaVideoCapture) return "your camera" - if (feature === WebEngineViewExperimental.MediaAudioVideoDevices) + if (feature === WebEngineViewExperimental.MediaAudioVideoCapture) return "your camera and microphone" + if (feature === WebEngineViewExperimental.Geolocation) + return "your position" } } diff --git a/tests/quicktestbrowser/ZoomController.qml b/tests/quicktestbrowser/ZoomController.qml new file mode 100644 index 000000000..a714ed2a9 --- /dev/null +++ b/tests/quicktestbrowser/ZoomController.qml @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** 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 Digia Plc and its Subsidiary(-ies) 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.3 +import QtQuick.Controls 1.2 +import QtQuick.Layouts 1.1 + +Rectangle { + property alias zoomFactor: slider.value ; + function zoomIn() { + visible = true + visibilityTimer.restart() + zoomFactor = zoomFactor + 0.25; + } + function zoomOut() { + visible = true + visibilityTimer.restart() + zoomFactor = zoomFactor - 0.25; + } + function reset() { zoomFactor = 1.0 } + + width: 220 + height: 30 + color: palette.window + visible: false + radius: 4 + + SystemPalette { + id: palette + } + Timer { + id: visibilityTimer + interval: 3000 + repeat: false + onTriggered: zoomController.visible = false + } + + RowLayout { + anchors.margins: 4 + anchors.fill: parent + ToolButton { + id: plusButton + text: '+' + onClicked: zoomIn() + } + ToolButton { + text: '\u2014' + id: minusButton + onClicked: zoomOut() + } + Slider { + id: slider + maximumValue: 5.0 + minimumValue: 0.25 + Layout.fillWidth: true; + stepSize: 0.05 + value: 1 + onValueChanged: visibilityTimer.restart() + } + Button { + text: "Reset" + onClicked: reset() + } + } +} diff --git a/tests/quicktestbrowser/quicktestbrowser.pro b/tests/quicktestbrowser/quicktestbrowser.pro index ac8fe74b3..1da197590 100644 --- a/tests/quicktestbrowser/quicktestbrowser.pro +++ b/tests/quicktestbrowser/quicktestbrowser.pro @@ -10,6 +10,7 @@ SOURCES = quickwindow.cpp \ OTHER_FILES += ButtonWithMenu.qml \ ContextMenuExtras.qml \ + DownloadView.qml \ FeaturePermissionBar.qml \ quickwindow.qml diff --git a/tests/quicktestbrowser/quickwindow.qml b/tests/quicktestbrowser/quickwindow.qml index 6a5ef3187..d840ac7d0 100644 --- a/tests/quicktestbrowser/quickwindow.qml +++ b/tests/quicktestbrowser/quickwindow.qml @@ -39,7 +39,7 @@ ****************************************************************************/ import QtQuick 2.1 -import QtWebEngine 1.0 +import QtWebEngine 1.1 import QtWebEngine.experimental 1.0 import QtQuick.Controls 1.0 @@ -73,6 +73,21 @@ ApplicationWindow { property alias errorPageEnabled: errorPageEnabled.checked; } + WebEngineProfile { + id: testProfile + storageName: "Test" + httpCacheType: httpDiskCacheEnabled.checked ? WebEngineProfile.DiskHttpCache : WebEngineProfile.MemoryHttpCache; + onDownloadStarted: { + downloadView.visible = true + downloadView.append(download) + } + } + + WebEngineProfile { + id: otrProfile + offTheRecord: true + } + // Make sure the Qt.WindowFullscreenButtonHint is set on Mac. Component.onCompleted: flags = flags | Qt.WindowFullscreenButtonHint @@ -81,6 +96,12 @@ ApplicationWindow { StyleItem { id: styleItem } property bool platformIsMac: styleItem.style == "mac" + Action { + shortcut: "Ctrl+D" + onTriggered: { + downloadView.visible = !downloadView.visible + } + } Action { id: focus @@ -122,6 +143,18 @@ ApplicationWindow { browserWindow.showNormal() } } + Action { + shortcut: "Ctrl+0" + onTriggered: zoomController.reset() + } + Action { + shortcut: "Ctrl+-" + onTriggered: zoomController.zoomOut() + } + Action { + shortcut: "Ctrl+=" + onTriggered: zoomController.zoomIn() + } Menu { id: backHistoryMenu @@ -223,6 +256,18 @@ ApplicationWindow { checked: WebEngine.settings.errorPageEnabled onCheckedChanged: WebEngine.settings.errorPageEnabled = checked } + MenuItem { + id: offTheRecordEnabled + text: "Off The Record" + checkable: true + checked: false + } + MenuItem { + id: httpDiskCacheEnabled + text: "HTTP Disk Cache" + checkable: true + checked: (testProfile.httpCacheType == WebEngineProfile.DiskHttpCache) + } } } } @@ -300,6 +345,7 @@ ApplicationWindow { WebEngineView { id: webEngineView + profile: offTheRecordEnabled.checked ? otrProfile : testProfile anchors { fill: parent @@ -342,7 +388,7 @@ ApplicationWindow { var tab = tabs.createEmptyTab() request.openIn(tab.item.webView) } else if (request.destination == WebEngineView.NewViewInDialog) { - var dialog = dialogComponent.createObject() + var dialog = dialogComponent.createObject(webEngineView) request.openIn(dialog.webView) } else { var component = Qt.createComponent("quickwindow.qml") @@ -399,4 +445,23 @@ ApplicationWindow { } } } + + DownloadView { + id: downloadView + visible: false + anchors.fill: parent + } + + ZoomController { + id: zoomController + y: parent.mapFromItem(currentWebView, 0 , 0).y - 4 + anchors.right: parent.right + width: (parent.width > 800) ? parent.width * 0.25 : 220 + anchors.rightMargin: (parent.width > 400) ? 100 : 0 + } + Binding { + target: currentWebView + property: "zoomFactor" + value: zoomController.zoomFactor + } } diff --git a/tests/quicktestbrowser/resources.qrc b/tests/quicktestbrowser/resources.qrc index cdc3d2304..3c9fd5dd7 100644 --- a/tests/quicktestbrowser/resources.qrc +++ b/tests/quicktestbrowser/resources.qrc @@ -4,6 +4,8 @@ <file>ContextMenuExtras.qml</file> <file>FeaturePermissionBar.qml</file> <file>ButtonWithMenu.qml</file> + <file>DownloadView.qml</file> + <file>ZoomController.qml</file> </qresource> <qresource prefix="icons"> <!-- To the risk of this breaking more often, do not duplicate the resources since this application won't be deployed --> diff --git a/tests/quicktestbrowser/util.h b/tests/quicktestbrowser/util.h index bad41d6a7..85db8c25b 100644 --- a/tests/quicktestbrowser/util.h +++ b/tests/quicktestbrowser/util.h @@ -50,7 +50,7 @@ QUrl urlFromUserInput(const QString& userInput) { QFileInfo fileInfo(userInput); if (fileInfo.exists()) - return QUrl(fileInfo.absoluteFilePath()); + return QUrl::fromLocalFile(fileInfo.absoluteFilePath()); return QUrl::fromUserInput(userInput); } diff --git a/tools/qmake/mkspecs/features/functions.prf b/tools/qmake/mkspecs/features/functions.prf index 4c2547d57..338a9ec27 100644 --- a/tools/qmake/mkspecs/features/functions.prf +++ b/tools/qmake/mkspecs/features/functions.prf @@ -73,7 +73,7 @@ defineReplace(findMocables) { for (file, input): \ infiles += $$absolute_path($$file, $$_PRO_FILE_PWD_) mocables = $$system("python $$QTWEBENGINE_ROOT/tools/buildscripts/find-mocables $$infiles") - mocables = $$replace(mocables, $$_PRO_FILE_PWD_/, '') + mocables = $$replace(mocables, $$re_escape($${_PRO_FILE_PWD_}/), '') return($$mocables) } @@ -87,8 +87,10 @@ defineReplace(findIncludedMocFiles) { defineReplace(mocOutput) { out = $$1 # The order is important, since the output of the second replace would end up accidentaly transformed by the first one - out = $$replace(out, ^(.*)($$join(QMAKE_EXT_CPP,|)), $${QMAKE_CPP_MOD_MOC}\\1$${QMAKE_EXT_CPP_MOC}) - out = $$replace(out, ^(.*)($$join(QMAKE_EXT_H,|)), $${QMAKE_H_MOD_MOC}\\1$${first(QMAKE_EXT_CPP)}) + for(ext, $$list($${QMAKE_EXT_CPP})): \ + out = $$replace(out, ^(.*)($$re_escape($${ext})), $${QMAKE_CPP_MOD_MOC}\\1$${QMAKE_EXT_CPP_MOC}) + for(ext, $$list($${QMAKE_EXT_H})): \ + out = $$replace(out, ^(.*)($$re_escape($${ext})), $${QMAKE_H_MOD_MOC}\\1$${first(QMAKE_EXT_CPP)}) return($$out) } diff --git a/tools/scripts/take_snapshot.py b/tools/scripts/take_snapshot.py index 3696b9a7a..3db3bac6c 100755 --- a/tools/scripts/take_snapshot.py +++ b/tools/scripts/take_snapshot.py @@ -61,6 +61,7 @@ def isInGitBlacklist(file_path): False if ( '.gitignore' in file_path or '.gitmodules' in file_path + or '.gitattributes' in file_path or '.DEPS' in file_path ): return True @@ -108,13 +109,17 @@ def isInChromiumBlacklist(file_path): not file_path.endswith('version.py') and not file_path.endswith('.grd') and not file_path.endswith('.grdp') and - not file_path.endswith('.json')) + not file_path.endswith('.json') and + not file_path.endswith('chrome_version.rc.version')) or file_path.startswith('chrome_frame') or file_path.startswith('chromeos') or file_path.startswith('cloud_print') or (file_path.startswith('components') and not file_path.startswith('components/tracing') and - not file_path.startswith('components/visitedlink')) + not file_path.startswith('components/visitedlink') and + not file_path.startswith('components/error_page') and + not file_path.endswith('.grdp') and + not 'components_strings' in file_path) or file_path.startswith('content/public/android/java') or file_path.startswith('content/shell') or file_path.startswith('courgette') @@ -157,9 +162,11 @@ def isInChromiumBlacklist(file_path): or file_path.startswith('third_party/cros_dbus_cplusplus') or file_path.startswith('third_party/cros_system_api') or file_path.startswith('third_party/cygwin') + or file_path.startswith('third_party/cython') or file_path.startswith('third_party/elfutils') or file_path.startswith('third_party/eyesfree') or file_path.startswith('third_party/findbugs') + or file_path.startswith('third_party/google_input_tools') or file_path.startswith('third_party/gperf') or file_path.startswith('third_party/gnu_binutils') or file_path.startswith('third_party/gtk+') @@ -173,6 +180,7 @@ def isInChromiumBlacklist(file_path): or file_path.startswith('third_party/instrumented_libraries') or file_path.startswith('third_party/jarjar') or file_path.startswith('third_party/jsr-305/src') + or file_path.startswith('third_party/junit') or file_path.startswith('third_party/libphonenumber') or file_path.startswith('third_party/libaddressinput') or file_path.startswith('third_party/libc++') @@ -182,6 +190,7 @@ def isInChromiumBlacklist(file_path): or file_path.startswith('third_party/markdown') or file_path.startswith('third_party/mingw-w64') or file_path.startswith('third_party/nacl_sdk_binaries') + or file_path.startswith('third_party/polymer') or file_path.startswith('third_party/pdfsqueeze') or file_path.startswith('third_party/pefile') or file_path.startswith('third_party/perl') @@ -248,7 +257,7 @@ def clearDirectory(directory): os.chdir(directory) print 'clearing the directory:' + directory for direntry in os.listdir(directory): - if not direntry == '.git': + if not direntry == '.git' and os.path.isdir(direntry): print 'clearing:' + direntry shutil.rmtree(direntry) os.chdir(currentDir) @@ -304,6 +313,12 @@ if not commandNotFound: if commandNotFound or dos2unixVersion < StrictVersion('6.0.6'): raise Exception("You need dos2unix version 6.0.6 minimum.") +os.chdir(third_party) +ignore_case_setting = subprocess.Popen(['git', 'config', '--get', 'core.ignorecase'], stdout=subprocess.PIPE).communicate()[0] +if 'true' in ignore_case_setting: + raise Exception("Your 3rdparty repository is configured to ignore case. " + "A snapshot created with these settings would cause problems on case sensitive file systems.") + clearDirectory(third_party) exportNinja() |