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