render_widget_host_view_guest.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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/view_messages.h" 16#include "content/common/webplugin_geometry.h" 17#include "content/public/common/content_switches.h" 18#include "skia/ext/platform_canvas.h" 19#include "third_party/WebKit/public/platform/WebScreenInfo.h" 20 21#if defined(OS_MACOSX) 22#import "content/browser/renderer_host/render_widget_host_view_mac_dictionary_helper.h" 23#endif 24 25#if defined(OS_WIN) || defined(USE_AURA) 26#include "content/browser/renderer_host/ui_events_helper.h" 27#endif 28 29namespace content { 30 31namespace { 32 33#if defined(OS_WIN) || defined(USE_AURA) 34blink::WebGestureEvent CreateFlingCancelEvent(double time_stamp) { 35 blink::WebGestureEvent gesture_event; 36 gesture_event.timeStampSeconds = time_stamp; 37 gesture_event.type = blink::WebGestureEvent::GestureFlingCancel; 38 gesture_event.sourceDevice = blink::WebGestureEvent::Touchscreen; 39 return gesture_event; 40} 41#endif // defined(OS_WIN) || defined(USE_AURA) 42 43} // namespace 44 45RenderWidgetHostViewGuest::RenderWidgetHostViewGuest( 46 RenderWidgetHost* widget_host, 47 BrowserPluginGuest* guest, 48 RenderWidgetHostView* platform_view) 49 : RenderWidgetHostViewChildFrame(widget_host), 50 // |guest| is NULL during test. 51 guest_(guest ? guest->AsWeakPtr() : base::WeakPtr<BrowserPluginGuest>()), 52 platform_view_(static_cast<RenderWidgetHostViewPort*>(platform_view)) { 53#if defined(OS_WIN) || defined(USE_AURA) 54 gesture_recognizer_.reset(ui::GestureRecognizer::Create()); 55 gesture_recognizer_->AddGestureEventHelper(this); 56#endif // defined(OS_WIN) || defined(USE_AURA) 57} 58 59RenderWidgetHostViewGuest::~RenderWidgetHostViewGuest() { 60#if defined(OS_WIN) || defined(USE_AURA) 61 gesture_recognizer_->RemoveGestureEventHelper(this); 62#endif // defined(OS_WIN) || defined(USE_AURA) 63} 64 65void RenderWidgetHostViewGuest::WasShown() { 66 // If the WebContents associated with us showed an interstitial page in the 67 // beginning, the teardown path might call WasShown() while |host_| is in 68 // the process of destruction. Avoid calling WasShown below in this case. 69 // TODO(lazyboy): We shouldn't be showing interstitial pages in guests in the 70 // first place: http://crbug.com/273089. 71 // 72 // |guest_| is NULL during test. 73 if ((guest_ && guest_->is_in_destruction()) || !host_->is_hidden()) 74 return; 75 host_->WasShown(); 76} 77 78void RenderWidgetHostViewGuest::WasHidden() { 79 // |guest_| is NULL during test. 80 if ((guest_ && guest_->is_in_destruction()) || host_->is_hidden()) 81 return; 82 host_->WasHidden(); 83} 84 85void RenderWidgetHostViewGuest::SetSize(const gfx::Size& size) { 86 size_ = size; 87 host_->WasResized(); 88} 89 90void RenderWidgetHostViewGuest::SetBounds(const gfx::Rect& rect) { 91 SetSize(rect.size()); 92} 93 94#if defined(OS_WIN) || defined(USE_AURA) 95void RenderWidgetHostViewGuest::ProcessAckedTouchEvent( 96 const TouchEventWithLatencyInfo& touch, InputEventAckState ack_result) { 97 // TODO(fsamuel): Currently we will only take this codepath if the guest has 98 // requested touch events. A better solution is to always forward touchpresses 99 // to the embedder process to target a BrowserPlugin, and then route all 100 // subsequent touch points of that touchdown to the appropriate guest until 101 // that touch point is released. 102 ScopedVector<ui::TouchEvent> events; 103 if (!MakeUITouchEventsFromWebTouchEvents(touch, &events, LOCAL_COORDINATES)) 104 return; 105 106 ui::EventResult result = (ack_result == 107 INPUT_EVENT_ACK_STATE_CONSUMED) ? ui::ER_HANDLED : ui::ER_UNHANDLED; 108 for (ScopedVector<ui::TouchEvent>::iterator iter = events.begin(), 109 end = events.end(); iter != end; ++iter) { 110 scoped_ptr<ui::GestureRecognizer::Gestures> gestures; 111 gestures.reset(gesture_recognizer_->ProcessTouchEventForGesture( 112 *(*iter), result, this)); 113 ProcessGestures(gestures.get()); 114 } 115} 116#endif 117 118gfx::Rect RenderWidgetHostViewGuest::GetViewBounds() const { 119 if (!guest_) 120 return gfx::Rect(); 121 122 RenderWidgetHostViewPort* rwhv = static_cast<RenderWidgetHostViewPort*>( 123 guest_->GetEmbedderRenderWidgetHostView()); 124 gfx::Rect embedder_bounds; 125 if (rwhv) 126 embedder_bounds = rwhv->GetViewBounds(); 127 gfx::Rect shifted_rect = guest_->ToGuestRect(embedder_bounds); 128 shifted_rect.set_width(size_.width()); 129 shifted_rect.set_height(size_.height()); 130 return shifted_rect; 131} 132 133void RenderWidgetHostViewGuest::RenderProcessGone( 134 base::TerminationStatus status, 135 int error_code) { 136 platform_view_->RenderProcessGone(status, error_code); 137 // Destroy the guest view instance only, so we don't end up calling 138 // platform_view_->Destroy(). 139 DestroyGuestView(); 140} 141 142void RenderWidgetHostViewGuest::Destroy() { 143 // The RenderWidgetHost's destruction led here, so don't call it. 144 DestroyGuestView(); 145 146 platform_view_->Destroy(); 147} 148 149gfx::Size RenderWidgetHostViewGuest::GetPhysicalBackingSize() const { 150 return RenderWidgetHostViewBase::GetPhysicalBackingSize(); 151} 152 153base::string16 RenderWidgetHostViewGuest::GetSelectedText() const { 154 return platform_view_->GetSelectedText(); 155} 156 157void RenderWidgetHostViewGuest::SetTooltipText( 158 const base::string16& tooltip_text) { 159 platform_view_->SetTooltipText(tooltip_text); 160} 161 162void RenderWidgetHostViewGuest::AcceleratedSurfaceBuffersSwapped( 163 const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params, 164 int gpu_host_id) { 165 if (!guest_) 166 return; 167 168 // If accelerated surface buffers are getting swapped then we're not using 169 // the software path. 170 guest_->clear_damage_buffer(); 171 FrameMsg_BuffersSwapped_Params guest_params; 172 guest_params.size = params.size; 173 guest_params.mailbox = params.mailbox; 174 guest_params.gpu_route_id = params.route_id; 175 guest_params.gpu_host_id = gpu_host_id; 176 guest_->SendMessageToEmbedder( 177 new BrowserPluginMsg_BuffersSwapped(guest_->instance_id(), 178 guest_params)); 179} 180 181void RenderWidgetHostViewGuest::AcceleratedSurfacePostSubBuffer( 182 const GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params& params, 183 int gpu_host_id) { 184 NOTREACHED(); 185} 186 187void RenderWidgetHostViewGuest::OnSwapCompositorFrame( 188 uint32 output_surface_id, 189 scoped_ptr<cc::CompositorFrame> frame) { 190 if (!guest_) 191 return; 192 193 guest_->clear_damage_buffer(); 194 195 if (!guest_->attached()) { 196 // If the guest doesn't have an embedder then there's nothing to give the 197 // the frame to. 198 return; 199 } 200 if (frame->software_frame_data) { 201 cc::SoftwareFrameData* frame_data = frame->software_frame_data.get(); 202#ifdef OS_WIN 203 base::SharedMemory shared_memory(frame_data->handle, true, 204 host_->GetProcess()->GetHandle()); 205#else 206 base::SharedMemory shared_memory(frame_data->handle, true); 207#endif 208 209 RenderWidgetHostView* embedder_rwhv = 210 guest_->GetEmbedderRenderWidgetHostView(); 211 base::ProcessHandle embedder_pid = 212 embedder_rwhv->GetRenderWidgetHost()->GetProcess()->GetHandle(); 213 214 shared_memory.GiveToProcess(embedder_pid, &frame_data->handle); 215 } 216 217 FrameMsg_CompositorFrameSwapped_Params guest_params; 218 frame->AssignTo(&guest_params.frame); 219 guest_params.output_surface_id = output_surface_id; 220 guest_params.producing_route_id = host_->GetRoutingID(); 221 guest_params.producing_host_id = host_->GetProcess()->GetID(); 222 223 guest_->SendMessageToEmbedder( 224 new BrowserPluginMsg_CompositorFrameSwapped(guest_->instance_id(), 225 guest_params)); 226} 227 228bool RenderWidgetHostViewGuest::OnMessageReceived(const IPC::Message& msg) { 229 return platform_view_->OnMessageReceived(msg); 230} 231 232void RenderWidgetHostViewGuest::InitAsChild( 233 gfx::NativeView parent_view) { 234 platform_view_->InitAsChild(parent_view); 235} 236 237void RenderWidgetHostViewGuest::InitAsPopup( 238 RenderWidgetHostView* parent_host_view, const gfx::Rect& pos) { 239 // This should never get called. 240 NOTREACHED(); 241} 242 243void RenderWidgetHostViewGuest::InitAsFullscreen( 244 RenderWidgetHostView* reference_host_view) { 245 // This should never get called. 246 NOTREACHED(); 247} 248 249gfx::NativeView RenderWidgetHostViewGuest::GetNativeView() const { 250 if (!guest_) 251 return gfx::NativeView(); 252 253 RenderWidgetHostView* rwhv = guest_->GetEmbedderRenderWidgetHostView(); 254 if (!rwhv) 255 return gfx::NativeView(); 256 return rwhv->GetNativeView(); 257} 258 259gfx::NativeViewId RenderWidgetHostViewGuest::GetNativeViewId() const { 260 if (!guest_) 261 return static_cast<gfx::NativeViewId>(NULL); 262 263 RenderWidgetHostView* rwhv = guest_->GetEmbedderRenderWidgetHostView(); 264 if (!rwhv) 265 return static_cast<gfx::NativeViewId>(NULL); 266 return rwhv->GetNativeViewId(); 267} 268 269gfx::NativeViewAccessible RenderWidgetHostViewGuest::GetNativeViewAccessible() { 270 if (!guest_) 271 return gfx::NativeViewAccessible(); 272 273 RenderWidgetHostView* rwhv = guest_->GetEmbedderRenderWidgetHostView(); 274 if (!rwhv) 275 return gfx::NativeViewAccessible(); 276 return rwhv->GetNativeViewAccessible(); 277} 278 279void RenderWidgetHostViewGuest::MovePluginWindows( 280 const gfx::Vector2d& scroll_offset, 281 const std::vector<WebPluginGeometry>& moves) { 282 platform_view_->MovePluginWindows(scroll_offset, moves); 283} 284 285void RenderWidgetHostViewGuest::UpdateCursor(const WebCursor& cursor) { 286 platform_view_->UpdateCursor(cursor); 287} 288 289void RenderWidgetHostViewGuest::SetIsLoading(bool is_loading) { 290 platform_view_->SetIsLoading(is_loading); 291} 292 293void RenderWidgetHostViewGuest::TextInputTypeChanged( 294 ui::TextInputType type, 295 ui::TextInputMode input_mode, 296 bool can_compose_inline) { 297 if (!guest_) 298 return; 299 300 RenderWidgetHostViewPort* rwhv = RenderWidgetHostViewPort::FromRWHV( 301 guest_->GetEmbedderRenderWidgetHostView()); 302 if (!rwhv) 303 return; 304 // Forward the information to embedding RWHV. 305 rwhv->TextInputTypeChanged(type, input_mode, can_compose_inline); 306} 307 308void RenderWidgetHostViewGuest::ImeCancelComposition() { 309 if (!guest_) 310 return; 311 312 RenderWidgetHostViewPort* rwhv = RenderWidgetHostViewPort::FromRWHV( 313 guest_->GetEmbedderRenderWidgetHostView()); 314 if (!rwhv) 315 return; 316 // Forward the information to embedding RWHV. 317 rwhv->ImeCancelComposition(); 318} 319 320#if defined(OS_MACOSX) || defined(OS_WIN) || defined(USE_AURA) 321void RenderWidgetHostViewGuest::ImeCompositionRangeChanged( 322 const gfx::Range& range, 323 const std::vector<gfx::Rect>& character_bounds) { 324 if (!guest_) 325 return; 326 327 RenderWidgetHostViewPort* rwhv = RenderWidgetHostViewPort::FromRWHV( 328 guest_->GetEmbedderRenderWidgetHostView()); 329 if (!rwhv) 330 return; 331 std::vector<gfx::Rect> guest_character_bounds; 332 for (size_t i = 0; i < character_bounds.size(); ++i) { 333 gfx::Rect guest_rect = guest_->ToGuestRect(character_bounds[i]); 334 guest_character_bounds.push_back(guest_rect); 335 } 336 // Forward the information to embedding RWHV. 337 rwhv->ImeCompositionRangeChanged(range, guest_character_bounds); 338} 339#endif 340 341void RenderWidgetHostViewGuest::DidUpdateBackingStore( 342 const gfx::Rect& scroll_rect, 343 const gfx::Vector2d& scroll_delta, 344 const std::vector<gfx::Rect>& copy_rects, 345 const std::vector<ui::LatencyInfo>& latency_info) { 346 NOTREACHED(); 347} 348 349void RenderWidgetHostViewGuest::SelectionChanged(const base::string16& text, 350 size_t offset, 351 const gfx::Range& range) { 352 platform_view_->SelectionChanged(text, offset, range); 353} 354 355void RenderWidgetHostViewGuest::SelectionBoundsChanged( 356 const ViewHostMsg_SelectionBounds_Params& params) { 357 if (!guest_) 358 return; 359 360 RenderWidgetHostViewPort* rwhv = RenderWidgetHostViewPort::FromRWHV( 361 guest_->GetEmbedderRenderWidgetHostView()); 362 if (!rwhv) 363 return; 364 ViewHostMsg_SelectionBounds_Params guest_params(params); 365 guest_params.anchor_rect = guest_->ToGuestRect(params.anchor_rect); 366 guest_params.focus_rect = guest_->ToGuestRect(params.focus_rect); 367 rwhv->SelectionBoundsChanged(guest_params); 368} 369 370void RenderWidgetHostViewGuest::CopyFromCompositingSurface( 371 const gfx::Rect& src_subrect, 372 const gfx::Size& dst_size, 373 const base::Callback<void(bool, const SkBitmap&)>& callback, 374 const SkBitmap::Config config) { 375 CHECK(guest_); 376 guest_->CopyFromCompositingSurface(src_subrect, dst_size, callback); 377} 378 379void RenderWidgetHostViewGuest::SetBackground(const SkBitmap& background) { 380 platform_view_->SetBackground(background); 381} 382 383void RenderWidgetHostViewGuest::SetHasHorizontalScrollbar( 384 bool has_horizontal_scrollbar) { 385 platform_view_->SetHasHorizontalScrollbar(has_horizontal_scrollbar); 386} 387 388void RenderWidgetHostViewGuest::SetScrollOffsetPinning( 389 bool is_pinned_to_left, bool is_pinned_to_right) { 390 platform_view_->SetScrollOffsetPinning( 391 is_pinned_to_left, is_pinned_to_right); 392} 393 394bool RenderWidgetHostViewGuest::LockMouse() { 395 return platform_view_->LockMouse(); 396} 397 398void RenderWidgetHostViewGuest::UnlockMouse() { 399 return platform_view_->UnlockMouse(); 400} 401 402void RenderWidgetHostViewGuest::GetScreenInfo(blink::WebScreenInfo* results) { 403 if (!guest_) 404 return; 405 RenderWidgetHostViewPort* embedder_view = 406 RenderWidgetHostViewPort::FromRWHV( 407 guest_->GetEmbedderRenderWidgetHostView()); 408 if (embedder_view) 409 embedder_view->GetScreenInfo(results); 410} 411 412#if defined(OS_MACOSX) 413void RenderWidgetHostViewGuest::SetActive(bool active) { 414 platform_view_->SetActive(active); 415} 416 417void RenderWidgetHostViewGuest::SetTakesFocusOnlyOnMouseDown(bool flag) { 418 platform_view_->SetTakesFocusOnlyOnMouseDown(flag); 419} 420 421void RenderWidgetHostViewGuest::SetWindowVisibility(bool visible) { 422 platform_view_->SetWindowVisibility(visible); 423} 424 425void RenderWidgetHostViewGuest::WindowFrameChanged() { 426 platform_view_->WindowFrameChanged(); 427} 428 429void RenderWidgetHostViewGuest::ShowDefinitionForSelection() { 430 if (!guest_) 431 return; 432 433 gfx::Point origin; 434 gfx::Rect guest_bounds = GetViewBounds(); 435 RenderWidgetHostView* rwhv = guest_->GetEmbedderRenderWidgetHostView(); 436 gfx::Rect embedder_bounds; 437 if (rwhv) 438 embedder_bounds = rwhv->GetViewBounds(); 439 440 gfx::Vector2d guest_offset = gfx::Vector2d( 441 // Horizontal offset of guest from embedder. 442 guest_bounds.x() - embedder_bounds.x(), 443 // Vertical offset from guest's top to embedder's bottom edge. 444 embedder_bounds.bottom() - guest_bounds.y()); 445 446 RenderWidgetHostViewMacDictionaryHelper helper(platform_view_); 447 helper.SetTargetView(rwhv); 448 helper.set_offset(guest_offset); 449 helper.ShowDefinitionForSelection(); 450} 451 452bool RenderWidgetHostViewGuest::SupportsSpeech() const { 453 return platform_view_->SupportsSpeech(); 454} 455 456void RenderWidgetHostViewGuest::SpeakSelection() { 457 platform_view_->SpeakSelection(); 458} 459 460bool RenderWidgetHostViewGuest::IsSpeaking() const { 461 return platform_view_->IsSpeaking(); 462} 463 464void RenderWidgetHostViewGuest::StopSpeaking() { 465 platform_view_->StopSpeaking(); 466} 467 468bool RenderWidgetHostViewGuest::PostProcessEventForPluginIme( 469 const NativeWebKeyboardEvent& event) { 470 return false; 471} 472 473#endif // defined(OS_MACOSX) 474 475#if defined(OS_ANDROID) 476void RenderWidgetHostViewGuest::ShowDisambiguationPopup( 477 const gfx::Rect& target_rect, 478 const SkBitmap& zoomed_bitmap) { 479} 480#endif // defined(OS_ANDROID) 481 482#if defined(TOOLKIT_GTK) 483GdkEventButton* RenderWidgetHostViewGuest::GetLastMouseDown() { 484 return NULL; 485} 486 487gfx::NativeView RenderWidgetHostViewGuest::BuildInputMethodsGtkMenu() { 488 return platform_view_->BuildInputMethodsGtkMenu(); 489} 490#endif // defined(TOOLKIT_GTK) 491 492#if defined(OS_WIN) 493void RenderWidgetHostViewGuest::SetParentNativeViewAccessible( 494 gfx::NativeViewAccessible accessible_parent) { 495} 496 497gfx::NativeViewId RenderWidgetHostViewGuest::GetParentForWindowlessPlugin() 498 const { 499 return NULL; 500} 501#endif 502 503void RenderWidgetHostViewGuest::DestroyGuestView() { 504 host_->SetView(NULL); 505 host_ = NULL; 506 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); 507} 508 509bool RenderWidgetHostViewGuest::CanDispatchToConsumer( 510 ui::GestureConsumer* consumer) { 511 CHECK_EQ(static_cast<RenderWidgetHostViewGuest*>(consumer), this); 512 return true; 513} 514 515void RenderWidgetHostViewGuest::DispatchPostponedGestureEvent( 516 ui::GestureEvent* event) { 517 ForwardGestureEventToRenderer(event); 518} 519 520void RenderWidgetHostViewGuest::DispatchCancelTouchEvent( 521 ui::TouchEvent* event) { 522 if (!host_) 523 return; 524 525 blink::WebTouchEvent cancel_event; 526 cancel_event.type = blink::WebInputEvent::TouchCancel; 527 cancel_event.timeStampSeconds = event->time_stamp().InSecondsF(); 528 host_->ForwardTouchEventWithLatencyInfo(cancel_event, *event->latency()); 529} 530 531bool RenderWidgetHostViewGuest::ForwardGestureEventToRenderer( 532 ui::GestureEvent* gesture) { 533#if defined(OS_WIN) || defined(USE_AURA) 534 if (!host_) 535 return false; 536 537 if ((gesture->type() == ui::ET_GESTURE_PINCH_BEGIN || 538 gesture->type() == ui::ET_GESTURE_PINCH_UPDATE || 539 gesture->type() == ui::ET_GESTURE_PINCH_END) && !pinch_zoom_enabled_) { 540 return true; 541 } 542 543 blink::WebGestureEvent web_gesture = 544 MakeWebGestureEventFromUIEvent(*gesture); 545 const gfx::Point& client_point = gesture->location(); 546 const gfx::Point& screen_point = gesture->location(); 547 548 web_gesture.x = client_point.x(); 549 web_gesture.y = client_point.y(); 550 web_gesture.globalX = screen_point.x(); 551 web_gesture.globalY = screen_point.y(); 552 553 if (web_gesture.type == blink::WebGestureEvent::Undefined) 554 return false; 555 if (web_gesture.type == blink::WebGestureEvent::GestureTapDown) { 556 host_->ForwardGestureEvent( 557 CreateFlingCancelEvent(gesture->time_stamp().InSecondsF())); 558 } 559 host_->ForwardGestureEvent(web_gesture); 560 return true; 561#else 562 return false; 563#endif 564} 565 566void RenderWidgetHostViewGuest::ProcessGestures( 567 ui::GestureRecognizer::Gestures* gestures) { 568 if ((gestures == NULL) || gestures->empty()) 569 return; 570 for (ui::GestureRecognizer::Gestures::iterator g_it = gestures->begin(); 571 g_it != gestures->end(); 572 ++g_it) { 573 ForwardGestureEventToRenderer(*g_it); 574 } 575} 576 577 578} // namespace content 579