Revert of Refactor the avatar button/icon class (patchset #14 id:320001 of https...
[chromium-blink-merge.git] / components / guest_view / browser / guest_view_manager.cc
blob04cc220531bf8291e9ac0c789180fe93d7ac3d77
1 // Copyright 2014 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 "components/guest_view/browser/guest_view_manager.h"
7 #include "base/macros.h"
8 #include "base/strings/stringprintf.h"
9 #include "components/guest_view/browser/guest_view_base.h"
10 #include "components/guest_view/browser/guest_view_manager_delegate.h"
11 #include "components/guest_view/browser/guest_view_manager_factory.h"
12 #include "components/guest_view/common/guest_view_constants.h"
13 #include "content/public/browser/browser_context.h"
14 #include "content/public/browser/render_frame_host.h"
15 #include "content/public/browser/render_process_host.h"
16 #include "content/public/browser/render_view_host.h"
17 #include "content/public/browser/user_metrics.h"
18 #include "content/public/browser/web_contents_observer.h"
19 #include "content/public/common/child_process_host.h"
20 #include "content/public/common/result_codes.h"
21 #include "content/public/common/url_constants.h"
22 #include "url/gurl.h"
24 using content::BrowserContext;
25 using content::SiteInstance;
26 using content::WebContents;
28 namespace guest_view {
30 // static
31 GuestViewManagerFactory* GuestViewManager::factory_ = nullptr;
33 GuestViewManager::GuestViewManager(
34 content::BrowserContext* context,
35 scoped_ptr<GuestViewManagerDelegate> delegate)
36 : current_instance_id_(0),
37 last_instance_id_removed_(0),
38 context_(context),
39 delegate_(delegate.Pass()) {
42 GuestViewManager::~GuestViewManager() {}
44 // static
45 GuestViewManager* GuestViewManager::CreateWithDelegate(
46 BrowserContext* context,
47 scoped_ptr<GuestViewManagerDelegate> delegate) {
48 GuestViewManager* guest_manager = FromBrowserContext(context);
49 if (!guest_manager) {
50 if (factory_) {
51 guest_manager =
52 factory_->CreateGuestViewManager(context, delegate.Pass());
53 } else {
54 guest_manager = new GuestViewManager(context, delegate.Pass());
56 context->SetUserData(kGuestViewManagerKeyName, guest_manager);
58 return guest_manager;
61 // static
62 GuestViewManager* GuestViewManager::FromBrowserContext(
63 BrowserContext* context) {
64 return static_cast<GuestViewManager*>(context->GetUserData(
65 kGuestViewManagerKeyName));
68 content::WebContents* GuestViewManager::GetGuestByInstanceIDSafely(
69 int guest_instance_id,
70 int embedder_render_process_id) {
71 if (!CanEmbedderAccessInstanceIDMaybeKill(embedder_render_process_id,
72 guest_instance_id)) {
73 return nullptr;
75 return GetGuestByInstanceID(guest_instance_id);
78 void GuestViewManager::AttachGuest(int embedder_process_id,
79 int element_instance_id,
80 int guest_instance_id,
81 const base::DictionaryValue& attach_params) {
82 auto guest_view = GuestViewBase::From(embedder_process_id, guest_instance_id);
83 if (!guest_view)
84 return;
86 ElementInstanceKey key(embedder_process_id, element_instance_id);
87 auto it = instance_id_map_.find(key);
88 // If there is an existing guest attached to the element, then destroy the
89 // existing guest.
90 if (it != instance_id_map_.end()) {
91 int old_guest_instance_id = it->second;
92 if (old_guest_instance_id == guest_instance_id)
93 return;
95 auto old_guest_view = GuestViewBase::From(embedder_process_id,
96 old_guest_instance_id);
97 old_guest_view->Destroy();
99 instance_id_map_[key] = guest_instance_id;
100 reverse_instance_id_map_[guest_instance_id] = key;
101 guest_view->SetAttachParams(attach_params);
104 void GuestViewManager::DetachGuest(GuestViewBase* guest) {
105 if (!guest->attached())
106 return;
108 auto reverse_it = reverse_instance_id_map_.find(guest->guest_instance_id());
109 if (reverse_it == reverse_instance_id_map_.end())
110 return;
112 const ElementInstanceKey& key = reverse_it->second;
114 auto it = instance_id_map_.find(key);
115 DCHECK(it != instance_id_map_.end());
117 reverse_instance_id_map_.erase(reverse_it);
118 instance_id_map_.erase(it);
121 bool GuestViewManager::IsOwnedByExtension(GuestViewBase* guest) {
122 return delegate_->IsOwnedByExtension(guest);
125 int GuestViewManager::GetNextInstanceID() {
126 return ++current_instance_id_;
129 void GuestViewManager::CreateGuest(const std::string& view_type,
130 content::WebContents* owner_web_contents,
131 const base::DictionaryValue& create_params,
132 const WebContentsCreatedCallback& callback) {
133 GuestViewBase* guest = CreateGuestInternal(owner_web_contents, view_type);
134 if (!guest) {
135 callback.Run(nullptr);
136 return;
138 guest->Init(create_params, callback);
141 content::WebContents* GuestViewManager::CreateGuestWithWebContentsParams(
142 const std::string& view_type,
143 content::WebContents* owner_web_contents,
144 const content::WebContents::CreateParams& create_params) {
145 auto guest = CreateGuestInternal(owner_web_contents, view_type);
146 if (!guest)
147 return nullptr;
148 content::WebContents::CreateParams guest_create_params(create_params);
149 guest_create_params.guest_delegate = guest;
150 auto guest_web_contents = WebContents::Create(guest_create_params);
151 guest->InitWithWebContents(base::DictionaryValue(), guest_web_contents);
152 return guest_web_contents;
155 content::WebContents* GuestViewManager::GetGuestByInstanceID(
156 int owner_process_id,
157 int element_instance_id) {
158 int guest_instance_id = GetGuestInstanceIDForElementID(owner_process_id,
159 element_instance_id);
160 if (guest_instance_id == kInstanceIDNone)
161 return nullptr;
163 return GetGuestByInstanceID(guest_instance_id);
166 int GuestViewManager::GetGuestInstanceIDForElementID(int owner_process_id,
167 int element_instance_id) {
168 auto iter = instance_id_map_.find(
169 ElementInstanceKey(owner_process_id, element_instance_id));
170 if (iter == instance_id_map_.end())
171 return kInstanceIDNone;
172 return iter->second;
175 SiteInstance* GuestViewManager::GetGuestSiteInstance(
176 const GURL& guest_site) {
177 for (const auto& guest : guest_web_contents_by_instance_id_) {
178 if (guest.second->GetSiteInstance()->GetSiteURL() == guest_site)
179 return guest.second->GetSiteInstance();
181 return nullptr;
184 bool GuestViewManager::ForEachGuest(WebContents* owner_web_contents,
185 const GuestCallback& callback) {
186 for (const auto& guest : guest_web_contents_by_instance_id_) {
187 auto guest_view = GuestViewBase::FromWebContents(guest.second);
188 if (guest_view->owner_web_contents() != owner_web_contents)
189 continue;
191 if (callback.Run(guest_view->web_contents()))
192 return true;
194 return false;
197 WebContents* GuestViewManager::GetFullPageGuest(
198 WebContents* embedder_web_contents) {
199 WebContents* result = nullptr;
200 ForEachGuest(embedder_web_contents,
201 base::Bind(&GuestViewManager::GetFullPageGuestHelper, &result));
202 return result;
205 void GuestViewManager::AddGuest(int guest_instance_id,
206 WebContents* guest_web_contents) {
207 CHECK(!ContainsKey(guest_web_contents_by_instance_id_, guest_instance_id));
208 CHECK(CanUseGuestInstanceID(guest_instance_id));
209 guest_web_contents_by_instance_id_[guest_instance_id] = guest_web_contents;
212 void GuestViewManager::RemoveGuest(int guest_instance_id) {
213 auto it = guest_web_contents_by_instance_id_.find(guest_instance_id);
214 DCHECK(it != guest_web_contents_by_instance_id_.end());
215 guest_web_contents_by_instance_id_.erase(it);
217 auto id_iter = reverse_instance_id_map_.find(guest_instance_id);
218 if (id_iter != reverse_instance_id_map_.end()) {
219 const ElementInstanceKey& instance_id_key = id_iter->second;
220 instance_id_map_.erase(instance_id_map_.find(instance_id_key));
221 reverse_instance_id_map_.erase(id_iter);
224 // All the instance IDs that lie within [0, last_instance_id_removed_]
225 // are invalid.
226 // The remaining sparse invalid IDs are kept in |removed_instance_ids_| set.
227 // The following code compacts the set by incrementing
228 // |last_instance_id_removed_|.
229 if (guest_instance_id == last_instance_id_removed_ + 1) {
230 ++last_instance_id_removed_;
231 // Compact.
232 auto iter = removed_instance_ids_.begin();
233 while (iter != removed_instance_ids_.end()) {
234 int instance_id = *iter;
235 // The sparse invalid IDs must not lie within
236 // [0, last_instance_id_removed_]
237 DCHECK(instance_id > last_instance_id_removed_);
238 if (instance_id != last_instance_id_removed_ + 1)
239 break;
240 ++last_instance_id_removed_;
241 removed_instance_ids_.erase(iter++);
243 } else {
244 removed_instance_ids_.insert(guest_instance_id);
248 GuestViewBase* GuestViewManager::CreateGuestInternal(
249 content::WebContents* owner_web_contents,
250 const std::string& view_type) {
251 if (guest_view_registry_.empty())
252 RegisterGuestViewTypes();
254 auto it = guest_view_registry_.find(view_type);
255 if (it == guest_view_registry_.end()) {
256 NOTREACHED();
257 return nullptr;
260 return it->second.Run(owner_web_contents);
263 void GuestViewManager::RegisterGuestViewTypes() {
264 delegate_->RegisterAdditionalGuestViewTypes();
267 bool GuestViewManager::IsGuestAvailableToContext(GuestViewBase* guest) {
268 return delegate_->IsGuestAvailableToContext(guest);
271 void GuestViewManager::DispatchEvent(const std::string& event_name,
272 scoped_ptr<base::DictionaryValue> args,
273 GuestViewBase* guest,
274 int instance_id) {
275 // TODO(fsamuel): GuestViewManager should probably do something more useful
276 // here like log an error if the event could not be dispatched.
277 delegate_->DispatchEvent(event_name, args.Pass(), guest, instance_id);
280 content::WebContents* GuestViewManager::GetGuestByInstanceID(
281 int guest_instance_id) {
282 auto it = guest_web_contents_by_instance_id_.find(guest_instance_id);
283 if (it == guest_web_contents_by_instance_id_.end())
284 return nullptr;
285 return it->second;
288 bool GuestViewManager::CanEmbedderAccessInstanceIDMaybeKill(
289 int embedder_render_process_id,
290 int guest_instance_id) {
291 if (!CanEmbedderAccessInstanceID(embedder_render_process_id,
292 guest_instance_id)) {
293 // The embedder process is trying to access a guest it does not own.
294 content::RecordAction(
295 base::UserMetricsAction("BadMessageTerminate_BPGM"));
296 content::RenderProcessHost::FromID(embedder_render_process_id)
297 ->Shutdown(content::RESULT_CODE_KILLED_BAD_MESSAGE, false);
298 return false;
300 return true;
303 bool GuestViewManager::CanUseGuestInstanceID(int guest_instance_id) {
304 if (guest_instance_id <= last_instance_id_removed_)
305 return false;
306 return !ContainsKey(removed_instance_ids_, guest_instance_id);
309 // static
310 bool GuestViewManager::GetFullPageGuestHelper(
311 content::WebContents** result,
312 content::WebContents* guest_web_contents) {
313 auto guest_view = GuestViewBase::FromWebContents(guest_web_contents);
314 if (guest_view && guest_view->is_full_page_plugin()) {
315 *result = guest_web_contents;
316 return true;
318 return false;
321 bool GuestViewManager::CanEmbedderAccessInstanceID(
322 int embedder_render_process_id,
323 int guest_instance_id) {
324 // The embedder is trying to access a guest with a negative or zero
325 // instance ID.
326 if (guest_instance_id <= kInstanceIDNone)
327 return false;
329 // The embedder is trying to access an instance ID that has not yet been
330 // allocated by GuestViewManager. This could cause instance ID
331 // collisions in the future, and potentially give one embedder access to a
332 // guest it does not own.
333 if (guest_instance_id > current_instance_id_)
334 return false;
336 // We might get some late arriving messages at tear down. Let's let the
337 // embedder tear down in peace.
338 auto it = guest_web_contents_by_instance_id_.find(guest_instance_id);
339 if (it == guest_web_contents_by_instance_id_.end())
340 return true;
342 auto guest_view = GuestViewBase::FromWebContents(it->second);
343 if (!guest_view)
344 return false;
346 return embedder_render_process_id ==
347 guest_view->owner_web_contents()->GetRenderProcessHost()->GetID();
350 GuestViewManager::ElementInstanceKey::ElementInstanceKey()
351 : embedder_process_id(content::ChildProcessHost::kInvalidUniqueID),
352 element_instance_id(content::ChildProcessHost::kInvalidUniqueID) {
355 GuestViewManager::ElementInstanceKey::ElementInstanceKey(
356 int embedder_process_id,
357 int element_instance_id)
358 : embedder_process_id(embedder_process_id),
359 element_instance_id(element_instance_id) {
362 bool GuestViewManager::ElementInstanceKey::operator<(
363 const GuestViewManager::ElementInstanceKey& other) const {
364 if (embedder_process_id != other.embedder_process_id)
365 return embedder_process_id < other.embedder_process_id;
367 return element_instance_id < other.element_instance_id;
370 bool GuestViewManager::ElementInstanceKey::operator==(
371 const GuestViewManager::ElementInstanceKey& other) const {
372 return (embedder_process_id == other.embedder_process_id) &&
373 (element_instance_id == other.element_instance_id);
376 } // namespace guest_view