summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2019-06-11 12:57:07 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2019-06-11 12:57:42 +0200
commit147d70f330648acd105d6eb62493366fcf1e3abd (patch)
treeb47c0939bc7dfa155b787448da5102a10a156cfe
parent7f89badd0e1b71dabb5a88d1330b08ce9d8b6eb7 (diff)
parentaf1c0087e51b6e2ad905259bb7a1d50101735d2d (diff)
Merge remote-tracking branch 'origin/5.12' into 5.13
Conflicts: .qmake.conf src/3rdparty src/core/configure.json src/core/profile_io_data_qt.cpp tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp Change-Id: Ie8ae4aa03881a0733ff497fff46e3f7040735650
-rw-r--r--dist/changes-5.12.477
-rw-r--r--examples/webengine/quicknanobrowser/BrowserWindow.qml62
-rw-r--r--src/core/configure.json10
-rw-r--r--src/core/core_module.pro2
-rw-r--r--src/core/devtools_frontend_qt.cpp3
-rw-r--r--src/core/web_contents_adapter.cpp6
-rw-r--r--src/core/web_contents_adapter.h1
-rw-r--r--src/core/web_contents_adapter_client.h1
-rw-r--r--src/core/web_contents_delegate_qt.cpp59
-rw-r--r--src/core/web_contents_delegate_qt.h21
-rw-r--r--src/webengine/api/qquickwebengineaction.cpp3
-rw-r--r--src/webengine/api/qquickwebengineview.cpp22
-rw-r--r--src/webengine/api/qquickwebengineview_p_p.h1
-rw-r--r--src/webengine/doc/src/webengineview_lgpl.qdoc7
-rw-r--r--src/webenginewidgets/api/qwebenginepage.cpp22
-rw-r--r--src/webenginewidgets/api/qwebenginepage_p.h1
-rw-r--r--src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc8
-rw-r--r--src/webenginewidgets/doc/src/qwebengineview_lgpl.qdoc9
-rw-r--r--tests/auto/quick/qmltests/data/tst_action.qml54
-rw-r--r--tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp95
20 files changed, 446 insertions, 18 deletions
diff --git a/dist/changes-5.12.4 b/dist/changes-5.12.4
new file mode 100644
index 000000000..986c6871b
--- /dev/null
+++ b/dist/changes-5.12.4
@@ -0,0 +1,77 @@
+Qt 5.12.4 is a bug-fix release. It maintains both forward and backward
+compatibility (source and binary) with Qt 5.12.0 through 5.12.3.
+
+For more details, refer to the online documentation included in this
+distribution. The documentation is also available online:
+
+https://doc.qt.io/qt-5/index.html
+
+The Qt version 5.12 series is binary compatible with the 5.11.x series.
+Applications compiled for 5.11 will continue to run with 5.12.
+
+Some of the changes listed in this file include issue tracking numbers
+corresponding to tasks in the Qt Bug Tracker:
+
+https://bugreports.qt.io/
+
+Each of these identifiers can be entered in the bug tracker to obtain more
+information about a particular change.
+
+****************************************************************************
+* Qt 5.12.4 Changes *
+****************************************************************************
+
+General
+-------
+
+ - [QTBUG-57729, QTBUG-75539] Fixed automatic NTLM authentication, and added
+ support for --auth-server-whitelist.
+ - [QTBUG-60203] Fixed setting referer HTTP header in request interceptor.
+ - [QTBUG-74251, QTBUG-74698] Normalize download paths on Windows.
+ - [QTBUG-74864] Fixed resolving relative URLs with custom schemes.
+ - [QTBUG-75092] Fixed printing in landscape orientation.
+ - [QTBUG-75212] Added support for building with VS 2019.
+ - [QTBUG-75304] Fixed running non-MainWorld DocumentCreations scripts when
+ JavaScript is disabled.
+ - [QTBUG-75465] Fixed -no-gui builds.
+ - [QTBUG-75629] Fixed crash on Linux when pulseaudio had no devices.
+ - [QTBUG-76045] Fixed desktop capture on macOS.
+ - [QTBUG-73799] Try different versions when creating a CoreProfile context on macOS
+
+Chromium
+--------
+
+ - Security fixes from Chromium up to version 74.0.3729.157, including:
+
+ - CVE-2019-5805
+ - CVE-2019-5806
+ - CVE-2019-5808
+ - CVE-2019-5814
+ - CVE-2019-5815
+ - CVE-2019-5818
+ - CVE-2019-5819
+ - CVE-2019-5820
+ - CVE-2019-5821
+ - CVE-2019-5822
+ - CVE-2019-5823
+ - CVE-2019-5824
+ - CVE-2019-5825
+ - CVE-2019-5826
+ - CVE-2019-5827
+ - security issue 894933
+ - security issue 908669
+ - security issue 931949
+ - security issue 937663
+ - security issue 939316
+ - security issue 940205
+ - security issue 949015
+ - security issue 951322
+
+Qt WebEngine Widgets
+--------------------
+
+ - [QTBUG-75131, QTBUG-75175] Fixed QWebEngineView::setPage not deleting
+ old page.
+ - [QTBUG-75547] Fixed crash on exit when page and profile were deleted in
+ the wrong order.
+ - [QTBUG-75566] Added path validation to QWebEngineDownloadItem::setPath().
diff --git a/examples/webengine/quicknanobrowser/BrowserWindow.qml b/examples/webengine/quicknanobrowser/BrowserWindow.qml
index d3d597e2b..d095703fb 100644
--- a/examples/webengine/quicknanobrowser/BrowserWindow.qml
+++ b/examples/webengine/quicknanobrowser/BrowserWindow.qml
@@ -116,7 +116,7 @@ ApplicationWindow {
Action {
shortcut: StandardKey.AddTab
onTriggered: {
- tabs.createEmptyTab(currentWebView.profile);
+ tabs.createEmptyTab(tabs.count != 0 ? currentWebView.profile : defaultProfile);
tabs.currentIndex = tabs.count - 1;
addressBar.forceActiveFocus();
addressBar.selectAll();
@@ -295,18 +295,22 @@ ApplicationWindow {
id: offTheRecordEnabled
text: "Off The Record"
checkable: true
- checked: currentWebView.profile === otrProfile
+ checked: currentWebView && currentWebView.profile === otrProfile
onToggled: function(checked) {
- currentWebView.profile = checked ? otrProfile : defaultProfile;
+ if (currentWebView) {
+ currentWebView.profile = checked ? otrProfile : defaultProfile;
+ }
}
}
MenuItem {
id: httpDiskCacheEnabled
text: "HTTP Disk Cache"
- checkable: !currentWebView.profile.offTheRecord
- checked: (currentWebView.profile.httpCacheType === WebEngineProfile.DiskHttpCache)
+ checkable: currentWebView && !currentWebView.profile.offTheRecord
+ checked: currentWebView && (currentWebView.profile.httpCacheType === WebEngineProfile.DiskHttpCache)
onToggled: function(checked) {
- currentWebView.profile.httpCacheType = checked ? WebEngineProfile.DiskHttpCache : WebEngineProfile.MemoryHttpCache;
+ if (currentWebView) {
+ currentWebView.profile.httpCacheType = checked ? WebEngineProfile.DiskHttpCache : WebEngineProfile.MemoryHttpCache;
+ }
}
}
MenuItem {
@@ -380,6 +384,52 @@ ApplicationWindow {
anchors.right: parent.right
Component.onCompleted: createEmptyTab(defaultProfile)
+ // Add custom tab view style so we can customize the tabs to include a close button
+ style: TabViewStyle {
+ property color frameColor: "#999"
+ property color fillColor: "#eee"
+ property color nonSelectedColor: "#ddd"
+ frameOverlap: 1
+ frame: Rectangle {
+ color: "#eee"
+ border.color: frameColor
+ }
+ tab: Rectangle {
+ id: tabRectangle
+ color: styleData.selected ? fillColor : nonSelectedColor
+ border.width: 1
+ border.color: frameColor
+ implicitWidth: Math.max(text.width + 30, 80)
+ implicitHeight: Math.max(text.height + 10, 20)
+ Rectangle { height: 1 ; width: parent.width ; color: frameColor}
+ Rectangle { height: parent.height ; width: 1; color: frameColor}
+ Rectangle { x: parent.width - 2; height: parent.height ; width: 1; color: frameColor}
+ Text {
+ id: text
+ anchors.left: parent.left
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.leftMargin: 6
+ text: styleData.title
+ elide: Text.ElideRight
+ color: styleData.selected ? "black" : frameColor
+ }
+ Button {
+ anchors.right: parent.right
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.rightMargin: 4
+ height: 12
+ style: ButtonStyle {
+ background: Rectangle {
+ implicitWidth: 12
+ implicitHeight: 12
+ color: control.hovered ? "#ccc" : tabRectangle.color
+ Text {text: "x" ; anchors.centerIn: parent ; color: "gray"}
+ }}
+ onClicked: tabs.removeTab(styleData.index);
+ }
+ }
+ }
+
Component {
id: tabComponent
WebEngineView {
diff --git a/src/core/configure.json b/src/core/configure.json
index bb8ad7997..db900f046 100644
--- a/src/core/configure.json
+++ b/src/core/configure.json
@@ -335,6 +335,11 @@
"webengine-extensions-gcc-version" : {
"label": "GCC 6 or newer",
"type": "hasGcc6OrNewer"
+ },
+ "webengine-noexecstack" : {
+ "label": "linker supports -z noexecstack",
+ "type": "linkerSupportsFlag",
+ "flag": "-z,noexecstack"
}
},
@@ -678,6 +683,11 @@
"purpose": "Provides WebEngine Qml support.",
"section": "WebEngine",
"output": [ "privateFeature" ]
+ },
+ "webengine-noexecstack": {
+ "label": "linker supports -z noexecstack",
+ "condition": "config.unix && tests.webengine-noexecstack",
+ "output": [ "privateFeature" ]
}
},
diff --git a/src/core/core_module.pro b/src/core/core_module.pro
index f5234f88b..02aa6ac38 100644
--- a/src/core/core_module.pro
+++ b/src/core/core_module.pro
@@ -39,6 +39,8 @@ LIBS_PRIVATE += $$NINJA_LIB_DIRS $$NINJA_LIBS
# GN's LFLAGS doesn't always work across all the Linux configurations we support.
# The Windows and macOS ones from GN does provide a few useful flags however
+unix:qtConfig(webengine-noexecstack): \
+ QMAKE_LFLAGS += -Wl,-z,noexecstack
linux {
QMAKE_LFLAGS += -Wl,--gc-sections -Wl,-O1 -Wl,-z,now
# Embedded address sanitizer symbols are undefined and are picked up by the dynamic link loader
diff --git a/src/core/devtools_frontend_qt.cpp b/src/core/devtools_frontend_qt.cpp
index 9eedee42a..28af84bd3 100644
--- a/src/core/devtools_frontend_qt.cpp
+++ b/src/core/devtools_frontend_qt.cpp
@@ -79,7 +79,6 @@
#include "services/network/public/cpp/simple_url_loader.h"
#include "services/network/public/cpp/simple_url_loader_stream_consumer.h"
-#include <QDebug>
using namespace QtWebEngineCore;
namespace {
@@ -192,7 +191,7 @@ DevToolsFrontendQt *DevToolsFrontendQt::Show(QSharedPointer<WebContentsAdapter>
content::WebContents *contents = frontendAdapter->webContents();
if (contents == inspectedContents) {
- qWarning() << "You can not inspect youself";
+ LOG(WARNING) << "You can not inspect yourself";
return nullptr;
}
diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp
index c4f4591e3..0ec5af0fe 100644
--- a/src/core/web_contents_adapter.cpp
+++ b/src/core/web_contents_adapter.cpp
@@ -1630,6 +1630,12 @@ bool WebContentsAdapter::isFindTextInProgress() const
return m_lastFindRequestId != m_webContentsDelegate->lastReceivedFindReply();
}
+bool WebContentsAdapter::hasFocusedFrame() const
+{
+ CHECK_INITIALIZED(false);
+ return m_webContents->GetFocusedFrame() != nullptr;
+}
+
WebContentsAdapterClient::RenderProcessTerminationStatus
WebContentsAdapterClient::renderProcessExitStatus(int terminationStatus) {
auto status = WebContentsAdapterClient::RenderProcessTerminationStatus(-1);
diff --git a/src/core/web_contents_adapter.h b/src/core/web_contents_adapter.h
index 79aa68456..da4bc9190 100644
--- a/src/core/web_contents_adapter.h
+++ b/src/core/web_contents_adapter.h
@@ -217,6 +217,7 @@ public:
bool canViewSource();
void focusIfNecessary();
bool isFindTextInProgress() const;
+ bool hasFocusedFrame() const;
// meant to be used within WebEngineCore only
void initialize(content::SiteInstance *site);
diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h
index b388b28d0..540dd5f1f 100644
--- a/src/core/web_contents_adapter_client.h
+++ b/src/core/web_contents_adapter_client.h
@@ -469,6 +469,7 @@ public:
virtual void updateScrollPosition(const QPointF &position) = 0;
virtual void updateContentsSize(const QSizeF &size) = 0;
virtual void updateNavigationActions() = 0;
+ virtual void updateEditActions() = 0;
virtual void startDragging(const content::DropData &dropData, Qt::DropActions allowedActions,
const QPixmap &pixmap, const QPoint &offset) = 0;
virtual bool supportsDragging() const = 0;
diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp
index 021044a71..c8fac0d54 100644
--- a/src/core/web_contents_delegate_qt.cpp
+++ b/src/core/web_contents_delegate_qt.cpp
@@ -64,6 +64,7 @@
#include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
#include "components/web_cache/browser/web_cache_manager.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/browser_context.h"
@@ -104,6 +105,7 @@ WebContentsDelegateQt::WebContentsDelegateQt(content::WebContents *webContents,
, m_lastReceivedFindReply(0)
, m_faviconManager(new FaviconManager(webContents, adapterClient))
, m_lastLoadProgress(-1)
+ , m_frameFocusedObserver(adapterClient)
{
webContents->SetDelegate(this);
Observe(webContents);
@@ -262,11 +264,30 @@ bool WebContentsDelegateQt::HandleKeyboardEvent(content::WebContents *, const co
return true;
}
+void WebContentsDelegateQt::RenderFrameCreated(content::RenderFrameHost *render_frame_host)
+{
+ content::FrameTreeNode *node = static_cast<content::RenderFrameHostImpl *>(render_frame_host)->frame_tree_node();
+ m_frameFocusedObserver.addNode(node);
+}
+
void WebContentsDelegateQt::RenderFrameDeleted(content::RenderFrameHost *render_frame_host)
{
m_loadingErrorFrameList.removeOne(render_frame_host->GetRoutingID());
}
+void WebContentsDelegateQt::RenderFrameHostChanged(content::RenderFrameHost *old_host, content::RenderFrameHost *new_host)
+{
+ if (old_host) {
+ content::FrameTreeNode *old_node = static_cast<content::RenderFrameHostImpl *>(old_host)->frame_tree_node();
+ m_frameFocusedObserver.removeNode(old_node);
+ }
+
+ if (new_host) {
+ content::FrameTreeNode *new_node = static_cast<content::RenderFrameHostImpl *>(new_host)->frame_tree_node();
+ m_frameFocusedObserver.addNode(new_node);
+ }
+}
+
void WebContentsDelegateQt::RenderViewHostChanged(content::RenderViewHost *, content::RenderViewHost *newHost)
{
if (newHost && newHost->GetWidget() && newHost->GetWidget()->GetView()) {
@@ -724,4 +745,42 @@ WebContentsAdapter *WebContentsDelegateQt::webContentsAdapter() const
return m_viewClient->webContentsAdapter();
}
+
+FrameFocusedObserver::FrameFocusedObserver(WebContentsAdapterClient *adapterClient)
+ : m_viewClient(adapterClient)
+{}
+
+void FrameFocusedObserver::addNode(content::FrameTreeNode *node)
+{
+ if (m_observedNodes.contains(node))
+ return;
+
+ node->AddObserver(this);
+ m_observedNodes.append(node);
+}
+
+void FrameFocusedObserver::removeNode(content::FrameTreeNode *node)
+{
+ node->RemoveObserver(this);
+ m_observedNodes.removeOne(node);
+}
+
+void FrameFocusedObserver::OnFrameTreeNodeFocused(content::FrameTreeNode *node)
+{
+ Q_UNUSED(node);
+ m_viewClient->updateEditActions();
+}
+
+void FrameFocusedObserver::OnFrameTreeNodeDestroyed(content::FrameTreeNode *node)
+{
+ m_observedNodes.removeOne(node);
+ m_viewClient->updateEditActions();
+}
+
+FrameFocusedObserver::~FrameFocusedObserver()
+{
+ for (content::FrameTreeNode *node : m_observedNodes)
+ node->RemoveObserver(this);
+}
+
} // namespace QtWebEngineCore
diff --git a/src/core/web_contents_delegate_qt.h b/src/core/web_contents_delegate_qt.h
index 1629222c2..f6ba71256 100644
--- a/src/core/web_contents_delegate_qt.h
+++ b/src/core/web_contents_delegate_qt.h
@@ -40,6 +40,7 @@
#ifndef WEB_CONTENTS_DELEGATE_QT_H
#define WEB_CONTENTS_DELEGATE_QT_H
+#include "content/browser/frame_host/frame_tree_node.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/browser/web_contents_observer.h"
#include "third_party/skia/include/core/SkColor.h"
@@ -70,6 +71,23 @@ class WebContentsAdapter;
class WebContentsAdapterClient;
class WebEngineSettings;
+class FrameFocusedObserver : public content::FrameTreeNode::Observer
+{
+public:
+ FrameFocusedObserver(WebContentsAdapterClient *adapterClient);
+ ~FrameFocusedObserver();
+ void addNode(content::FrameTreeNode *node);
+ void removeNode(content::FrameTreeNode *node);
+
+protected:
+ void OnFrameTreeNodeFocused(content::FrameTreeNode *node) override;
+ void OnFrameTreeNodeDestroyed(content::FrameTreeNode *node) override;
+
+private:
+ WebContentsAdapterClient *m_viewClient;
+ QVector<content::FrameTreeNode *> m_observedNodes;
+};
+
class SavePageInfo
{
public:
@@ -132,7 +150,9 @@ public:
bool TakeFocus(content::WebContents *source, bool reverse) override;
// WebContentsObserver overrides
+ void RenderFrameCreated(content::RenderFrameHost *render_frame_host) override;
void RenderFrameDeleted(content::RenderFrameHost *render_frame_host) override;
+ void RenderFrameHostChanged(content::RenderFrameHost *old_host, content::RenderFrameHost *new_host) override;
void RenderViewHostChanged(content::RenderViewHost *old_host, content::RenderViewHost *new_host) override;
void DidStartNavigation(content::NavigationHandle *navigation_handle) override;
void DidFinishNavigation(content::NavigationHandle *navigation_handle) override;
@@ -175,6 +195,7 @@ private:
QSharedPointer<FilePickerController> m_filePickerController;
QUrl m_initialTargetUrl;
int m_lastLoadProgress;
+ FrameFocusedObserver m_frameFocusedObserver;
QUrl m_url;
QString m_title;
diff --git a/src/webengine/api/qquickwebengineaction.cpp b/src/webengine/api/qquickwebengineaction.cpp
index 69a05f29b..77ac8d340 100644
--- a/src/webengine/api/qquickwebengineaction.cpp
+++ b/src/webengine/api/qquickwebengineaction.cpp
@@ -146,8 +146,7 @@ QString QQuickWebEngineAction::iconName() const
/*!
\qmlproperty bool WebEngineAction::enabled
- This property holds whether the action is enabled. Context-dependent
- actions are always enabled.
+ This property holds whether the action is enabled.
*/
bool QQuickWebEngineAction::isEnabled() const
{
diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp
index 976e6ed04..bb8428951 100644
--- a/src/webengine/api/qquickwebengineview.cpp
+++ b/src/webengine/api/qquickwebengineview.cpp
@@ -942,6 +942,16 @@ void QQuickWebEngineViewPrivate::updateAction(QQuickWebEngineView::WebAction act
case QQuickWebEngineView::ViewSource:
enabled = adapter->canViewSource();
break;
+ case QQuickWebEngineView::Cut:
+ case QQuickWebEngineView::Copy:
+ case QQuickWebEngineView::Paste:
+ case QQuickWebEngineView::Undo:
+ case QQuickWebEngineView::Redo:
+ case QQuickWebEngineView::SelectAll:
+ case QQuickWebEngineView::PasteAndMatchStyle:
+ case QQuickWebEngineView::Unselect:
+ enabled = adapter->hasFocusedFrame();
+ break;
default:
break;
}
@@ -959,6 +969,18 @@ void QQuickWebEngineViewPrivate::updateNavigationActions()
updateAction(QQuickWebEngineView::ViewSource);
}
+void QQuickWebEngineViewPrivate::updateEditActions()
+{
+ updateAction(QQuickWebEngineView::Cut);
+ updateAction(QQuickWebEngineView::Copy);
+ updateAction(QQuickWebEngineView::Paste);
+ updateAction(QQuickWebEngineView::Undo);
+ updateAction(QQuickWebEngineView::Redo);
+ updateAction(QQuickWebEngineView::SelectAll);
+ updateAction(QQuickWebEngineView::PasteAndMatchStyle);
+ updateAction(QQuickWebEngineView::Unselect);
+}
+
QUrl QQuickWebEngineView::url() const
{
Q_D(const QQuickWebEngineView);
diff --git a/src/webengine/api/qquickwebengineview_p_p.h b/src/webengine/api/qquickwebengineview_p_p.h
index aa0a765f8..10fe5c2fd 100644
--- a/src/webengine/api/qquickwebengineview_p_p.h
+++ b/src/webengine/api/qquickwebengineview_p_p.h
@@ -151,6 +151,7 @@ public:
void updateScrollPosition(const QPointF &position) override;
void updateContentsSize(const QSizeF &size) override;
void updateNavigationActions() override;
+ void updateEditActions() override;
void startDragging(const content::DropData &dropData, Qt::DropActions allowedActions,
const QPixmap &pixmap, const QPoint &offset) override;
bool supportsDragging() const override;
diff --git a/src/webengine/doc/src/webengineview_lgpl.qdoc b/src/webengine/doc/src/webengineview_lgpl.qdoc
index 38c84f848..d256997cc 100644
--- a/src/webengine/doc/src/webengineview_lgpl.qdoc
+++ b/src/webengine/doc/src/webengineview_lgpl.qdoc
@@ -376,7 +376,8 @@
which references HTML pages via URL.
External objects, such as stylesheets or images referenced in the HTML
- document, should be located relative to \a baseUrl. For example, if \a html
+ document, should be located relative to \a baseUrl. For external objects to
+ be loaded, \c baseUrl cannot be empty. For example, if \a html
is retrieved from \c http://www.example.com/documents/overview.html, which
is the base URL, then an image referenced with the relative URL, \c diagram.png,
should be at \c{http://www.example.com/documents/diagram.png}.
@@ -756,6 +757,10 @@
Redo the last editing action.
\value WebEngineView.SelectAll
Select all content.
+ This action is only enabled when the page's content is focused.
+ The focus can be forced by the JavaScript \c{window.focus()} call, or the
+ \l{WebEngineSettings::focusOnNavigationEnabled} {focusOnNavigationEnabled} setting
+ should be enabled to get automatic focus.
\value WebEngineView.PasteAndMatchStyle
Paste content from the clipboard with current style.
\value WebEngineView.OpenLinkInThisWindow
diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp
index 86736d42b..a350433b8 100644
--- a/src/webenginewidgets/api/qwebenginepage.cpp
+++ b/src/webenginewidgets/api/qwebenginepage.cpp
@@ -590,6 +590,16 @@ void QWebEnginePagePrivate::updateAction(QWebEnginePage::WebAction action) const
case QWebEnginePage::ViewSource:
enabled = adapter->canViewSource();
break;
+ case QWebEnginePage::Cut:
+ case QWebEnginePage::Copy:
+ case QWebEnginePage::Paste:
+ case QWebEnginePage::Undo:
+ case QWebEnginePage::Redo:
+ case QWebEnginePage::SelectAll:
+ case QWebEnginePage::PasteAndMatchStyle:
+ case QWebEnginePage::Unselect:
+ enabled = adapter->hasFocusedFrame();
+ break;
default:
break;
}
@@ -608,6 +618,18 @@ void QWebEnginePagePrivate::updateNavigationActions()
updateAction(QWebEnginePage::ViewSource);
}
+void QWebEnginePagePrivate::updateEditActions()
+{
+ updateAction(QWebEnginePage::Cut);
+ updateAction(QWebEnginePage::Copy);
+ updateAction(QWebEnginePage::Paste);
+ updateAction(QWebEnginePage::Undo);
+ updateAction(QWebEnginePage::Redo);
+ updateAction(QWebEnginePage::SelectAll);
+ updateAction(QWebEnginePage::PasteAndMatchStyle);
+ updateAction(QWebEnginePage::Unselect);
+}
+
#ifndef QT_NO_ACTION
void QWebEnginePagePrivate::_q_webActionTriggered(bool checked)
{
diff --git a/src/webenginewidgets/api/qwebenginepage_p.h b/src/webenginewidgets/api/qwebenginepage_p.h
index 5feefeb0e..dc0ead534 100644
--- a/src/webenginewidgets/api/qwebenginepage_p.h
+++ b/src/webenginewidgets/api/qwebenginepage_p.h
@@ -146,6 +146,7 @@ public:
void updateScrollPosition(const QPointF &position) override;
void updateContentsSize(const QSizeF &size) override;
void updateNavigationActions() override;
+ void updateEditActions() override;
void startDragging(const content::DropData &dropData, Qt::DropActions allowedActions,
const QPixmap &pixmap, const QPoint &offset) override;
bool supportsDragging() const override;
diff --git a/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc b/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc
index e63423be8..b68caed59 100644
--- a/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc
+++ b/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc
@@ -112,8 +112,7 @@
Actions only have an effect when they are applicable.
The availability of actions can be be determined by checking
- \l{QAction::}{isEnabled()} on the action returned by action(). Context-dependent
- actions are always enabled.
+ \l{QAction::}{isEnabled()} on the action returned by action().
\value NoWebAction No action is triggered.
\value Back Navigate back in the history of navigated links.
@@ -126,7 +125,10 @@
\value Paste Paste content from the clipboard.
\value Undo Undo the last editing action.
\value Redo Redo the last editing action.
- \value SelectAll Select all content.
+ \value SelectAll Select all content. This action is only enabled when the page's content is focused.
+ The focus can be forced by the JavaScript \c{window.focus()} call, or the
+ \l{QWebEngineSettings::FocusOnNavigationEnabled} {FocusOnNavigationEnabled} setting
+ should be enabled to get automatic focus.
\value PasteAndMatchStyle Paste content from the clipboard with current style.
\value OpenLinkInThisWindow Open the current link in the current window. (Added in Qt 5.6)
diff --git a/src/webenginewidgets/doc/src/qwebengineview_lgpl.qdoc b/src/webenginewidgets/doc/src/qwebengineview_lgpl.qdoc
index fce1e8d8f..1b7812dff 100644
--- a/src/webenginewidgets/doc/src/qwebengineview_lgpl.qdoc
+++ b/src/webenginewidgets/doc/src/qwebengineview_lgpl.qdoc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2015 The Qt Company Ltd.
+ Copyright (C) 2019 The Qt Company Ltd.
Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
Copyright (C) 2008 Holger Hans Peter Freyther
Copyright (C) 2009 Girish Ramakrishnan <girish@forwardbias.in>
@@ -125,7 +125,11 @@
Sets the content of the web view to the specified \a html content.
External objects, such as stylesheets or images referenced in the HTML
- document, are located relative to \a baseUrl.
+ document, are located relative to \a baseUrl. For external objects to
+ be loaded, \c baseUrl cannot be empty. For example, if \a html
+ is retrieved from \c http://www.example.com/documents/overview.html, which
+ is the base URL, then an image referenced with the relative URL, \c diagram.png,
+ should be at \c{http://www.example.com/documents/diagram.png}.
The HTML document is loaded immediately, whereas external objects are loaded asynchronously.
@@ -156,6 +160,7 @@
is empty, it is assumed that the content is \c{text/plain,charset=US-ASCII}.
External objects referenced in the content are located relative to \a baseUrl.
+ For external objects to be loaded, \c baseUrl cannot be empty.
The data is loaded immediately; external objects are loaded asynchronously.
diff --git a/tests/auto/quick/qmltests/data/tst_action.qml b/tests/auto/quick/qmltests/data/tst_action.qml
index f6d8669fe..56a91d8d0 100644
--- a/tests/auto/quick/qmltests/data/tst_action.qml
+++ b/tests/auto/quick/qmltests/data/tst_action.qml
@@ -127,5 +127,59 @@ TestWebEngineView {
stopAction.trigger();
compare(stopTriggerSpy.count, 0);
}
+
+ function test_editActionsWithExplicitFocus() {
+ var webView = Qt.createQmlObject("TestWebEngineView { visible: false; }", webEngineView);
+ webView.settings.focusOnNavigationEnabled = false;
+
+ // The view is hidden and no focus on the page. Edit actions should be disabled.
+ var selectAllAction = webView.action(WebEngineView.SelectAll);
+ verify(selectAllAction);
+ verify(!selectAllAction.enabled);
+
+ var triggerSpy = createTemporaryObject(signalSpy, webEngineView, {target: selectAllAction, signalName: "triggered"});
+ var enabledSpy = createTemporaryObject(signalSpy, webEngineView, {target: selectAllAction, signalName: "enabledChanged"});
+
+ webView.loadHtml("<html><body><div>foo bar</div></body></html>");
+ verify(webView.waitForLoadSucceeded());
+
+ // Still no focus because focus on navigation is disabled. Edit actions don't do anything (should not crash).
+ verify(!selectAllAction.enabled);
+ compare(enabledSpy.count, 0);
+ selectAllAction.trigger();
+ compare(triggerSpy.count, 0);
+ compare(getTextSelection(), "");
+
+ // Focus content by focusing window from JavaScript. Edit actions should be enabled and functional.
+ webView.runJavaScript("window.focus();");
+ tryVerify(function() { return enabledSpy.count === 1 });
+ verify(selectAllAction.enabled);
+ selectAllAction.trigger();
+ compare(triggerSpy.count, 1);
+ tryVerify(function() { return webView.getTextSelection() === "foo bar" });
+ }
+
+ function test_editActionsWithInitialFocus() {
+ var webView = Qt.createQmlObject("TestWebEngineView { visible: false; }", webEngineView);
+ webView.settings.focusOnNavigationEnabled = true;
+
+ // The view is hidden and no focus on the page. Edit actions should be disabled.
+ var selectAllAction = webView.action(WebEngineView.SelectAll);
+ verify(selectAllAction);
+ verify(!selectAllAction.enabled);
+
+ var triggerSpy = createTemporaryObject(signalSpy, webEngineView, {target: selectAllAction, signalName: "triggered"});
+ var enabledSpy = createTemporaryObject(signalSpy, webEngineView, {target: selectAllAction, signalName: "enabledChanged"});
+
+ webView.loadHtml("<html><body><div>foo bar</div></body></html>");
+ verify(webView.waitForLoadSucceeded());
+
+ // Content gets initial focus.
+ tryVerify(function() { return enabledSpy.count === 1 });
+ verify(selectAllAction.enabled);
+ selectAllAction.trigger();
+ compare(triggerSpy.count, 1);
+ tryVerify(function() { return webView.getTextSelection() === "foo bar" });
+ }
}
}
diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
index dd1140a4f..47ae0bdb5 100644
--- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
+++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
@@ -202,6 +202,10 @@ private Q_SLOTS:
void sendNotification();
void contentsSize();
+ void editActionsWithExplicitFocus();
+ void editActionsWithInitialFocus();
+ void editActionsWithFocusOnIframe();
+
private:
static QPoint elementCenter(QWebEnginePage *page, const QString &id);
@@ -709,8 +713,8 @@ void tst_QWebEnginePage::textSelection()
// these actions must exist
QVERIFY(page->action(QWebEnginePage::SelectAll) != 0);
- // ..but SelectAll is awalys enabled
- QCOMPARE(page->action(QWebEnginePage::SelectAll)->isEnabled(), true);
+ // ..but SelectAll is disabled because the page has no focus due to disabled FocusOnNavigationEnabled.
+ QCOMPARE(page->action(QWebEnginePage::SelectAll)->isEnabled(), false);
// Verify hasSelection returns false since there is no selection yet...
QCOMPARE(page->hasSelection(), false);
@@ -3398,6 +3402,93 @@ void tst_QWebEnginePage::contentsSize()
QCOMPARE(m_page->contentsSize().height(), 1216);
}
+void tst_QWebEnginePage::editActionsWithExplicitFocus()
+{
+ QWebEngineView view;
+ QWebEnginePage *page = view.page();
+ view.settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, false);
+
+ QSignalSpy loadFinishedSpy(page, &QWebEnginePage::loadFinished);
+ QSignalSpy selectionChangedSpy(page, &QWebEnginePage::selectionChanged);
+ QSignalSpy actionChangedSpy(page->action(QWebEnginePage::SelectAll), &QAction::changed);
+
+ // The view is hidden and no focus on the page. Edit actions should be disabled.
+ QVERIFY(!view.isVisible());
+ QVERIFY(!page->action(QWebEnginePage::SelectAll)->isEnabled());
+
+ page->setHtml(QString("<html><body><div>foo bar</div></body></html>"));
+ QTRY_COMPARE(loadFinishedSpy.count(), 1);
+
+ // Still no focus because focus on navigation is disabled. Edit actions don't do anything (should not crash).
+ QVERIFY(!page->action(QWebEnginePage::SelectAll)->isEnabled());
+ view.page()->triggerAction(QWebEnginePage::SelectAll);
+ QCOMPARE(selectionChangedSpy.count(), 0);
+ QCOMPARE(page->hasSelection(), false);
+
+ // Focus content by focusing window from JavaScript. Edit actions should be enabled and functional.
+ evaluateJavaScriptSync(page, "window.focus();");
+ QTRY_COMPARE(actionChangedSpy.count(), 1);
+ QVERIFY(page->action(QWebEnginePage::SelectAll)->isEnabled());
+ view.page()->triggerAction(QWebEnginePage::SelectAll);
+ QTRY_COMPARE(selectionChangedSpy.count(), 1);
+ QCOMPARE(page->hasSelection(), true);
+ QCOMPARE(page->selectedText(), QStringLiteral("foo bar"));
+}
+
+void tst_QWebEnginePage::editActionsWithInitialFocus()
+{
+ QWebEngineView view;
+ QWebEnginePage *page = view.page();
+ view.settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, true);
+
+ QSignalSpy loadFinishedSpy(page, &QWebEnginePage::loadFinished);
+ QSignalSpy selectionChangedSpy(page, &QWebEnginePage::selectionChanged);
+ QSignalSpy actionChangedSpy(page->action(QWebEnginePage::SelectAll), &QAction::changed);
+
+ // The view is hidden and no focus on the page. Edit actions should be disabled.
+ QVERIFY(!view.isVisible());
+ QVERIFY(!page->action(QWebEnginePage::SelectAll)->isEnabled());
+
+ page->setHtml(QString("<html><body><div>foo bar</div></body></html>"));
+ QTRY_COMPARE(loadFinishedSpy.count(), 1);
+
+ // Content gets initial focus.
+ QTRY_COMPARE(actionChangedSpy.count(), 1);
+ QVERIFY(page->action(QWebEnginePage::SelectAll)->isEnabled());
+ view.page()->triggerAction(QWebEnginePage::SelectAll);
+ QTRY_COMPARE(selectionChangedSpy.count(), 1);
+ QCOMPARE(page->hasSelection(), true);
+ QCOMPARE(page->selectedText(), QStringLiteral("foo bar"));
+}
+
+void tst_QWebEnginePage::editActionsWithFocusOnIframe()
+{
+ QWebEngineView view;
+ QWebEnginePage *page = view.page();
+ view.settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, false);
+
+ QSignalSpy loadFinishedSpy(page, &QWebEnginePage::loadFinished);
+ QSignalSpy selectionChangedSpy(page, &QWebEnginePage::selectionChanged);
+ QSignalSpy actionChangedSpy(page->action(QWebEnginePage::SelectAll), &QAction::changed);
+
+ // The view is hidden and no focus on the page. Edit actions should be disabled.
+ QVERIFY(!view.isVisible());
+ QVERIFY(!page->action(QWebEnginePage::SelectAll)->isEnabled());
+
+ page->load(QUrl("qrc:///resources/iframe2.html"));
+ QTRY_COMPARE(loadFinishedSpy.count(), 1);
+ QVERIFY(!page->action(QWebEnginePage::SelectAll)->isEnabled());
+
+ // Focusing an iframe.
+ evaluateJavaScriptSync(page, "document.getElementsByTagName('iframe')[0].contentWindow.focus()");
+ QTRY_COMPARE(actionChangedSpy.count(), 1);
+ QVERIFY(page->action(QWebEnginePage::SelectAll)->isEnabled());
+ view.page()->triggerAction(QWebEnginePage::SelectAll);
+ QTRY_COMPARE(selectionChangedSpy.count(), 1);
+ QCOMPARE(page->hasSelection(), true);
+ QCOMPARE(page->selectedText(), QStringLiteral("inner"));
+}
+
static QByteArrayList params = {QByteArrayLiteral("--use-fake-device-for-media-stream")};
W_QTEST_MAIN(tst_QWebEnginePage, params)