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