Upstream version 7.36.149.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/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::WebGestureEvent::Touchscreen;
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::TextInputTypeChanged(
291     ui::TextInputType type,
292     ui::TextInputMode input_mode,
293     bool can_compose_inline) {
294   if (!guest_)
295     return;
296
297   RenderWidgetHostViewBase* rwhv = GetGuestRenderWidgetHostView();
298   if (!rwhv)
299     return;
300   // Forward the information to embedding RWHV.
301   rwhv->TextInputTypeChanged(type, input_mode, can_compose_inline);
302 }
303
304 void RenderWidgetHostViewGuest::ImeCancelComposition() {
305   if (!guest_)
306     return;
307
308   RenderWidgetHostViewBase* rwhv = GetGuestRenderWidgetHostView();
309   if (!rwhv)
310     return;
311   // Forward the information to embedding RWHV.
312   rwhv->ImeCancelComposition();
313 }
314
315 #if defined(OS_MACOSX) || defined(USE_AURA)
316 void RenderWidgetHostViewGuest::ImeCompositionRangeChanged(
317     const gfx::Range& range,
318     const std::vector<gfx::Rect>& character_bounds) {
319   if (!guest_)
320     return;
321
322   RenderWidgetHostViewBase* rwhv = GetGuestRenderWidgetHostView();
323   if (!rwhv)
324     return;
325   std::vector<gfx::Rect> guest_character_bounds;
326   for (size_t i = 0; i < character_bounds.size(); ++i) {
327     gfx::Rect guest_rect = guest_->ToGuestRect(character_bounds[i]);
328     guest_character_bounds.push_back(guest_rect);
329   }
330   // Forward the information to embedding RWHV.
331   rwhv->ImeCompositionRangeChanged(range, guest_character_bounds);
332 }
333 #endif
334
335 void RenderWidgetHostViewGuest::SelectionChanged(const base::string16& text,
336                                                  size_t offset,
337                                                  const gfx::Range& range) {
338   platform_view_->SelectionChanged(text, offset, range);
339 }
340
341 void RenderWidgetHostViewGuest::SelectionBoundsChanged(
342     const ViewHostMsg_SelectionBounds_Params& params) {
343   if (!guest_)
344     return;
345
346   RenderWidgetHostViewBase* rwhv = GetGuestRenderWidgetHostView();
347   if (!rwhv)
348     return;
349   ViewHostMsg_SelectionBounds_Params guest_params(params);
350   guest_params.anchor_rect = guest_->ToGuestRect(params.anchor_rect);
351   guest_params.focus_rect = guest_->ToGuestRect(params.focus_rect);
352   rwhv->SelectionBoundsChanged(guest_params);
353 }
354
355 #if defined(OS_ANDROID)
356 void RenderWidgetHostViewGuest::SelectionRootBoundsChanged(
357     const gfx::Rect& bounds) {
358   if (!guest_)
359     return;
360
361   RenderWidgetHostViewBase* rwhv = GetGuestRenderWidgetHostView();
362   if (!rwhv)
363     return;
364
365   rwhv->SelectionRootBoundsChanged(guest_->ToGuestRect(bounds));
366 }
367 #endif
368
369 void RenderWidgetHostViewGuest::CopyFromCompositingSurface(
370     const gfx::Rect& src_subrect,
371     const gfx::Size& dst_size,
372     const base::Callback<void(bool, const SkBitmap&)>& callback,
373     const SkBitmap::Config config) {
374   CHECK(guest_);
375   guest_->CopyFromCompositingSurface(src_subrect, dst_size, callback);
376 }
377
378 void RenderWidgetHostViewGuest::SetBackground(const SkBitmap& background) {
379   platform_view_->SetBackground(background);
380 }
381
382 void RenderWidgetHostViewGuest::SetScrollOffsetPinning(
383     bool is_pinned_to_left, bool is_pinned_to_right) {
384   platform_view_->SetScrollOffsetPinning(
385       is_pinned_to_left, is_pinned_to_right);
386 }
387
388 bool RenderWidgetHostViewGuest::LockMouse() {
389   return platform_view_->LockMouse();
390 }
391
392 void RenderWidgetHostViewGuest::UnlockMouse() {
393   return platform_view_->UnlockMouse();
394 }
395
396 void RenderWidgetHostViewGuest::GetScreenInfo(blink::WebScreenInfo* results) {
397   if (!guest_)
398     return;
399   RenderWidgetHostViewBase* embedder_view = GetGuestRenderWidgetHostView();
400   if (embedder_view)
401     embedder_view->GetScreenInfo(results);
402 }
403
404 #if defined(OS_MACOSX)
405 void RenderWidgetHostViewGuest::SetActive(bool active) {
406   platform_view_->SetActive(active);
407 }
408
409 void RenderWidgetHostViewGuest::SetTakesFocusOnlyOnMouseDown(bool flag) {
410   platform_view_->SetTakesFocusOnlyOnMouseDown(flag);
411 }
412
413 void RenderWidgetHostViewGuest::SetWindowVisibility(bool visible) {
414   platform_view_->SetWindowVisibility(visible);
415 }
416
417 void RenderWidgetHostViewGuest::WindowFrameChanged() {
418   platform_view_->WindowFrameChanged();
419 }
420
421 void RenderWidgetHostViewGuest::ShowDefinitionForSelection() {
422   if (!guest_)
423     return;
424
425   gfx::Point origin;
426   gfx::Rect guest_bounds = GetViewBounds();
427   RenderWidgetHostView* rwhv = guest_->GetEmbedderRenderWidgetHostView();
428   gfx::Rect embedder_bounds;
429   if (rwhv)
430     embedder_bounds = rwhv->GetViewBounds();
431
432   gfx::Vector2d guest_offset = gfx::Vector2d(
433       // Horizontal offset of guest from embedder.
434       guest_bounds.x() - embedder_bounds.x(),
435       // Vertical offset from guest's top to embedder's bottom edge.
436       embedder_bounds.bottom() - guest_bounds.y());
437
438   RenderWidgetHostViewMacDictionaryHelper helper(platform_view_);
439   helper.SetTargetView(rwhv);
440   helper.set_offset(guest_offset);
441   helper.ShowDefinitionForSelection();
442 }
443
444 bool RenderWidgetHostViewGuest::SupportsSpeech() const {
445   return platform_view_->SupportsSpeech();
446 }
447
448 void RenderWidgetHostViewGuest::SpeakSelection() {
449   platform_view_->SpeakSelection();
450 }
451
452 bool RenderWidgetHostViewGuest::IsSpeaking() const {
453   return platform_view_->IsSpeaking();
454 }
455
456 void RenderWidgetHostViewGuest::StopSpeaking() {
457   platform_view_->StopSpeaking();
458 }
459
460 bool RenderWidgetHostViewGuest::PostProcessEventForPluginIme(
461     const NativeWebKeyboardEvent& event) {
462   return false;
463 }
464
465 #endif  // defined(OS_MACOSX)
466
467 #if defined(OS_ANDROID)
468 void RenderWidgetHostViewGuest::ShowDisambiguationPopup(
469     const gfx::Rect& target_rect,
470     const SkBitmap& zoomed_bitmap) {
471 }
472
473 void RenderWidgetHostViewGuest::LockCompositingSurface() {
474 }
475
476 void RenderWidgetHostViewGuest::UnlockCompositingSurface() {
477 }
478 #endif  // defined(OS_ANDROID)
479
480 #if defined(OS_WIN)
481 void RenderWidgetHostViewGuest::SetParentNativeViewAccessible(
482     gfx::NativeViewAccessible accessible_parent) {
483 }
484
485 gfx::NativeViewId RenderWidgetHostViewGuest::GetParentForWindowlessPlugin()
486     const {
487   return NULL;
488 }
489 #endif
490
491 void RenderWidgetHostViewGuest::DestroyGuestView() {
492   host_->SetView(NULL);
493   host_ = NULL;
494   base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
495 }
496
497 bool RenderWidgetHostViewGuest::CanDispatchToConsumer(
498     ui::GestureConsumer* consumer) {
499   CHECK_EQ(static_cast<RenderWidgetHostViewGuest*>(consumer), this);
500   return true;
501 }
502
503 void RenderWidgetHostViewGuest::DispatchGestureEvent(
504     ui::GestureEvent* event) {
505   ForwardGestureEventToRenderer(event);
506 }
507
508 void RenderWidgetHostViewGuest::DispatchCancelTouchEvent(
509     ui::TouchEvent* event) {
510   if (!host_)
511     return;
512
513   blink::WebTouchEvent cancel_event;
514   // TODO(rbyers): This event has no touches in it.  Don't we need to know what
515   // touches are currently active in order to cancel them all properly?
516   WebTouchEventTraits::ResetType(blink::WebInputEvent::TouchCancel,
517                                  event->time_stamp().InSecondsF(),
518                                  &cancel_event);
519
520   host_->ForwardTouchEventWithLatencyInfo(cancel_event, *event->latency());
521 }
522
523 bool RenderWidgetHostViewGuest::ForwardGestureEventToRenderer(
524     ui::GestureEvent* gesture) {
525 #if defined(USE_AURA)
526   if (!host_)
527     return false;
528
529   if ((gesture->type() == ui::ET_GESTURE_PINCH_BEGIN ||
530       gesture->type() == ui::ET_GESTURE_PINCH_UPDATE ||
531       gesture->type() == ui::ET_GESTURE_PINCH_END) && !pinch_zoom_enabled_) {
532     return true;
533   }
534
535   blink::WebGestureEvent web_gesture =
536       MakeWebGestureEventFromUIEvent(*gesture);
537   const gfx::Point& client_point = gesture->location();
538   const gfx::Point& screen_point = gesture->location();
539
540   web_gesture.x = client_point.x();
541   web_gesture.y = client_point.y();
542   web_gesture.globalX = screen_point.x();
543   web_gesture.globalY = screen_point.y();
544
545   if (web_gesture.type == blink::WebGestureEvent::Undefined)
546     return false;
547   if (web_gesture.type == blink::WebGestureEvent::GestureTapDown) {
548     host_->ForwardGestureEvent(
549         CreateFlingCancelEvent(gesture->time_stamp().InSecondsF()));
550   }
551   host_->ForwardGestureEvent(web_gesture);
552   return true;
553 #else
554   return false;
555 #endif
556 }
557
558 void RenderWidgetHostViewGuest::ProcessGestures(
559     ui::GestureRecognizer::Gestures* gestures) {
560   if ((gestures == NULL) || gestures->empty())
561     return;
562   for (ui::GestureRecognizer::Gestures::iterator g_it = gestures->begin();
563       g_it != gestures->end();
564       ++g_it) {
565     ForwardGestureEventToRenderer(*g_it);
566   }
567 }
568
569 SkBitmap::Config RenderWidgetHostViewGuest::PreferredReadbackFormat() {
570   return SkBitmap::kARGB_8888_Config;
571 }
572
573 RenderWidgetHostViewBase*
574 RenderWidgetHostViewGuest::GetGuestRenderWidgetHostView() const {
575   return static_cast<RenderWidgetHostViewBase*>(
576       guest_->GetEmbedderRenderWidgetHostView());
577 }
578
579 }  // namespace content