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

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

Powered by Google App Engine
This is Rietveld 408576698