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 "chrome/browser/guest_view/guest_view_base.h"
7 #include "base/lazy_instance.h"
8 #include "chrome/browser/guest_view/ad_view/ad_view_guest.h"
9 #include "chrome/browser/guest_view/guest_view_constants.h"
10 #include "chrome/browser/guest_view/guest_view_manager.h"
11 #include "chrome/browser/guest_view/web_view/web_view_guest.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/common/content_settings.h"
14 #include "content/public/browser/render_process_host.h"
15 #include "content/public/browser/web_contents.h"
16 #include "content/public/common/url_constants.h"
17 #include "extensions/browser/event_router.h"
18 #include "net/base/escape.h"
19 #include "third_party/WebKit/public/web/WebInputEvent.h"
21 using content::WebContents
;
25 typedef std::map
<WebContents
*, GuestViewBase
*> WebContentsGuestViewMap
;
26 static base::LazyInstance
<WebContentsGuestViewMap
> webcontents_guestview_map
=
27 LAZY_INSTANCE_INITIALIZER
;
31 GuestViewBase::Event::Event(const std::string
& name
,
32 scoped_ptr
<base::DictionaryValue
> args
)
33 : name_(name
), args_(args
.Pass()) {
36 GuestViewBase::Event::~Event() {
39 scoped_ptr
<base::DictionaryValue
> GuestViewBase::Event::GetArguments() {
43 GuestViewBase::GuestViewBase(int guest_instance_id
,
44 WebContents
* guest_web_contents
,
45 const std::string
& embedder_extension_id
)
46 : guest_web_contents_(guest_web_contents
),
47 embedder_web_contents_(NULL
),
48 embedder_extension_id_(embedder_extension_id
),
49 embedder_render_process_id_(0),
50 browser_context_(guest_web_contents
->GetBrowserContext()),
51 guest_instance_id_(guest_instance_id
),
52 view_instance_id_(guestview::kInstanceIDNone
),
53 weak_ptr_factory_(this) {
54 guest_web_contents
->SetDelegate(this);
55 webcontents_guestview_map
.Get().insert(
56 std::make_pair(guest_web_contents
, this));
57 GuestViewManager::FromBrowserContext(browser_context_
)->
58 AddGuest(guest_instance_id_
, guest_web_contents
);
62 GuestViewBase
* GuestViewBase::Create(
63 int guest_instance_id
,
64 WebContents
* guest_web_contents
,
65 const std::string
& embedder_extension_id
,
66 const std::string
& view_type
) {
67 if (view_type
== "webview") {
68 return new WebViewGuest(guest_instance_id
,
70 embedder_extension_id
);
71 } else if (view_type
== "adview") {
72 return new AdViewGuest(guest_instance_id
,
74 embedder_extension_id
);
81 GuestViewBase
* GuestViewBase::FromWebContents(WebContents
* web_contents
) {
82 WebContentsGuestViewMap
* guest_map
= webcontents_guestview_map
.Pointer();
83 WebContentsGuestViewMap::iterator it
= guest_map
->find(web_contents
);
84 return it
== guest_map
->end() ? NULL
: it
->second
;
88 GuestViewBase
* GuestViewBase::From(int embedder_process_id
,
89 int guest_instance_id
) {
90 content::RenderProcessHost
* host
=
91 content::RenderProcessHost::FromID(embedder_process_id
);
95 content::WebContents
* guest_web_contents
=
96 GuestViewManager::FromBrowserContext(host
->GetBrowserContext())->
97 GetGuestByInstanceIDSafely(guest_instance_id
, embedder_process_id
);
98 if (!guest_web_contents
)
101 return GuestViewBase::FromWebContents(guest_web_contents
);
105 bool GuestViewBase::IsGuest(WebContents
* web_contents
) {
106 return !!GuestViewBase::FromWebContents(web_contents
);
110 bool GuestViewBase::GetGuestPartitionConfigForSite(
112 std::string
* partition_domain
,
113 std::string
* partition_name
,
115 if (!site
.SchemeIs(content::kGuestScheme
))
118 // Since guest URLs are only used for packaged apps, there must be an app
120 CHECK(site
.has_host());
121 *partition_domain
= site
.host();
122 // Since persistence is optional, the path must either be empty or the
124 *in_memory
= (site
.path() != "/persist");
125 // The partition name is user supplied value, which we have encoded when the
126 // URL was created, so it needs to be decoded.
128 net::UnescapeURLComponent(site
.query(), net::UnescapeRule::NORMAL
);
133 void GuestViewBase::GetDefaultContentSettingRules(
134 RendererContentSettingRules
* rules
,
136 rules
->image_rules
.push_back(
137 ContentSettingPatternSource(ContentSettingsPattern::Wildcard(),
138 ContentSettingsPattern::Wildcard(),
139 CONTENT_SETTING_ALLOW
,
143 rules
->script_rules
.push_back(
144 ContentSettingPatternSource(ContentSettingsPattern::Wildcard(),
145 ContentSettingsPattern::Wildcard(),
146 CONTENT_SETTING_ALLOW
,
151 base::WeakPtr
<GuestViewBase
> GuestViewBase::AsWeakPtr() {
152 return weak_ptr_factory_
.GetWeakPtr();
155 void GuestViewBase::Attach(content::WebContents
* embedder_web_contents
,
156 const base::DictionaryValue
& args
) {
157 embedder_web_contents_
= embedder_web_contents
;
158 embedder_render_process_id_
=
159 embedder_web_contents
->GetRenderProcessHost()->GetID();
160 args
.GetInteger(guestview::kParameterInstanceId
, &view_instance_id_
);
161 extra_params_
.reset(args
.DeepCopy());
163 // GuestViewBase::Attach is called prior to initialization (and initial
164 // navigation) of the guest in the content layer in order to permit mapping
165 // the necessary associations between the <*view> element and its guest. This
166 // is needed by the <webview> WebRequest API to allow intercepting resource
167 // requests during navigation. However, queued events should be fired after
168 // content layer initialization in order to ensure that load events (such as
169 // 'loadstop') fire in embedder after the contentWindow is available.
173 base::MessageLoop::current()->PostTask(
175 base::Bind(&GuestViewBase::SendQueuedEvents
,
176 weak_ptr_factory_
.GetWeakPtr()));
179 void GuestViewBase::Destroy() {
180 if (!destruction_callback_
.is_null())
181 destruction_callback_
.Run(guest_web_contents());
182 delete guest_web_contents();
186 void GuestViewBase::SetOpener(GuestViewBase
* guest
) {
187 if (guest
&& guest
->IsViewType(GetViewType())) {
188 opener_
= guest
->AsWeakPtr();
191 opener_
= base::WeakPtr
<GuestViewBase
>();
194 void GuestViewBase::RegisterDestructionCallback(
195 const DestructionCallback
& callback
) {
196 destruction_callback_
= callback
;
199 bool GuestViewBase::ShouldFocusPageAfterCrash() {
200 // Focus is managed elsewhere.
204 bool GuestViewBase::PreHandleGestureEvent(content::WebContents
* source
,
205 const blink::WebGestureEvent
& event
) {
206 return event
.type
== blink::WebGestureEvent::GesturePinchBegin
||
207 event
.type
== blink::WebGestureEvent::GesturePinchUpdate
||
208 event
.type
== blink::WebGestureEvent::GesturePinchEnd
;
211 GuestViewBase::~GuestViewBase() {
212 std::pair
<int, int> key(embedder_render_process_id_
, guest_instance_id_
);
214 webcontents_guestview_map
.Get().erase(guest_web_contents());
216 GuestViewManager::FromBrowserContext(browser_context_
)->
217 RemoveGuest(guest_instance_id_
);
219 pending_events_
.clear();
222 void GuestViewBase::DispatchEvent(Event
* event
) {
223 scoped_ptr
<Event
> event_ptr(event
);
224 if (!in_extension()) {
230 pending_events_
.push_back(linked_ptr
<Event
>(event_ptr
.release()));
234 Profile
* profile
= Profile::FromBrowserContext(browser_context_
);
236 extensions::EventFilteringInfo info
;
238 info
.SetInstanceID(guest_instance_id_
);
239 scoped_ptr
<base::ListValue
> args(new base::ListValue());
240 args
->Append(event
->GetArguments().release());
242 extensions::EventRouter::DispatchEvent(
243 embedder_web_contents_
,
245 embedder_extension_id_
,
248 extensions::EventRouter::USER_GESTURE_UNKNOWN
,
252 void GuestViewBase::SendQueuedEvents() {
255 while (!pending_events_
.empty()) {
256 linked_ptr
<Event
> event_ptr
= pending_events_
.front();
257 pending_events_
.pop_front();
258 DispatchEvent(event_ptr
.release());