summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2018-01-08 10:12:58 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2018-01-08 10:47:57 +0100
commit233258f132134caaa3c4acf924b47d7e548865e7 (patch)
tree2afbcb2923f13b03fbb1dc15c1c5b3622842ef1e
parent6666e23ed6252c3ef53c5f17d4f28bfe63736e33 (diff)
parent9ef3a8263098c6a32db8b824aabf85587d1f1140 (diff)
Merge remote-tracking branch 'origin/5.9' into 5.10
Conflicts: .qmake.conf src/core/api/qwebengineurlrequestjob.cpp src/core/browser_context_adapter.cpp src/core/renderer/user_resource_controller.cpp src/core/web_engine_context.cpp src/webenginewidgets/api/qwebenginepage.cpp Change-Id: I5278e5e22e1776d42975fc94d70ff8ca4f81fb9a
-rw-r--r--mkspecs/features/gn_generator.prf11
-rw-r--r--src/core/api/qwebengineurlrequestjob.cpp8
-rw-r--r--src/core/browser_context_adapter.cpp14
-rw-r--r--src/core/browser_context_adapter.h2
-rw-r--r--src/core/content_browser_client_qt.cpp9
-rw-r--r--src/core/delegated_frame_node.cpp2
-rw-r--r--src/core/pdfium_document_wrapper_qt.cpp20
-rw-r--r--src/core/pdfium_document_wrapper_qt.h6
-rw-r--r--src/core/renderer/user_resource_controller.cpp25
-rw-r--r--src/core/web_contents_adapter.cpp8
-rw-r--r--src/core/web_contents_delegate_qt.cpp25
-rw-r--r--src/core/web_engine_context.cpp21
-rw-r--r--src/core/web_engine_context.h5
-rw-r--r--src/core/web_event_factory.cpp3
-rw-r--r--src/webenginewidgets/api/qwebenginepage.cpp24
-rw-r--r--src/webenginewidgets/api/qwebengineprofile.cpp9
-rw-r--r--src/webenginewidgets/api/qwebengineprofile_p.h2
-rw-r--r--src/webenginewidgets/api/qwebengineview.cpp15
-rw-r--r--src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc5
-rw-r--r--src/webenginewidgets/doc/src/qwebengineview_lgpl.qdoc5
-rw-r--r--tests/auto/quick/qmltests/data/tst_favicon.qml91
-rw-r--r--tests/auto/widgets/qwebenginefaviconmanager/tst_qwebenginefaviconmanager.cpp30
-rw-r--r--tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp20
23 files changed, 266 insertions, 94 deletions
diff --git a/mkspecs/features/gn_generator.prf b/mkspecs/features/gn_generator.prf
index 072b0444e..a54a96c5a 100644
--- a/mkspecs/features/gn_generator.prf
+++ b/mkspecs/features/gn_generator.prf
@@ -148,17 +148,6 @@ for (define, DEFINES): {
define = $$replace(define,\',)
GN_CONTENTS += " \"$$define\","
}
-!isEmpty(QT_SYSROOT) {
- !isEmpty(QMAKE_LIBDIR_EGL):
- GN_CONTENTS += " \"QT_LIBDIR_EGL=\\\"$${QMAKE_DIR_SEP}$$relative_path($$QMAKE_LIBDIR_EGL, $$[QT_SYSROOT])\\\"\","
- !isEmpty(QMAKE_LIBDIR_OPENGL_ES2)
- GN_CONTENTS += " \"QT_LIBDIR_GLES2=\\\"$${QMAKE_DIR_SEP}$$relative_path($$QMAKE_LIBDIR_OPENGL_ES2, $$[QT_SYSROOT])\\\"\","
-} else {
- !isEmpty(QMAKE_LIBDIR_EGL):
- GN_CONTENTS += " \"QT_LIBDIR_EGL=\\\"$$QMAKE_LIBDIR_EGL\\\"\","
- !isEmpty(QMAKE_LIBDIR_OPENGL_ES2)
- GN_CONTENTS += " \"QT_LIBDIR_GLES2=\\\"$$QMAKE_LIBDIR_OPENGL_ES2\\\"\","
-}
GN_CONTENTS += " ]"
# Source files to compile
diff --git a/src/core/api/qwebengineurlrequestjob.cpp b/src/core/api/qwebengineurlrequestjob.cpp
index a071adbd5..47aab48a0 100644
--- a/src/core/api/qwebengineurlrequestjob.cpp
+++ b/src/core/api/qwebengineurlrequestjob.cpp
@@ -115,12 +115,20 @@ QByteArray QWebEngineUrlRequestJob::requestMethod() const
/*!
Replies to the request with \a device and the MIME type \a contentType.
+
The user has to be aware that \a device will be used on another thread
until the job is deleted. In case simultaneous access from the main thread
is desired, the user is reponsible for making access to \a device thread-safe
for example by using QMutex. Note that the \a device object is not owned by
the web engine. Therefore, the signal QObject::destroyed() of
QWebEngineUrlRequestJob must be monitored.
+
+ The device should remain available at least as long as the job exists.
+ When calling this method with a newly constructed device, one solution is to
+ make the device delete itself when closed, like this:
+ \code
+ connect(device, &QIODevice::aboutToClose, device, &QObject::deleteLater);
+ \endcode
*/
void QWebEngineUrlRequestJob::reply(const QByteArray &contentType, QIODevice *device)
{
diff --git a/src/core/browser_context_adapter.cpp b/src/core/browser_context_adapter.cpp
index 0f392f9f8..3f8397752 100644
--- a/src/core/browser_context_adapter.cpp
+++ b/src/core/browser_context_adapter.cpp
@@ -42,6 +42,7 @@
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/browsing_data_remover.h"
+#include "content/public/browser/download_manager.h"
#include "browser_context_qt.h"
#include "content_client_qt.h"
@@ -102,9 +103,16 @@ BrowserContextAdapter::BrowserContextAdapter(const QString &storageName)
BrowserContextAdapter::~BrowserContextAdapter()
{
+ Q_ASSERT(!m_downloadManagerDelegate);
+}
+
+void BrowserContextAdapter::shutdown()
+{
m_browserContext->ShutdownStoragePartitions();
- if (m_downloadManagerDelegate)
- content::BrowserThread::DeleteSoon(content::BrowserThread::UI, FROM_HERE, m_downloadManagerDelegate.take());
+ if (m_downloadManagerDelegate) {
+ m_browserContext->GetDownloadManager(m_browserContext.data())->Shutdown();
+ m_downloadManagerDelegate.reset();
+ }
BrowserContextDependencyManager::GetInstance()->DestroyBrowserContextServices(m_browserContext.data());
}
@@ -178,6 +186,8 @@ void BrowserContextAdapter::addClient(BrowserContextAdapterClient *adapterClient
void BrowserContextAdapter::removeClient(BrowserContextAdapterClient *adapterClient)
{
m_clients.removeOne(adapterClient);
+ if (m_clients.isEmpty() && this != WebEngineContext::current()->m_defaultBrowserContext.data())
+ shutdown();
}
void BrowserContextAdapter::cancelDownload(quint32 downloadId)
diff --git a/src/core/browser_context_adapter.h b/src/core/browser_context_adapter.h
index 5960014b9..b647bc30c 100644
--- a/src/core/browser_context_adapter.h
+++ b/src/core/browser_context_adapter.h
@@ -73,6 +73,8 @@ public:
static QSharedPointer<BrowserContextAdapter> defaultContext();
static QObject* globalQObjectRoot();
+ void shutdown();
+
VisitedLinksManagerQt *visitedLinksManager();
DownloadManagerDelegateQt *downloadManagerDelegate();
diff --git a/src/core/content_browser_client_qt.cpp b/src/core/content_browser_client_qt.cpp
index 3ec119e0a..2495e1d70 100644
--- a/src/core/content_browser_client_qt.cpp
+++ b/src/core/content_browser_client_qt.cpp
@@ -105,6 +105,10 @@
#include "web_engine_context.h"
#include "web_engine_library_info.h"
+#if defined(Q_OS_WIN)
+#include "ui/display/win/screen_win.h"
+#endif
+
#if defined(Q_OS_LINUX)
#include "global_descriptors_qt.h"
#include "ui/base/resource/resource_bundle.h"
@@ -295,8 +299,11 @@ public:
{
base::ThreadRestrictions::SetIOAllowed(true);
// Like ChromeBrowserMainExtraPartsViews::PreCreateThreads does.
+#if defined(Q_OS_WIN)
+ display::Screen::SetScreenInstance(new display::win::ScreenWin);
+#else
display::Screen::SetScreenInstance(new DesktopScreenQt);
-
+#endif
return 0;
}
diff --git a/src/core/delegated_frame_node.cpp b/src/core/delegated_frame_node.cpp
index 6f4a4e8db..de39300c9 100644
--- a/src/core/delegated_frame_node.cpp
+++ b/src/core/delegated_frame_node.cpp
@@ -739,6 +739,7 @@ void DelegatedFrameNode::preprocess()
if (!mailboxesToFetch.isEmpty())
fetchAndSyncMailboxes(mailboxesToFetch);
+#endif
// Then render any intermediate RenderPass in order.
typedef QPair<int, QSharedPointer<QSGLayer> > Pair;
@@ -748,7 +749,6 @@ void DelegatedFrameNode::preprocess()
// Proceed with the actual update.
pair.second->updateTexture();
}
-#endif
}
static YUVVideoMaterial::ColorSpace toQt(cc::YUVVideoDrawQuad::ColorSpace color_space)
diff --git a/src/core/pdfium_document_wrapper_qt.cpp b/src/core/pdfium_document_wrapper_qt.cpp
index df829a426..ca1e8cd07 100644
--- a/src/core/pdfium_document_wrapper_qt.cpp
+++ b/src/core/pdfium_document_wrapper_qt.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtWebEngine module of the Qt Toolkit.
@@ -129,7 +129,9 @@ private:
};
-PdfiumDocumentWrapperQt::PdfiumDocumentWrapperQt(const void *pdfData, size_t size, const QSize& imageSize, const char *password)
+PdfiumDocumentWrapperQt::PdfiumDocumentWrapperQt(const void *pdfData, size_t size,
+ const QSize& imageSize,
+ const char *password)
: m_imageSize(imageSize * 2.0)
{
Q_ASSERT(pdfData);
@@ -153,21 +155,13 @@ QImage PdfiumDocumentWrapperQt::pageAsQImage(size_t index)
return QImage();
}
- PdfiumPageWrapperQt *pageWrapper = nullptr;
- if (!m_cachedPages.contains(index)) {
- pageWrapper = new PdfiumPageWrapperQt(m_documentHandle, index,
- m_imageSize.width(), m_imageSize.height());
- m_cachedPages.insert(index, pageWrapper);
- } else {
- pageWrapper = m_cachedPages.value(index);
- }
-
- return pageWrapper->image();
+ PdfiumPageWrapperQt pageWrapper(m_documentHandle, index,
+ m_imageSize.width(), m_imageSize.height());
+ return pageWrapper.image();
}
PdfiumDocumentWrapperQt::~PdfiumDocumentWrapperQt()
{
- qDeleteAll(m_cachedPages);
FPDF_CloseDocument(m_documentHandle);
if (--m_libraryUsers == 0)
FPDF_DestroyLibrary();
diff --git a/src/core/pdfium_document_wrapper_qt.h b/src/core/pdfium_document_wrapper_qt.h
index 42ac94a28..28c490ae5 100644
--- a/src/core/pdfium_document_wrapper_qt.h
+++ b/src/core/pdfium_document_wrapper_qt.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtWebEngine module of the Qt Toolkit.
@@ -53,7 +53,8 @@ class PdfiumPageWrapperQt;
class QWEBENGINE_EXPORT PdfiumDocumentWrapperQt
{
public:
- PdfiumDocumentWrapperQt(const void *pdfData, size_t size, const QSize &imageSize, const char *password = nullptr);
+ PdfiumDocumentWrapperQt(const void *pdfData, size_t size, const QSize &imageSize,
+ const char *password = nullptr);
virtual ~PdfiumDocumentWrapperQt();
QImage pageAsQImage(size_t index);
int pageCount() const { return m_pageCount; }
@@ -63,7 +64,6 @@ private:
int m_pageCount;
void *m_documentHandle;
QSize m_imageSize;
- QHash<int, PdfiumPageWrapperQt*> m_cachedPages;
};
} // namespace QtWebEngineCore
diff --git a/src/core/renderer/user_resource_controller.cpp b/src/core/renderer/user_resource_controller.cpp
index b4375dfdb..f85879053 100644
--- a/src/core/renderer/user_resource_controller.cpp
+++ b/src/core/renderer/user_resource_controller.cpp
@@ -148,9 +148,14 @@ void UserResourceController::RenderFrameObserverHelper::runScripts(UserScriptDat
void UserResourceController::runScripts(UserScriptData::InjectionPoint p, blink::WebLocalFrame *frame)
{
content::RenderFrame *renderFrame = content::RenderFrame::FromWebFrame(frame);
- content::RenderView *renderView = renderFrame->GetRenderView();
+ if (!renderFrame)
+ return;
const bool isMainFrame = renderFrame->IsMainFrame();
+ content::RenderView *renderView = renderFrame->GetRenderView();
+ if (!renderView)
+ return;
+
QList<uint64_t> scriptsToRun = m_viewUserScriptMap.value(0).toList();
scriptsToRun.append(m_viewUserScriptMap.value(renderView).toList());
@@ -233,7 +238,8 @@ void UserResourceController::RenderFrameObserverHelper::OnDestruct()
void UserResourceController::RenderViewObserverHelper::OnDestruct()
{
// Remove all scripts associated with the render view.
- UserResourceController::instance()->renderViewDestroyed(render_view());
+ if (content::RenderView *view = render_view())
+ UserResourceController::instance()->renderViewDestroyed(view);
delete this;
}
@@ -251,20 +257,23 @@ bool UserResourceController::RenderFrameObserverHelper::OnMessageReceived(const
void UserResourceController::RenderFrameObserverHelper::onUserScriptAdded(const UserScriptData &script)
{
- content::RenderView *view = render_frame()->GetRenderView();
- UserResourceController::instance()->addScriptForView(script, view);
+ if (content::RenderFrame *frame = render_frame())
+ if (content::RenderView *view = frame->GetRenderView())
+ UserResourceController::instance()->addScriptForView(script, view);
}
void UserResourceController::RenderFrameObserverHelper::onUserScriptRemoved(const UserScriptData &script)
{
- content::RenderView *view = render_frame()->GetRenderView();
- UserResourceController::instance()->removeScriptForView(script, view);
+ if (content::RenderFrame *frame = render_frame())
+ if (content::RenderView *view = frame->GetRenderView())
+ UserResourceController::instance()->removeScriptForView(script, view);
}
void UserResourceController::RenderFrameObserverHelper::onScriptsCleared()
{
- content::RenderView *view = render_frame()->GetRenderView();
- UserResourceController::instance()->clearScriptsForView(view);
+ if (content::RenderFrame *frame = render_frame())
+ if (content::RenderView *view = frame->GetRenderView())
+ UserResourceController::instance()->clearScriptsForView(view);
}
UserResourceController *UserResourceController::instance()
diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp
index e2aedc9bb..0592e36fb 100644
--- a/src/core/web_contents_adapter.cpp
+++ b/src/core/web_contents_adapter.cpp
@@ -624,9 +624,11 @@ void WebContentsAdapter::setContent(const QByteArray &data, const QString &mimeT
CHECK_VALID_RENDER_WIDGET_HOST_VIEW(d->webContents->GetRenderViewHost());
QByteArray encodedData = data.toPercentEncoding();
- std::string urlString("data:");
- urlString.append(mimeType.toStdString());
- urlString.append(",");
+ std::string urlString;
+ if (!mimeType.isEmpty())
+ urlString = std::string("data:") + mimeType.toStdString() + std::string(",");
+ else
+ urlString = std::string("data:text/plain;charset=US-ASCII,");
urlString.append(encodedData.constData(), encodedData.length());
GURL dataUrlToLoad(urlString);
diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp
index 96c7c4c41..f51a6dff3 100644
--- a/src/core/web_contents_delegate_qt.cpp
+++ b/src/core/web_contents_delegate_qt.cpp
@@ -79,6 +79,16 @@
namespace QtWebEngineCore {
+static gfx::Rect rootViewToScreenRect(content::WebContents *web_contents, const gfx::Rect &anchor_in_root_view)
+{
+ RenderWidgetHostViewQt *rwhv = static_cast<RenderWidgetHostViewQt *>(web_contents->GetRenderWidgetHostView());
+ if (!rwhv)
+ return gfx::Rect();
+ content::ScreenInfo screenInfo;
+ rwhv->GetScreenInfo(&screenInfo);
+ return gfx::ScaleToEnclosingRect(anchor_in_root_view, 1 / screenInfo.device_scale_factor);
+}
+
// Maps the LogSeverity defines in base/logging.h to the web engines message levels.
static WebContentsAdapterClient::JavaScriptConsoleMessageLevel mapToJavascriptConsoleMessageLevel(int32_t messageLevel) {
if (messageLevel < 1)
@@ -335,6 +345,9 @@ void WebContentsDelegateQt::DidUpdateFaviconURL(const std::vector<content::Favic
faviconCandidates.append(toFaviconInfo(candidate));
}
+ // Favicon URL can be changed from JavaScript too. Thus we need to reset
+ // the current candidate icon list to not handle previous icon as a candidate.
+ m_faviconManager->resetCandidates();
m_faviconManager->update(faviconCandidates);
}
@@ -515,8 +528,10 @@ void WebContentsDelegateQt::launchExternalURL(const QUrl &url, ui::PageTransitio
void WebContentsDelegateQt::ShowValidationMessage(content::WebContents *web_contents, const gfx::Rect &anchor_in_root_view, const base::string16 &main_text, const base::string16 &sub_text)
{
- Q_UNUSED(web_contents);
- m_viewClient->showValidationMessage(toQt(anchor_in_root_view), toQt(main_text), toQt(sub_text));
+ gfx::Rect anchor = rootViewToScreenRect(web_contents, anchor_in_root_view);
+ if (anchor.IsEmpty())
+ return;
+ m_viewClient->showValidationMessage(toQt(anchor), toQt(main_text), toQt(sub_text));
}
void WebContentsDelegateQt::HideValidationMessage(content::WebContents *web_contents)
@@ -527,8 +542,10 @@ void WebContentsDelegateQt::HideValidationMessage(content::WebContents *web_cont
void WebContentsDelegateQt::MoveValidationMessage(content::WebContents *web_contents, const gfx::Rect &anchor_in_root_view)
{
- Q_UNUSED(web_contents);
- m_viewClient->moveValidationMessage(toQt(anchor_in_root_view));
+ gfx::Rect anchor = rootViewToScreenRect(web_contents, anchor_in_root_view);
+ if (anchor.IsEmpty())
+ return;
+ m_viewClient->moveValidationMessage(toQt(anchor));
}
void WebContentsDelegateQt::BeforeUnloadFired(content::WebContents *tab, bool proceed, bool *proceed_to_fire_unload)
diff --git a/src/core/web_engine_context.cpp b/src/core/web_engine_context.cpp
index 3f008fe49..9199bd102 100644
--- a/src/core/web_engine_context.cpp
+++ b/src/core/web_engine_context.cpp
@@ -121,7 +121,11 @@ void destroyContext()
// Before destroying MessageLoop via destroying BrowserMainRunner destructor
// WebEngineContext's pointer is used.
sContext->destroy();
- sContext = 0;
+#if !defined(NDEBUG)
+ if (!sContext->HasOneRef())
+ qWarning("WebEngineContext leaked on exit, likely due to leaked WebEngine View or Page");
+#endif
+ sContext = nullptr;
s_destroyed = true;
}
@@ -197,20 +201,27 @@ void WebEngineContext::destroy()
{
if (m_devtoolsServer)
m_devtoolsServer->stop();
- delete m_globalQObject;
- m_globalQObject = 0;
base::MessagePump::Delegate *delegate =
static_cast<base::MessageLoop *>(m_runLoop->delegate_);
// Flush the UI message loop before quitting.
while (delegate->DoWork()) { }
+
+ if (m_defaultBrowserContext)
+ m_defaultBrowserContext->shutdown();
+ // Delete the global object and thus custom profiles
+ delete m_globalQObject;
+ m_globalQObject = nullptr;
+ // Handle any events posted by browser-context shutdown.
+ while (delegate->DoWork()) { }
+
GLContextHelper::destroy();
- m_devtoolsServer.reset(0);
+ m_devtoolsServer.reset();
m_runLoop->AfterRun();
// Force to destroy RenderProcessHostImpl by destroying BrowserMainRunner.
// RenderProcessHostImpl should be destroyed before WebEngineContext since
// default BrowserContext might be used by the RenderprocessHostImpl's destructor.
- m_browserRunner.reset(0);
+ m_browserRunner.reset();
// Drop the false reference.
sContext->Release();
diff --git a/src/core/web_engine_context.h b/src/core/web_engine_context.h
index 92c45e260..1b4be48b1 100644
--- a/src/core/web_engine_context.h
+++ b/src/core/web_engine_context.h
@@ -80,7 +80,7 @@ class WebEngineContext : public base::RefCounted<WebEngineContext> {
public:
static scoped_refptr<WebEngineContext> current();
- QSharedPointer<QtWebEngineCore::BrowserContextAdapter> defaultBrowserContext();
+ QSharedPointer<BrowserContextAdapter> defaultBrowserContext();
QObject *globalQObject();
#if BUILDFLAG(ENABLE_BASIC_PRINTING)
printing::PrintJobManager* getPrintJobManager();
@@ -90,6 +90,7 @@ public:
private:
friend class base::RefCounted<WebEngineContext>;
+ friend class BrowserContextAdapter;
WebEngineContext();
~WebEngineContext();
@@ -98,7 +99,7 @@ private:
std::unique_ptr<content::ContentMainRunner> m_contentRunner;
std::unique_ptr<content::BrowserMainRunner> m_browserRunner;
QObject* m_globalQObject;
- QSharedPointer<QtWebEngineCore::BrowserContextAdapter> m_defaultBrowserContext;
+ QSharedPointer<BrowserContextAdapter> m_defaultBrowserContext;
std::unique_ptr<DevToolsServerQt> m_devtoolsServer;
#if BUILDFLAG(ENABLE_BASIC_PRINTING)
std::unique_ptr<printing::PrintJobManager> m_printJobManager;
diff --git a/src/core/web_event_factory.cpp b/src/core/web_event_factory.cpp
index 3193f885a..359eb5a58 100644
--- a/src/core/web_event_factory.cpp
+++ b/src/core/web_event_factory.cpp
@@ -1023,7 +1023,8 @@ static inline double currentTimeForEvent(const QEvent *event)
{
Q_ASSERT(event);
- if (const QInputEvent *inputEvent = static_cast<const QInputEvent *>(event)) {
+ if (event->type() != QEvent::Leave) {
+ const QInputEvent *inputEvent = static_cast<const QInputEvent *>(event);
if (inputEvent->timestamp())
return static_cast<double>(inputEvent->timestamp()) / 1000;
}
diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp
index 976f72fa4..438e3ea24 100644
--- a/src/webenginewidgets/api/qwebenginepage.cpp
+++ b/src/webenginewidgets/api/qwebenginepage.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtWebEngine module of the Qt Toolkit.
@@ -138,7 +138,8 @@ static bool printPdfDataOnPrinter(const QByteArray& data, QPrinter& printer)
QPainter painter;
if (!painter.begin(&printer)) {
- qWarning("Failure to print on printer %ls: Could not open printer for painting.", qUtf16Printable(printer.printerName()));
+ qWarning("Failure to print on printer %ls: Could not open printer for painting.",
+ qUtf16Printable(printer.printerName()));
return false;
}
@@ -1610,12 +1611,21 @@ bool QWebEnginePagePrivate::isEnabled() const
void QWebEnginePagePrivate::setToolTip(const QString &toolTipText)
{
- if (view) {
- QString wrappedTip;
- if (!toolTipText.isEmpty())
- wrappedTip = QLatin1String("<p>") % toolTipText.toHtmlEscaped().left(MaxTooltipLength) % QLatin1String("</p>");
- view->setToolTip(wrappedTip);
+ if (!view)
+ return;
+
+ // Hide tooltip if shown.
+ if (toolTipText.isEmpty()) {
+ if (!view->toolTip().isEmpty())
+ view->setToolTip(QString());
+
+ return;
}
+
+ // Update tooltip if text was changed.
+ QString wrappedTip = QLatin1String("<p>") % toolTipText.toHtmlEscaped().left(MaxTooltipLength) % QLatin1String("</p>");
+ if (view->toolTip() != wrappedTip)
+ view->setToolTip(wrappedTip);
}
QMenu *QWebEnginePage::createStandardContextMenu()
diff --git a/src/webenginewidgets/api/qwebengineprofile.cpp b/src/webenginewidgets/api/qwebengineprofile.cpp
index c4de46b67..5a6c0e18a 100644
--- a/src/webenginewidgets/api/qwebengineprofile.cpp
+++ b/src/webenginewidgets/api/qwebengineprofile.cpp
@@ -155,11 +155,18 @@ QWebEngineBrowserContext::QWebEngineBrowserContext(QSharedPointer<QtWebEngineCor
QWebEngineBrowserContext::~QWebEngineBrowserContext()
{
+ if (m_profile)
+ shutdown();
+}
+
+void QWebEngineBrowserContext::shutdown()
+{
Q_ASSERT(m_profile);
// In the case the user sets this profile as the parent of the interceptor
// it can be deleted before the browser-context still referencing it is.
browserContextRef->setRequestInterceptor(nullptr);
browserContextRef->removeClient(m_profile);
+ m_profile = 0;
}
QWebEngineProfilePrivate::QWebEngineProfilePrivate(QSharedPointer<QtWebEngineCore::BrowserContextAdapter> browserContext)
@@ -181,6 +188,8 @@ QWebEngineProfilePrivate::~QWebEngineProfilePrivate()
}
m_ongoingDownloads.clear();
+ if (m_browserContext)
+ m_browserContext->shutdown();
}
QSharedPointer<QtWebEngineCore::BrowserContextAdapter> QWebEngineProfilePrivate::browserContext() const
diff --git a/src/webenginewidgets/api/qwebengineprofile_p.h b/src/webenginewidgets/api/qwebengineprofile_p.h
index 7f02307d3..07aad9176 100644
--- a/src/webenginewidgets/api/qwebengineprofile_p.h
+++ b/src/webenginewidgets/api/qwebengineprofile_p.h
@@ -76,6 +76,8 @@ public:
QWebEngineBrowserContext(QSharedPointer<QtWebEngineCore::BrowserContextAdapter> browserContext, QWebEngineProfilePrivate *profile);
~QWebEngineBrowserContext();
+ void shutdown();
+
QSharedPointer<QtWebEngineCore::BrowserContextAdapter> browserContextRef;
private:
diff --git a/src/webenginewidgets/api/qwebengineview.cpp b/src/webenginewidgets/api/qwebengineview.cpp
index 9b3f62217..7ea451fc5 100644
--- a/src/webenginewidgets/api/qwebengineview.cpp
+++ b/src/webenginewidgets/api/qwebengineview.cpp
@@ -50,8 +50,9 @@
#include <QAction>
#include <QMenu>
#include <QContextMenuEvent>
-#include <QStackedLayout>
#include <QPageLayout>
+#include <QStackedLayout>
+#include <QToolTip>
QT_BEGIN_NAMESPACE
@@ -327,6 +328,18 @@ bool QWebEngineView::event(QEvent *ev)
ev->accept();
return true;
}
+
+ // Override QWidget's default ToolTip handler since it doesn't hide tooltip on empty text.
+ if (ev->type() == QEvent::ToolTip) {
+ if (!toolTip().isEmpty())
+ QToolTip::showText(static_cast<QHelpEvent *>(ev)->globalPos(), toolTip(), this, QRect(), toolTipDuration());
+ else
+ QToolTip::hideText();
+
+ ev->accept();
+ return true;
+ }
+
return QWidget::event(ev);
}
diff --git a/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc b/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc
index 4cad5a063..23b280b6d 100644
--- a/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc
+++ b/src/webenginewidgets/doc/src/qwebenginepage_lgpl.qdoc
@@ -686,9 +686,8 @@
/*!
\fn void QWebEnginePage::setContent(const QByteArray &data, const QString &mimeType, const QUrl &baseUrl)
- Sets the content of this page to \a data. If the \a mimeType argument
- is empty, it is currently assumed that the content is HTML but in future versions we may introduce
- auto-detection.
+ Sets the content of the web page to \a data. If the \a mimeType argument
+ 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.
diff --git a/src/webenginewidgets/doc/src/qwebengineview_lgpl.qdoc b/src/webenginewidgets/doc/src/qwebengineview_lgpl.qdoc
index 27ee96c5e..18d139c00 100644
--- a/src/webenginewidgets/doc/src/qwebengineview_lgpl.qdoc
+++ b/src/webenginewidgets/doc/src/qwebengineview_lgpl.qdoc
@@ -152,9 +152,8 @@
/*!
\fn void QWebEngineView::setContent(const QByteArray &data, const QString &mimeType, const QUrl &baseUrl)
- Sets the content of the web view to the specified content \a data. If the \a mimeType argument
- is empty, it is currently assumed that the content is HTML but in future versions we may
- introduce auto-detection.
+ Sets the content of the web view to \a data. If the \a mimeType argument
+ 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.
diff --git a/tests/auto/quick/qmltests/data/tst_favicon.qml b/tests/auto/quick/qmltests/data/tst_favicon.qml
index ea474e0dc..1159f3194 100644
--- a/tests/auto/quick/qmltests/data/tst_favicon.qml
+++ b/tests/auto/quick/qmltests/data/tst_favicon.qml
@@ -54,6 +54,35 @@ TestWebEngineView {
return url.toString().substring(16)
}
+ function getFaviconPixel(faviconImage) {
+ var grabImage = Qt.createQmlObject("
+ import QtQuick 2.5\n
+ Image { }", test)
+ var faviconCanvas = Qt.createQmlObject("
+ import QtQuick 2.5\n
+ Canvas { }", test)
+
+ test.tryVerify(function() { return faviconImage.status == Image.Ready });
+ faviconImage.grabToImage(function(result) {
+ grabImage.source = result.url
+ });
+ test.tryVerify(function() { return grabImage.status == Image.Ready });
+
+ faviconCanvas.width = faviconImage.width;
+ faviconCanvas.height = faviconImage.height;
+ var ctx = faviconCanvas.getContext("2d");
+ ctx.drawImage(grabImage, 0, 0, grabImage.width, grabImage.height);
+ var imageData = ctx.getImageData(Math.round(faviconCanvas.width/2),
+ Math.round(faviconCanvas.height/2),
+ faviconCanvas.width,
+ faviconCanvas.height);
+
+ grabImage.destroy();
+ faviconCanvas.destroy();
+
+ return imageData.data;
+ }
+
SignalSpy {
id: iconChangedSpy
target: webEngineView
@@ -285,12 +314,6 @@ TestWebEngineView {
var faviconImage = Qt.createQmlObject("
import QtQuick 2.5\n
Image { sourceSize: Qt.size(width, height) }", test)
- var grabImage = Qt.createQmlObject("
- import QtQuick 2.5\n
- Image { }", test)
- var faviconCanvas = Qt.createQmlObject("
- import QtQuick 2.5\n
- Canvas { }", test)
compare(iconChangedSpy.count, 0)
@@ -303,27 +326,53 @@ TestWebEngineView {
faviconImage.width = row.size
faviconImage.height = row.size
faviconImage.source = webEngineView.icon
- verify(_waitFor(function() { return faviconImage.status == Image.Ready } ))
- faviconImage.grabToImage(function(result) {
- grabImage.source = result.url
- })
- verify(_waitFor(function() { return grabImage.status == Image.Ready } ))
+ var pixel = getFaviconPixel(faviconImage);
+ compare(pixel[0], row.value)
- faviconCanvas.width = faviconImage.width
- faviconCanvas.height = faviconImage.height
- var ctx = faviconCanvas.getContext("2d")
- ctx.drawImage(grabImage, 0, 0, grabImage.width, grabImage.height)
+ faviconImage.destroy()
+ }
- var center = Math.round(row.size/2)
- var imageData = ctx.getImageData(center, center, center, center)
- var pixel = imageData.data
+ function test_dynamicFavicon() {
+ var faviconImage = Qt.createQmlObject("
+ import QtQuick 2.5\n
+ Image { width: 16; height: 16; sourceSize: Qt.size(width, height); }", test)
+ faviconImage.source = Qt.binding(function() { return webEngineView.icon; });
- compare(pixel[0], row.value)
+ var colors = [
+ {"url": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg==", "r": 255, "g": 0, "b": 0},
+ {"url": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M/wHwAEBgIApD5fRAAAAABJRU5ErkJggg==", "r": 0, "g": 255, "b": 0},
+ {"url": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPj/HwADBwIAMCbHYQAAAABJRU5ErkJggg==", "r": 0, "g": 0, "b": 255},
+ ];
+ var pixel;
+
+ compare(iconChangedSpy.count, 0);
+ webEngineView.loadHtml(
+ "<html>" +
+ "<link rel='icon' type='image/png' href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII='/>" +
+ "</html>"
+ );
+ verify(webEngineView.waitForLoadSucceeded());
+ tryCompare(iconChangedSpy, "count", 1);
+
+ pixel = getFaviconPixel(faviconImage);
+ compare(pixel[0], 0);
+ compare(pixel[1], 0);
+ compare(pixel[2], 0);
+
+ for (var i = 0; i < colors.length; ++i) {
+ iconChangedSpy.clear();
+ runJavaScript("document.getElementsByTagName('link')[0].href = 'data:image/png;base64," + colors[i]["url"] + "';");
+ tryCompare(faviconImage, "source", "image://favicon/data:image/png;base64," + colors[i]["url"]);
+ compare(iconChangedSpy.count, 1);
+
+ pixel = getFaviconPixel(faviconImage);
+ compare(pixel[0], colors[i]["r"]);
+ compare(pixel[1], colors[i]["g"]);
+ compare(pixel[2], colors[i]["b"]);
+ }
faviconImage.destroy()
- grabImage.destroy()
- faviconCanvas.destroy()
}
}
}
diff --git a/tests/auto/widgets/qwebenginefaviconmanager/tst_qwebenginefaviconmanager.cpp b/tests/auto/widgets/qwebenginefaviconmanager/tst_qwebenginefaviconmanager.cpp
index 38311cad2..8dcdb9f7a 100644
--- a/tests/auto/widgets/qwebenginefaviconmanager/tst_qwebenginefaviconmanager.cpp
+++ b/tests/auto/widgets/qwebenginefaviconmanager/tst_qwebenginefaviconmanager.cpp
@@ -60,6 +60,7 @@ private Q_SLOTS:
void downloadIconsDisabled();
void downloadTouchIconsEnabled_data();
void downloadTouchIconsEnabled();
+ void dynamicFavicon();
private:
QWebEngineView *m_view;
@@ -473,6 +474,35 @@ void tst_QWebEngineFaviconManager::downloadTouchIconsEnabled()
QVERIFY(icon.availableSizes().contains(expectedIconSize));
}
+void tst_QWebEngineFaviconManager::dynamicFavicon()
+{
+ QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool)));
+ QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl)));
+ QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon)));
+
+ QMap<Qt::GlobalColor, QString> colors;
+ colors.insert(Qt::red, QString("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg=="));
+ colors.insert(Qt::green, QString("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M/wHwAEBgIApD5fRAAAAABJRU5ErkJggg=="));
+ colors.insert(Qt::blue, QString("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPj/HwADBwIAMCbHYQAAAABJRU5ErkJggg=="));
+
+ m_page->setHtml("<html>"
+ "<link rel='icon' type='image/png' href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII='/>"
+ "</html>");
+ QTRY_COMPARE(loadFinishedSpy.count(), 1);
+ QTRY_COMPARE(iconUrlChangedSpy.count(), 1);
+ QTRY_COMPARE(iconChangedSpy.count(), 1);
+
+ QCOMPARE(m_page->icon().pixmap(1, 1).toImage().pixelColor(0, 0), QColor(Qt::black));
+
+ for (Qt::GlobalColor color : colors.keys()) {
+ iconChangedSpy.clear();
+ evaluateJavaScriptSync(m_page, "document.getElementsByTagName('link')[0].href = 'data:image/png;base64," + colors[color] + "';");
+ QTRY_COMPARE(iconChangedSpy.count(), 1);
+ QTRY_COMPARE(m_page->iconUrl().toString(), QString("data:image/png;base64," + colors[color]));
+ QCOMPARE(m_page->icon().pixmap(1, 1).toImage().pixelColor(0, 0), QColor(color));
+ }
+}
+
QTEST_MAIN(tst_QWebEngineFaviconManager)
#include "tst_qwebenginefaviconmanager.moc"
diff --git a/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp b/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp
index 294cc52b1..6961f3b6d 100644
--- a/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp
+++ b/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp
@@ -163,20 +163,25 @@ public:
class ReplyingUrlSchemeHandler : public QWebEngineUrlSchemeHandler
{
- QBuffer m_buffer;
- QByteArray m_bufferData;
public:
ReplyingUrlSchemeHandler(QObject *parent = nullptr)
: QWebEngineUrlSchemeHandler(parent)
{
- m_buffer.setBuffer(&m_bufferData);
+ }
+ ~ReplyingUrlSchemeHandler()
+ {
}
void requestStarted(QWebEngineUrlRequestJob *job)
{
- m_bufferData = job->requestUrl().toString().toUtf8();
- job->reply("text/plain;charset=utf-8", &m_buffer);
+ QBuffer *buffer = new QBuffer;
+ buffer->setData(job->requestUrl().toString().toUtf8());
+ connect(buffer, &QIODevice::aboutToClose, buffer, &QObject::deleteLater);
+ m_buffers.append(buffer);
+ job->reply("text/plain;charset=utf-8", buffer);
}
+
+ QList<QPointer<QBuffer>> m_buffers;
};
class StreamingIODevice : public QIODevice {
@@ -309,6 +314,11 @@ void tst_QWebEngineProfile::urlSchemeHandlers()
url = QUrl(QStringLiteral("aviancarrier:inspector.mortensen@politistyrke.dk"));
QVERIFY(loadSync(&view, url));
QCOMPARE(toPlainTextSync(view.page()), url.toString());
+
+ // Check that all buffers got deleted
+ QCOMPARE(gopherHandler.m_buffers.count(), 2);
+ for (int i = 0; i < gopherHandler.m_buffers.count(); ++i)
+ QVERIFY(gopherHandler.m_buffers.at(i).isNull());
}
class FailingUrlSchemeHandler : public QWebEngineUrlSchemeHandler