Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1005)

Side by Side Diff: extensions/browser/guest_view/web_view/web_view_content_script_manager.cc

Issue 959413003: Implement <webview>.addContentScript/removeContentScript API [1] (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add WebContentObserver for embedder's webcontents. Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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.
4
5 #include "extensions/browser/guest_view/web_view/web_view_content_script_manager .h"
6
7 #include "base/lazy_instance.h"
8 #include "base/memory/linked_ptr.h"
9 #include "content/public/browser/browser_context.h"
10 #include "content/public/browser/browser_thread.h"
11 #include "content/public/browser/navigation_details.h"
12 #include "content/public/browser/render_process_host.h"
13 #include "content/public/browser/web_contents.h"
14 #include "content/public/browser/web_contents_observer.h"
15 #include "extensions/browser/declarative_user_script_manager.h"
16 #include "extensions/browser/declarative_user_script_master.h"
17 #include "extensions/browser/extension_system.h"
18 #include "extensions/browser/guest_view/guest_view_manager.h"
19 #include "extensions/browser/guest_view/web_view/web_view_constants.h"
20 #include "extensions/browser/guest_view/web_view/web_view_guest.h"
21 #include "extensions/browser/guest_view/web_view/web_view_renderer_state.h"
22
23 using content::BrowserThread;
24
25 namespace {
26 bool RemoveContentScriptsForGuest(content::BrowserContext* browser_context,
27 HostID host_id,
28 content::WebContents* embedder_web_contents,
29 content::WebContents* guest_web_contents) {
30 auto guest = extensions::WebViewGuest::FromWebContents(guest_web_contents);
31 if (!guest)
32 return false;
33
34 extensions::WebViewContentScriptManager* manager =
35 extensions::WebViewContentScriptManager::Get(browser_context);
36 if (!manager)
37 return false;
38
39 manager->RemoveContentScripts(embedder_web_contents,
40 guest->view_instance_id(), host_id,
41 std::vector<std::string>());
42 return true;
Fady Samuel 2015/04/10 16:16:04 I think you should return false here too to allow
Xi Han 2015/04/10 18:27:07 Done.
43 }
44 }
45
46 namespace extensions {
47
48 // This observer ensures that the content scripts added by the guest are removed
49 // when its embedder goes away.
50 class WebViewContentScriptManager::OwnerWebContentsObserver
51 : public content::WebContentsObserver {
52 public:
53 OwnerWebContentsObserver(content::WebContents* embedder_web_contents,
54 const HostID& host_id,
55 WebViewContentScriptManager* manager)
56 : WebContentsObserver(embedder_web_contents),
57 host_id_(host_id),
58 web_view_content_script_manager_(manager) {}
59 ~OwnerWebContentsObserver() override {}
60
61 // WebContentsObserver:
62 void WebContentsDestroyed() override {
63 // If the embedder is destroyed then remove all the content scripts of the
64 // guest.
65 RemoveContentScripts();
66 }
67 void DidNavigateMainFrame(
68 const content::LoadCommittedDetails& details,
69 const content::FrameNavigateParams& params) override {
70 // If the embedder navigates to a different page then destroy the guest.
71 if (details.is_navigation_to_different_page())
72 RemoveContentScripts();
73 }
74 void RenderProcessGone(base::TerminationStatus status) override {
75 // If the embedder crashes, then destroy the guest.
76 RemoveContentScripts();
77 }
78
79 private:
80 void RemoveContentScripts() {
81 web_view_content_script_manager_->RemoveContentScripts(web_contents(),
82 host_id_);
83 }
84
85 HostID host_id_;
86 WebViewContentScriptManager* web_view_content_script_manager_;
87
88 DISALLOW_COPY_AND_ASSIGN(OwnerWebContentsObserver);
89 };
90
91 WebViewContentScriptManager::WebViewContentScriptManager(
92 content::BrowserContext* browser_context)
93 : browser_context_(browser_context) {
94 }
95
96 WebViewContentScriptManager::~WebViewContentScriptManager() {
97 }
98
99 WebViewContentScriptManager* WebViewContentScriptManager::Get(
100 content::BrowserContext* browser_context) {
101 DCHECK_CURRENTLY_ON(BrowserThread::UI);
102 WebViewContentScriptManager* manager =
103 static_cast<WebViewContentScriptManager*>(browser_context->GetUserData(
104 webview::kWebViewContentScriptManagerKeyName));
105 if (!manager) {
106 manager = new WebViewContentScriptManager(browser_context);
107 browser_context->SetUserData(webview::kWebViewContentScriptManagerKeyName,
108 manager);
109 }
110 return manager;
111 }
112
113 void WebViewContentScriptManager::AddContentScripts(
114 content::WebContents* embedder_web_contents,
115 int view_instance_id,
116 const HostID& host_id,
117 const std::map<std::string, UserScript>& scripts) {
118 DCHECK_CURRENTLY_ON(BrowserThread::UI);
119 DCHECK(embedder_web_contents);
120
121 DeclarativeUserScriptMaster* master =
122 ExtensionSystem::Get(browser_context_)
123 ->declarative_user_script_manager()
124 ->GetDeclarativeUserScriptMasterByID(host_id);
125 DCHECK(master);
126
127 // We need to update WebViewRenderState in the IO thread if the guest exists.
128 std::set<int> ids_to_add;
129
130 int embedder_process_id =
131 embedder_web_contents->GetRenderProcessHost()->GetID();
132 GuestMapKey key = std::pair<int, int>(embedder_process_id, view_instance_id);
133 GuestContentScriptMap::iterator iter = guest_content_script_map_.find(key);
134
135 // Step 1: finds the entry in guest_content_script_map_ by the given |key|.
136 // If there isn't any content script added for the given guest yet, insert an
137 // empty map first.
138 if (iter == guest_content_script_map_.end()) {
139 iter = guest_content_script_map_.insert(
140 iter, std::pair<GuestMapKey, ContentScriptMap>(
141 key, std::map<std::string, UserScript>()));
142 }
143
144 // Step 2: updates the guest_content_script_map_, and adds content scripts to
145 // the master.
146 ContentScriptMap& map = iter->second;
147 for (const std::pair<std::string, UserScript>& pair : scripts) {
148 auto map_iter = map.find(pair.first);
149 // If a content script has the same name as the new one, removes the old
150 // script first, and insert the new one.
151 if (map_iter != map.end()) {
152 master->RemoveScript(map_iter->second);
Devlin 2015/04/10 16:04:32 What happens when a WebUI has two webviews, and ad
Fady Samuel 2015/04/10 16:16:04 This API doesn't allow two webviews to share a con
Xi Han 2015/04/10 18:27:07 We will create two different user scripts for them
153 map.erase(map_iter);
154 }
155 map.insert(pair);
156 ids_to_add.insert(pair.second.id());
157 master->AddScript(pair.second);
158 }
159
160 // Step 3: creates owner web contents observer for the given
161 // |embedder_web_contents| if it doesn't exist.
162 auto observers_map_iter =
163 owner_web_contents_observer_map_.find(embedder_web_contents);
164 if (observers_map_iter == owner_web_contents_observer_map_.end()) {
165 linked_ptr<OwnerWebContentsObserver> observer(
166 new OwnerWebContentsObserver(embedder_web_contents, host_id, this));
167 owner_web_contents_observer_map_[embedder_web_contents] = observer;
168 }
169
170 // Step 4: updates WebViewRenderState in the IO thread.
171 if (!ids_to_add.empty()) {
172 content::BrowserThread::PostTask(
173 content::BrowserThread::IO, FROM_HERE,
174 base::Bind(&WebViewRendererState::AddContentScriptIDs,
175 base::Unretained(WebViewRendererState::GetInstance()),
176 embedder_process_id, view_instance_id, ids_to_add));
177 }
178 }
179
180 void WebViewContentScriptManager::RemoveContentScripts(
181 content::WebContents* embedder_web_contents,
182 int view_instance_id,
183 const HostID& host_id,
184 const std::vector<std::string>& script_name_list) {
185 DCHECK_CURRENTLY_ON(BrowserThread::UI);
186
187 int embedder_process_id =
188 embedder_web_contents->GetRenderProcessHost()->GetID();
189 GuestMapKey key = std::pair<int, int>(embedder_process_id, view_instance_id);
190 GuestContentScriptMap::iterator script_map_iter =
191 guest_content_script_map_.find(key);
192 if (script_map_iter == guest_content_script_map_.end())
193 return;
194
195 DeclarativeUserScriptMaster* master =
196 ExtensionSystem::Get(browser_context_)
197 ->declarative_user_script_manager()
198 ->GetDeclarativeUserScriptMasterByID(host_id);
199 CHECK(master);
200
201 // We need to update WebViewRenderState in the IO thread if the guest exists.
202 std::set<int> ids_to_delete;
203
204 std::vector<std::string> names_to_delete;
205
206 // Step 1: removed content scripts from |master| and updates
207 // |guest_content_script_map_|
208 std::map<std::string, UserScript>& map = script_map_iter->second;
209 // If the |script_name_list| is empty, all the content scripts added by the
210 // guest will be removed; otherwise, removes the scripts in the
211 // |script_name_list|.
212 if (script_name_list.empty()) {
213 for (const std::pair<std::string, UserScript>& iter : map)
214 names_to_delete.push_back(iter.first);
215 } else {
216 names_to_delete = script_name_list;
217 }
218
219 for (const std::string& name : names_to_delete) {
220 ContentScriptMap::iterator iter = map.find(name);
221 if (iter == map.end())
222 continue;
223 const UserScript& script = iter->second;
224 ids_to_delete.insert(script.id());
225 master->RemoveScript(script);
226 map.erase(iter);
227 }
228
229 // Step 2: Update WebViewRenderState in the IO thread.
230 if (!ids_to_delete.empty()) {
231 content::BrowserThread::PostTask(
232 content::BrowserThread::IO, FROM_HERE,
233 base::Bind(&WebViewRendererState::RemoveContentScriptIDs,
234 base::Unretained(WebViewRendererState::GetInstance()),
235 embedder_process_id, view_instance_id, ids_to_delete));
236 }
237 }
238
239 void WebViewContentScriptManager::RemoveContentScripts(
240 content::WebContents* embedder_web_contents,
241 const HostID& host_id) {
242 DCHECK_CURRENTLY_ON(BrowserThread::UI);
243
244 // Step 1: removes content scripts of all the guests embedded.
245 auto guest_view_manager =
246 GuestViewManager::FromBrowserContext(browser_context_);
247 guest_view_manager->ForEachGuest(
248 embedder_web_contents,
249 base::Bind(&RemoveContentScriptsForGuest, browser_context_, host_id,
250 embedder_web_contents));
251
252 // Step 2: removes the observer of the given |embedder_web_contents|.
253 owner_web_contents_observer_map_.erase(embedder_web_contents);
254 }
255
256 std::set<int> WebViewContentScriptManager::GetContentScriptIDSet(
257 int embedder_process_id,
258 int view_instance_id) {
259 std::set<int> ids;
260
261 GuestMapKey key = std::pair<int, int>(embedder_process_id, view_instance_id);
262 GuestContentScriptMap::const_iterator iter =
263 guest_content_script_map_.find(key);
264 if (iter == guest_content_script_map_.end())
265 return ids;
266 const ContentScriptMap& map = iter->second;
267 for (const auto& pair : map)
268 ids.insert(pair.second.id());
269
270 return ids;
271 }
272
273 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698