Allow only one bookmark to be added for multiple fast starring
[chromium-blink-merge.git] / extensions / browser / guest_view / web_view / web_view_content_script_manager.cc
blob8a5592bddb59bd7c1e18601f3532ad4cc2839f44
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "extensions/browser/guest_view/web_view/web_view_content_script_manager.h"
7 #include "content/public/browser/browser_context.h"
8 #include "content/public/browser/browser_thread.h"
9 #include "content/public/browser/navigation_details.h"
10 #include "content/public/browser/render_process_host.h"
11 #include "content/public/browser/render_view_host.h"
12 #include "extensions/browser/declarative_user_script_manager.h"
13 #include "extensions/browser/declarative_user_script_master.h"
14 #include "extensions/browser/extension_system.h"
15 #include "extensions/browser/guest_view/web_view/web_view_constants.h"
16 #include "extensions/browser/guest_view/web_view/web_view_renderer_state.h"
18 using content::BrowserThread;
20 namespace extensions {
22 WebViewContentScriptManager::WebViewContentScriptManager(
23 content::BrowserContext* browser_context)
24 : user_script_loader_observer_(this), browser_context_(browser_context) {
27 WebViewContentScriptManager::~WebViewContentScriptManager() {
30 WebViewContentScriptManager* WebViewContentScriptManager::Get(
31 content::BrowserContext* browser_context) {
32 DCHECK_CURRENTLY_ON(BrowserThread::UI);
33 WebViewContentScriptManager* manager =
34 static_cast<WebViewContentScriptManager*>(browser_context->GetUserData(
35 webview::kWebViewContentScriptManagerKeyName));
36 if (!manager) {
37 manager = new WebViewContentScriptManager(browser_context);
38 browser_context->SetUserData(webview::kWebViewContentScriptManagerKeyName,
39 manager);
41 return manager;
44 void WebViewContentScriptManager::AddContentScripts(
45 int embedder_process_id,
46 content::RenderViewHost* render_view_host,
47 int view_instance_id,
48 const HostID& host_id,
49 const std::set<UserScript>& scripts) {
50 DCHECK_CURRENTLY_ON(BrowserThread::UI);
52 DeclarativeUserScriptMaster* master =
53 DeclarativeUserScriptManager::Get(browser_context_)
54 ->GetDeclarativeUserScriptMasterByID(host_id);
55 DCHECK(master);
57 // We need to update WebViewRenderState in the IO thread if the guest exists.
58 std::set<int> ids_to_add;
60 GuestMapKey key = std::pair<int, int>(embedder_process_id, view_instance_id);
61 GuestContentScriptMap::iterator iter = guest_content_script_map_.find(key);
63 // Step 1: finds the entry in guest_content_script_map_ by the given |key|.
64 // If there isn't any content script added for the given guest yet, insert an
65 // empty map first.
66 if (iter == guest_content_script_map_.end()) {
67 iter = guest_content_script_map_.insert(
68 iter,
69 std::pair<GuestMapKey, ContentScriptMap>(key, ContentScriptMap()));
72 // Step 2: updates the guest_content_script_map_.
73 ContentScriptMap& map = iter->second;
74 std::set<UserScript> scripts_to_delete;
75 for (const UserScript& script : scripts) {
76 auto map_iter = map.find(script.name());
77 // If a content script has the same name as the new one, remove the old
78 // script first, and insert the new one.
79 if (map_iter != map.end()) {
80 scripts_to_delete.insert(map_iter->second);
81 map.erase(map_iter);
83 map.insert(std::pair<std::string, UserScript>(script.name(), script));
84 ids_to_add.insert(script.id());
87 if (!scripts_to_delete.empty()) {
88 master->RemoveScripts(scripts_to_delete);
91 // Step 3: makes WebViewContentScriptManager become an observer of the
92 // |loader| for scripts loaded event.
93 UserScriptLoader* loader = master->loader();
94 DCHECK(loader);
95 if (!user_script_loader_observer_.IsObserving(loader))
96 user_script_loader_observer_.Add(loader);
98 // Step 4: adds new scripts to the master.
99 master->AddScripts(scripts, embedder_process_id,
100 render_view_host->GetRoutingID());
102 // Step 5: creates an entry in |webview_host_id_map_| for the given
103 // |embedder_process_id| and |view_instance_id| if it doesn't exist.
104 auto host_it = webview_host_id_map_.find(key);
105 if (host_it == webview_host_id_map_.end())
106 webview_host_id_map_.insert(std::make_pair(key, host_id));
108 // Step 6: updates WebViewRenderState in the IO thread.
109 // It is safe to use base::Unretained(WebViewRendererState::GetInstance())
110 // since WebViewRendererState::GetInstance() always returns a Singleton of
111 // WebViewRendererState.
112 if (!ids_to_add.empty()) {
113 content::BrowserThread::PostTask(
114 content::BrowserThread::IO, FROM_HERE,
115 base::Bind(&WebViewRendererState::AddContentScriptIDs,
116 base::Unretained(WebViewRendererState::GetInstance()),
117 embedder_process_id, view_instance_id, ids_to_add));
121 void WebViewContentScriptManager::RemoveAllContentScriptsForWebView(
122 int embedder_process_id,
123 int view_instance_id) {
124 DCHECK_CURRENTLY_ON(BrowserThread::UI);
126 // Look up the host ID for the WebView.
127 GuestMapKey key = std::make_pair(embedder_process_id, view_instance_id);
128 auto host_it = webview_host_id_map_.find(key);
129 // If no entry exists, then this WebView has no content scripts.
130 if (host_it == webview_host_id_map_.end())
131 return;
133 // Remove all content scripts for the WebView.
134 RemoveContentScripts(embedder_process_id, view_instance_id, host_it->second,
135 std::vector<std::string>());
136 webview_host_id_map_.erase(host_it);
139 void WebViewContentScriptManager::RemoveContentScripts(
140 int embedder_process_id,
141 int view_instance_id,
142 const HostID& host_id,
143 const std::vector<std::string>& script_name_list) {
144 DCHECK_CURRENTLY_ON(BrowserThread::UI);
146 GuestMapKey key = std::pair<int, int>(embedder_process_id, view_instance_id);
147 GuestContentScriptMap::iterator script_map_iter =
148 guest_content_script_map_.find(key);
149 if (script_map_iter == guest_content_script_map_.end())
150 return;
152 DeclarativeUserScriptMaster* master =
153 DeclarativeUserScriptManager::Get(browser_context_)
154 ->GetDeclarativeUserScriptMasterByID(host_id);
155 CHECK(master);
157 // We need to update WebViewRenderState in the IO thread if the guest exists.
158 std::set<int> ids_to_delete;
159 std::set<UserScript> scripts_to_delete;
161 // Step 1: removes content scripts from |master| and updates
162 // |guest_content_script_map_|.
163 std::map<std::string, UserScript>& map = script_map_iter->second;
164 // If the |script_name_list| is empty, all the content scripts added by the
165 // guest will be removed; otherwise, removes the scripts in the
166 // |script_name_list|.
167 if (script_name_list.empty()) {
168 auto it = map.begin();
169 while (it != map.end()) {
170 scripts_to_delete.insert(it->second);
171 ids_to_delete.insert(it->second.id());
172 map.erase(it++);
174 } else {
175 for (const std::string& name : script_name_list) {
176 ContentScriptMap::iterator iter = map.find(name);
177 if (iter == map.end())
178 continue;
179 const UserScript& script = iter->second;
180 ids_to_delete.insert(script.id());
181 scripts_to_delete.insert(script);
182 map.erase(iter);
186 // Step 2: makes WebViewContentScriptManager become an observer of the
187 // |loader| for scripts loaded event.
188 UserScriptLoader* loader = master->loader();
189 DCHECK(loader);
190 if (!user_script_loader_observer_.IsObserving(loader))
191 user_script_loader_observer_.Add(loader);
193 // Step 3: removes content scripts from master.
194 master->RemoveScripts(scripts_to_delete);
196 // Step 4: updates WebViewRenderState in the IO thread.
197 if (!ids_to_delete.empty()) {
198 content::BrowserThread::PostTask(
199 content::BrowserThread::IO, FROM_HERE,
200 base::Bind(&WebViewRendererState::RemoveContentScriptIDs,
201 base::Unretained(WebViewRendererState::GetInstance()),
202 embedder_process_id, view_instance_id, ids_to_delete));
206 std::set<int> WebViewContentScriptManager::GetContentScriptIDSet(
207 int embedder_process_id,
208 int view_instance_id) {
209 std::set<int> ids;
211 GuestMapKey key = std::pair<int, int>(embedder_process_id, view_instance_id);
212 GuestContentScriptMap::const_iterator iter =
213 guest_content_script_map_.find(key);
214 if (iter == guest_content_script_map_.end())
215 return ids;
216 const ContentScriptMap& map = iter->second;
217 for (const auto& pair : map)
218 ids.insert(pair.second.id());
220 return ids;
223 void WebViewContentScriptManager::SignalOnScriptsLoaded(
224 const base::Closure& callback) {
225 if (!user_script_loader_observer_.IsObservingSources()) {
226 callback.Run();
227 return;
229 pending_scripts_loading_callbacks_.push_back(callback);
232 void WebViewContentScriptManager::OnScriptsLoaded(UserScriptLoader* loader) {
233 user_script_loader_observer_.Remove(loader);
234 RunCallbacksIfReady();
237 void WebViewContentScriptManager::OnUserScriptLoaderDestroyed(
238 UserScriptLoader* loader) {
239 user_script_loader_observer_.Remove(loader);
240 RunCallbacksIfReady();
243 void WebViewContentScriptManager::RunCallbacksIfReady() {
244 if (user_script_loader_observer_.IsObservingSources())
245 return;
246 for (auto& callback : pending_scripts_loading_callbacks_)
247 callback.Run();
248 pending_scripts_loading_callbacks_.clear();
251 } // namespace extensions