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