summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2016-06-13 10:16:32 +0200
committerAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2016-06-14 10:43:10 +0200
commit939d104cc5a8208a0bef94ca14889ccd584a3526 (patch)
tree4d89c122ad5014a32cd8d4fbad6b7418944d2fb6 /src/core
parent5a7063154520544fe19bb57af3609afef898bffb (diff)
parent6c2a111f8c82b56388abf409a61a3e0d56a52156 (diff)
Merge branch '5.7' into dev
Diffstat (limited to 'src/core')
-rw-r--r--src/core/api/core_api.pro1
-rw-r--r--src/core/browser_context_qt.h2
-rw-r--r--src/core/clipboard_qt.cpp7
-rw-r--r--src/core/config/desktop_linux.pri8
-rw-r--r--src/core/content_client_qt.cpp30
-rw-r--r--src/core/core_gyp_generator.pro2
-rw-r--r--src/core/core_module.pro2
-rw-r--r--src/core/gl_surface_qt.cpp82
-rw-r--r--src/core/gyp_run.pro2
-rw-r--r--src/core/location_provider_qt.cpp34
-rw-r--r--src/core/render_widget_host_view_qt.cpp6
-rw-r--r--src/core/renderer/pepper/pepper_flash_clipboard_message_filter_qt.cpp401
-rw-r--r--src/core/renderer/pepper/pepper_flash_clipboard_message_filter_qt.h108
-rw-r--r--src/core/renderer/pepper/pepper_host_factory_qt.cpp18
-rw-r--r--src/core/web_contents_adapter.cpp19
-rw-r--r--src/core/web_contents_adapter_client.h1
-rw-r--r--src/core/web_contents_view_qt.cpp2
17 files changed, 690 insertions, 35 deletions
diff --git a/src/core/api/core_api.pro b/src/core/api/core_api.pro
index 19b67876c..a9f5adaba 100644
--- a/src/core/api/core_api.pro
+++ b/src/core/api/core_api.pro
@@ -15,6 +15,7 @@ CONFIG -= create_prl
# Copy this logic from qt_module.prf so that the intermediate library can be
# created to the same rules as the final module linking in core_module.pro.
!host_build:if(win32|mac):!macx-xcode {
+ contains(QT_CONFIG, simulator_and_device): CONFIG += iphonesimulator_and_iphoneos
contains(QT_CONFIG, debug_and_release):CONFIG += debug_and_release
contains(QT_CONFIG, build_all):CONFIG += build_all
}
diff --git a/src/core/browser_context_qt.h b/src/core/browser_context_qt.h
index 68e1244e1..13f7220bd 100644
--- a/src/core/browser_context_qt.h
+++ b/src/core/browser_context_qt.h
@@ -97,7 +97,7 @@ public:
BrowserContextAdapter *adapter() { return m_adapter; }
#if defined(ENABLE_SPELLCHECK)
- void failedToLoadDictionary(const std::string& language) override;
+ void failedToLoadDictionary(const std::string& language);
void setSpellCheckLanguage(const QString &language);
QString spellCheckLanguage() const;
void setSpellCheckEnabled(bool enabled);
diff --git a/src/core/clipboard_qt.cpp b/src/core/clipboard_qt.cpp
index bd62f4872..712ff5703 100644
--- a/src/core/clipboard_qt.cpp
+++ b/src/core/clipboard_qt.cpp
@@ -56,6 +56,13 @@
namespace QtWebEngineCore {
+static void registerMetaTypes()
+{
+ qRegisterMetaType<QClipboard::Mode>("QClipboard::Mode");
+}
+
+Q_CONSTRUCTOR_FUNCTION(registerMetaTypes)
+
Q_GLOBAL_STATIC(ClipboardChangeObserver, clipboardChangeObserver)
ClipboardChangeObserver::ClipboardChangeObserver()
diff --git a/src/core/config/desktop_linux.pri b/src/core/config/desktop_linux.pri
index a78082581..de0fbbc6b 100644
--- a/src/core/config/desktop_linux.pri
+++ b/src/core/config/desktop_linux.pri
@@ -6,5 +6,9 @@ GYP_CONFIG += \
desktop_linux=1 \
enable_widevine=1
-linux-clang: GYP_CONFIG += clang=1 host_clang=1 clang_use_chrome_plugins=0 make_clang_dir=/usr
-else: GYP_CONFIG += clang=0 host_clang=0
+clang {
+ GYP_CONFIG += clang=1 host_clang=1 clang_use_chrome_plugins=0 make_clang_dir=/usr
+ linux-clang-libc++: GYP_CONFIG += use_system_libcxx=1
+} else {
+ GYP_CONFIG += clang=0 host_clang=0
+}
diff --git a/src/core/content_client_qt.cpp b/src/core/content_client_qt.cpp
index 158bb0895..49c018b23 100644
--- a/src/core/content_client_qt.cpp
+++ b/src/core/content_client_qt.cpp
@@ -57,6 +57,18 @@
#include <QLibraryInfo>
#include <QString>
+#if defined(Q_OS_WIN)
+#include <shlobj.h>
+static QString getLocalAppDataDir()
+{
+ QString result;
+ wchar_t path[MAX_PATH];
+ if (SHGetSpecialFolderPath(0, path, CSIDL_LOCAL_APPDATA, FALSE))
+ result = QDir::fromNativeSeparators(QString::fromWCharArray(path));
+ return result;
+}
+#endif
+
#if defined(ENABLE_PLUGINS)
// The plugin logic is based on chrome/common/chrome_content_client.cc:
@@ -199,10 +211,24 @@ void AddPepperWidevine(std::vector<content::PepperPluginInfo>* plugins)
pluginPaths << potentialWidevinePluginPath;
}
}
+#elif defined(Q_OS_WIN)
+ QDir potentialWidevineDir(getLocalAppDataDir() + "/Google/Chrome/User Data/WidevineCDM");
+ if (potentialWidevineDir.exists()) {
+ QFileInfoList widevineVersionDirs = potentialWidevineDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name | QDir::Reversed);
+ for (int i = 0; i < widevineVersionDirs.size(); ++i) {
+ QString versionDirPath(widevineVersionDirs.at(i).absoluteFilePath());
+#ifdef WIN64
+ QString potentialWidevinePluginPath = versionDirPath + "/_platform_specific/win_x64/" + QString::fromLatin1(kWidevineCdmAdapterFileName);
+#else
+ QString potentialWidevinePluginPath = versionDirPath + "/_platform_specific/win_x86/" + QString::fromLatin1(kWidevineCdmAdapterFileName);
#endif
-#if defined(Q_OS_LINUX)
+ pluginPaths << potentialWidevinePluginPath;
+ }
+ }
+#elif defined(Q_OS_LINUX)
pluginPaths << QStringLiteral("/opt/google/chrome/libwidevinecdmadapter.so") // Google Chrome
- << QStringLiteral("/usr/lib/chromium/libwidevinecdmadapter.so"); // Arch
+ << QStringLiteral("/usr/lib/chromium/libwidevinecdmadapter.so") // Arch
+ << QStringLiteral("/usr/lib64/chromium/libwidevinecdmadapter.so"); // OpenSUSE style
#endif
}
diff --git a/src/core/core_gyp_generator.pro b/src/core/core_gyp_generator.pro
index 3e6a9eac0..cdff4ed64 100644
--- a/src/core/core_gyp_generator.pro
+++ b/src/core/core_gyp_generator.pro
@@ -73,6 +73,7 @@ SOURCES = \
render_widget_host_view_qt.cpp \
renderer/content_renderer_client_qt.cpp \
renderer/pepper/pepper_flash_browser_host_qt.cpp \
+ renderer/pepper/pepper_flash_clipboard_message_filter_qt.cpp \
renderer/pepper/pepper_flash_renderer_host_qt.cpp \
renderer/pepper/pepper_host_factory_qt.cpp \
renderer/pepper/pepper_isolated_file_system_message_filter.cpp \
@@ -155,6 +156,7 @@ HEADERS = \
render_widget_host_view_qt_delegate.h \
renderer/content_renderer_client_qt.h \
renderer/pepper/pepper_flash_browser_host_qt.h \
+ renderer/pepper/pepper_flash_clipboard_message_filter_qt.h \
renderer/pepper/pepper_flash_renderer_host_qt.h \
renderer/pepper/pepper_host_factory_qt.h \
renderer/pepper/pepper_isolated_file_system_message_filter.h \
diff --git a/src/core/core_module.pro b/src/core/core_module.pro
index fa402cc63..702b92441 100644
--- a/src/core/core_module.pro
+++ b/src/core/core_module.pro
@@ -14,6 +14,8 @@ load(qt_module)
api_library_name = qtwebenginecoreapi$$qtPlatformTargetSuffix()
api_library_path = $$OUT_PWD/api/$$getConfigDir()
+# Do not precompile any headers. We are only interested in the linker step.
+PRECOMPILED_HEADER =
LIBS_PRIVATE += -L$$api_library_path
CONFIG *= no_smart_library_merge
diff --git a/src/core/gl_surface_qt.cpp b/src/core/gl_surface_qt.cpp
index ef5b1d172..3982b9bd1 100644
--- a/src/core/gl_surface_qt.cpp
+++ b/src/core/gl_surface_qt.cpp
@@ -87,6 +87,7 @@ void* g_display;
const char* g_extensions = NULL;
+bool g_egl_surfaceless_context_supported = false;
} // namespace
@@ -109,6 +110,26 @@ private:
DISALLOW_COPY_AND_ASSIGN(GLSurfaceQtEGL);
};
+// The following comment is cited from chromium/ui/gl/gl_surface_egl.cc:
+// SurfacelessEGL is used as Offscreen surface when platform supports
+// KHR_surfaceless_context and GL_OES_surfaceless_context. This would avoid the
+// need to create a dummy EGLsurface in case we render to client API targets.
+class GLSurfacelessQtEGL : public GLSurfaceQt {
+public:
+ explicit GLSurfacelessQtEGL(const gfx::Size& size);
+
+ public:
+ bool Initialize() Q_DECL_OVERRIDE;
+ void Destroy() Q_DECL_OVERRIDE;
+ bool IsSurfaceless() const Q_DECL_OVERRIDE;
+ bool Resize(const gfx::Size& size, float scale_factor, bool has_alpha) Q_DECL_OVERRIDE;
+ EGLSurface GetHandle() Q_DECL_OVERRIDE;
+ void* GetShareHandle() Q_DECL_OVERRIDE;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(GLSurfacelessQtEGL);
+};
+
GLSurfaceQt::~GLSurfaceQt()
{
@@ -342,6 +363,23 @@ bool GLSurfaceQtEGL::InitializeOneOff()
return false;
}
+ g_egl_surfaceless_context_supported = ExtensionsContain(g_extensions, "EGL_KHR_surfaceless_context");
+ if (g_egl_surfaceless_context_supported) {
+ scoped_refptr<GLSurface> surface = new GLSurfacelessQtEGL(Size(1, 1));
+ scoped_refptr<GLContext> context = GLContext::CreateGLContext(
+ NULL, surface.get(), PreferIntegratedGpu);
+
+ if (!context->MakeCurrent(surface.get()))
+ g_egl_surfaceless_context_supported = false;
+
+ // Ensure context supports GL_OES_surfaceless_context.
+ if (g_egl_surfaceless_context_supported) {
+ g_egl_surfaceless_context_supported = context->HasExtension(
+ "GL_OES_surfaceless_context");
+ context->ReleaseCurrent(surface.get());
+ }
+ }
+
initialized = true;
return true;
}
@@ -426,7 +464,7 @@ bool GLSurfaceQtEGL::Initialize()
g_config,
pbuffer_attributes);
if (!m_surfaceBuffer) {
- LOG(ERROR) << "eglCreatePbufferSurface failed with error ", GetLastEGLErrorString();
+ LOG(ERROR) << "eglCreatePbufferSurface failed with error " << GetLastEGLErrorString();
Destroy();
return false;
}
@@ -502,6 +540,41 @@ void* GLSurfaceQt::GetConfig()
return g_config;
}
+GLSurfacelessQtEGL::GLSurfacelessQtEGL(const gfx::Size& size)
+ : GLSurfaceQt(size)
+{
+}
+
+bool GLSurfacelessQtEGL::Initialize()
+{
+ return true;
+}
+
+void GLSurfacelessQtEGL::Destroy()
+{
+}
+
+bool GLSurfacelessQtEGL::IsSurfaceless() const
+{
+ return true;
+}
+
+bool GLSurfacelessQtEGL::Resize(const gfx::Size& size, float scale_factor, bool has_alpha)
+{
+ m_size = size;
+ return true;
+}
+
+EGLSurface GLSurfacelessQtEGL::GetHandle()
+{
+ return EGL_NO_SURFACE;
+}
+
+void* GLSurfacelessQtEGL::GetShareHandle()
+{
+ return NULL;
+}
+
// static
scoped_refptr<GLSurface>
GLSurface::CreateOffscreenGLSurface(const gfx::Size& size)
@@ -525,7 +598,12 @@ GLSurface::CreateOffscreenGLSurface(const gfx::Size& size)
#endif
}
case kGLImplementationEGLGLES2: {
- scoped_refptr<GLSurface> surface = new GLSurfaceQtEGL(size);
+ scoped_refptr<GLSurface> surface;
+ if (g_egl_surfaceless_context_supported)
+ surface = new GLSurfacelessQtEGL(size);
+ else
+ surface = new GLSurfaceQtEGL(size);
+
if (!surface->Initialize())
return NULL;
return surface;
diff --git a/src/core/gyp_run.pro b/src/core/gyp_run.pro
index 2e2422dce..35b85b4c7 100644
--- a/src/core/gyp_run.pro
+++ b/src/core/gyp_run.pro
@@ -34,6 +34,7 @@ force_debug_info {
# Copy this logic from qt_module.prf so that ninja can run according
# to the same rules as the final module linking in core_module.pro.
!host_build:if(win32|mac):!macx-xcode {
+ contains(QT_CONFIG, simulator_and_device): CONFIG += iphonesimulator_and_iphoneos
contains(QT_CONFIG, debug_and_release):CONFIG += debug_and_release
contains(QT_CONFIG, build_all):CONFIG += build_all
}
@@ -81,6 +82,7 @@ contains(QT_ARCH, "arm") {
else: GYP_CONFIG += arm_fpu=\"$$MFPU\" arm_neon=0 arm_neon_optional=0
}
+ contains(QMAKE_CFLAGS, "-marm"): GYP_CONFIG += arm_thumb=0
contains(QMAKE_CFLAGS, "-mthumb"): GYP_CONFIG += arm_thumb=1
}
diff --git a/src/core/location_provider_qt.cpp b/src/core/location_provider_qt.cpp
index cc87d8417..c07bd4b0c 100644
--- a/src/core/location_provider_qt.cpp
+++ b/src/core/location_provider_qt.cpp
@@ -44,11 +44,13 @@
#include "type_conversion.h"
#include <QtCore/QCoreApplication>
+#include <QtCore/QMetaObject>
#include <QtCore/QThread>
#include <QtPositioning/QGeoPositionInfoSource>
-#include "base/message_loop/message_loop.h"
#include "base/bind.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop.h"
#include "content/browser/geolocation/geolocation_provider_impl.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/geolocation_provider.h"
@@ -63,9 +65,9 @@ public:
QtPositioningHelper(LocationProviderQt *provider);
~QtPositioningHelper();
- void start(bool highAccuracy);
- void stop();
- void refresh();
+ Q_INVOKABLE void start(bool highAccuracy);
+ Q_INVOKABLE void stop();
+ Q_INVOKABLE void refresh();
private Q_SLOTS:
void updatePosition(const QGeoPositionInfo &);
@@ -75,6 +77,7 @@ private Q_SLOTS:
private:
LocationProviderQt *m_locationProvider;
QGeoPositionInfoSource *m_positionInfoSource;
+ base::WeakPtrFactory<LocationProviderQt> m_locationProviderFactory;
void postToLocationProvider(const base::Closure &task);
friend class LocationProviderQt;
@@ -83,14 +86,13 @@ private:
QtPositioningHelper::QtPositioningHelper(LocationProviderQt *provider)
: m_locationProvider(provider)
, m_positionInfoSource(0)
+ , m_locationProviderFactory(provider)
{
Q_ASSERT(provider);
}
QtPositioningHelper::~QtPositioningHelper()
{
- if (m_locationProvider)
- m_locationProvider->m_positioningHelper = 0;
}
static bool isHighAccuracySource(const QGeoPositionInfoSource *source)
@@ -186,7 +188,8 @@ void QtPositioningHelper::updatePosition(const QGeoPositionInfo &pos)
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));
+ if (m_locationProvider)
+ postToLocationProvider(base::Bind(&LocationProviderQt::updatePosition, m_locationProviderFactory.GetWeakPtr(), newPos));
}
void QtPositioningHelper::error(QGeoPositionInfoSource::Error positioningError)
@@ -203,7 +206,8 @@ void QtPositioningHelper::error(QGeoPositionInfoSource::Error positioningError)
newPos.error_code = content::Geoposition::ERROR_CODE_POSITION_UNAVAILABLE;
break;
}
- postToLocationProvider(base::Bind(&LocationProviderQt::updatePosition, base::Unretained(m_locationProvider), newPos));
+ if (m_locationProvider)
+ postToLocationProvider(base::Bind(&LocationProviderQt::updatePosition, m_locationProviderFactory.GetWeakPtr(), newPos));
}
void QtPositioningHelper::timeout()
@@ -213,7 +217,8 @@ void QtPositioningHelper::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));
+ if (m_locationProvider)
+ postToLocationProvider(base::Bind(&LocationProviderQt::updatePosition, m_locationProviderFactory.GetWeakPtr(), newPos));
}
inline void QtPositioningHelper::postToLocationProvider(const base::Closure &task)
@@ -230,6 +235,7 @@ LocationProviderQt::~LocationProviderQt()
{
if (m_positioningHelper) {
m_positioningHelper->m_locationProvider = 0;
+ m_positioningHelper->m_locationProviderFactory.InvalidateWeakPtrs();
m_positioningHelper->deleteLater();
}
}
@@ -241,23 +247,21 @@ bool LocationProviderQt::StartProvider(bool highAccuracy)
m_positioningHelper = new QtPositioningHelper(this);
m_positioningHelper->moveToThread(guiThread);
}
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(&QtPositioningHelper::start
- , base::Unretained(m_positioningHelper), highAccuracy));
+
+ QMetaObject::invokeMethod(m_positioningHelper, "start", Qt::QueuedConnection, Q_ARG(bool, highAccuracy));
return true;
}
void LocationProviderQt::StopProvider()
{
if (m_positioningHelper)
- BrowserThread::PostTask(BrowserThread::UI,FROM_HERE, base::Bind(&QtPositioningHelper::stop
- , base::Unretained(m_positioningHelper)));
+ QMetaObject::invokeMethod(m_positioningHelper, "stop", Qt::QueuedConnection);
}
void LocationProviderQt::RequestRefresh()
{
if (m_positioningHelper)
- BrowserThread::PostTask(BrowserThread::UI,FROM_HERE, base::Bind(&QtPositioningHelper::refresh
- , base::Unretained(m_positioningHelper)));
+ QMetaObject::invokeMethod(m_positioningHelper, "refresh", Qt::QueuedConnection);
}
void LocationProviderQt::OnPermissionGranted()
diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp
index 34782b8c2..d6f88f74f 100644
--- a/src/core/render_widget_host_view_qt.cpp
+++ b/src/core/render_widget_host_view_qt.cpp
@@ -830,12 +830,12 @@ void RenderWidgetHostViewQt::sendDelegatedFrameAck()
void RenderWidgetHostViewQt::processMotionEvent(const ui::MotionEvent &motionEvent)
{
- if (!m_gestureProvider.OnTouchEvent(motionEvent).succeeded)
+ auto result = m_gestureProvider.OnTouchEvent(motionEvent);
+ if (!result.succeeded)
return;
- bool causesScrollingIfUncancelled = true;
blink::WebTouchEvent touchEvent = ui::CreateWebTouchEventFromMotionEvent(motionEvent,
- causesScrollingIfUncancelled);
+ result.moved_beyond_slop_region);
m_host->ForwardTouchEventWithLatencyInfo(touchEvent, CreateLatencyInfo(touchEvent));
}
diff --git a/src/core/renderer/pepper/pepper_flash_clipboard_message_filter_qt.cpp b/src/core/renderer/pepper/pepper_flash_clipboard_message_filter_qt.cpp
new file mode 100644
index 000000000..3202548ae
--- /dev/null
+++ b/src/core/renderer/pepper/pepper_flash_clipboard_message_filter_qt.cpp
@@ -0,0 +1,401 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtWebEngine module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// based on chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.cc
+// 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 "pepper_flash_clipboard_message_filter_qt.h"
+
+#include "base/pickle.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/public/browser/browser_thread.h"
+#include "ipc/ipc_message.h"
+#include "ipc/ipc_message_macros.h"
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/c/private/ppb_flash_clipboard.h"
+#include "ppapi/host/dispatch_host_message.h"
+#include "ppapi/host/host_message_context.h"
+#include "ppapi/host/ppapi_host.h"
+#include "ppapi/proxy/ppapi_messages.h"
+#include "ppapi/proxy/resource_message_params.h"
+#include "ui/base/clipboard/scoped_clipboard_writer.h"
+
+using content::BrowserThread;
+
+namespace QtWebEngineCore {
+
+namespace {
+
+const size_t kMaxClipboardWriteSize = 1000000;
+
+ui::ClipboardType ConvertClipboardType(uint32_t type)
+{
+ switch (type) {
+ case PP_FLASH_CLIPBOARD_TYPE_STANDARD:
+ return ui::CLIPBOARD_TYPE_COPY_PASTE;
+ case PP_FLASH_CLIPBOARD_TYPE_SELECTION:
+ return ui::CLIPBOARD_TYPE_SELECTION;
+ }
+ NOTREACHED();
+ return ui::CLIPBOARD_TYPE_COPY_PASTE;
+}
+
+// Functions to pack/unpack custom data from a pickle. See the header file for
+// more detail on custom formats in Pepper.
+// TODO(raymes): Currently pepper custom formats are stored in their own
+// native format type. However we should be able to store them in the same way
+// as "Web Custom" formats are. This would allow clipboard data to be shared
+// between pepper applications and web applications. However currently web apps
+// assume all data that is placed on the clipboard is UTF16 and pepper allows
+// arbitrary data so this change would require some reworking of the chrome
+// clipboard interface for custom data.
+bool JumpToFormatInPickle(const base::string16& format, base::PickleIterator* iter)
+{
+ uint32_t size = 0;
+ if (!iter->ReadUInt32(&size))
+ return false;
+ for (uint32_t i = 0; i < size; ++i) {
+ base::string16 stored_format;
+ if (!iter->ReadString16(&stored_format))
+ return false;
+ if (stored_format == format)
+ return true;
+ int skip_length;
+ if (!iter->ReadLength(&skip_length))
+ return false;
+ if (!iter->SkipBytes(skip_length))
+ return false;
+ }
+ return false;
+}
+
+bool IsFormatAvailableInPickle(const base::string16& format, const base::Pickle& pickle)
+{
+ base::PickleIterator iter(pickle);
+ return JumpToFormatInPickle(format, &iter);
+}
+
+std::string ReadDataFromPickle(const base::string16& format, const base::Pickle& pickle)
+{
+ std::string result;
+ base::PickleIterator iter(pickle);
+ if (!JumpToFormatInPickle(format, &iter) || !iter.ReadString(&result))
+ return std::string();
+ return result;
+}
+
+bool WriteDataToPickle(const std::map<base::string16, std::string>& data, base::Pickle* pickle)
+{
+ pickle->WriteUInt32(data.size());
+ for (std::map<base::string16, std::string>::const_iterator it = data.begin(); it != data.end(); ++it) {
+ if (!pickle->WriteString16(it->first))
+ return false;
+ if (!pickle->WriteString(it->second))
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
+PepperFlashClipboardMessageFilter::PepperFlashClipboardMessageFilter() {}
+
+PepperFlashClipboardMessageFilter::~PepperFlashClipboardMessageFilter() {}
+
+scoped_refptr<base::TaskRunner>
+PepperFlashClipboardMessageFilter::OverrideTaskRunnerForMessage(const IPC::Message& msg)
+{
+ // Clipboard writes should always occur on the UI thread due to the
+ // restrictions of various platform APIs. In general, the clipboard is not
+ // thread-safe, so all clipboard calls should be serviced from the UI thread.
+ if (msg.type() == PpapiHostMsg_FlashClipboard_WriteData::ID)
+ return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
+
+ // Windows needs clipboard reads to be serviced from the IO thread because
+ // these are sync IPCs which can result in deadlocks with plugins if serviced
+ // from the UI thread. Note that Windows clipboard calls ARE thread-safe so it
+ // is ok for reads and writes to be serviced from different threads.
+#if !defined(OS_WIN)
+ return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
+#else
+ return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
+#endif
+}
+
+int32_t PepperFlashClipboardMessageFilter::OnResourceMessageReceived(const IPC::Message& msg,
+ ppapi::host::HostMessageContext* context)
+{
+ PPAPI_BEGIN_MESSAGE_MAP(PepperFlashClipboardMessageFilter, msg)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashClipboard_RegisterCustomFormat,
+ OnMsgRegisterCustomFormat)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashClipboard_IsFormatAvailable,
+ OnMsgIsFormatAvailable)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashClipboard_ReadData,
+ OnMsgReadData)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashClipboard_WriteData,
+ OnMsgWriteData)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashClipboard_GetSequenceNumber,
+ OnMsgGetSequenceNumber)
+ PPAPI_END_MESSAGE_MAP()
+ return PP_ERROR_FAILED;
+}
+
+int32_t PepperFlashClipboardMessageFilter::OnMsgRegisterCustomFormat(
+ ppapi::host::HostMessageContext* host_context,
+ const std::string& format_name)
+{
+ uint32_t format = m_custom_formats.RegisterFormat(format_name);
+ if (format == PP_FLASH_CLIPBOARD_FORMAT_INVALID)
+ return PP_ERROR_FAILED;
+ host_context->reply_msg = PpapiPluginMsg_FlashClipboard_RegisterCustomFormatReply(format);
+ return PP_OK;
+}
+
+int32_t PepperFlashClipboardMessageFilter::OnMsgIsFormatAvailable(
+ ppapi::host::HostMessageContext* host_context,
+ uint32_t clipboard_type,
+ uint32_t format)
+{
+ if (clipboard_type != PP_FLASH_CLIPBOARD_TYPE_STANDARD) {
+ NOTIMPLEMENTED();
+ return PP_ERROR_FAILED;
+ }
+
+ ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
+ ui::ClipboardType type = ConvertClipboardType(clipboard_type);
+ bool available = false;
+ switch (format) {
+ case PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT: {
+ bool plain = clipboard->IsFormatAvailable(ui::Clipboard::GetPlainTextFormatType(), type);
+ bool plainw = clipboard->IsFormatAvailable(ui::Clipboard::GetPlainTextWFormatType(), type);
+ available = plain || plainw;
+ break;
+ }
+ case PP_FLASH_CLIPBOARD_FORMAT_HTML:
+ available = clipboard->IsFormatAvailable(ui::Clipboard::GetHtmlFormatType(), type);
+ break;
+ case PP_FLASH_CLIPBOARD_FORMAT_RTF:
+ available = clipboard->IsFormatAvailable(ui::Clipboard::GetRtfFormatType(), type);
+ break;
+ case PP_FLASH_CLIPBOARD_FORMAT_INVALID:
+ break;
+ default:
+ if (m_custom_formats.IsFormatRegistered(format)) {
+ std::string format_name = m_custom_formats.GetFormatName(format);
+ std::string clipboard_data;
+ clipboard->ReadData(ui::Clipboard::GetPepperCustomDataFormatType(), &clipboard_data);
+ base::Pickle pickle(clipboard_data.data(), clipboard_data.size());
+ available = IsFormatAvailableInPickle(base::UTF8ToUTF16(format_name), pickle);
+ }
+ break;
+ }
+
+ return available ? PP_OK : PP_ERROR_FAILED;
+}
+
+int32_t PepperFlashClipboardMessageFilter::OnMsgReadData(
+ ppapi::host::HostMessageContext* host_context,
+ uint32_t clipboard_type,
+ uint32_t format)
+{
+ if (clipboard_type != PP_FLASH_CLIPBOARD_TYPE_STANDARD) {
+ NOTIMPLEMENTED();
+ return PP_ERROR_FAILED;
+ }
+
+ ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
+ ui::ClipboardType type = ConvertClipboardType(clipboard_type);
+ std::string clipboard_string;
+ int32_t result = PP_ERROR_FAILED;
+ switch (format) {
+ case PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT: {
+ if (clipboard->IsFormatAvailable(ui::Clipboard::GetPlainTextWFormatType(), type)) {
+ base::string16 text;
+ clipboard->ReadText(type, &text);
+ if (!text.empty()) {
+ result = PP_OK;
+ clipboard_string = base::UTF16ToUTF8(text);
+ break;
+ }
+ }
+ // If the PlainTextW format isn't available or is empty, take the
+ // ASCII text format.
+ if (clipboard->IsFormatAvailable(ui::Clipboard::GetPlainTextFormatType(), type)) {
+ result = PP_OK;
+ clipboard->ReadAsciiText(type, &clipboard_string);
+ }
+ break;
+ }
+ case PP_FLASH_CLIPBOARD_FORMAT_HTML: {
+ if (!clipboard->IsFormatAvailable(ui::Clipboard::GetHtmlFormatType(), type)) {
+ break;
+ }
+
+ base::string16 html;
+ std::string url;
+ uint32_t fragment_start;
+ uint32_t fragment_end;
+ clipboard->ReadHTML(type, &html, &url, &fragment_start, &fragment_end);
+ result = PP_OK;
+ clipboard_string = base::UTF16ToUTF8(html.substr(fragment_start, fragment_end - fragment_start));
+ break;
+ }
+ case PP_FLASH_CLIPBOARD_FORMAT_RTF: {
+ if (!clipboard->IsFormatAvailable(ui::Clipboard::GetRtfFormatType(), type)) {
+ break;
+ }
+ result = PP_OK;
+ clipboard->ReadRTF(type, &clipboard_string);
+ break;
+ }
+ case PP_FLASH_CLIPBOARD_FORMAT_INVALID:
+ break;
+ default:
+ if (m_custom_formats.IsFormatRegistered(format)) {
+ base::string16 format_name =
+ base::UTF8ToUTF16(m_custom_formats.GetFormatName(format));
+ std::string clipboard_data;
+ clipboard->ReadData(ui::Clipboard::GetPepperCustomDataFormatType(),
+ &clipboard_data);
+ base::Pickle pickle(clipboard_data.data(), clipboard_data.size());
+ if (IsFormatAvailableInPickle(format_name, pickle)) {
+ result = PP_OK;
+ clipboard_string = ReadDataFromPickle(format_name, pickle);
+ }
+ }
+ break;
+ }
+
+ if (result == PP_OK) {
+ host_context->reply_msg = PpapiPluginMsg_FlashClipboard_ReadDataReply(clipboard_string);
+ }
+ return result;
+}
+
+int32_t PepperFlashClipboardMessageFilter::OnMsgWriteData(
+ ppapi::host::HostMessageContext* host_context,
+ uint32_t clipboard_type,
+ const std::vector<uint32_t>& formats,
+ const std::vector<std::string>& data)
+{
+ if (clipboard_type != PP_FLASH_CLIPBOARD_TYPE_STANDARD) {
+ NOTIMPLEMENTED();
+ return PP_ERROR_FAILED;
+ }
+ if (formats.size() != data.size())
+ return PP_ERROR_FAILED;
+
+ ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
+ ui::ClipboardType type = ConvertClipboardType(clipboard_type);
+ // If no formats are passed in clear the clipboard.
+ if (formats.size() == 0) {
+ clipboard->Clear(type);
+ return PP_OK;
+ }
+
+ ui::ScopedClipboardWriter scw(type);
+ std::map<base::string16, std::string> custom_data_map;
+ int32_t res = PP_OK;
+ for (uint32_t i = 0; i < formats.size(); ++i) {
+ if (data[i].length() > kMaxClipboardWriteSize) {
+ res = PP_ERROR_NOSPACE;
+ break;
+ }
+
+ switch (formats[i]) {
+ case PP_FLASH_CLIPBOARD_FORMAT_PLAINTEXT:
+ scw.WriteText(base::UTF8ToUTF16(data[i]));
+ break;
+ case PP_FLASH_CLIPBOARD_FORMAT_HTML:
+ scw.WriteHTML(base::UTF8ToUTF16(data[i]), std::string());
+ break;
+ case PP_FLASH_CLIPBOARD_FORMAT_RTF:
+ scw.WriteRTF(data[i]);
+ break;
+ case PP_FLASH_CLIPBOARD_FORMAT_INVALID:
+ res = PP_ERROR_BADARGUMENT;
+ break;
+ default:
+ if (m_custom_formats.IsFormatRegistered(formats[i])) {
+ std::string format_name = m_custom_formats.GetFormatName(formats[i]);
+ custom_data_map[base::UTF8ToUTF16(format_name)] = data[i];
+ } else {
+ // Invalid format.
+ res = PP_ERROR_BADARGUMENT;
+ break;
+ }
+ }
+
+ if (res != PP_OK)
+ break;
+ }
+
+ if (custom_data_map.size() > 0) {
+ base::Pickle pickle;
+ if (WriteDataToPickle(custom_data_map, &pickle)) {
+ scw.WritePickledData(pickle, ui::Clipboard::GetPepperCustomDataFormatType());
+ } else {
+ res = PP_ERROR_BADARGUMENT;
+ }
+ }
+
+ if (res != PP_OK) {
+ // Need to clear the objects so nothing is written.
+ scw.Reset();
+ }
+
+ return res;
+}
+
+int32_t PepperFlashClipboardMessageFilter::OnMsgGetSequenceNumber(
+ ppapi::host::HostMessageContext* host_context,
+ uint32_t clipboard_type)
+{
+ if (clipboard_type != PP_FLASH_CLIPBOARD_TYPE_STANDARD) {
+ NOTIMPLEMENTED();
+ return PP_ERROR_FAILED;
+ }
+
+ ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
+ ui::ClipboardType type = ConvertClipboardType(clipboard_type);
+ int64_t sequence_number = clipboard->GetSequenceNumber(type);
+ host_context->reply_msg = PpapiPluginMsg_FlashClipboard_GetSequenceNumberReply(sequence_number);
+ return PP_OK;
+}
+
+} // namespace QtWebEngineCore
diff --git a/src/core/renderer/pepper/pepper_flash_clipboard_message_filter_qt.h b/src/core/renderer/pepper/pepper_flash_clipboard_message_filter_qt.h
new file mode 100644
index 000000000..c00e668ea
--- /dev/null
+++ b/src/core/renderer/pepper/pepper_flash_clipboard_message_filter_qt.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtWebEngine module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// based on chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.h
+// 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.
+
+#ifndef PEPPER_FLASH_CLIPBOARD_MESSAGE_FILTER_QT_H
+#define PEPPER_FLASH_CLIPBOARD_MESSAGE_FILTER_QT_H
+
+#include <string>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "ppapi/host/resource_message_filter.h"
+#include "ppapi/shared_impl/flash_clipboard_format_registry.h"
+
+namespace ppapi {
+namespace host {
+struct HostMessageContext;
+}
+}
+
+namespace ui {
+class ScopedClipboardWriter;
+}
+
+namespace QtWebEngineCore {
+
+// Resource message filter for accessing the clipboard in Pepper. Pepper
+// supports reading/writing custom formats from the clipboard. Currently, all
+// custom formats that are read/written from the clipboard through pepper are
+// stored in a single real clipboard format (in the same way the "web custom"
+// clipboard formats are). This is done so that we don't have to have use real
+// clipboard types for each custom clipboard format which may be a limited
+// resource on a particular platform.
+class PepperFlashClipboardMessageFilter : public ppapi::host::ResourceMessageFilter {
+public:
+ PepperFlashClipboardMessageFilter();
+
+protected:
+ // ppapi::host::ResourceMessageFilter overrides.
+ scoped_refptr<base::TaskRunner> OverrideTaskRunnerForMessage(const IPC::Message& msg) override;
+ int32_t OnResourceMessageReceived(const IPC::Message& msg, ppapi::host::HostMessageContext* context) override;
+
+private:
+ ~PepperFlashClipboardMessageFilter() override;
+
+ int32_t OnMsgRegisterCustomFormat(ppapi::host::HostMessageContext* host_context, const std::string& format_name);
+ int32_t OnMsgIsFormatAvailable(ppapi::host::HostMessageContext* host_context,
+ uint32_t clipboard_type,
+ uint32_t format);
+ int32_t OnMsgReadData(ppapi::host::HostMessageContext* host_context,
+ uint32_t clipoard_type,
+ uint32_t format);
+ int32_t OnMsgWriteData(ppapi::host::HostMessageContext* host_context,
+ uint32_t clipboard_type,
+ const std::vector<uint32_t>& formats,
+ const std::vector<std::string>& data);
+ int32_t OnMsgGetSequenceNumber(ppapi::host::HostMessageContext* host_context,
+ uint32_t clipboard_type);
+
+ int32_t WriteClipboardDataItem(uint32_t format,
+ const std::string& data,
+ ui::ScopedClipboardWriter* scw);
+
+ ppapi::FlashClipboardFormatRegistry m_custom_formats;
+
+ DISALLOW_COPY_AND_ASSIGN(PepperFlashClipboardMessageFilter);
+};
+
+} // namespace QtWebEngineCore
+
+#endif // PEPPER_FLASH_CLIPBOARD_MESSAGE_FILTER_QT_H
diff --git a/src/core/renderer/pepper/pepper_host_factory_qt.cpp b/src/core/renderer/pepper/pepper_host_factory_qt.cpp
index a0bab1e51..9aece100c 100644
--- a/src/core/renderer/pepper/pepper_host_factory_qt.cpp
+++ b/src/core/renderer/pepper/pepper_host_factory_qt.cpp
@@ -54,10 +54,10 @@
#include "ppapi/shared_impl/ppapi_permissions.h"
#include "pepper_flash_browser_host_qt.h"
+#include "pepper_flash_clipboard_message_filter_qt.h"
#include "pepper_isolated_file_system_message_filter.h"
using ppapi::host::MessageFilterHost;
-using ppapi::host::ResourceHost;
using ppapi::host::ResourceMessageFilter;
namespace QtWebEngineCore {
@@ -80,10 +80,18 @@ std::unique_ptr<ppapi::host::ResourceHost> PepperHostFactoryQt::CreateResourceHo
if (!host_->IsValidInstance(instance))
return nullptr;
- if (host_->GetPpapiHost()->permissions().HasPermission(ppapi::PERMISSION_FLASH)
- && message.type() == PpapiHostMsg_Flash_Create::ID)
- return base::WrapUnique(
- new PepperFlashBrowserHostQt(host_, instance, resource));
+ // Flash interfaces.
+ if (host_->GetPpapiHost()->permissions().HasPermission(ppapi::PERMISSION_FLASH)) {
+ switch (message.type()) {
+ case PpapiHostMsg_Flash_Create::ID:
+ return base::WrapUnique(new PepperFlashBrowserHostQt(host_, instance, resource));
+ case PpapiHostMsg_FlashClipboard_Create::ID: {
+ scoped_refptr<ResourceMessageFilter> clipboard_filter(new PepperFlashClipboardMessageFilter);
+ return base::WrapUnique(new MessageFilterHost(
+ host_->GetPpapiHost(), instance, resource, clipboard_filter));
+ }
+ }
+ }
// Permissions for the following interfaces will be checked at the
// time of the corresponding instance's methods calls (because
diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp
index 134b5b63c..15125b9d8 100644
--- a/src/core/web_contents_adapter.cpp
+++ b/src/core/web_contents_adapter.cpp
@@ -70,6 +70,7 @@
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/favicon_status.h"
+#include "content/public/common/content_constants.h"
#include <content/public/common/drop_data.h>
#include "content/public/common/page_state.h"
#include "content/public/common/page_zoom.h"
@@ -517,7 +518,12 @@ void WebContentsAdapter::setContent(const QByteArray &data, const QString &mimeT
urlString.append(",");
urlString.append(encodedData.constData(), encodedData.length());
- content::NavigationController::LoadURLParams params((GURL(urlString)));
+ GURL dataUrlToLoad(urlString);
+ if (dataUrlToLoad.spec().size() > url::kMaxURLChars) {
+ d->adapterClient->loadFinished(false, baseUrl, false, net::ERR_ABORTED);
+ return;
+ }
+ content::NavigationController::LoadURLParams params((dataUrlToLoad));
params.load_type = content::NavigationController::LOAD_TYPE_DATA;
params.base_url_for_data_url = toGurl(baseUrl);
params.virtual_url_for_data_url = baseUrl.isEmpty() ? GURL(url::kAboutBlankURL) : toGurl(baseUrl);
@@ -1114,10 +1120,7 @@ static blink::WebDragOperationsMask toWeb(const Qt::DropActions action)
static void fillDropDataFromMimeData(content::DropData *dropData, const QMimeData *mimeData)
{
- if (mimeData->hasText())
- dropData->text = toNullableString16(mimeData->text());
- if (mimeData->hasHtml())
- dropData->html = toNullableString16(mimeData->html());
+ Q_ASSERT(dropData->filenames.empty());
Q_FOREACH (const QUrl &url, mimeData->urls()) {
if (url.isLocalFile()) {
ui::FileInfo uifi;
@@ -1125,6 +1128,12 @@ static void fillDropDataFromMimeData(content::DropData *dropData, const QMimeDat
dropData->filenames.push_back(uifi);
}
}
+ if (!dropData->filenames.empty())
+ return;
+ if (mimeData->hasHtml())
+ dropData->html = toNullableString16(mimeData->html());
+ else if (mimeData->hasText())
+ dropData->text = toNullableString16(mimeData->text());
}
void WebContentsAdapter::enterDrag(QDragEnterEvent *e, const QPoint &screenPos)
diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h
index 80aabaa4d..c50f38b38 100644
--- a/src/core/web_contents_adapter_client.h
+++ b/src/core/web_contents_adapter_client.h
@@ -257,6 +257,7 @@ public:
virtual void updateContentsSize(const QSizeF &size) = 0;
virtual void startDragging(const content::DropData &dropData, Qt::DropActions allowedActions,
const QPixmap &pixmap, const QPoint &offset) = 0;
+ virtual bool isEnabled() const = 0;
virtual QSharedPointer<BrowserContextAdapter> browserContextAdapter() = 0;
virtual WebContentsAdapter* webContentsAdapter() = 0;
diff --git a/src/core/web_contents_view_qt.cpp b/src/core/web_contents_view_qt.cpp
index 1d39d8af8..e487fca46 100644
--- a/src/core/web_contents_view_qt.cpp
+++ b/src/core/web_contents_view_qt.cpp
@@ -120,6 +120,8 @@ void WebContentsViewQt::GetContainerBounds(gfx::Rect* out) const
void WebContentsViewQt::Focus()
{
+ if (!m_client->isEnabled())
+ return;
if (content::RenderWidgetHostView *rwhv = m_webContents->GetRenderWidgetHostView())
rwhv->Focus();
m_client->focusContainer();