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.
4
5 #include "chrome/browser/guest_view/guest_view_base.h"
6
7 #include "base/lazy_instance.h"
8 #include "base/strings/utf_string_conversions.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_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/web_contents.h"
18 #include "content/public/common/url_constants.h"
19 #include "extensions/browser/event_router.h"
20 #include "third_party/WebKit/public/web/WebInputEvent.h"
21
22 using content::WebContents;
23
24 namespace {
25
26 typedef std::map<WebContents*, GuestViewBase*> WebContentsGuestViewMap;
27 static base::LazyInstance<WebContentsGuestViewMap> webcontents_guestview_map =
28 LAZY_INSTANCE_INITIALIZER;
29
30 } // namespace
31
Event(const std::string & name,scoped_ptr<base::DictionaryValue> args)32 GuestViewBase::Event::Event(const std::string& name,
33 scoped_ptr<base::DictionaryValue> args)
34 : name_(name), args_(args.Pass()) {
35 }
36
~Event()37 GuestViewBase::Event::~Event() {
38 }
39
GetArguments()40 scoped_ptr<base::DictionaryValue> GuestViewBase::Event::GetArguments() {
41 return args_.Pass();
42 }
43
44 // This observer ensures that the GuestViewBase destroys itself when its
45 // embedder goes away.
46 class GuestViewBase::EmbedderWebContentsObserver : public WebContentsObserver {
47 public:
EmbedderWebContentsObserver(GuestViewBase * guest)48 explicit EmbedderWebContentsObserver(GuestViewBase* guest)
49 : WebContentsObserver(guest->embedder_web_contents()),
50 guest_(guest) {
51 }
52
~EmbedderWebContentsObserver()53 virtual ~EmbedderWebContentsObserver() {
54 }
55
56 // WebContentsObserver implementation.
WebContentsDestroyed()57 virtual void WebContentsDestroyed() OVERRIDE {
58 guest_->embedder_web_contents_ = NULL;
59 guest_->EmbedderDestroyed();
60 guest_->Destroy();
61 }
62
63 private:
64 GuestViewBase* guest_;
65
66 DISALLOW_COPY_AND_ASSIGN(EmbedderWebContentsObserver);
67 };
68
GuestViewBase(int guest_instance_id)69 GuestViewBase::GuestViewBase(int guest_instance_id)
70 : embedder_web_contents_(NULL),
71 embedder_render_process_id_(0),
72 browser_context_(NULL),
73 guest_instance_id_(guest_instance_id),
74 view_instance_id_(guestview::kInstanceIDNone),
75 initialized_(false),
76 weak_ptr_factory_(this) {
77 }
78
Init(WebContents * guest_web_contents,const std::string & embedder_extension_id)79 void GuestViewBase::Init(WebContents* guest_web_contents,
80 const std::string& embedder_extension_id) {
81 if (initialized_)
82 return;
83 initialized_ = true;
84 browser_context_ = guest_web_contents->GetBrowserContext();
85 embedder_extension_id_ = embedder_extension_id;
86
87 WebContentsObserver::Observe(guest_web_contents);
88 guest_web_contents->SetDelegate(this);
89 webcontents_guestview_map.Get().insert(
90 std::make_pair(guest_web_contents, this));
91 GuestViewManager::FromBrowserContext(browser_context_)->
92 AddGuest(guest_instance_id_, guest_web_contents);
93 }
94
95 // static
Create(int guest_instance_id,WebContents * guest_web_contents,const std::string & embedder_extension_id,const std::string & view_type)96 GuestViewBase* GuestViewBase::Create(
97 int guest_instance_id,
98 WebContents* guest_web_contents,
99 const std::string& embedder_extension_id,
100 const std::string& view_type) {
101 if (view_type == "webview") {
102 return new WebViewGuest(guest_instance_id,
103 guest_web_contents,
104 embedder_extension_id);
105 }
106 NOTREACHED();
107 return NULL;
108 }
109
110 // static
FromWebContents(WebContents * web_contents)111 GuestViewBase* GuestViewBase::FromWebContents(WebContents* web_contents) {
112 WebContentsGuestViewMap* guest_map = webcontents_guestview_map.Pointer();
113 WebContentsGuestViewMap::iterator it = guest_map->find(web_contents);
114 return it == guest_map->end() ? NULL : it->second;
115 }
116
117 // static
From(int embedder_process_id,int guest_instance_id)118 GuestViewBase* GuestViewBase::From(int embedder_process_id,
119 int guest_instance_id) {
120 content::RenderProcessHost* host =
121 content::RenderProcessHost::FromID(embedder_process_id);
122 if (!host)
123 return NULL;
124
125 content::WebContents* guest_web_contents =
126 GuestViewManager::FromBrowserContext(host->GetBrowserContext())->
127 GetGuestByInstanceIDSafely(guest_instance_id, embedder_process_id);
128 if (!guest_web_contents)
129 return NULL;
130
131 return GuestViewBase::FromWebContents(guest_web_contents);
132 }
133
134 // static
IsGuest(WebContents * web_contents)135 bool GuestViewBase::IsGuest(WebContents* web_contents) {
136 return !!GuestViewBase::FromWebContents(web_contents);
137 }
138
139 // static
GetDefaultContentSettingRules(RendererContentSettingRules * rules,bool incognito)140 void GuestViewBase::GetDefaultContentSettingRules(
141 RendererContentSettingRules* rules,
142 bool incognito) {
143 rules->image_rules.push_back(
144 ContentSettingPatternSource(ContentSettingsPattern::Wildcard(),
145 ContentSettingsPattern::Wildcard(),
146 CONTENT_SETTING_ALLOW,
147 std::string(),
148 incognito));
149
150 rules->script_rules.push_back(
151 ContentSettingPatternSource(ContentSettingsPattern::Wildcard(),
152 ContentSettingsPattern::Wildcard(),
153 CONTENT_SETTING_ALLOW,
154 std::string(),
155 incognito));
156 }
157
AsWeakPtr()158 base::WeakPtr<GuestViewBase> GuestViewBase::AsWeakPtr() {
159 return weak_ptr_factory_.GetWeakPtr();
160 }
161
IsDragAndDropEnabled() const162 bool GuestViewBase::IsDragAndDropEnabled() const {
163 return false;
164 }
165
Destroy()166 void GuestViewBase::Destroy() {
167 WillDestroy();
168 if (!destruction_callback_.is_null())
169 destruction_callback_.Run();
170 delete guest_web_contents();
171 }
172
DidAttach()173 void GuestViewBase::DidAttach() {
174 // Give the derived class an opportunity to perform some actions.
175 DidAttachToEmbedder();
176
177 SendQueuedEvents();
178 }
179
SetOpener(GuestViewBase * guest)180 void GuestViewBase::SetOpener(GuestViewBase* guest) {
181 if (guest && guest->IsViewType(GetViewType())) {
182 opener_ = guest->AsWeakPtr();
183 return;
184 }
185 opener_ = base::WeakPtr<GuestViewBase>();
186 }
187
RegisterDestructionCallback(const DestructionCallback & callback)188 void GuestViewBase::RegisterDestructionCallback(
189 const DestructionCallback& callback) {
190 destruction_callback_ = callback;
191 }
192
WillAttach(content::WebContents * embedder_web_contents,const base::DictionaryValue & extra_params)193 void GuestViewBase::WillAttach(content::WebContents* embedder_web_contents,
194 const base::DictionaryValue& extra_params) {
195 embedder_web_contents_ = embedder_web_contents;
196 embedder_web_contents_observer_.reset(
197 new EmbedderWebContentsObserver(this));
198 embedder_render_process_id_ =
199 embedder_web_contents->GetRenderProcessHost()->GetID();
200 extra_params.GetInteger(guestview::kParameterInstanceId, &view_instance_id_);
201 extra_params_.reset(extra_params.DeepCopy());
202
203 WillAttachToEmbedder();
204 }
205
DidStopLoading(content::RenderViewHost * render_view_host)206 void GuestViewBase::DidStopLoading(content::RenderViewHost* render_view_host) {
207 if (!IsDragAndDropEnabled()) {
208 const char script[] = "window.addEventListener('dragstart', function() { "
209 " window.event.preventDefault(); "
210 "});";
211 render_view_host->GetMainFrame()->ExecuteJavaScript(
212 base::ASCIIToUTF16(script));
213 }
214 DidStopLoading();
215 }
216
WebContentsDestroyed()217 void GuestViewBase::WebContentsDestroyed() {
218 GuestDestroyed();
219 delete this;
220 }
221
ShouldFocusPageAfterCrash()222 bool GuestViewBase::ShouldFocusPageAfterCrash() {
223 // Focus is managed elsewhere.
224 return false;
225 }
226
PreHandleGestureEvent(content::WebContents * source,const blink::WebGestureEvent & event)227 bool GuestViewBase::PreHandleGestureEvent(content::WebContents* source,
228 const blink::WebGestureEvent& event) {
229 return event.type == blink::WebGestureEvent::GesturePinchBegin ||
230 event.type == blink::WebGestureEvent::GesturePinchUpdate ||
231 event.type == blink::WebGestureEvent::GesturePinchEnd;
232 }
233
~GuestViewBase()234 GuestViewBase::~GuestViewBase() {
235 std::pair<int, int> key(embedder_render_process_id_, guest_instance_id_);
236
237 webcontents_guestview_map.Get().erase(guest_web_contents());
238
239 GuestViewManager::FromBrowserContext(browser_context_)->
240 RemoveGuest(guest_instance_id_);
241
242 pending_events_.clear();
243 }
244
DispatchEvent(Event * event)245 void GuestViewBase::DispatchEvent(Event* event) {
246 scoped_ptr<Event> event_ptr(event);
247 if (!in_extension()) {
248 NOTREACHED();
249 return;
250 }
251
252 if (!attached()) {
253 pending_events_.push_back(linked_ptr<Event>(event_ptr.release()));
254 return;
255 }
256
257 Profile* profile = Profile::FromBrowserContext(browser_context_);
258
259 extensions::EventFilteringInfo info;
260 info.SetInstanceID(view_instance_id_);
261 scoped_ptr<base::ListValue> args(new base::ListValue());
262 args->Append(event->GetArguments().release());
263
264 extensions::EventRouter::DispatchEvent(
265 embedder_web_contents_,
266 profile,
267 embedder_extension_id_,
268 event->name(),
269 args.Pass(),
270 extensions::EventRouter::USER_GESTURE_UNKNOWN,
271 info);
272 }
273
SendQueuedEvents()274 void GuestViewBase::SendQueuedEvents() {
275 if (!attached())
276 return;
277 while (!pending_events_.empty()) {
278 linked_ptr<Event> event_ptr = pending_events_.front();
279 pending_events_.pop_front();
280 DispatchEvent(event_ptr.release());
281 }
282 }
283