cc: Make picture pile base thread safe.
[chromium-blink-merge.git] / content / browser / frame_host / render_widget_host_view_guest.cc
bloba5839e2b82d01313b4ee4306aa278f0bc3270c6d
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 "base/bind_helpers.h"
6 #include "base/command_line.h"
7 #include "base/logging.h"
8 #include "base/message_loop/message_loop.h"
9 #include "content/browser/browser_plugin/browser_plugin_guest.h"
10 #include "content/browser/frame_host/render_widget_host_view_guest.h"
11 #include "content/browser/renderer_host/render_view_host_impl.h"
12 #include "content/common/browser_plugin/browser_plugin_messages.h"
13 #include "content/common/frame_messages.h"
14 #include "content/common/gpu/gpu_messages.h"
15 #include "content/common/input/web_touch_event_traits.h"
16 #include "content/common/view_messages.h"
17 #include "content/common/webplugin_geometry.h"
18 #include "content/public/common/content_switches.h"
19 #include "skia/ext/platform_canvas.h"
20 #include "third_party/WebKit/public/platform/WebScreenInfo.h"
22 #if defined(OS_MACOSX)
23 #import "content/browser/renderer_host/render_widget_host_view_mac_dictionary_helper.h"
24 #endif
26 #if defined(USE_AURA)
27 #include "content/browser/renderer_host/ui_events_helper.h"
28 #endif
30 namespace content {
32 namespace {
34 #if defined(USE_AURA)
35 blink::WebGestureEvent CreateFlingCancelEvent(double time_stamp) {
36 blink::WebGestureEvent gesture_event;
37 gesture_event.timeStampSeconds = time_stamp;
38 gesture_event.type = blink::WebGestureEvent::GestureFlingCancel;
39 gesture_event.sourceDevice = blink::WebGestureDeviceTouchscreen;
40 return gesture_event;
42 #endif // defined(USE_AURA)
44 } // namespace
46 RenderWidgetHostViewGuest::RenderWidgetHostViewGuest(
47 RenderWidgetHost* widget_host,
48 BrowserPluginGuest* guest,
49 base::WeakPtr<RenderWidgetHostViewBase> platform_view)
50 : RenderWidgetHostViewChildFrame(widget_host),
51 // |guest| is NULL during test.
52 guest_(guest ? guest->AsWeakPtr() : base::WeakPtr<BrowserPluginGuest>()),
53 platform_view_(platform_view) {
54 #if defined(USE_AURA)
55 gesture_recognizer_.reset(ui::GestureRecognizer::Create());
56 gesture_recognizer_->AddGestureEventHelper(this);
57 #endif // defined(USE_AURA)
60 RenderWidgetHostViewGuest::~RenderWidgetHostViewGuest() {
61 #if defined(USE_AURA)
62 gesture_recognizer_->RemoveGestureEventHelper(this);
63 #endif // defined(USE_AURA)
66 bool RenderWidgetHostViewGuest::OnMessageReceivedFromEmbedder(
67 const IPC::Message& message,
68 RenderWidgetHostImpl* embedder) {
69 bool handled = true;
70 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(RenderWidgetHostViewGuest, message,
71 embedder)
72 IPC_MESSAGE_HANDLER(BrowserPluginHostMsg_HandleInputEvent,
73 OnHandleInputEvent)
74 IPC_MESSAGE_UNHANDLED(handled = false)
75 IPC_END_MESSAGE_MAP()
76 return handled;
79 void RenderWidgetHostViewGuest::WasShown() {
80 // If the WebContents associated with us showed an interstitial page in the
81 // beginning, the teardown path might call WasShown() while |host_| is in
82 // the process of destruction. Avoid calling WasShown below in this case.
83 // TODO(lazyboy): We shouldn't be showing interstitial pages in guests in the
84 // first place: http://crbug.com/273089.
86 // |guest_| is NULL during test.
87 if ((guest_ && guest_->is_in_destruction()) || !host_->is_hidden())
88 return;
89 // Make sure the size of this view matches the size of the WebContentsView.
90 // The two sizes may fall out of sync if we switch RenderWidgetHostViews,
91 // resize, and then switch page, as is the case with interstitial pages.
92 // NOTE: |guest_| is NULL in unit tests.
93 if (guest_)
94 SetSize(guest_->web_contents()->GetViewBounds().size());
95 host_->WasShown(ui::LatencyInfo());
98 void RenderWidgetHostViewGuest::WasHidden() {
99 // |guest_| is NULL during test.
100 if ((guest_ && guest_->is_in_destruction()) || host_->is_hidden())
101 return;
102 host_->WasHidden();
105 void RenderWidgetHostViewGuest::SetSize(const gfx::Size& size) {
106 size_ = size;
107 host_->WasResized();
110 void RenderWidgetHostViewGuest::SetBounds(const gfx::Rect& rect) {
111 SetSize(rect.size());
114 void RenderWidgetHostViewGuest::Focus() {
115 // InterstitialPageImpl focuses views directly, so we place focus logic here.
116 // InterstitialPages are not WebContents, and so BrowserPluginGuest does not
117 // have direct access to the interstitial page's RenderWidgetHost.
118 if (guest_)
119 guest_->SetFocus(host_, true);
122 bool RenderWidgetHostViewGuest::HasFocus() const {
123 if (!guest_)
124 return false;
125 return guest_->focused();
128 #if defined(USE_AURA)
129 void RenderWidgetHostViewGuest::ProcessAckedTouchEvent(
130 const TouchEventWithLatencyInfo& touch, InputEventAckState ack_result) {
131 // TODO(fsamuel): Currently we will only take this codepath if the guest has
132 // requested touch events. A better solution is to always forward touchpresses
133 // to the embedder process to target a BrowserPlugin, and then route all
134 // subsequent touch points of that touchdown to the appropriate guest until
135 // that touch point is released.
136 ScopedVector<ui::TouchEvent> events;
137 if (!MakeUITouchEventsFromWebTouchEvents(touch, &events, LOCAL_COORDINATES))
138 return;
140 ui::EventResult result = (ack_result ==
141 INPUT_EVENT_ACK_STATE_CONSUMED) ? ui::ER_HANDLED : ui::ER_UNHANDLED;
142 for (ScopedVector<ui::TouchEvent>::iterator iter = events.begin(),
143 end = events.end(); iter != end; ++iter) {
144 if (!gesture_recognizer_->ProcessTouchEventPreDispatch(*(*iter), this))
145 continue;
147 scoped_ptr<ui::GestureRecognizer::Gestures> gestures;
148 gestures.reset(gesture_recognizer_->ProcessTouchEventPostDispatch(
149 *(*iter), result, this));
150 ProcessGestures(gestures.get());
153 #endif
155 gfx::Rect RenderWidgetHostViewGuest::GetViewBounds() const {
156 if (!guest_)
157 return gfx::Rect();
159 RenderWidgetHostViewBase* rwhv = GetGuestRenderWidgetHostView();
160 gfx::Rect embedder_bounds;
161 if (rwhv)
162 embedder_bounds = rwhv->GetViewBounds();
163 return gfx::Rect(
164 guest_->GetScreenCoordinates(embedder_bounds.origin()), size_);
167 void RenderWidgetHostViewGuest::RenderProcessGone(
168 base::TerminationStatus status,
169 int error_code) {
170 platform_view_->RenderProcessGone(status, error_code);
171 // Destroy the guest view instance only, so we don't end up calling
172 // platform_view_->Destroy().
173 DestroyGuestView();
176 void RenderWidgetHostViewGuest::Destroy() {
177 // The RenderWidgetHost's destruction led here, so don't call it.
178 DestroyGuestView();
180 if (platform_view_) // The platform view might have been destroyed already.
181 platform_view_->Destroy();
184 gfx::Size RenderWidgetHostViewGuest::GetPhysicalBackingSize() const {
185 return RenderWidgetHostViewBase::GetPhysicalBackingSize();
188 base::string16 RenderWidgetHostViewGuest::GetSelectedText() const {
189 return platform_view_->GetSelectedText();
192 void RenderWidgetHostViewGuest::SetTooltipText(
193 const base::string16& tooltip_text) {
194 if (guest_)
195 guest_->SetTooltipText(tooltip_text);
198 void RenderWidgetHostViewGuest::OnSwapCompositorFrame(
199 uint32 output_surface_id,
200 scoped_ptr<cc::CompositorFrame> frame) {
201 if (!guest_)
202 return;
204 last_scroll_offset_ = frame->metadata.root_scroll_offset;
205 guest_->SwapCompositorFrame(output_surface_id,
206 host_->GetProcess()->GetID(),
207 host_->GetRoutingID(),
208 frame.Pass());
211 bool RenderWidgetHostViewGuest::OnMessageReceived(const IPC::Message& msg) {
212 return platform_view_->OnMessageReceived(msg);
215 void RenderWidgetHostViewGuest::InitAsChild(
216 gfx::NativeView parent_view) {
217 platform_view_->InitAsChild(parent_view);
220 void RenderWidgetHostViewGuest::InitAsPopup(
221 RenderWidgetHostView* parent_host_view, const gfx::Rect& pos) {
222 // This should never get called.
223 NOTREACHED();
226 void RenderWidgetHostViewGuest::InitAsFullscreen(
227 RenderWidgetHostView* reference_host_view) {
228 // This should never get called.
229 NOTREACHED();
232 gfx::NativeView RenderWidgetHostViewGuest::GetNativeView() const {
233 if (!guest_)
234 return gfx::NativeView();
236 RenderWidgetHostView* rwhv = guest_->GetEmbedderRenderWidgetHostView();
237 if (!rwhv)
238 return gfx::NativeView();
239 return rwhv->GetNativeView();
242 gfx::NativeViewId RenderWidgetHostViewGuest::GetNativeViewId() const {
243 if (!guest_)
244 return static_cast<gfx::NativeViewId>(NULL);
246 RenderWidgetHostView* rwhv = guest_->GetEmbedderRenderWidgetHostView();
247 if (!rwhv)
248 return static_cast<gfx::NativeViewId>(NULL);
249 return rwhv->GetNativeViewId();
252 gfx::NativeViewAccessible RenderWidgetHostViewGuest::GetNativeViewAccessible() {
253 if (!guest_)
254 return gfx::NativeViewAccessible();
256 RenderWidgetHostView* rwhv = guest_->GetEmbedderRenderWidgetHostView();
257 if (!rwhv)
258 return gfx::NativeViewAccessible();
259 return rwhv->GetNativeViewAccessible();
262 void RenderWidgetHostViewGuest::MovePluginWindows(
263 const std::vector<WebPluginGeometry>& moves) {
264 platform_view_->MovePluginWindows(moves);
267 void RenderWidgetHostViewGuest::UpdateCursor(const WebCursor& cursor) {
268 // InterstitialPages are not WebContents so we cannot intercept
269 // ViewHostMsg_SetCursor for interstitial pages in BrowserPluginGuest.
270 // All guest RenderViewHosts have RenderWidgetHostViewGuests however,
271 // and so we will always hit this code path.
272 if (!guest_)
273 return;
274 guest_->SendMessageToEmbedder(
275 new BrowserPluginMsg_SetCursor(guest_->browser_plugin_instance_id(),
276 cursor));
280 void RenderWidgetHostViewGuest::SetIsLoading(bool is_loading) {
281 platform_view_->SetIsLoading(is_loading);
284 void RenderWidgetHostViewGuest::TextInputTypeChanged(
285 ui::TextInputType type,
286 ui::TextInputMode input_mode,
287 bool can_compose_inline,
288 int flags) {
289 if (!guest_)
290 return;
292 RenderWidgetHostViewBase* rwhv = GetGuestRenderWidgetHostView();
293 if (!rwhv)
294 return;
295 // Forward the information to embedding RWHV.
296 rwhv->TextInputTypeChanged(type, input_mode, can_compose_inline, flags);
299 void RenderWidgetHostViewGuest::ImeCancelComposition() {
300 if (!guest_)
301 return;
303 RenderWidgetHostViewBase* rwhv = GetGuestRenderWidgetHostView();
304 if (!rwhv)
305 return;
306 // Forward the information to embedding RWHV.
307 rwhv->ImeCancelComposition();
310 #if defined(OS_MACOSX) || defined(USE_AURA)
311 void RenderWidgetHostViewGuest::ImeCompositionRangeChanged(
312 const gfx::Range& range,
313 const std::vector<gfx::Rect>& character_bounds) {
314 if (!guest_)
315 return;
317 RenderWidgetHostViewBase* rwhv = GetGuestRenderWidgetHostView();
318 if (!rwhv)
319 return;
320 std::vector<gfx::Rect> guest_character_bounds;
321 for (size_t i = 0; i < character_bounds.size(); ++i) {
322 guest_character_bounds.push_back(gfx::Rect(
323 guest_->GetScreenCoordinates(character_bounds[i].origin()),
324 character_bounds[i].size()));
326 // Forward the information to embedding RWHV.
327 rwhv->ImeCompositionRangeChanged(range, guest_character_bounds);
329 #endif
331 void RenderWidgetHostViewGuest::SelectionChanged(const base::string16& text,
332 size_t offset,
333 const gfx::Range& range) {
334 platform_view_->SelectionChanged(text, offset, range);
337 void RenderWidgetHostViewGuest::SelectionBoundsChanged(
338 const ViewHostMsg_SelectionBounds_Params& params) {
339 if (!guest_)
340 return;
342 RenderWidgetHostViewBase* rwhv = GetGuestRenderWidgetHostView();
343 if (!rwhv)
344 return;
345 ViewHostMsg_SelectionBounds_Params guest_params(params);
346 guest_params.anchor_rect.set_origin(
347 guest_->GetScreenCoordinates(params.anchor_rect.origin()));
348 guest_params.focus_rect.set_origin(
349 guest_->GetScreenCoordinates(params.focus_rect.origin()));
350 rwhv->SelectionBoundsChanged(guest_params);
353 void RenderWidgetHostViewGuest::CopyFromCompositingSurface(
354 const gfx::Rect& src_subrect,
355 const gfx::Size& dst_size,
356 CopyFromCompositingSurfaceCallback& callback,
357 const SkColorType color_type) {
358 CHECK(guest_);
359 guest_->CopyFromCompositingSurface(src_subrect, dst_size, callback);
362 void RenderWidgetHostViewGuest::SetBackgroundColor(SkColor color) {
363 // Content embedders can toggle opaque backgrounds through this API.
364 // We plumb the value here so that BrowserPlugin updates its compositing
365 // state in response to this change. We also want to preserve this flag
366 // after recovering from a crash so we let BrowserPluginGuest store it.
367 if (!guest_)
368 return;
369 RenderWidgetHostViewBase::SetBackgroundColor(color);
370 bool opaque = GetBackgroundOpaque();
371 host_->SetBackgroundOpaque(opaque);
372 guest_->SetContentsOpaque(opaque);
375 bool RenderWidgetHostViewGuest::LockMouse() {
376 return platform_view_->LockMouse();
379 void RenderWidgetHostViewGuest::UnlockMouse() {
380 return platform_view_->UnlockMouse();
383 void RenderWidgetHostViewGuest::GetScreenInfo(blink::WebScreenInfo* results) {
384 if (!guest_)
385 return;
386 RenderWidgetHostViewBase* embedder_view = GetGuestRenderWidgetHostView();
387 if (embedder_view)
388 embedder_view->GetScreenInfo(results);
391 #if defined(OS_MACOSX)
392 void RenderWidgetHostViewGuest::SetActive(bool active) {
393 platform_view_->SetActive(active);
396 void RenderWidgetHostViewGuest::SetWindowVisibility(bool visible) {
397 platform_view_->SetWindowVisibility(visible);
400 void RenderWidgetHostViewGuest::WindowFrameChanged() {
401 platform_view_->WindowFrameChanged();
404 void RenderWidgetHostViewGuest::ShowDefinitionForSelection() {
405 if (!guest_)
406 return;
408 gfx::Point origin;
409 gfx::Rect guest_bounds = GetViewBounds();
410 RenderWidgetHostView* rwhv = guest_->GetEmbedderRenderWidgetHostView();
411 gfx::Rect embedder_bounds;
412 if (rwhv)
413 embedder_bounds = rwhv->GetViewBounds();
415 gfx::Vector2d guest_offset = gfx::Vector2d(
416 // Horizontal offset of guest from embedder.
417 guest_bounds.x() - embedder_bounds.x(),
418 // Vertical offset from guest's top to embedder's bottom edge.
419 embedder_bounds.bottom() - guest_bounds.y());
421 RenderWidgetHostViewMacDictionaryHelper helper(platform_view_.get());
422 helper.SetTargetView(rwhv);
423 helper.set_offset(guest_offset);
424 helper.ShowDefinitionForSelection();
427 bool RenderWidgetHostViewGuest::SupportsSpeech() const {
428 return platform_view_->SupportsSpeech();
431 void RenderWidgetHostViewGuest::SpeakSelection() {
432 platform_view_->SpeakSelection();
435 bool RenderWidgetHostViewGuest::IsSpeaking() const {
436 return platform_view_->IsSpeaking();
439 void RenderWidgetHostViewGuest::StopSpeaking() {
440 platform_view_->StopSpeaking();
443 bool RenderWidgetHostViewGuest::PostProcessEventForPluginIme(
444 const NativeWebKeyboardEvent& event) {
445 return false;
448 #endif // defined(OS_MACOSX)
450 #if defined(OS_ANDROID) || defined(TOOLKIT_VIEWS)
451 void RenderWidgetHostViewGuest::ShowDisambiguationPopup(
452 const gfx::Rect& rect_pixels,
453 const SkBitmap& zoomed_bitmap) {
455 #endif // defined(OS_ANDROID) || defined(TOOLKIT_VIEWS)
457 #if defined(OS_ANDROID)
458 void RenderWidgetHostViewGuest::LockCompositingSurface() {
461 void RenderWidgetHostViewGuest::UnlockCompositingSurface() {
463 #endif // defined(OS_ANDROID)
465 #if defined(OS_WIN)
466 void RenderWidgetHostViewGuest::SetParentNativeViewAccessible(
467 gfx::NativeViewAccessible accessible_parent) {
470 gfx::NativeViewId RenderWidgetHostViewGuest::GetParentForWindowlessPlugin()
471 const {
472 return NULL;
474 #endif
476 void RenderWidgetHostViewGuest::DestroyGuestView() {
477 host_->SetView(NULL);
478 host_ = NULL;
479 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
482 bool RenderWidgetHostViewGuest::CanDispatchToConsumer(
483 ui::GestureConsumer* consumer) {
484 CHECK_EQ(static_cast<RenderWidgetHostViewGuest*>(consumer), this);
485 return true;
488 void RenderWidgetHostViewGuest::DispatchGestureEvent(
489 ui::GestureEvent* event) {
490 ForwardGestureEventToRenderer(event);
493 void RenderWidgetHostViewGuest::DispatchCancelTouchEvent(
494 ui::TouchEvent* event) {
495 if (!host_)
496 return;
498 blink::WebTouchEvent cancel_event;
499 // TODO(rbyers): This event has no touches in it. Don't we need to know what
500 // touches are currently active in order to cancel them all properly?
501 WebTouchEventTraits::ResetType(blink::WebInputEvent::TouchCancel,
502 event->time_stamp().InSecondsF(),
503 &cancel_event);
505 host_->ForwardTouchEventWithLatencyInfo(cancel_event, *event->latency());
508 bool RenderWidgetHostViewGuest::ForwardGestureEventToRenderer(
509 ui::GestureEvent* gesture) {
510 #if defined(USE_AURA)
511 if (!host_)
512 return false;
514 if ((gesture->type() == ui::ET_GESTURE_PINCH_BEGIN ||
515 gesture->type() == ui::ET_GESTURE_PINCH_UPDATE ||
516 gesture->type() == ui::ET_GESTURE_PINCH_END) && !pinch_zoom_enabled_) {
517 return true;
520 blink::WebGestureEvent web_gesture =
521 MakeWebGestureEventFromUIEvent(*gesture);
522 const gfx::Point& client_point = gesture->location();
523 const gfx::Point& screen_point = gesture->location();
525 web_gesture.x = client_point.x();
526 web_gesture.y = client_point.y();
527 web_gesture.globalX = screen_point.x();
528 web_gesture.globalY = screen_point.y();
530 if (web_gesture.type == blink::WebGestureEvent::Undefined)
531 return false;
532 if (web_gesture.type == blink::WebGestureEvent::GestureTapDown) {
533 host_->ForwardGestureEvent(
534 CreateFlingCancelEvent(gesture->time_stamp().InSecondsF()));
536 host_->ForwardGestureEvent(web_gesture);
537 return true;
538 #else
539 return false;
540 #endif
543 void RenderWidgetHostViewGuest::ProcessGestures(
544 ui::GestureRecognizer::Gestures* gestures) {
545 if ((gestures == NULL) || gestures->empty())
546 return;
547 for (ui::GestureRecognizer::Gestures::iterator g_it = gestures->begin();
548 g_it != gestures->end();
549 ++g_it) {
550 ForwardGestureEventToRenderer(*g_it);
554 SkColorType RenderWidgetHostViewGuest::PreferredReadbackFormat() {
555 return kN32_SkColorType;
558 RenderWidgetHostViewBase*
559 RenderWidgetHostViewGuest::GetGuestRenderWidgetHostView() const {
560 return static_cast<RenderWidgetHostViewBase*>(
561 guest_->GetEmbedderRenderWidgetHostView());
564 void RenderWidgetHostViewGuest::OnHandleInputEvent(
565 RenderWidgetHostImpl* embedder,
566 int browser_plugin_instance_id,
567 const gfx::Rect& guest_window_rect,
568 const blink::WebInputEvent* event) {
569 if (blink::WebInputEvent::isMouseEventType(event->type)) {
570 host_->ForwardMouseEvent(
571 *static_cast<const blink::WebMouseEvent*>(event));
572 return;
575 if (event->type == blink::WebInputEvent::MouseWheel) {
576 host_->ForwardWheelEvent(
577 *static_cast<const blink::WebMouseWheelEvent*>(event));
578 return;
581 if (blink::WebInputEvent::isKeyboardEventType(event->type)) {
582 if (!embedder->GetLastKeyboardEvent())
583 return;
584 NativeWebKeyboardEvent keyboard_event(*embedder->GetLastKeyboardEvent());
585 host_->ForwardKeyboardEvent(keyboard_event);
586 return;
589 if (blink::WebInputEvent::isTouchEventType(event->type)) {
590 host_->ForwardTouchEventWithLatencyInfo(
591 *static_cast<const blink::WebTouchEvent*>(event),
592 ui::LatencyInfo());
593 return;
596 if (blink::WebInputEvent::isGestureEventType(event->type)) {
597 host_->ForwardGestureEvent(
598 *static_cast<const blink::WebGestureEvent*>(event));
599 return;
603 } // namespace content