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

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: Delvin's comments. 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 extensions {
26
27 // This observer ensures that the content scripts added by the guest are removed
28 // when its embedder goes away.
29 // The OwnerWebContentsObserver object will be destroyed when the embedder web
30 // contents it observed is gone.
31 class WebViewContentScriptManager::OwnerWebContentsObserver
32 : public content::WebContentsObserver {
33 public:
34 OwnerWebContentsObserver(content::WebContents* embedder_web_contents,
35 const HostID& host_id,
36 WebViewContentScriptManager* manager)
37 : WebContentsObserver(embedder_web_contents),
38 host_id_(host_id),
39 web_view_content_script_manager_(manager) {}
40 ~OwnerWebContentsObserver() override {}
41
42 // WebContentsObserver:
43 void WebContentsDestroyed() override {
44 // If the embedder is destroyed then remove all the content scripts of the
45 // guest.
46 RemoveContentScripts();
47 }
48 void DidNavigateMainFrame(
49 const content::LoadCommittedDetails& details,
50 const content::FrameNavigateParams& params) override {
51 // If the embedder navigates to a different page then destroy the guest.
52 if (details.is_navigation_to_different_page())
53 RemoveContentScripts();
54 }
55 void RenderProcessGone(base::TerminationStatus status) override {
56 // If the embedder crashes, then destroy the guest.
57 RemoveContentScripts();
58 }
59
60 void add_view_instance_id(int view_instance_id) {
61 view_instance_ids_.push_back(view_instance_id);
62 }
63
64 private:
65 void RemoveContentScripts() {
66 DCHECK(web_view_content_script_manager_);
67
68 // Step 1: removes content scripts of all the guests embedded.
69 for (int view_instance_id : view_instance_ids_) {
70 web_view_content_script_manager_->RemoveContentScripts(
71 web_contents(), view_instance_id, host_id_,
72 std::vector<std::string>());
73 }
74 // Step 2: removes this observer.
75 // This object can be deleted after this line.
76 web_view_content_script_manager_->RemoveObserver(web_contents());
77 }
78
79 HostID host_id_;
80 std::vector<int> view_instance_ids_;
Devlin 2015/04/14 23:04:57 This should be a set.
Xi Han 2015/04/15 19:43:55 Done.
81 WebViewContentScriptManager* web_view_content_script_manager_;
82
83 DISALLOW_COPY_AND_ASSIGN(OwnerWebContentsObserver);
84 };
85
86 WebViewContentScriptManager::WebViewContentScriptManager(
87 content::BrowserContext* browser_context)
88 : browser_context_(browser_context) {
89 }
90
91 WebViewContentScriptManager::~WebViewContentScriptManager() {
92 }
93
94 WebViewContentScriptManager* WebViewContentScriptManager::Get(
95 content::BrowserContext* browser_context) {
96 DCHECK_CURRENTLY_ON(BrowserThread::UI);
97 WebViewContentScriptManager* manager =
98 static_cast<WebViewContentScriptManager*>(browser_context->GetUserData(
99 webview::kWebViewContentScriptManagerKeyName));
100 if (!manager) {
101 manager = new WebViewContentScriptManager(browser_context);
102 browser_context->SetUserData(webview::kWebViewContentScriptManagerKeyName,
103 manager);
104 }
105 return manager;
106 }
107
108 void WebViewContentScriptManager::AddContentScripts(
109 content::WebContents* embedder_web_contents,
110 int view_instance_id,
111 const HostID& host_id,
112 const std::set<UserScript>& scripts) {
113 DCHECK_CURRENTLY_ON(BrowserThread::UI);
114 DCHECK(embedder_web_contents);
115
116 DeclarativeUserScriptMaster* master =
117 ExtensionSystem::Get(browser_context_)
118 ->declarative_user_script_manager()
119 ->GetDeclarativeUserScriptMasterByID(host_id);
120 DCHECK(master);
121
122 // We need to update WebViewRenderState in the IO thread if the guest exists.
123 std::set<int> ids_to_add;
124
125 int embedder_process_id =
126 embedder_web_contents->GetRenderProcessHost()->GetID();
127 GuestMapKey key = std::pair<int, int>(embedder_process_id, view_instance_id);
128 GuestContentScriptMap::iterator iter = guest_content_script_map_.find(key);
129
130 // Step 1: finds the entry in guest_content_script_map_ by the given |key|.
131 // If there isn't any content script added for the given guest yet, insert an
132 // empty map first.
133 if (iter == guest_content_script_map_.end()) {
134 iter = guest_content_script_map_.insert(
135 iter,
136 std::pair<GuestMapKey, ContentScriptMap>(key, ContentScriptMap()));
137 }
138
139 // Step 2: updates the guest_content_script_map_.
140 ContentScriptMap& map = iter->second;
141 for (const UserScript& script : scripts) {
142 auto map_iter = map.find(script.name());
143 // If a content script has the same name as the new one, removes the old
Devlin 2015/04/14 23:04:57 s/removes/remove
Xi Han 2015/04/15 19:43:55 Done.
144 // script first, and insert the new one.
145 if (map_iter != map.end()) {
146 master->RemoveScript(map_iter->second);
147 map.erase(map_iter);
148 }
149 map.insert(std::pair<std::string, UserScript>(script.name(), script));
150 ids_to_add.insert(script.id());
151 }
152
153 // Step 3: adds new scripts to the master.
154 master->AddScripts(scripts);
155
156 // Step 4: creates owner web contents observer for the given
157 // |embedder_web_contents| if it doesn't exist.
158 if (owner_web_contents_observer_map_.find(embedder_web_contents) ==
159 owner_web_contents_observer_map_.end()) {
160 linked_ptr<OwnerWebContentsObserver> observer(
161 new OwnerWebContentsObserver(embedder_web_contents, host_id, this));
162 observer->add_view_instance_id(view_instance_id);
Devlin 2015/04/14 23:04:57 Your if guard on line 158 means each observer will
Xi Han 2015/04/15 19:43:55 Great catch, it is a bug. Fixed.
163 owner_web_contents_observer_map_[embedder_web_contents] = observer;
164 }
165
166 // Step 5: updates WebViewRenderState in the IO thread.
167 // It is safe to use base::Unretained(WebViewRendererState::GetInstance())
168 // since WebViewRendererState::GetInstance() always returns a Singleton of
169 // WebViewRendererState.
170 if (!ids_to_add.empty()) {
171 content::BrowserThread::PostTask(
172 content::BrowserThread::IO, FROM_HERE,
173 base::Bind(&WebViewRendererState::AddContentScriptIDs,
174 base::Unretained(WebViewRendererState::GetInstance()),
175 embedder_process_id, view_instance_id, ids_to_add));
176 }
177 }
178
179 void WebViewContentScriptManager::RemoveContentScripts(
180 content::WebContents* embedder_web_contents,
181 int view_instance_id,
182 const HostID& host_id,
183 const std::vector<std::string>& script_name_list) {
184 DCHECK_CURRENTLY_ON(BrowserThread::UI);
185
186 int embedder_process_id =
187 embedder_web_contents->GetRenderProcessHost()->GetID();
188 GuestMapKey key = std::pair<int, int>(embedder_process_id, view_instance_id);
189 GuestContentScriptMap::iterator script_map_iter =
190 guest_content_script_map_.find(key);
191 if (script_map_iter == guest_content_script_map_.end())
192 return;
193
194 DeclarativeUserScriptMaster* master =
195 ExtensionSystem::Get(browser_context_)
196 ->declarative_user_script_manager()
197 ->GetDeclarativeUserScriptMasterByID(host_id);
198 CHECK(master);
199
200 // We need to update WebViewRenderState in the IO thread if the guest exists.
201 std::set<int> ids_to_delete;
202
203 std::vector<std::string> names_to_delete;
204
205 // Step 1: removes content scripts from |master| and updates
206 // |guest_content_script_map_|
207 std::map<std::string, UserScript>& map = script_map_iter->second;
208 // If the |script_name_list| is empty, all the content scripts added by the
209 // guest will be removed; otherwise, removes the scripts in the
210 // |script_name_list|.
211 if (script_name_list.empty()) {
212 for (const std::pair<std::string, UserScript>& iter : map)
213 names_to_delete.push_back(iter.first);
214 } else {
215 names_to_delete = script_name_list;
216 }
217
218 std::set<UserScript> scripts_to_delete;
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 scripts_to_delete.insert(script);
226 map.erase(iter);
227 }
228
229 // Step 2: removes content scripts from master.
230 master->RemoveScripts(scripts_to_delete);
231
232 // Step 3: updates WebViewRenderState in the IO thread.
233 if (!ids_to_delete.empty()) {
234 content::BrowserThread::PostTask(
235 content::BrowserThread::IO, FROM_HERE,
236 base::Bind(&WebViewRendererState::RemoveContentScriptIDs,
237 base::Unretained(WebViewRendererState::GetInstance()),
238 embedder_process_id, view_instance_id, ids_to_delete));
239 }
240 }
241
242 void WebViewContentScriptManager::RemoveObserver(
243 content::WebContents* embedder_web_contents) {
244 owner_web_contents_observer_map_.erase(embedder_web_contents);
245 }
246
247 std::set<int> WebViewContentScriptManager::GetContentScriptIDSet(
248 int embedder_process_id,
249 int view_instance_id) {
250 std::set<int> ids;
251
252 GuestMapKey key = std::pair<int, int>(embedder_process_id, view_instance_id);
253 GuestContentScriptMap::const_iterator iter =
254 guest_content_script_map_.find(key);
255 if (iter == guest_content_script_map_.end())
256 return ids;
257 const ContentScriptMap& map = iter->second;
258 for (const auto& pair : map)
259 ids.insert(pair.second.id());
260
261 return ids;
262 }
263
264 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698