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