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
));
37 manager
= new WebViewContentScriptManager(browser_context
);
38 browser_context
->SetUserData(webview::kWebViewContentScriptManagerKeyName
,
44 void WebViewContentScriptManager::AddContentScripts(
45 int embedder_process_id
,
46 content::RenderViewHost
* render_view_host
,
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
);
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
66 if (iter
== guest_content_script_map_
.end()) {
67 iter
= guest_content_script_map_
.insert(
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
);
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();
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())
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())
152 DeclarativeUserScriptMaster
* master
=
153 DeclarativeUserScriptManager::Get(browser_context_
)
154 ->GetDeclarativeUserScriptMasterByID(host_id
);
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());
175 for (const std::string
& name
: script_name_list
) {
176 ContentScriptMap::iterator iter
= map
.find(name
);
177 if (iter
== map
.end())
179 const UserScript
& script
= iter
->second
;
180 ids_to_delete
.insert(script
.id());
181 scripts_to_delete
.insert(script
);
186 // Step 2: makes WebViewContentScriptManager become an observer of the
187 // |loader| for scripts loaded event.
188 UserScriptLoader
* loader
= master
->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
) {
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())
216 const ContentScriptMap
& map
= iter
->second
;
217 for (const auto& pair
: map
)
218 ids
.insert(pair
.second
.id());
223 void WebViewContentScriptManager::SignalOnScriptsLoaded(
224 const base::Closure
& callback
) {
225 if (!user_script_loader_observer_
.IsObservingSources()) {
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())
246 for (auto& callback
: pending_scripts_loading_callbacks_
)
248 pending_scripts_loading_callbacks_
.clear();
251 } // namespace extensions