diff options
Diffstat (limited to 'src/core/renderer/user_resource_controller.cpp')
-rw-r--r-- | src/core/renderer/user_resource_controller.cpp | 325 |
1 files changed, 142 insertions, 183 deletions
diff --git a/src/core/renderer/user_resource_controller.cpp b/src/core/renderer/user_resource_controller.cpp index 3c1ad0477..eff304981 100644 --- a/src/core/renderer/user_resource_controller.cpp +++ b/src/core/renderer/user_resource_controller.cpp @@ -1,60 +1,20 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://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 https://www.qt.io/terms-conditions. For further -** information use the contact form at https://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.LGPL3 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-3.0.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 (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "user_resource_controller.h" #include "base/memory/weak_ptr.h" -#include "base/pending_task.h" #include "base/strings/pattern.h" +#include "base/task/single_thread_task_runner.h" #include "content/public/renderer/render_frame.h" -#include "content/public/renderer/render_view.h" #include "content/public/renderer/render_frame_observer.h" -#include "content/public/renderer/render_view_observer.h" #include "extensions/common/url_pattern.h" -#include "third_party/blink/public/web/web_document.h" #include "third_party/blink/public/web/web_local_frame.h" #include "third_party/blink/public/web/web_script_source.h" -#include "third_party/blink/public/web/web_view.h" -#include "v8/include/v8.h" +#include "mojo/public/cpp/bindings/associated_receiver.h" +#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h" -#include "common/qt_messages.h" -#include "common/user_script_data.h" +#include "qtwebengine/userscript/user_script_data.h" #include "type_conversion.h" #include "user_script.h" @@ -62,9 +22,9 @@ #include <bitset> -Q_GLOBAL_STATIC(UserResourceController, qt_webengine_userResourceController) +namespace QtWebEngineCore { -static content::RenderView *const globalScriptsIndex = nullptr; +static content::RenderFrame *const globalScriptsIndex = nullptr; // Scripts meant to run after the load event will be run 500ms after DOMContentLoaded if the load event doesn't come within that delay. static const int afterLoadTimeout = 500; @@ -97,7 +57,7 @@ static bool includeRuleMatchesURL(const std::string &pat, const GURL &url) return false; } -static bool scriptMatchesURL(const UserScriptData &scriptData, const GURL &url) +static bool scriptMatchesURL(const QtWebEngineCore::UserScriptData &scriptData, const GURL &url) { // Logic taken from Chromium (extensions/common/user_script.cc) bool matchFound; @@ -132,26 +92,34 @@ static bool scriptMatchesURL(const UserScriptData &scriptData, const GURL &url) return true; } -class UserResourceController::RenderFrameObserverHelper : public content::RenderFrameObserver +// using UserScriptDataPtr = mojo::StructPtr<qtwebengine::mojom::UserScriptData>; + +class UserResourceController::RenderFrameObserverHelper + : public content::RenderFrameObserver, + public qtwebengine::mojom::UserResourceControllerRenderFrame { public: - RenderFrameObserverHelper(content::RenderFrame *render_frame); + RenderFrameObserverHelper(content::RenderFrame *render_frame, + UserResourceController *controller); + void BindReceiver( + mojo::PendingAssociatedReceiver<qtwebengine::mojom::UserResourceControllerRenderFrame> + receiver); private: // RenderFrameObserver implementation. - void DidCommitProvisionalLoad(bool is_same_document_navigation, ui::PageTransition transition) override; - void DidFinishDocumentLoad() override; + void DidCommitProvisionalLoad(ui::PageTransition transition) override; + void DidDispatchDOMContentLoadedEvent() override; void DidFinishLoad() override; - void FrameDetached() override; + void WillDetach() override; void OnDestruct() override; - bool OnMessageReceived(const IPC::Message &message) override; - - void onUserScriptAdded(const UserScriptData &); - void onUserScriptRemoved(const UserScriptData &); - void onScriptsCleared(); + void AddScript(const QtWebEngineCore::UserScriptData &data) override; + void RemoveScript(const QtWebEngineCore::UserScriptData &data) override; + void ClearScripts() override; class Runner; QScopedPointer<Runner> m_runner; + mojo::AssociatedReceiver<qtwebengine::mojom::UserResourceControllerRenderFrame> m_binding; + UserResourceController *m_userResourceController; }; // Helper class to create WeakPtrs so the AfterLoad tasks can be canceled and to @@ -159,13 +127,16 @@ private: class UserResourceController::RenderFrameObserverHelper::Runner : public base::SupportsWeakPtr<Runner> { public: - explicit Runner(blink::WebLocalFrame *frame) : m_frame(frame) {} + explicit Runner(blink::WebLocalFrame *frame, UserResourceController *controller) + : m_frame(frame), m_userResourceController(controller) + { + } - void run(UserScriptData::InjectionPoint p) + void run(QtWebEngineCore::UserScriptData::InjectionPoint p) { DCHECK_LT(p, m_ran.size()); if (!m_ran[p]) { - UserResourceController::instance()->runScripts(p, m_frame); + m_userResourceController->runScripts(p, m_frame); m_ran[p] = true; } } @@ -173,42 +144,29 @@ public: private: blink::WebLocalFrame *m_frame; std::bitset<3> m_ran; + UserResourceController *m_userResourceController; }; -// Used only for script cleanup on RenderView destruction. -class UserResourceController::RenderViewObserverHelper : public content::RenderViewObserver -{ -public: - RenderViewObserverHelper(content::RenderView *render_view); - -private: - // RenderViewObserver implementation. - void OnDestruct() override; -}; - -void UserResourceController::runScripts(UserScriptData::InjectionPoint p, blink::WebLocalFrame *frame) +void UserResourceController::runScripts(QtWebEngineCore::UserScriptData::InjectionPoint p, + blink::WebLocalFrame *frame) { content::RenderFrame *renderFrame = content::RenderFrame::FromWebFrame(frame); if (!renderFrame) return; const bool isMainFrame = renderFrame->IsMainFrame(); - content::RenderView *renderView = renderFrame->GetRenderView(); - if (!renderView) - return; - - QList<uint64_t> scriptsToRun = m_viewUserScriptMap.value(0).values(); - scriptsToRun.append(m_viewUserScriptMap.value(renderView).values()); + QList<uint64_t> scriptsToRun = m_frameUserScriptMap.value(globalScriptsIndex); + scriptsToRun.append(m_frameUserScriptMap.value(renderFrame)); - for (uint64_t id : qAsConst(scriptsToRun)) { - const UserScriptData &script = m_scripts.value(id); + for (uint64_t id : std::as_const(scriptsToRun)) { + const QtWebEngineCore::UserScriptData &script = m_scripts.value(id); if (script.injectionPoint != p || (!script.injectForSubframes && !isMainFrame)) continue; if (!scriptMatchesURL(script, frame->GetDocument().Url())) continue; blink::WebScriptSource source(blink::WebString::FromUTF8(script.source), script.url); if (script.worldId) - frame->ExecuteScriptInIsolatedWorld(script.worldId, source); + frame->ExecuteScriptInIsolatedWorld(script.worldId, source, blink::BackForwardCacheAware::kAllow); // FIXME, check else frame->ExecuteScript(source); } @@ -216,119 +174,103 @@ void UserResourceController::runScripts(UserScriptData::InjectionPoint p, blink: void UserResourceController::RunScriptsAtDocumentEnd(content::RenderFrame *render_frame) { - runScripts(UserScriptData::DocumentLoadFinished, render_frame->GetWebFrame()); + runScripts(QtWebEngineCore::UserScriptData::DocumentLoadFinished, render_frame->GetWebFrame()); } -UserResourceController::RenderFrameObserverHelper::RenderFrameObserverHelper(content::RenderFrame *render_frame) +UserResourceController::RenderFrameObserverHelper::RenderFrameObserverHelper( + content::RenderFrame *render_frame, UserResourceController *controller) : content::RenderFrameObserver(render_frame) -{} + , m_binding(this) + , m_userResourceController(controller) +{ + render_frame->GetAssociatedInterfaceRegistry()->AddInterface<qtwebengine::mojom::UserResourceControllerRenderFrame>( + base::BindRepeating(&UserResourceController::RenderFrameObserverHelper::BindReceiver, + base::Unretained(this))); +} -UserResourceController::RenderViewObserverHelper::RenderViewObserverHelper(content::RenderView *render_view) - : content::RenderViewObserver(render_view) -{} -void UserResourceController::RenderFrameObserverHelper::DidCommitProvisionalLoad(bool is_same_document_navigation, - ui::PageTransition /*transitionbool*/) +void UserResourceController::RenderFrameObserverHelper::BindReceiver( + mojo::PendingAssociatedReceiver<qtwebengine::mojom::UserResourceControllerRenderFrame> + receiver) { - if (is_same_document_navigation) - return; + m_binding.Bind(std::move(receiver)); +} +void UserResourceController::RenderFrameObserverHelper::DidCommitProvisionalLoad(ui::PageTransition /*transition*/) +{ // We are almost ready to run scripts. We still have to wait until the host // process has been notified of the DidCommitProvisionalLoad event to ensure // that the WebChannelTransportHost is ready to receive messages. - m_runner.reset(new Runner(render_frame()->GetWebFrame())); + m_runner.reset(new Runner(render_frame()->GetWebFrame(), m_userResourceController)); - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&Runner::run, m_runner->AsWeakPtr(), UserScriptData::DocumentElementCreation)); + base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( + FROM_HERE, + base::BindOnce(&Runner::run, m_runner->AsWeakPtr(), + QtWebEngineCore::UserScriptData::DocumentElementCreation)); } -void UserResourceController::RenderFrameObserverHelper::DidFinishDocumentLoad() +void UserResourceController::RenderFrameObserverHelper::DidDispatchDOMContentLoadedEvent() { // Don't run scripts if provisional load failed (DidFailProvisionalLoad // called instead of DidCommitProvisionalLoad). if (m_runner) - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, base::BindOnce(&Runner::run, m_runner->AsWeakPtr(), UserScriptData::AfterLoad), - base::TimeDelta::FromMilliseconds(afterLoadTimeout)); + base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask( + FROM_HERE, + base::BindOnce(&Runner::run, m_runner->AsWeakPtr(), + QtWebEngineCore::UserScriptData::AfterLoad), + base::Milliseconds(afterLoadTimeout)); } void UserResourceController::RenderFrameObserverHelper::DidFinishLoad() { if (m_runner) - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(&Runner::run, m_runner->AsWeakPtr(), UserScriptData::AfterLoad)); + base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( + FROM_HERE, + base::BindOnce(&Runner::run, m_runner->AsWeakPtr(), + QtWebEngineCore::UserScriptData::AfterLoad)); } -void UserResourceController::RenderFrameObserverHelper::FrameDetached() +void UserResourceController::RenderFrameObserverHelper::WillDetach() { m_runner.reset(); } void UserResourceController::RenderFrameObserverHelper::OnDestruct() { + if (content::RenderFrame *frame = render_frame()) { + m_userResourceController->renderFrameDestroyed(frame); + } delete this; } -void UserResourceController::RenderViewObserverHelper::OnDestruct() -{ - // Remove all scripts associated with the render view. - if (content::RenderView *view = render_view()) - UserResourceController::instance()->renderViewDestroyed(view); - delete this; -} - -bool UserResourceController::RenderFrameObserverHelper::OnMessageReceived(const IPC::Message &message) -{ - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(UserResourceController::RenderFrameObserverHelper, message) - IPC_MESSAGE_HANDLER(RenderFrameObserverHelper_AddScript, onUserScriptAdded) - IPC_MESSAGE_HANDLER(RenderFrameObserverHelper_RemoveScript, onUserScriptRemoved) - IPC_MESSAGE_HANDLER(RenderFrameObserverHelper_ClearScripts, onScriptsCleared) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} - -void UserResourceController::RenderFrameObserverHelper::onUserScriptAdded(const UserScriptData &script) +void UserResourceController::RenderFrameObserverHelper::AddScript( + const QtWebEngineCore::UserScriptData &script) { if (content::RenderFrame *frame = render_frame()) - if (content::RenderView *view = frame->GetRenderView()) - UserResourceController::instance()->addScriptForView(script, view); + m_userResourceController->addScriptForFrame(script, frame); } -void UserResourceController::RenderFrameObserverHelper::onUserScriptRemoved(const UserScriptData &script) +void UserResourceController::RenderFrameObserverHelper::RemoveScript( + const QtWebEngineCore::UserScriptData &script) { if (content::RenderFrame *frame = render_frame()) - if (content::RenderView *view = frame->GetRenderView()) - UserResourceController::instance()->removeScriptForView(script, view); + m_userResourceController->removeScriptForFrame(script, frame); } -void UserResourceController::RenderFrameObserverHelper::onScriptsCleared() +void UserResourceController::RenderFrameObserverHelper::ClearScripts() { if (content::RenderFrame *frame = render_frame()) - if (content::RenderView *view = frame->GetRenderView()) - UserResourceController::instance()->clearScriptsForView(view); + m_userResourceController->clearScriptsForFrame(frame); } -UserResourceController *UserResourceController::instance() +void UserResourceController::BindReceiver( + mojo::PendingAssociatedReceiver<qtwebengine::mojom::UserResourceController> receiver) { - return qt_webengine_userResourceController(); + m_binding.Bind(std::move(receiver)); } -bool UserResourceController::OnControlMessageReceived(const IPC::Message &message) -{ - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(UserResourceController, message) - IPC_MESSAGE_HANDLER(UserResourceController_AddScript, onAddScript) - IPC_MESSAGE_HANDLER(UserResourceController_RemoveScript, onRemoveScript) - IPC_MESSAGE_HANDLER(UserResourceController_ClearScripts, onClearScripts) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} - -UserResourceController::UserResourceController() +UserResourceController::UserResourceController() : m_binding(this) { #if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS) static bool onlyCalledOnce = true; @@ -340,68 +282,85 @@ UserResourceController::UserResourceController() void UserResourceController::renderFrameCreated(content::RenderFrame *renderFrame) { // Will destroy itself when the RenderFrame is destroyed. - new RenderFrameObserverHelper(renderFrame); + new RenderFrameObserverHelper(renderFrame, this); } -void UserResourceController::renderViewCreated(content::RenderView *renderView) +void UserResourceController::renderFrameDestroyed(content::RenderFrame *renderFrame) { - // Will destroy itself when the RenderView is destroyed. - new RenderViewObserverHelper(renderView); + FrameUserScriptMap::iterator it = m_frameUserScriptMap.find(renderFrame); + if (it == m_frameUserScriptMap.end()) // ASSERT maybe? + return; + if (renderFrame->IsMainFrame()) { + for (uint64_t id : std::as_const(it.value())) + m_scripts.remove(id); + } + m_frameUserScriptMap.erase(it); } -void UserResourceController::renderViewDestroyed(content::RenderView *renderView) +void UserResourceController::addScriptForFrame(const QtWebEngineCore::UserScriptData &script, + content::RenderFrame *frame) { - ViewUserScriptMap::iterator it = m_viewUserScriptMap.find(renderView); - if (it == m_viewUserScriptMap.end()) // ASSERT maybe? - return; - for (uint64_t id : qAsConst(it.value())) { - m_scripts.remove(id); - } - m_viewUserScriptMap.remove(renderView); + FrameUserScriptMap::iterator it = m_frameUserScriptMap.find(frame); + if (it == m_frameUserScriptMap.end()) + it = m_frameUserScriptMap.insert(frame, UserScriptList()); + + if (!(*it).contains(script.scriptId)) + (*it).append(script.scriptId); + if (!frame || frame->IsMainFrame()) + m_scripts.insert(script.scriptId, script); } -void UserResourceController::addScriptForView(const UserScriptData &script, content::RenderView *view) +void UserResourceController::removeScriptForFrame(const QtWebEngineCore::UserScriptData &script, + content::RenderFrame *frame) { - ViewUserScriptMap::iterator it = m_viewUserScriptMap.find(view); - if (it == m_viewUserScriptMap.end()) - it = m_viewUserScriptMap.insert(view, UserScriptSet()); + FrameUserScriptMap::iterator it = m_frameUserScriptMap.find(frame); + if (it == m_frameUserScriptMap.end()) + return; - (*it).insert(script.scriptId); - m_scripts.insert(script.scriptId, script); + (*it).removeOne(script.scriptId); + if (!frame || frame->IsMainFrame()) + m_scripts.remove(script.scriptId); } -void UserResourceController::removeScriptForView(const UserScriptData &script, content::RenderView *view) +void UserResourceController::clearScriptsForFrame(content::RenderFrame *frame) { - ViewUserScriptMap::iterator it = m_viewUserScriptMap.find(view); - if (it == m_viewUserScriptMap.end()) + FrameUserScriptMap::iterator it = m_frameUserScriptMap.find(frame); + if (it == m_frameUserScriptMap.end()) return; + if (!frame || frame->IsMainFrame()) { + for (uint64_t id : std::as_const(it.value())) + m_scripts.remove(id); + } - (*it).remove(script.scriptId); - m_scripts.remove(script.scriptId); + m_frameUserScriptMap.remove(frame); } -void UserResourceController::clearScriptsForView(content::RenderView *view) +void UserResourceController::AddScript(const QtWebEngineCore::UserScriptData &script) { - ViewUserScriptMap::iterator it = m_viewUserScriptMap.find(view); - if (it == m_viewUserScriptMap.end()) - return; - for (uint64_t id : qAsConst(it.value())) - m_scripts.remove(id); + addScriptForFrame(script, globalScriptsIndex); +} - m_viewUserScriptMap.remove(view); +void UserResourceController::RemoveScript(const QtWebEngineCore::UserScriptData &script) +{ + removeScriptForFrame(script, globalScriptsIndex); } -void UserResourceController::onAddScript(const UserScriptData &script) +void UserResourceController::ClearScripts() { - addScriptForView(script, globalScriptsIndex); + clearScriptsForFrame(globalScriptsIndex); } -void UserResourceController::onRemoveScript(const UserScriptData &script) +void UserResourceController::RegisterMojoInterfaces( + blink::AssociatedInterfaceRegistry *associated_interfaces) { - removeScriptForView(script, globalScriptsIndex); + associated_interfaces->AddInterface<qtwebengine::mojom::UserResourceController>( + base::BindRepeating(&UserResourceController::BindReceiver, base::Unretained(this))); } -void UserResourceController::onClearScripts() +void UserResourceController::UnregisterMojoInterfaces( + blink::AssociatedInterfaceRegistry *associated_interfaces) { - clearScriptsForView(globalScriptsIndex); + associated_interfaces->RemoveInterface(qtwebengine::mojom::UserResourceController::Name_); } + +} // namespace |