render_widget_host_view_guest.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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 "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" 21 22#if defined(OS_MACOSX) 23#import "content/browser/renderer_host/render_widget_host_view_mac_dictionary_helper.h" 24#endif 25 26#if defined(USE_AURA) 27#include "content/browser/renderer_host/ui_events_helper.h" 28#endif 29 30namespace content { 31 32namespace { 33 34#if defined(USE_AURA) 35blink::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; 41} 42#endif // defined(USE_AURA) 43 44} // namespace 45 46RenderWidgetHostViewGuest::RenderWidgetHostViewGuest( 47 RenderWidgetHost* widget_host, 48 BrowserPluginGuest* guest, 49 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) 58} 59 60RenderWidgetHostViewGuest::~RenderWidgetHostViewGuest() { 61#if defined(USE_AURA) 62 gesture_recognizer_->RemoveGestureEventHelper(this); 63#endif // defined(USE_AURA) 64} 65 66bool 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; 77} 78 79void 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. 85 // 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()); 96} 97 98void RenderWidgetHostViewGuest::WasHidden() { 99 // |guest_| is NULL during test. 100 if ((guest_ && guest_->is_in_destruction()) || host_->is_hidden()) 101 return; 102 host_->WasHidden(); 103} 104 105void RenderWidgetHostViewGuest::SetSize(const gfx::Size& size) { 106 size_ = size; 107 host_->WasResized(); 108} 109 110void RenderWidgetHostViewGuest::SetBounds(const gfx::Rect& rect) { 111 SetSize(rect.size()); 112} 113 114void 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); 120} 121 122bool RenderWidgetHostViewGuest::HasFocus() const { 123 if (!guest_) 124 return false; 125 return guest_->focused(); 126} 127 128#if defined(USE_AURA) 129void 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; 139 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; 146 147 scoped_ptr<ui::GestureRecognizer::Gestures> gestures; 148 gestures.reset(gesture_recognizer_->ProcessTouchEventPostDispatch( 149 *(*iter), result, this)); 150 ProcessGestures(gestures.get()); 151 } 152} 153#endif 154 155gfx::Rect RenderWidgetHostViewGuest::GetViewBounds() const { 156 if (!guest_) 157 return gfx::Rect(); 158 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_); 165} 166 167void 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(); 174} 175 176void RenderWidgetHostViewGuest::Destroy() { 177 // The RenderWidgetHost's destruction led here, so don't call it. 178 DestroyGuestView(); 179 180 platform_view_->Destroy(); 181} 182 183gfx::Size RenderWidgetHostViewGuest::GetPhysicalBackingSize() const { 184 return RenderWidgetHostViewBase::GetPhysicalBackingSize(); 185} 186 187base::string16 RenderWidgetHostViewGuest::GetSelectedText() const { 188 return platform_view_->GetSelectedText(); 189} 190 191void RenderWidgetHostViewGuest::SetTooltipText( 192 const base::string16& tooltip_text) { 193 platform_view_->SetTooltipText(tooltip_text); 194} 195 196void RenderWidgetHostViewGuest::AcceleratedSurfaceBuffersSwapped( 197 const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params, 198 int gpu_host_id) { 199 NOTREACHED(); 200} 201 202void RenderWidgetHostViewGuest::AcceleratedSurfacePostSubBuffer( 203 const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params, 204 int gpu_host_id) { 205 NOTREACHED(); 206} 207 208void RenderWidgetHostViewGuest::OnSwapCompositorFrame( 209 uint32 output_surface_id, 210 scoped_ptr<cc::CompositorFrame> frame) { 211 if (!guest_) 212 return; 213 214 last_scroll_offset_ = frame->metadata.root_scroll_offset; 215 guest_->SwapCompositorFrame(output_surface_id, 216 host_->GetProcess()->GetID(), 217 host_->GetRoutingID(), 218 frame.Pass()); 219} 220 221bool RenderWidgetHostViewGuest::OnMessageReceived(const IPC::Message& msg) { 222 return platform_view_->OnMessageReceived(msg); 223} 224 225void RenderWidgetHostViewGuest::InitAsChild( 226 gfx::NativeView parent_view) { 227 platform_view_->InitAsChild(parent_view); 228} 229 230void RenderWidgetHostViewGuest::InitAsPopup( 231 RenderWidgetHostView* parent_host_view, const gfx::Rect& pos) { 232 // This should never get called. 233 NOTREACHED(); 234} 235 236void RenderWidgetHostViewGuest::InitAsFullscreen( 237 RenderWidgetHostView* reference_host_view) { 238 // This should never get called. 239 NOTREACHED(); 240} 241 242gfx::NativeView RenderWidgetHostViewGuest::GetNativeView() const { 243 if (!guest_) 244 return gfx::NativeView(); 245 246 RenderWidgetHostView* rwhv = guest_->GetEmbedderRenderWidgetHostView(); 247 if (!rwhv) 248 return gfx::NativeView(); 249 return rwhv->GetNativeView(); 250} 251 252gfx::NativeViewId RenderWidgetHostViewGuest::GetNativeViewId() const { 253 if (!guest_) 254 return static_cast<gfx::NativeViewId>(NULL); 255 256 RenderWidgetHostView* rwhv = guest_->GetEmbedderRenderWidgetHostView(); 257 if (!rwhv) 258 return static_cast<gfx::NativeViewId>(NULL); 259 return rwhv->GetNativeViewId(); 260} 261 262gfx::NativeViewAccessible RenderWidgetHostViewGuest::GetNativeViewAccessible() { 263 if (!guest_) 264 return gfx::NativeViewAccessible(); 265 266 RenderWidgetHostView* rwhv = guest_->GetEmbedderRenderWidgetHostView(); 267 if (!rwhv) 268 return gfx::NativeViewAccessible(); 269 return rwhv->GetNativeViewAccessible(); 270} 271 272void RenderWidgetHostViewGuest::MovePluginWindows( 273 const std::vector<WebPluginGeometry>& moves) { 274 platform_view_->MovePluginWindows(moves); 275} 276 277void RenderWidgetHostViewGuest::UpdateCursor(const WebCursor& cursor) { 278 // InterstitialPages are not WebContents so we cannot intercept 279 // ViewHostMsg_SetCursor for interstitial pages in BrowserPluginGuest. 280 // All guest RenderViewHosts have RenderWidgetHostViewGuests however, 281 // and so we will always hit this code path. 282 if (!guest_) 283 return; 284 guest_->SendMessageToEmbedder( 285 new BrowserPluginMsg_SetCursor(guest_->browser_plugin_instance_id(), 286 cursor)); 287 288} 289 290void RenderWidgetHostViewGuest::SetIsLoading(bool is_loading) { 291 platform_view_->SetIsLoading(is_loading); 292} 293 294void RenderWidgetHostViewGuest::TextInputStateChanged( 295 const ViewHostMsg_TextInputState_Params& params) { 296 if (!guest_) 297 return; 298 299 RenderWidgetHostViewBase* rwhv = GetGuestRenderWidgetHostView(); 300 if (!rwhv) 301 return; 302 // Forward the information to embedding RWHV. 303 rwhv->TextInputStateChanged(params); 304} 305 306void RenderWidgetHostViewGuest::ImeCancelComposition() { 307 if (!guest_) 308 return; 309 310 RenderWidgetHostViewBase* rwhv = GetGuestRenderWidgetHostView(); 311 if (!rwhv) 312 return; 313 // Forward the information to embedding RWHV. 314 rwhv->ImeCancelComposition(); 315} 316 317#if defined(OS_MACOSX) || defined(USE_AURA) 318void RenderWidgetHostViewGuest::ImeCompositionRangeChanged( 319 const gfx::Range& range, 320 const std::vector<gfx::Rect>& character_bounds) { 321 if (!guest_) 322 return; 323 324 RenderWidgetHostViewBase* rwhv = GetGuestRenderWidgetHostView(); 325 if (!rwhv) 326 return; 327 std::vector<gfx::Rect> guest_character_bounds; 328 for (size_t i = 0; i < character_bounds.size(); ++i) { 329 guest_character_bounds.push_back(gfx::Rect( 330 guest_->GetScreenCoordinates(character_bounds[i].origin()), 331 character_bounds[i].size())); 332 } 333 // Forward the information to embedding RWHV. 334 rwhv->ImeCompositionRangeChanged(range, guest_character_bounds); 335} 336#endif 337 338void RenderWidgetHostViewGuest::SelectionChanged(const base::string16& text, 339 size_t offset, 340 const gfx::Range& range) { 341 platform_view_->SelectionChanged(text, offset, range); 342} 343 344void RenderWidgetHostViewGuest::SelectionBoundsChanged( 345 const ViewHostMsg_SelectionBounds_Params& params) { 346 if (!guest_) 347 return; 348 349 RenderWidgetHostViewBase* rwhv = GetGuestRenderWidgetHostView(); 350 if (!rwhv) 351 return; 352 ViewHostMsg_SelectionBounds_Params guest_params(params); 353 guest_params.anchor_rect.set_origin( 354 guest_->GetScreenCoordinates(params.anchor_rect.origin())); 355 guest_params.focus_rect.set_origin( 356 guest_->GetScreenCoordinates(params.focus_rect.origin())); 357 rwhv->SelectionBoundsChanged(guest_params); 358} 359 360void RenderWidgetHostViewGuest::CopyFromCompositingSurface( 361 const gfx::Rect& src_subrect, 362 const gfx::Size& dst_size, 363 CopyFromCompositingSurfaceCallback& callback, 364 const SkColorType color_type) { 365 CHECK(guest_); 366 guest_->CopyFromCompositingSurface(src_subrect, dst_size, callback); 367} 368 369void RenderWidgetHostViewGuest::SetBackgroundOpaque(bool opaque) { 370 // Content embedders can toggle opaque backgrounds through this API. 371 // We plumb the value here so that BrowserPlugin updates its compositing 372 // state in response to this change. We also want to preserve this flag 373 // after recovering from a crash so we let BrowserPluginGuest store it. 374 if (!guest_) 375 return; 376 RenderWidgetHostViewBase::SetBackgroundOpaque(opaque); 377 host_->SetBackgroundOpaque(opaque); 378 guest_->SetContentsOpaque(opaque); 379} 380 381bool RenderWidgetHostViewGuest::LockMouse() { 382 return platform_view_->LockMouse(); 383} 384 385void RenderWidgetHostViewGuest::UnlockMouse() { 386 return platform_view_->UnlockMouse(); 387} 388 389void RenderWidgetHostViewGuest::GetScreenInfo(blink::WebScreenInfo* results) { 390 if (!guest_) 391 return; 392 RenderWidgetHostViewBase* embedder_view = GetGuestRenderWidgetHostView(); 393 if (embedder_view) 394 embedder_view->GetScreenInfo(results); 395} 396 397#if defined(OS_MACOSX) 398void RenderWidgetHostViewGuest::SetActive(bool active) { 399 platform_view_->SetActive(active); 400} 401 402void RenderWidgetHostViewGuest::SetTakesFocusOnlyOnMouseDown(bool flag) { 403 platform_view_->SetTakesFocusOnlyOnMouseDown(flag); 404} 405 406void RenderWidgetHostViewGuest::SetWindowVisibility(bool visible) { 407 platform_view_->SetWindowVisibility(visible); 408} 409 410void RenderWidgetHostViewGuest::WindowFrameChanged() { 411 platform_view_->WindowFrameChanged(); 412} 413 414void RenderWidgetHostViewGuest::ShowDefinitionForSelection() { 415 if (!guest_) 416 return; 417 418 gfx::Point origin; 419 gfx::Rect guest_bounds = GetViewBounds(); 420 RenderWidgetHostView* rwhv = guest_->GetEmbedderRenderWidgetHostView(); 421 gfx::Rect embedder_bounds; 422 if (rwhv) 423 embedder_bounds = rwhv->GetViewBounds(); 424 425 gfx::Vector2d guest_offset = gfx::Vector2d( 426 // Horizontal offset of guest from embedder. 427 guest_bounds.x() - embedder_bounds.x(), 428 // Vertical offset from guest's top to embedder's bottom edge. 429 embedder_bounds.bottom() - guest_bounds.y()); 430 431 RenderWidgetHostViewMacDictionaryHelper helper(platform_view_); 432 helper.SetTargetView(rwhv); 433 helper.set_offset(guest_offset); 434 helper.ShowDefinitionForSelection(); 435} 436 437bool RenderWidgetHostViewGuest::SupportsSpeech() const { 438 return platform_view_->SupportsSpeech(); 439} 440 441void RenderWidgetHostViewGuest::SpeakSelection() { 442 platform_view_->SpeakSelection(); 443} 444 445bool RenderWidgetHostViewGuest::IsSpeaking() const { 446 return platform_view_->IsSpeaking(); 447} 448 449void RenderWidgetHostViewGuest::StopSpeaking() { 450 platform_view_->StopSpeaking(); 451} 452 453bool RenderWidgetHostViewGuest::PostProcessEventForPluginIme( 454 const NativeWebKeyboardEvent& event) { 455 return false; 456} 457 458#endif // defined(OS_MACOSX) 459 460#if defined(OS_ANDROID) || defined(TOOLKIT_VIEWS) 461void RenderWidgetHostViewGuest::ShowDisambiguationPopup( 462 const gfx::Rect& rect_pixels, 463 const SkBitmap& zoomed_bitmap) { 464} 465#endif // defined(OS_ANDROID) || defined(TOOLKIT_VIEWS) 466 467#if defined(OS_ANDROID) 468void RenderWidgetHostViewGuest::LockCompositingSurface() { 469} 470 471void RenderWidgetHostViewGuest::UnlockCompositingSurface() { 472} 473#endif // defined(OS_ANDROID) 474 475#if defined(OS_WIN) 476void RenderWidgetHostViewGuest::SetParentNativeViewAccessible( 477 gfx::NativeViewAccessible accessible_parent) { 478} 479 480gfx::NativeViewId RenderWidgetHostViewGuest::GetParentForWindowlessPlugin() 481 const { 482 return NULL; 483} 484#endif 485 486void RenderWidgetHostViewGuest::DestroyGuestView() { 487 host_->SetView(NULL); 488 host_ = NULL; 489 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); 490} 491 492bool RenderWidgetHostViewGuest::CanDispatchToConsumer( 493 ui::GestureConsumer* consumer) { 494 CHECK_EQ(static_cast<RenderWidgetHostViewGuest*>(consumer), this); 495 return true; 496} 497 498void RenderWidgetHostViewGuest::DispatchGestureEvent( 499 ui::GestureEvent* event) { 500 ForwardGestureEventToRenderer(event); 501} 502 503void RenderWidgetHostViewGuest::DispatchCancelTouchEvent( 504 ui::TouchEvent* event) { 505 if (!host_) 506 return; 507 508 blink::WebTouchEvent cancel_event; 509 // TODO(rbyers): This event has no touches in it. Don't we need to know what 510 // touches are currently active in order to cancel them all properly? 511 WebTouchEventTraits::ResetType(blink::WebInputEvent::TouchCancel, 512 event->time_stamp().InSecondsF(), 513 &cancel_event); 514 515 host_->ForwardTouchEventWithLatencyInfo(cancel_event, *event->latency()); 516} 517 518bool RenderWidgetHostViewGuest::ForwardGestureEventToRenderer( 519 ui::GestureEvent* gesture) { 520#if defined(USE_AURA) 521 if (!host_) 522 return false; 523 524 if ((gesture->type() == ui::ET_GESTURE_PINCH_BEGIN || 525 gesture->type() == ui::ET_GESTURE_PINCH_UPDATE || 526 gesture->type() == ui::ET_GESTURE_PINCH_END) && !pinch_zoom_enabled_) { 527 return true; 528 } 529 530 blink::WebGestureEvent web_gesture = 531 MakeWebGestureEventFromUIEvent(*gesture); 532 const gfx::Point& client_point = gesture->location(); 533 const gfx::Point& screen_point = gesture->location(); 534 535 web_gesture.x = client_point.x(); 536 web_gesture.y = client_point.y(); 537 web_gesture.globalX = screen_point.x(); 538 web_gesture.globalY = screen_point.y(); 539 540 if (web_gesture.type == blink::WebGestureEvent::Undefined) 541 return false; 542 if (web_gesture.type == blink::WebGestureEvent::GestureTapDown) { 543 host_->ForwardGestureEvent( 544 CreateFlingCancelEvent(gesture->time_stamp().InSecondsF())); 545 } 546 host_->ForwardGestureEvent(web_gesture); 547 return true; 548#else 549 return false; 550#endif 551} 552 553void RenderWidgetHostViewGuest::ProcessGestures( 554 ui::GestureRecognizer::Gestures* gestures) { 555 if ((gestures == NULL) || gestures->empty()) 556 return; 557 for (ui::GestureRecognizer::Gestures::iterator g_it = gestures->begin(); 558 g_it != gestures->end(); 559 ++g_it) { 560 ForwardGestureEventToRenderer(*g_it); 561 } 562} 563 564SkColorType RenderWidgetHostViewGuest::PreferredReadbackFormat() { 565 return kN32_SkColorType; 566} 567 568RenderWidgetHostViewBase* 569RenderWidgetHostViewGuest::GetGuestRenderWidgetHostView() const { 570 return static_cast<RenderWidgetHostViewBase*>( 571 guest_->GetEmbedderRenderWidgetHostView()); 572} 573 574void RenderWidgetHostViewGuest::OnHandleInputEvent( 575 RenderWidgetHostImpl* embedder, 576 int browser_plugin_instance_id, 577 const gfx::Rect& guest_window_rect, 578 const blink::WebInputEvent* event) { 579 if (blink::WebInputEvent::isMouseEventType(event->type)) { 580 host_->ForwardMouseEvent( 581 *static_cast<const blink::WebMouseEvent*>(event)); 582 return; 583 } 584 585 if (event->type == blink::WebInputEvent::MouseWheel) { 586 host_->ForwardWheelEvent( 587 *static_cast<const blink::WebMouseWheelEvent*>(event)); 588 return; 589 } 590 591 if (blink::WebInputEvent::isKeyboardEventType(event->type)) { 592 if (!embedder->GetLastKeyboardEvent()) 593 return; 594 NativeWebKeyboardEvent keyboard_event(*embedder->GetLastKeyboardEvent()); 595 host_->ForwardKeyboardEvent(keyboard_event); 596 return; 597 } 598 599 if (blink::WebInputEvent::isTouchEventType(event->type)) { 600 host_->ForwardTouchEventWithLatencyInfo( 601 *static_cast<const blink::WebTouchEvent*>(event), 602 ui::LatencyInfo()); 603 return; 604 } 605 606 if (blink::WebInputEvent::isGestureEventType(event->type)) { 607 host_->ForwardGestureEvent( 608 *static_cast<const blink::WebGestureEvent*>(event)); 609 return; 610 } 611} 612 613} // namespace content 614