summaryrefslogtreecommitdiff
path: root/Source/WebKit2/UIProcess/UserContent/WebUserContentControllerProxy.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebKit2/UIProcess/UserContent/WebUserContentControllerProxy.cpp')
-rw-r--r--Source/WebKit2/UIProcess/UserContent/WebUserContentControllerProxy.cpp368
1 files changed, 368 insertions, 0 deletions
diff --git a/Source/WebKit2/UIProcess/UserContent/WebUserContentControllerProxy.cpp b/Source/WebKit2/UIProcess/UserContent/WebUserContentControllerProxy.cpp
new file mode 100644
index 000000000..b02622437
--- /dev/null
+++ b/Source/WebKit2/UIProcess/UserContent/WebUserContentControllerProxy.cpp
@@ -0,0 +1,368 @@
+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WebUserContentControllerProxy.h"
+
+#include "APIArray.h"
+#include "APIUserContentWorld.h"
+#include "APIUserScript.h"
+#include "APIUserStyleSheet.h"
+#include "DataReference.h"
+#include "WebProcessProxy.h"
+#include "WebScriptMessageHandler.h"
+#include "WebUserContentControllerDataTypes.h"
+#include "WebUserContentControllerMessages.h"
+#include "WebUserContentControllerProxyMessages.h"
+#include <WebCore/SerializedScriptValue.h>
+
+#if ENABLE(CONTENT_EXTENSIONS)
+#include "APIUserContentExtension.h"
+#include "WebCompiledContentExtension.h"
+#endif
+
+namespace WebKit {
+
+static uint64_t generateIdentifier()
+{
+ static uint64_t identifier;
+
+ return ++identifier;
+}
+
+WebUserContentControllerProxy::WebUserContentControllerProxy()
+ : m_identifier(generateIdentifier())
+ , m_userScripts(API::Array::create())
+ , m_userStyleSheets(API::Array::create())
+{
+}
+
+WebUserContentControllerProxy::~WebUserContentControllerProxy()
+{
+ for (WebProcessProxy* process : m_processes) {
+ process->removeMessageReceiver(Messages::WebUserContentControllerProxy::messageReceiverName(), m_identifier);
+ process->didDestroyWebUserContentControllerProxy(*this);
+ }
+}
+
+void WebUserContentControllerProxy::addProcess(WebProcessProxy& webProcessProxy)
+{
+ ASSERT(webProcessProxy.state() == WebProcessProxy::State::Running);
+
+ if (!m_processes.add(&webProcessProxy).isNewEntry)
+ return;
+
+ webProcessProxy.addMessageReceiver(Messages::WebUserContentControllerProxy::messageReceiverName(), m_identifier, *this);
+
+ Vector<std::pair<uint64_t, String>> userContentWorlds;
+ for (const auto& world : m_userContentWorlds)
+ userContentWorlds.append(std::make_pair(world.key->identifier(), world.key->name()));
+ webProcessProxy.connection()->send(Messages::WebUserContentController::AddUserContentWorlds(userContentWorlds), m_identifier);
+
+ Vector<WebUserScriptData> userScripts;
+ for (const auto& userScript : m_userScripts->elementsOfType<API::UserScript>())
+ userScripts.append({ userScript->identifier(), userScript->userContentWorld().identifier(), userScript->userScript() });
+ webProcessProxy.connection()->send(Messages::WebUserContentController::AddUserScripts(userScripts), m_identifier);
+
+ Vector<WebUserStyleSheetData> userStyleSheets;
+ for (const auto& userStyleSheet : m_userStyleSheets->elementsOfType<API::UserStyleSheet>())
+ userStyleSheets.append({ userStyleSheet->identifier(), userStyleSheet->userContentWorld().identifier(), userStyleSheet->userStyleSheet() });
+ webProcessProxy.connection()->send(Messages::WebUserContentController::AddUserStyleSheets(userStyleSheets), m_identifier);
+
+ Vector<WebScriptMessageHandlerData> messageHandlers;
+ for (auto& handler : m_scriptMessageHandlers.values())
+ messageHandlers.append({ handler->identifier(), handler->userContentWorld().identifier(), handler->name() });
+ webProcessProxy.connection()->send(Messages::WebUserContentController::AddUserScriptMessageHandlers(messageHandlers), m_identifier);
+
+#if ENABLE(CONTENT_EXTENSIONS)
+ Vector<std::pair<String, WebCompiledContentExtensionData>> userContentExtensions;
+ for (const auto& userContentExtension : m_userContentExtensions.values())
+ userContentExtensions.append(std::make_pair(userContentExtension->name(), userContentExtension->compiledExtension().data()));
+ webProcessProxy.connection()->send(Messages::WebUserContentController::AddUserContentExtensions(userContentExtensions), m_identifier);
+#endif
+}
+
+void WebUserContentControllerProxy::removeProcess(WebProcessProxy& webProcessProxy)
+{
+ ASSERT(m_processes.contains(&webProcessProxy));
+
+ m_processes.remove(&webProcessProxy);
+ webProcessProxy.removeMessageReceiver(Messages::WebUserContentControllerProxy::messageReceiverName(), m_identifier);
+}
+
+void WebUserContentControllerProxy::addUserContentWorldUse(API::UserContentWorld& world)
+{
+ if (&world == &API::UserContentWorld::normalWorld())
+ return;
+
+ auto addResult = m_userContentWorlds.add(&world);
+ if (addResult.isNewEntry) {
+ for (WebProcessProxy* process : m_processes)
+ process->connection()->send(Messages::WebUserContentController::AddUserContentWorlds({ std::make_pair(world.identifier(), world.name()) }), m_identifier);
+ }
+}
+
+bool WebUserContentControllerProxy::shouldSendRemoveUserContentWorldsMessage(API::UserContentWorld& world, unsigned numberOfUsesToRemove)
+{
+ if (&world == &API::UserContentWorld::normalWorld())
+ return false;
+
+ auto it = m_userContentWorlds.find(&world);
+ for (unsigned i = 0; i < numberOfUsesToRemove; ++i) {
+ if (m_userContentWorlds.remove(it)) {
+ ASSERT(i == (numberOfUsesToRemove - 1));
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void WebUserContentControllerProxy::removeUserContentWorldUses(API::UserContentWorld& world, unsigned numberOfUsesToRemove)
+{
+ if (shouldSendRemoveUserContentWorldsMessage(world, numberOfUsesToRemove)) {
+ for (WebProcessProxy* process : m_processes)
+ process->connection()->send(Messages::WebUserContentController::RemoveUserContentWorlds({ world.identifier() }), m_identifier);
+ }
+}
+
+void WebUserContentControllerProxy::removeUserContentWorldUses(HashCountedSet<RefPtr<API::UserContentWorld>>& worlds)
+{
+ Vector<uint64_t> worldsToRemove;
+ for (auto& worldUsePair : worlds) {
+ if (shouldSendRemoveUserContentWorldsMessage(*worldUsePair.key.get(), worldUsePair.value))
+ worldsToRemove.append(worldUsePair.key->identifier());
+ }
+
+ for (WebProcessProxy* process : m_processes)
+ process->connection()->send(Messages::WebUserContentController::RemoveUserContentWorlds(worldsToRemove), m_identifier);
+}
+
+void WebUserContentControllerProxy::addUserScript(API::UserScript& userScript)
+{
+ Ref<API::UserContentWorld> world = userScript.userContentWorld();
+
+ addUserContentWorldUse(world.get());
+
+ m_userScripts->elements().append(&userScript);
+
+ for (WebProcessProxy* process : m_processes)
+ process->connection()->send(Messages::WebUserContentController::AddUserScripts({ { userScript.identifier(), world->identifier(), userScript.userScript() } }), m_identifier);
+}
+
+void WebUserContentControllerProxy::removeUserScript(API::UserScript& userScript)
+{
+ Ref<API::UserContentWorld> world = userScript.userContentWorld();
+
+ for (WebProcessProxy* process : m_processes)
+ process->connection()->send(Messages::WebUserContentController::RemoveUserScript(world->identifier(), userScript.identifier()), m_identifier);
+
+ m_userScripts->elements().removeAll(&userScript);
+
+ removeUserContentWorldUses(world.get(), 1);
+}
+
+void WebUserContentControllerProxy::removeAllUserScripts(API::UserContentWorld& world)
+{
+ for (WebProcessProxy* process : m_processes)
+ process->connection()->send(Messages::WebUserContentController::RemoveAllUserScripts({ world.identifier() }), m_identifier);
+
+ unsigned userScriptsRemoved = m_userScripts->removeAllOfTypeMatching<API::UserScript>([&](const auto& userScript) {
+ return &userScript->userContentWorld() == &world;
+ });
+
+ removeUserContentWorldUses(world, userScriptsRemoved);
+}
+
+void WebUserContentControllerProxy::removeAllUserScripts()
+{
+ HashCountedSet<RefPtr<API::UserContentWorld>> worlds;
+ for (const auto& userScript : m_userScripts->elementsOfType<API::UserScript>())
+ worlds.add(const_cast<API::UserContentWorld*>(&userScript->userContentWorld()));
+
+ Vector<uint64_t> worldIdentifiers;
+ worldIdentifiers.reserveInitialCapacity(worlds.size());
+ for (const auto& worldCountPair : worlds)
+ worldIdentifiers.uncheckedAppend(worldCountPair.key->identifier());
+
+ for (WebProcessProxy* process : m_processes)
+ process->connection()->send(Messages::WebUserContentController::RemoveAllUserScripts(worldIdentifiers), m_identifier);
+
+ m_userScripts->elements().clear();
+
+ removeUserContentWorldUses(worlds);
+}
+
+void WebUserContentControllerProxy::addUserStyleSheet(API::UserStyleSheet& userStyleSheet)
+{
+ Ref<API::UserContentWorld> world = userStyleSheet.userContentWorld();
+
+ addUserContentWorldUse(world.get());
+
+ m_userStyleSheets->elements().append(&userStyleSheet);
+
+ for (WebProcessProxy* process : m_processes)
+ process->connection()->send(Messages::WebUserContentController::AddUserStyleSheets({ { userStyleSheet.identifier(), world->identifier(), userStyleSheet.userStyleSheet() } }), m_identifier);
+}
+
+void WebUserContentControllerProxy::removeUserStyleSheet(API::UserStyleSheet& userStyleSheet)
+{
+ Ref<API::UserContentWorld> world = userStyleSheet.userContentWorld();
+
+ for (WebProcessProxy* process : m_processes)
+ process->connection()->send(Messages::WebUserContentController::RemoveUserStyleSheet(world->identifier(), userStyleSheet.identifier()), m_identifier);
+
+ m_userStyleSheets->elements().removeAll(&userStyleSheet);
+
+ removeUserContentWorldUses(world.get(), 1);
+}
+
+void WebUserContentControllerProxy::removeAllUserStyleSheets(API::UserContentWorld& world)
+{
+ for (WebProcessProxy* process : m_processes)
+ process->connection()->send(Messages::WebUserContentController::RemoveAllUserStyleSheets({ world.identifier() }), m_identifier);
+
+ unsigned userStyleSheetsRemoved = m_userStyleSheets->removeAllOfTypeMatching<API::UserStyleSheet>([&](const auto& userStyleSheet) {
+ return &userStyleSheet->userContentWorld() == &world;
+ });
+
+ removeUserContentWorldUses(world, userStyleSheetsRemoved);
+}
+
+void WebUserContentControllerProxy::removeAllUserStyleSheets()
+{
+ HashCountedSet<RefPtr<API::UserContentWorld>> worlds;
+ for (const auto& userStyleSheet : m_userStyleSheets->elementsOfType<API::UserStyleSheet>())
+ worlds.add(const_cast<API::UserContentWorld*>(&userStyleSheet->userContentWorld()));
+
+ Vector<uint64_t> worldIdentifiers;
+ worldIdentifiers.reserveInitialCapacity(worlds.size());
+ for (const auto& worldCountPair : worlds)
+ worldIdentifiers.uncheckedAppend(worldCountPair.key->identifier());
+
+ for (WebProcessProxy* process : m_processes)
+ process->connection()->send(Messages::WebUserContentController::RemoveAllUserStyleSheets(worldIdentifiers), m_identifier);
+
+ m_userStyleSheets->elements().clear();
+
+ removeUserContentWorldUses(worlds);
+}
+
+bool WebUserContentControllerProxy::addUserScriptMessageHandler(WebScriptMessageHandler& handler)
+{
+ Ref<API::UserContentWorld> world = handler.userContentWorld();
+
+ for (auto& existingHandler : m_scriptMessageHandlers.values()) {
+ if (existingHandler->name() == handler.name() && &existingHandler->userContentWorld() == world.ptr())
+ return false;
+ }
+
+ addUserContentWorldUse(world.get());
+
+ m_scriptMessageHandlers.add(handler.identifier(), &handler);
+
+ for (WebProcessProxy* process : m_processes)
+ process->connection()->send(Messages::WebUserContentController::AddUserScriptMessageHandlers({ { handler.identifier(), world->identifier(), handler.name() } }), m_identifier);
+
+ return true;
+}
+
+void WebUserContentControllerProxy::removeUserMessageHandlerForName(const String& name, API::UserContentWorld& world)
+{
+ for (auto it = m_scriptMessageHandlers.begin(), end = m_scriptMessageHandlers.end(); it != end; ++it) {
+ if (it->value->name() == name && &it->value->userContentWorld() == &world) {
+ for (WebProcessProxy* process : m_processes)
+ process->connection()->send(Messages::WebUserContentController::RemoveUserScriptMessageHandler(world.identifier(), it->value->identifier()), m_identifier);
+
+ m_scriptMessageHandlers.remove(it);
+
+ removeUserContentWorldUses(world, 1);
+ return;
+ }
+ }
+}
+
+void WebUserContentControllerProxy::removeAllUserMessageHandlers(API::UserContentWorld& world)
+{
+ for (WebProcessProxy* process : m_processes)
+ process->connection()->send(Messages::WebUserContentController::RemoveAllUserScriptMessageHandlers({ world.identifier() }), m_identifier);
+
+ unsigned numberRemoved = 0;
+ m_scriptMessageHandlers.removeIf([&](auto& entry) {
+ if (&entry.value->userContentWorld() == &world) {
+ ++numberRemoved;
+ return true;
+ }
+ return false;
+ });
+
+ removeUserContentWorldUses(world, numberRemoved);
+}
+
+void WebUserContentControllerProxy::didPostMessage(IPC::Connection& connection, uint64_t pageID, const FrameInfoData& frameInfoData, uint64_t messageHandlerID, const IPC::DataReference& dataReference)
+{
+ WebPageProxy* page = WebProcessProxy::webPage(pageID);
+ if (!page)
+ return;
+
+ if (!HashMap<uint64_t, RefPtr<WebScriptMessageHandler>>::isValidKey(messageHandlerID))
+ return;
+
+ RefPtr<WebScriptMessageHandler> handler = m_scriptMessageHandlers.get(messageHandlerID);
+ if (!handler)
+ return;
+
+ handler->client().didPostMessage(*page, frameInfoData, WebCore::SerializedScriptValue::adopt(dataReference.vector()));
+}
+
+#if ENABLE(CONTENT_EXTENSIONS)
+void WebUserContentControllerProxy::addUserContentExtension(API::UserContentExtension& userContentExtension)
+{
+ m_userContentExtensions.set(userContentExtension.name(), &userContentExtension);
+
+ auto pair = std::make_pair(userContentExtension.name(), userContentExtension.compiledExtension().data());
+
+ for (WebProcessProxy* process : m_processes)
+ process->connection()->send(Messages::WebUserContentController::AddUserContentExtensions({ pair }), m_identifier);
+}
+
+void WebUserContentControllerProxy::removeUserContentExtension(const String& name)
+{
+ m_userContentExtensions.remove(name);
+
+ for (WebProcessProxy* process : m_processes)
+ process->connection()->send(Messages::WebUserContentController::RemoveUserContentExtension(name), m_identifier);
+}
+
+void WebUserContentControllerProxy::removeAllUserContentExtensions()
+{
+ m_userContentExtensions.clear();
+
+ for (WebProcessProxy* process : m_processes)
+ process->connection()->send(Messages::WebUserContentController::RemoveAllUserContentExtensions(), m_identifier);
+}
+#endif
+
+} // namespace WebKit