OLD | NEW |
| (Empty) |
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 "extensions/browser/guest_view/guest_view_base.h" | |
6 | |
7 #include "base/lazy_instance.h" | |
8 #include "base/strings/utf_string_conversions.h" | |
9 #include "components/ui/zoom/page_zoom.h" | |
10 #include "components/ui/zoom/zoom_controller.h" | |
11 #include "content/public/browser/navigation_details.h" | |
12 #include "content/public/browser/render_frame_host.h" | |
13 #include "content/public/browser/render_process_host.h" | |
14 #include "content/public/browser/render_view_host.h" | |
15 #include "content/public/browser/render_widget_host_view.h" | |
16 #include "content/public/browser/web_contents.h" | |
17 #include "content/public/common/page_zoom.h" | |
18 #include "content/public/common/url_constants.h" | |
19 #include "extensions/browser/guest_view/guest_view_event.h" | |
20 #include "extensions/browser/guest_view/guest_view_manager.h" | |
21 #include "extensions/common/guest_view/guest_view_constants.h" | |
22 #include "extensions/common/guest_view/guest_view_messages.h" | |
23 #include "third_party/WebKit/public/web/WebInputEvent.h" | |
24 | |
25 using content::WebContents; | |
26 | |
27 namespace content { | |
28 struct FrameNavigateParams; | |
29 } | |
30 | |
31 namespace extensions { | |
32 | |
33 namespace { | |
34 | |
35 using WebContentsGuestViewMap = std::map<const WebContents*, GuestViewBase*>; | |
36 static base::LazyInstance<WebContentsGuestViewMap> webcontents_guestview_map = | |
37 LAZY_INSTANCE_INITIALIZER; | |
38 | |
39 } // namespace | |
40 | |
41 SetSizeParams::SetSizeParams() { | |
42 } | |
43 SetSizeParams::~SetSizeParams() { | |
44 } | |
45 | |
46 // This observer ensures that the GuestViewBase destroys itself when its | |
47 // embedder goes away. It also tracks when the embedder's fullscreen is | |
48 // toggled so the guest can change itself accordingly. | |
49 class GuestViewBase::OwnerContentsObserver : public WebContentsObserver { | |
50 public: | |
51 OwnerContentsObserver(GuestViewBase* guest, | |
52 content::WebContents* embedder_web_contents) | |
53 : WebContentsObserver(embedder_web_contents), | |
54 is_fullscreen_(false), | |
55 destroyed_(false), | |
56 guest_(guest) {} | |
57 | |
58 ~OwnerContentsObserver() override {} | |
59 | |
60 // WebContentsObserver implementation. | |
61 void WebContentsDestroyed() override { | |
62 // If the embedder is destroyed then destroy the guest. | |
63 Destroy(); | |
64 } | |
65 | |
66 void DidNavigateMainFrame( | |
67 const content::LoadCommittedDetails& details, | |
68 const content::FrameNavigateParams& params) override { | |
69 // If the embedder navigates to a different page then destroy the guest. | |
70 if (details.is_navigation_to_different_page()) | |
71 Destroy(); | |
72 } | |
73 | |
74 void RenderProcessGone(base::TerminationStatus status) override { | |
75 // If the embedder crashes, then destroy the guest. | |
76 Destroy(); | |
77 } | |
78 | |
79 void DidToggleFullscreenModeForTab(bool entered_fullscreen) override { | |
80 if (destroyed_) | |
81 return; | |
82 | |
83 is_fullscreen_ = entered_fullscreen; | |
84 guest_->EmbedderFullscreenToggled(is_fullscreen_); | |
85 } | |
86 | |
87 void MainFrameWasResized(bool width_changed) override { | |
88 if (destroyed_) | |
89 return; | |
90 | |
91 if (!web_contents()->GetDelegate()) | |
92 return; | |
93 | |
94 bool current_fullscreen = | |
95 web_contents()->GetDelegate()->IsFullscreenForTabOrPending( | |
96 web_contents()); | |
97 if (is_fullscreen_ && !current_fullscreen) { | |
98 is_fullscreen_ = false; | |
99 guest_->EmbedderFullscreenToggled(is_fullscreen_); | |
100 } | |
101 } | |
102 | |
103 private: | |
104 bool is_fullscreen_; | |
105 bool destroyed_; | |
106 GuestViewBase* guest_; | |
107 | |
108 void Destroy() { | |
109 if (destroyed_) | |
110 return; | |
111 | |
112 destroyed_ = true; | |
113 guest_->EmbedderWillBeDestroyed(); | |
114 guest_->Destroy(); | |
115 } | |
116 | |
117 DISALLOW_COPY_AND_ASSIGN(OwnerContentsObserver); | |
118 }; | |
119 | |
120 // This observer ensures that the GuestViewBase destroys itself when its | |
121 // embedder goes away. | |
122 class GuestViewBase::OpenerLifetimeObserver : public WebContentsObserver { | |
123 public: | |
124 OpenerLifetimeObserver(GuestViewBase* guest) | |
125 : WebContentsObserver(guest->GetOpener()->web_contents()), | |
126 guest_(guest) {} | |
127 | |
128 ~OpenerLifetimeObserver() override {} | |
129 | |
130 // WebContentsObserver implementation. | |
131 void WebContentsDestroyed() override { | |
132 if (guest_->attached()) | |
133 return; | |
134 | |
135 // If the opener is destroyed then destroy the guest. | |
136 guest_->Destroy(); | |
137 } | |
138 | |
139 private: | |
140 GuestViewBase* guest_; | |
141 | |
142 DISALLOW_COPY_AND_ASSIGN(OpenerLifetimeObserver); | |
143 }; | |
144 | |
145 GuestViewBase::GuestViewBase(content::WebContents* owner_web_contents) | |
146 : owner_web_contents_(owner_web_contents), | |
147 browser_context_(owner_web_contents->GetBrowserContext()), | |
148 guest_instance_id_( | |
149 GuestViewManager::FromBrowserContext(browser_context_)-> | |
150 GetNextInstanceID()), | |
151 view_instance_id_(guestview::kInstanceIDNone), | |
152 element_instance_id_(guestview::kInstanceIDNone), | |
153 initialized_(false), | |
154 is_being_destroyed_(false), | |
155 guest_host_(nullptr), | |
156 auto_size_enabled_(false), | |
157 is_full_page_plugin_(false), | |
158 guest_proxy_routing_id_(MSG_ROUTING_NONE), | |
159 weak_ptr_factory_(this) { | |
160 owner_host_ = GuestViewManager::FromBrowserContext(browser_context_)-> | |
161 IsOwnedByExtension(this) ? | |
162 owner_web_contents->GetLastCommittedURL().host() : std::string(); | |
163 } | |
164 | |
165 void GuestViewBase::Init(const base::DictionaryValue& create_params, | |
166 const WebContentsCreatedCallback& callback) { | |
167 if (initialized_) | |
168 return; | |
169 initialized_ = true; | |
170 | |
171 if (!GuestViewManager::FromBrowserContext(browser_context_)-> | |
172 IsGuestAvailableToContext(this)) { | |
173 // The derived class did not create a WebContents so this class serves no | |
174 // purpose. Let's self-destruct. | |
175 delete this; | |
176 callback.Run(nullptr); | |
177 return; | |
178 } | |
179 | |
180 scoped_ptr<base::DictionaryValue> params(create_params.DeepCopy()); | |
181 CreateWebContents(create_params, | |
182 base::Bind(&GuestViewBase::CompleteInit, | |
183 weak_ptr_factory_.GetWeakPtr(), | |
184 base::Passed(¶ms), | |
185 callback)); | |
186 } | |
187 | |
188 void GuestViewBase::InitWithWebContents( | |
189 const base::DictionaryValue& create_params, | |
190 content::WebContents* guest_web_contents) { | |
191 DCHECK(guest_web_contents); | |
192 | |
193 // Create a ZoomController to allow the guest's contents to be zoomed. | |
194 // Do this before adding the GuestView as a WebContents Observer so that | |
195 // the GuestView and its derived classes can re-configure the ZoomController | |
196 // after the latter has handled WebContentsObserver events (observers are | |
197 // notified of events in the same order they are added as observers). For | |
198 // example, GuestViewBase may wish to put its guest into isolated zoom mode | |
199 // in DidNavigateMainFrame, but since ZoomController always resets to default | |
200 // zoom mode on this event, GuestViewBase would need to do so after | |
201 // ZoomController::DidNavigateMainFrame has completed. | |
202 ui_zoom::ZoomController::CreateForWebContents(guest_web_contents); | |
203 | |
204 // At this point, we have just created the guest WebContents, we need to add | |
205 // an observer to the owner WebContents. This observer will be responsible | |
206 // for destroying the guest WebContents if the owner goes away. | |
207 owner_contents_observer_.reset( | |
208 new OwnerContentsObserver(this, owner_web_contents_)); | |
209 | |
210 WebContentsObserver::Observe(guest_web_contents); | |
211 guest_web_contents->SetDelegate(this); | |
212 webcontents_guestview_map.Get().insert( | |
213 std::make_pair(guest_web_contents, this)); | |
214 GuestViewManager::FromBrowserContext(browser_context_)-> | |
215 AddGuest(guest_instance_id_, guest_web_contents); | |
216 | |
217 // Populate the view instance ID if we have it on creation. | |
218 create_params.GetInteger(guestview::kParameterInstanceId, | |
219 &view_instance_id_); | |
220 | |
221 if (CanRunInDetachedState()) | |
222 SetUpSizing(create_params); | |
223 | |
224 // Observe guest zoom changes. | |
225 auto zoom_controller = | |
226 ui_zoom::ZoomController::FromWebContents(web_contents()); | |
227 zoom_controller->AddObserver(this); | |
228 | |
229 // Give the derived class an opportunity to perform additional initialization. | |
230 DidInitialize(create_params); | |
231 } | |
232 | |
233 void GuestViewBase::LoadURLWithParams( | |
234 const content::NavigationController::LoadURLParams& load_params) { | |
235 int guest_proxy_routing_id = host()->LoadURLWithParams(load_params); | |
236 DCHECK(guest_proxy_routing_id_ == MSG_ROUTING_NONE || | |
237 guest_proxy_routing_id == guest_proxy_routing_id_); | |
238 guest_proxy_routing_id_ = guest_proxy_routing_id; | |
239 } | |
240 | |
241 void GuestViewBase::DispatchOnResizeEvent(const gfx::Size& old_size, | |
242 const gfx::Size& new_size) { | |
243 if (new_size == old_size) | |
244 return; | |
245 | |
246 // Dispatch the onResize event. | |
247 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); | |
248 args->SetInteger(guestview::kOldWidth, old_size.width()); | |
249 args->SetInteger(guestview::kOldHeight, old_size.height()); | |
250 args->SetInteger(guestview::kNewWidth, new_size.width()); | |
251 args->SetInteger(guestview::kNewHeight, new_size.height()); | |
252 DispatchEventToGuestProxy( | |
253 new GuestViewEvent(guestview::kEventResize, args.Pass())); | |
254 } | |
255 | |
256 gfx::Size GuestViewBase::GetDefaultSize() const { | |
257 if (is_full_page_plugin()) { | |
258 // Full page plugins default to the size of the owner's viewport. | |
259 return owner_web_contents() | |
260 ->GetRenderWidgetHostView() | |
261 ->GetVisibleViewportSize(); | |
262 } else { | |
263 return gfx::Size(guestview::kDefaultWidth, guestview::kDefaultHeight); | |
264 } | |
265 } | |
266 | |
267 void GuestViewBase::SetSize(const SetSizeParams& params) { | |
268 bool enable_auto_size = | |
269 params.enable_auto_size ? *params.enable_auto_size : auto_size_enabled_; | |
270 gfx::Size min_size = params.min_size ? *params.min_size : min_auto_size_; | |
271 gfx::Size max_size = params.max_size ? *params.max_size : max_auto_size_; | |
272 | |
273 if (params.normal_size) | |
274 normal_size_ = *params.normal_size; | |
275 | |
276 min_auto_size_ = min_size; | |
277 min_auto_size_.SetToMin(max_size); | |
278 max_auto_size_ = max_size; | |
279 max_auto_size_.SetToMax(min_size); | |
280 | |
281 enable_auto_size &= !min_auto_size_.IsEmpty() && !max_auto_size_.IsEmpty() && | |
282 IsAutoSizeSupported(); | |
283 | |
284 content::RenderViewHost* rvh = web_contents()->GetRenderViewHost(); | |
285 if (enable_auto_size) { | |
286 // Autosize is being enabled. | |
287 rvh->EnableAutoResize(min_auto_size_, max_auto_size_); | |
288 normal_size_.SetSize(0, 0); | |
289 } else { | |
290 // Autosize is being disabled. | |
291 // Use default width/height if missing from partially defined normal size. | |
292 if (normal_size_.width() && !normal_size_.height()) | |
293 normal_size_.set_height(GetDefaultSize().height()); | |
294 if (!normal_size_.width() && normal_size_.height()) | |
295 normal_size_.set_width(GetDefaultSize().width()); | |
296 | |
297 gfx::Size new_size; | |
298 if (!normal_size_.IsEmpty()) { | |
299 new_size = normal_size_; | |
300 } else if (!guest_size_.IsEmpty()) { | |
301 new_size = guest_size_; | |
302 } else { | |
303 new_size = GetDefaultSize(); | |
304 } | |
305 | |
306 if (auto_size_enabled_) { | |
307 // Autosize was previously enabled. | |
308 rvh->DisableAutoResize(new_size); | |
309 GuestSizeChangedDueToAutoSize(guest_size_, new_size); | |
310 } else { | |
311 // Autosize was already disabled. | |
312 guest_host_->SizeContents(new_size); | |
313 } | |
314 | |
315 DispatchOnResizeEvent(guest_size_, new_size); | |
316 guest_size_ = new_size; | |
317 } | |
318 | |
319 auto_size_enabled_ = enable_auto_size; | |
320 } | |
321 | |
322 // static | |
323 GuestViewBase* GuestViewBase::FromWebContents(const WebContents* web_contents) { | |
324 WebContentsGuestViewMap* guest_map = webcontents_guestview_map.Pointer(); | |
325 auto it = guest_map->find(web_contents); | |
326 return it == guest_map->end() ? nullptr : it->second; | |
327 } | |
328 | |
329 // static | |
330 GuestViewBase* GuestViewBase::From(int owner_process_id, | |
331 int guest_instance_id) { | |
332 auto host = content::RenderProcessHost::FromID(owner_process_id); | |
333 if (!host) | |
334 return nullptr; | |
335 | |
336 content::WebContents* guest_web_contents = | |
337 GuestViewManager::FromBrowserContext( | |
338 host->GetBrowserContext())-> | |
339 GetGuestByInstanceIDSafely(guest_instance_id, owner_process_id); | |
340 if (!guest_web_contents) | |
341 return nullptr; | |
342 | |
343 return GuestViewBase::FromWebContents(guest_web_contents); | |
344 } | |
345 | |
346 // static | |
347 WebContents* GuestViewBase::GetTopLevelWebContents(WebContents* web_contents) { | |
348 while (GuestViewBase* guest = FromWebContents(web_contents)) | |
349 web_contents = guest->owner_web_contents(); | |
350 return web_contents; | |
351 } | |
352 | |
353 // static | |
354 bool GuestViewBase::IsGuest(WebContents* web_contents) { | |
355 return !!GuestViewBase::FromWebContents(web_contents); | |
356 } | |
357 | |
358 bool GuestViewBase::IsAutoSizeSupported() const { | |
359 return false; | |
360 } | |
361 | |
362 bool GuestViewBase::IsPreferredSizeModeEnabled() const { | |
363 return false; | |
364 } | |
365 | |
366 bool GuestViewBase::IsDragAndDropEnabled() const { | |
367 return false; | |
368 } | |
369 | |
370 bool GuestViewBase::ZoomPropagatesFromEmbedderToGuest() const { | |
371 return true; | |
372 } | |
373 | |
374 content::WebContents* GuestViewBase::CreateNewGuestWindow( | |
375 const content::WebContents::CreateParams& create_params) { | |
376 auto guest_manager = GuestViewManager::FromBrowserContext(browser_context()); | |
377 return guest_manager->CreateGuestWithWebContentsParams( | |
378 GetViewType(), | |
379 owner_web_contents(), | |
380 create_params); | |
381 } | |
382 | |
383 void GuestViewBase::DidAttach(int guest_proxy_routing_id) { | |
384 DCHECK(guest_proxy_routing_id_ == MSG_ROUTING_NONE || | |
385 guest_proxy_routing_id == guest_proxy_routing_id_); | |
386 guest_proxy_routing_id_ = guest_proxy_routing_id; | |
387 | |
388 opener_lifetime_observer_.reset(); | |
389 | |
390 SetUpSizing(*attach_params()); | |
391 | |
392 // Give the derived class an opportunity to perform some actions. | |
393 DidAttachToEmbedder(); | |
394 | |
395 // Inform the associated GuestViewContainer that the contentWindow is ready. | |
396 embedder_web_contents()->Send(new GuestViewMsg_GuestAttached( | |
397 element_instance_id_, | |
398 guest_proxy_routing_id)); | |
399 | |
400 SendQueuedEvents(); | |
401 } | |
402 | |
403 void GuestViewBase::DidDetach() { | |
404 GuestViewManager::FromBrowserContext(browser_context_)->DetachGuest(this); | |
405 StopTrackingEmbedderZoomLevel(); | |
406 owner_web_contents()->Send(new GuestViewMsg_GuestDetached( | |
407 element_instance_id_)); | |
408 element_instance_id_ = guestview::kInstanceIDNone; | |
409 } | |
410 | |
411 WebContents* GuestViewBase::GetOwnerWebContents() const { | |
412 return owner_web_contents_; | |
413 } | |
414 | |
415 void GuestViewBase::GuestSizeChanged(const gfx::Size& new_size) { | |
416 if (!auto_size_enabled_) | |
417 return; | |
418 GuestSizeChangedDueToAutoSize(guest_size_, new_size); | |
419 DispatchOnResizeEvent(guest_size_, new_size); | |
420 guest_size_ = new_size; | |
421 } | |
422 | |
423 const GURL& GuestViewBase::GetOwnerSiteURL() const { | |
424 return owner_web_contents()->GetLastCommittedURL(); | |
425 } | |
426 | |
427 void GuestViewBase::Destroy() { | |
428 if (is_being_destroyed_) | |
429 return; | |
430 | |
431 is_being_destroyed_ = true; | |
432 | |
433 // It is important to clear owner_web_contents_ after the call to | |
434 // StopTrackingEmbedderZoomLevel(), but before the rest of | |
435 // the statements in this function. | |
436 StopTrackingEmbedderZoomLevel(); | |
437 owner_web_contents_ = nullptr; | |
438 | |
439 DCHECK(web_contents()); | |
440 | |
441 // Give the derived class an opportunity to perform some cleanup. | |
442 WillDestroy(); | |
443 | |
444 // Invalidate weak pointers now so that bound callbacks cannot be called late | |
445 // into destruction. We must call this after WillDestroy because derived types | |
446 // may wish to access their openers. | |
447 weak_ptr_factory_.InvalidateWeakPtrs(); | |
448 | |
449 // Give the content module an opportunity to perform some cleanup. | |
450 guest_host_->WillDestroy(); | |
451 guest_host_ = nullptr; | |
452 | |
453 webcontents_guestview_map.Get().erase(web_contents()); | |
454 GuestViewManager::FromBrowserContext(browser_context_)-> | |
455 RemoveGuest(guest_instance_id_); | |
456 pending_events_.clear(); | |
457 | |
458 delete web_contents(); | |
459 } | |
460 | |
461 void GuestViewBase::SetAttachParams(const base::DictionaryValue& params) { | |
462 attach_params_.reset(params.DeepCopy()); | |
463 attach_params_->GetInteger(guestview::kParameterInstanceId, | |
464 &view_instance_id_); | |
465 } | |
466 | |
467 void GuestViewBase::SetOpener(GuestViewBase* guest) { | |
468 if (guest && guest->IsViewType(GetViewType())) { | |
469 opener_ = guest->weak_ptr_factory_.GetWeakPtr(); | |
470 if (!attached()) | |
471 opener_lifetime_observer_.reset(new OpenerLifetimeObserver(this)); | |
472 return; | |
473 } | |
474 opener_ = base::WeakPtr<GuestViewBase>(); | |
475 opener_lifetime_observer_.reset(); | |
476 } | |
477 | |
478 void GuestViewBase::SetGuestHost(content::GuestHost* guest_host) { | |
479 guest_host_ = guest_host; | |
480 } | |
481 | |
482 void GuestViewBase::WillAttach(content::WebContents* embedder_web_contents, | |
483 int element_instance_id, | |
484 bool is_full_page_plugin) { | |
485 if (owner_web_contents_ != embedder_web_contents) { | |
486 DCHECK_EQ(owner_contents_observer_->web_contents(), owner_web_contents_); | |
487 // Stop tracking the old embedder's zoom level. | |
488 StopTrackingEmbedderZoomLevel(); | |
489 owner_web_contents_ = embedder_web_contents; | |
490 owner_contents_observer_.reset( | |
491 new OwnerContentsObserver(this, embedder_web_contents)); | |
492 owner_host_ = GuestViewManager::FromBrowserContext(browser_context_)-> | |
493 IsOwnedByExtension(this) ? | |
494 owner_web_contents()->GetLastCommittedURL().host() : std::string(); | |
495 } | |
496 | |
497 // Start tracking the new embedder's zoom level. | |
498 StartTrackingEmbedderZoomLevel(); | |
499 element_instance_id_ = element_instance_id; | |
500 is_full_page_plugin_ = is_full_page_plugin; | |
501 | |
502 WillAttachToEmbedder(); | |
503 } | |
504 | |
505 int GuestViewBase::LogicalPixelsToPhysicalPixels(double logical_pixels) const { | |
506 DCHECK(logical_pixels >= 0); | |
507 double zoom_factor = GetEmbedderZoomFactor(); | |
508 return lround(logical_pixels * zoom_factor); | |
509 } | |
510 | |
511 double GuestViewBase::PhysicalPixelsToLogicalPixels(int physical_pixels) const { | |
512 DCHECK(physical_pixels >= 0); | |
513 double zoom_factor = GetEmbedderZoomFactor(); | |
514 return physical_pixels / zoom_factor; | |
515 } | |
516 | |
517 void GuestViewBase::DidStopLoading() { | |
518 content::RenderViewHost* rvh = web_contents()->GetRenderViewHost(); | |
519 | |
520 if (IsPreferredSizeModeEnabled()) | |
521 rvh->EnablePreferredSizeMode(); | |
522 if (!IsDragAndDropEnabled()) { | |
523 const char script[] = | |
524 "window.addEventListener('dragstart', function() { " | |
525 " window.event.preventDefault(); " | |
526 "});"; | |
527 rvh->GetMainFrame()->ExecuteJavaScript(base::ASCIIToUTF16(script)); | |
528 } | |
529 GuestViewDidStopLoading(); | |
530 } | |
531 | |
532 void GuestViewBase::RenderViewReady() { | |
533 GuestReady(); | |
534 } | |
535 | |
536 void GuestViewBase::WebContentsDestroyed() { | |
537 // Let the derived class know that its WebContents is in the process of | |
538 // being destroyed. web_contents() is still valid at this point. | |
539 // TODO(fsamuel): This allows for reentrant code into WebContents during | |
540 // destruction. This could potentially lead to bugs. Perhaps we should get rid | |
541 // of this? | |
542 GuestDestroyed(); | |
543 | |
544 // Self-destruct. | |
545 delete this; | |
546 } | |
547 | |
548 void GuestViewBase::DidNavigateMainFrame( | |
549 const content::LoadCommittedDetails& details, | |
550 const content::FrameNavigateParams& params) { | |
551 if (attached() && ZoomPropagatesFromEmbedderToGuest()) | |
552 SetGuestZoomLevelToMatchEmbedder(); | |
553 } | |
554 | |
555 void GuestViewBase::ActivateContents(WebContents* web_contents) { | |
556 if (!attached() || !embedder_web_contents()->GetDelegate()) | |
557 return; | |
558 | |
559 embedder_web_contents()->GetDelegate()->ActivateContents( | |
560 embedder_web_contents()); | |
561 } | |
562 | |
563 void GuestViewBase::DeactivateContents(WebContents* web_contents) { | |
564 if (!attached() || !embedder_web_contents()->GetDelegate()) | |
565 return; | |
566 | |
567 embedder_web_contents()->GetDelegate()->DeactivateContents( | |
568 embedder_web_contents()); | |
569 } | |
570 | |
571 void GuestViewBase::ContentsMouseEvent(content::WebContents* source, | |
572 const gfx::Point& location, | |
573 bool motion) { | |
574 if (!attached() || !embedder_web_contents()->GetDelegate()) | |
575 return; | |
576 | |
577 embedder_web_contents()->GetDelegate()->ContentsMouseEvent( | |
578 embedder_web_contents(), location, motion); | |
579 } | |
580 | |
581 void GuestViewBase::ContentsZoomChange(bool zoom_in) { | |
582 ui_zoom::PageZoom::Zoom( | |
583 embedder_web_contents(), | |
584 zoom_in ? content::PAGE_ZOOM_IN : content::PAGE_ZOOM_OUT); | |
585 } | |
586 | |
587 void GuestViewBase::HandleKeyboardEvent( | |
588 WebContents* source, | |
589 const content::NativeWebKeyboardEvent& event) { | |
590 if (!attached()) | |
591 return; | |
592 | |
593 // Send the keyboard events back to the embedder to reprocess them. | |
594 embedder_web_contents()->GetDelegate()-> | |
595 HandleKeyboardEvent(embedder_web_contents(), event); | |
596 } | |
597 | |
598 void GuestViewBase::LoadingStateChanged(content::WebContents* source, | |
599 bool to_different_document) { | |
600 if (!attached() || !embedder_web_contents()->GetDelegate()) | |
601 return; | |
602 | |
603 embedder_web_contents()->GetDelegate()->LoadingStateChanged( | |
604 embedder_web_contents(), to_different_document); | |
605 } | |
606 | |
607 content::ColorChooser* GuestViewBase::OpenColorChooser( | |
608 WebContents* web_contents, | |
609 SkColor color, | |
610 const std::vector<content::ColorSuggestion>& suggestions) { | |
611 if (!attached() || !embedder_web_contents()->GetDelegate()) | |
612 return nullptr; | |
613 | |
614 return embedder_web_contents()->GetDelegate()->OpenColorChooser( | |
615 web_contents, color, suggestions); | |
616 } | |
617 | |
618 void GuestViewBase::RunFileChooser(WebContents* web_contents, | |
619 const content::FileChooserParams& params) { | |
620 if (!attached() || !embedder_web_contents()->GetDelegate()) | |
621 return; | |
622 | |
623 embedder_web_contents()->GetDelegate()->RunFileChooser(web_contents, params); | |
624 } | |
625 | |
626 bool GuestViewBase::ShouldFocusPageAfterCrash() { | |
627 // Focus is managed elsewhere. | |
628 return false; | |
629 } | |
630 | |
631 bool GuestViewBase::PreHandleGestureEvent(content::WebContents* source, | |
632 const blink::WebGestureEvent& event) { | |
633 return event.type == blink::WebGestureEvent::GesturePinchBegin || | |
634 event.type == blink::WebGestureEvent::GesturePinchUpdate || | |
635 event.type == blink::WebGestureEvent::GesturePinchEnd; | |
636 } | |
637 | |
638 void GuestViewBase::UpdatePreferredSize( | |
639 content::WebContents* target_web_contents, | |
640 const gfx::Size& pref_size) { | |
641 // In theory it's not necessary to check IsPreferredSizeModeEnabled() because | |
642 // there will only be events if it was enabled in the first place. However, | |
643 // something else may have turned on preferred size mode, so double check. | |
644 DCHECK_EQ(web_contents(), target_web_contents); | |
645 if (IsPreferredSizeModeEnabled()) { | |
646 OnPreferredSizeChanged(pref_size); | |
647 } | |
648 } | |
649 | |
650 void GuestViewBase::UpdateTargetURL(content::WebContents* source, | |
651 const GURL& url) { | |
652 if (!attached() || !embedder_web_contents()->GetDelegate()) | |
653 return; | |
654 | |
655 embedder_web_contents()->GetDelegate()->UpdateTargetURL( | |
656 embedder_web_contents(), url); | |
657 } | |
658 | |
659 bool GuestViewBase::ShouldResumeRequestsForCreatedWindow() { | |
660 return false; | |
661 } | |
662 | |
663 GuestViewBase::~GuestViewBase() { | |
664 } | |
665 | |
666 void GuestViewBase::OnZoomChanged( | |
667 const ui_zoom::ZoomController::ZoomChangedEventData& data) { | |
668 if (data.web_contents == embedder_web_contents()) { | |
669 // The embedder's zoom level has changed. | |
670 auto guest_zoom_controller = | |
671 ui_zoom::ZoomController::FromWebContents(web_contents()); | |
672 if (content::ZoomValuesEqual(data.new_zoom_level, | |
673 guest_zoom_controller->GetZoomLevel())) { | |
674 return; | |
675 } | |
676 // When the embedder's zoom level doesn't match the guest's, then update the | |
677 // guest's zoom level to match. | |
678 guest_zoom_controller->SetZoomLevel(data.new_zoom_level); | |
679 | |
680 EmbedderZoomChanged(data.old_zoom_level, data.new_zoom_level); | |
681 return; | |
682 } | |
683 | |
684 if (data.web_contents == web_contents()) { | |
685 // The guest's zoom level has changed. | |
686 GuestZoomChanged(data.old_zoom_level, data.new_zoom_level); | |
687 } | |
688 } | |
689 | |
690 void GuestViewBase::DispatchEventToGuestProxy(GuestViewEvent* event) { | |
691 event->Dispatch(this, guest_instance_id_); | |
692 } | |
693 | |
694 void GuestViewBase::DispatchEventToView(GuestViewEvent* event) { | |
695 if (!attached() && | |
696 (!CanRunInDetachedState() || !can_owner_receive_events())) { | |
697 pending_events_.push_back(linked_ptr<GuestViewEvent>(event)); | |
698 return; | |
699 } | |
700 | |
701 event->Dispatch(this, view_instance_id_); | |
702 } | |
703 | |
704 void GuestViewBase::SendQueuedEvents() { | |
705 if (!attached()) | |
706 return; | |
707 while (!pending_events_.empty()) { | |
708 linked_ptr<GuestViewEvent> event_ptr = pending_events_.front(); | |
709 pending_events_.pop_front(); | |
710 event_ptr.release()->Dispatch(this, view_instance_id_); | |
711 } | |
712 } | |
713 | |
714 void GuestViewBase::CompleteInit( | |
715 scoped_ptr<base::DictionaryValue> create_params, | |
716 const WebContentsCreatedCallback& callback, | |
717 content::WebContents* guest_web_contents) { | |
718 if (!guest_web_contents) { | |
719 // The derived class did not create a WebContents so this class serves no | |
720 // purpose. Let's self-destruct. | |
721 delete this; | |
722 callback.Run(nullptr); | |
723 return; | |
724 } | |
725 InitWithWebContents(*create_params, guest_web_contents); | |
726 callback.Run(guest_web_contents); | |
727 } | |
728 | |
729 double GuestViewBase::GetEmbedderZoomFactor() const { | |
730 if (!embedder_web_contents()) | |
731 return 1.0; | |
732 | |
733 return content::ZoomLevelToZoomFactor( | |
734 ui_zoom::ZoomController::GetZoomLevelForWebContents( | |
735 embedder_web_contents())); | |
736 } | |
737 | |
738 void GuestViewBase::SetUpSizing(const base::DictionaryValue& params) { | |
739 // Read the autosize parameters passed in from the embedder. | |
740 bool auto_size_enabled = auto_size_enabled_; | |
741 params.GetBoolean(guestview::kAttributeAutoSize, &auto_size_enabled); | |
742 | |
743 int max_height = max_auto_size_.height(); | |
744 int max_width = max_auto_size_.width(); | |
745 params.GetInteger(guestview::kAttributeMaxHeight, &max_height); | |
746 params.GetInteger(guestview::kAttributeMaxWidth, &max_width); | |
747 | |
748 int min_height = min_auto_size_.height(); | |
749 int min_width = min_auto_size_.width(); | |
750 params.GetInteger(guestview::kAttributeMinHeight, &min_height); | |
751 params.GetInteger(guestview::kAttributeMinWidth, &min_width); | |
752 | |
753 double element_height = 0.0; | |
754 double element_width = 0.0; | |
755 params.GetDouble(guestview::kElementHeight, &element_height); | |
756 params.GetDouble(guestview::kElementWidth, &element_width); | |
757 | |
758 // Set the normal size to the element size so that the guestview will fit | |
759 // the element initially if autosize is disabled. | |
760 int normal_height = normal_size_.height(); | |
761 int normal_width = normal_size_.width(); | |
762 // If the element size was provided in logical units (versus physical), then | |
763 // it will be converted to physical units. | |
764 bool element_size_is_logical = false; | |
765 params.GetBoolean(guestview::kElementSizeIsLogical, &element_size_is_logical); | |
766 if (element_size_is_logical) { | |
767 // Convert the element size from logical pixels to physical pixels. | |
768 normal_height = LogicalPixelsToPhysicalPixels(element_height); | |
769 normal_width = LogicalPixelsToPhysicalPixels(element_width); | |
770 } else { | |
771 normal_height = lround(element_height); | |
772 normal_width = lround(element_width); | |
773 } | |
774 | |
775 SetSizeParams set_size_params; | |
776 set_size_params.enable_auto_size.reset(new bool(auto_size_enabled)); | |
777 set_size_params.min_size.reset(new gfx::Size(min_width, min_height)); | |
778 set_size_params.max_size.reset(new gfx::Size(max_width, max_height)); | |
779 set_size_params.normal_size.reset(new gfx::Size(normal_width, normal_height)); | |
780 | |
781 // Call SetSize to apply all the appropriate validation and clipping of | |
782 // values. | |
783 SetSize(set_size_params); | |
784 } | |
785 | |
786 void GuestViewBase::SetGuestZoomLevelToMatchEmbedder() { | |
787 auto embedder_zoom_controller = | |
788 ui_zoom::ZoomController::FromWebContents(owner_web_contents()); | |
789 if (!embedder_zoom_controller) | |
790 return; | |
791 | |
792 ui_zoom::ZoomController::FromWebContents(web_contents()) | |
793 ->SetZoomLevel(embedder_zoom_controller->GetZoomLevel()); | |
794 } | |
795 | |
796 void GuestViewBase::StartTrackingEmbedderZoomLevel() { | |
797 if (!ZoomPropagatesFromEmbedderToGuest()) | |
798 return; | |
799 | |
800 auto embedder_zoom_controller = | |
801 ui_zoom::ZoomController::FromWebContents(owner_web_contents()); | |
802 // Chrome Apps do not have a ZoomController. | |
803 if (!embedder_zoom_controller) | |
804 return; | |
805 // Listen to the embedder's zoom changes. | |
806 embedder_zoom_controller->AddObserver(this); | |
807 | |
808 // Set the guest's initial zoom level to be equal to the embedder's. | |
809 SetGuestZoomLevelToMatchEmbedder(); | |
810 } | |
811 | |
812 void GuestViewBase::StopTrackingEmbedderZoomLevel() { | |
813 if (!attached() || !ZoomPropagatesFromEmbedderToGuest()) | |
814 return; | |
815 | |
816 auto embedder_zoom_controller = | |
817 ui_zoom::ZoomController::FromWebContents(owner_web_contents()); | |
818 // Chrome Apps do not have a ZoomController. | |
819 if (!embedder_zoom_controller) | |
820 return; | |
821 embedder_zoom_controller->RemoveObserver(this); | |
822 } | |
823 | |
824 } // namespace extensions | |
OLD | NEW |