web_contents_view_aura.cc revision bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3
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 "content/browser/web_contents/web_contents_view_aura.h"
6
7#include "base/auto_reset.h"
8#include "base/command_line.h"
9#include "base/metrics/histogram.h"
10#include "base/strings/utf_string_conversions.h"
11#include "content/browser/renderer_host/dip_util.h"
12#include "content/browser/renderer_host/overscroll_controller.h"
13#include "content/browser/renderer_host/render_view_host_factory.h"
14#include "content/browser/renderer_host/render_view_host_impl.h"
15#include "content/browser/renderer_host/render_widget_host_impl.h"
16#include "content/browser/renderer_host/render_widget_host_view_aura.h"
17#include "content/browser/web_contents/aura/image_window_delegate.h"
18#include "content/browser/web_contents/aura/shadow_layer_delegate.h"
19#include "content/browser/web_contents/aura/window_slider.h"
20#include "content/browser/web_contents/interstitial_page_impl.h"
21#include "content/browser/web_contents/navigation_entry_impl.h"
22#include "content/browser/web_contents/touch_editable_impl_aura.h"
23#include "content/browser/web_contents/web_contents_impl.h"
24#include "content/public/browser/notification_observer.h"
25#include "content/public/browser/notification_registrar.h"
26#include "content/public/browser/notification_source.h"
27#include "content/public/browser/notification_types.h"
28#include "content/public/browser/overscroll_configuration.h"
29#include "content/public/browser/render_view_host.h"
30#include "content/public/browser/render_widget_host.h"
31#include "content/public/browser/render_widget_host_view.h"
32#include "content/public/browser/web_contents_delegate.h"
33#include "content/public/browser/web_contents_observer.h"
34#include "content/public/browser/web_contents_view_delegate.h"
35#include "content/public/browser/web_drag_dest_delegate.h"
36#include "content/public/common/content_switches.h"
37#include "content/public/common/drop_data.h"
38#include "third_party/WebKit/public/web/WebInputEvent.h"
39#include "ui/aura/client/aura_constants.h"
40#include "ui/aura/client/drag_drop_client.h"
41#include "ui/aura/client/drag_drop_delegate.h"
42#include "ui/aura/root_window.h"
43#include "ui/aura/root_window_observer.h"
44#include "ui/aura/window.h"
45#include "ui/aura/window_observer.h"
46#include "ui/base/clipboard/clipboard.h"
47#include "ui/base/clipboard/custom_data_helper.h"
48#include "ui/base/dragdrop/drag_drop_types.h"
49#include "ui/base/dragdrop/drag_utils.h"
50#include "ui/base/dragdrop/os_exchange_data.h"
51#include "ui/base/events/event.h"
52#include "ui/base/events/event_utils.h"
53#include "ui/base/hit_test.h"
54#include "ui/compositor/layer.h"
55#include "ui/compositor/scoped_layer_animation_settings.h"
56#include "ui/gfx/canvas.h"
57#include "ui/gfx/image/image.h"
58#include "ui/gfx/image/image_png_rep.h"
59#include "ui/gfx/image/image_skia.h"
60#include "ui/gfx/screen.h"
61
62namespace content {
63WebContentsViewPort* CreateWebContentsView(
64    WebContentsImpl* web_contents,
65    WebContentsViewDelegate* delegate,
66    RenderViewHostDelegateView** render_view_host_delegate_view) {
67  WebContentsViewAura* rv = new WebContentsViewAura(web_contents, delegate);
68  *render_view_host_delegate_view = rv;
69  return rv;
70}
71
72namespace {
73
74bool IsScrollEndEffectEnabled() {
75  return CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
76      switches::kScrollEndEffect) == "1";
77}
78
79bool ShouldNavigateForward(const NavigationController& controller,
80                           OverscrollMode mode) {
81  return mode == (base::i18n::IsRTL() ? OVERSCROLL_EAST : OVERSCROLL_WEST) &&
82         controller.CanGoForward();
83}
84
85bool ShouldNavigateBack(const NavigationController& controller,
86                        OverscrollMode mode) {
87  return mode == (base::i18n::IsRTL() ? OVERSCROLL_WEST : OVERSCROLL_EAST) &&
88         controller.CanGoBack();
89}
90
91RenderWidgetHostViewAura* ToRenderWidgetHostViewAura(
92    RenderWidgetHostView* view) {
93  if (!view || RenderViewHostFactory::has_factory())
94    return NULL;  // Can't cast to RenderWidgetHostViewAura in unit tests.
95  RenderProcessHostImpl* process = static_cast<RenderProcessHostImpl*>(
96      view->GetRenderWidgetHost()->GetProcess());
97  if (process->IsGuest())
98    return NULL;
99  return static_cast<RenderWidgetHostViewAura*>(view);
100}
101
102// The window delegate for the overscroll window. This redirects trackpad events
103// to the web-contents window. The delegate destroys itself when the window is
104// destroyed.
105class OverscrollWindowDelegate : public ImageWindowDelegate {
106 public:
107  OverscrollWindowDelegate(WebContentsImpl* web_contents,
108                           OverscrollMode overscroll_mode)
109      : web_contents_(web_contents),
110        forward_events_(true) {
111    const NavigationControllerImpl& controller = web_contents->GetController();
112    const NavigationEntryImpl* entry = NULL;
113    if (ShouldNavigateForward(controller, overscroll_mode)) {
114      entry = NavigationEntryImpl::FromNavigationEntry(
115          controller.GetEntryAtOffset(1));
116    } else if (ShouldNavigateBack(controller, overscroll_mode)) {
117      entry = NavigationEntryImpl::FromNavigationEntry(
118          controller.GetEntryAtOffset(-1));
119    }
120
121    gfx::Image image;
122    if (entry && entry->screenshot().get()) {
123      std::vector<gfx::ImagePNGRep> image_reps;
124      image_reps.push_back(gfx::ImagePNGRep(entry->screenshot(),
125            ui::GetScaleFactorForNativeView(web_contents_window())));
126      image = gfx::Image(image_reps);
127    }
128    SetImage(image);
129  }
130
131  void stop_forwarding_events() { forward_events_ = false; }
132
133 private:
134  virtual ~OverscrollWindowDelegate() {}
135
136  aura::Window* web_contents_window() {
137    return web_contents_->GetView()->GetContentNativeView();
138  }
139
140  // Overridden from ui::EventHandler.
141  virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE {
142    if (forward_events_ && web_contents_window())
143      web_contents_window()->delegate()->OnScrollEvent(event);
144  }
145
146  virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
147    if (forward_events_ && web_contents_window())
148      web_contents_window()->delegate()->OnGestureEvent(event);
149  }
150
151  WebContents* web_contents_;
152
153  // The window is displayed both during the gesture, and after the gesture
154  // while the navigation is in progress. During the gesture, it is necessary to
155  // forward input events to the content page (e.g. when the overscroll window
156  // slides under the cursor and starts receiving scroll events). However, once
157  // the gesture is complete, and the window is being displayed as an overlay
158  // window during navigation, events should not be forwarded anymore.
159  bool forward_events_;
160
161  DISALLOW_COPY_AND_ASSIGN(OverscrollWindowDelegate);
162};
163
164// Listens to all mouse drag events during a drag and drop and sends them to
165// the renderer.
166class WebDragSourceAura : public base::MessageLoopForUI::Observer,
167                          public NotificationObserver {
168 public:
169  WebDragSourceAura(aura::Window* window, WebContentsImpl* contents)
170      : window_(window),
171        contents_(contents) {
172    base::MessageLoopForUI::current()->AddObserver(this);
173    registrar_.Add(this,
174                   NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
175                   Source<WebContents>(contents));
176  }
177
178  virtual ~WebDragSourceAura() {
179    base::MessageLoopForUI::current()->RemoveObserver(this);
180  }
181
182  // MessageLoop::Observer implementation:
183  virtual base::EventStatus WillProcessEvent(
184      const base::NativeEvent& event) OVERRIDE {
185    return base::EVENT_CONTINUE;
186  }
187  virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE {
188    if (!contents_)
189      return;
190    ui::EventType type = ui::EventTypeFromNative(event);
191    RenderViewHost* rvh = NULL;
192    switch (type) {
193      case ui::ET_MOUSE_DRAGGED:
194        rvh = contents_->GetRenderViewHost();
195        if (rvh) {
196          gfx::Point screen_loc_in_pixel = ui::EventLocationFromNative(event);
197          gfx::Point screen_loc = ConvertViewPointToDIP(rvh->GetView(),
198              screen_loc_in_pixel);
199          gfx::Point client_loc = screen_loc;
200          aura::Window* window = rvh->GetView()->GetNativeView();
201          aura::Window::ConvertPointToTarget(window->GetRootWindow(),
202              window, &client_loc);
203          contents_->DragSourceMovedTo(client_loc.x(), client_loc.y(),
204              screen_loc.x(), screen_loc.y());
205        }
206        break;
207      default:
208        break;
209    }
210  }
211
212  virtual void Observe(int type,
213      const NotificationSource& source,
214      const NotificationDetails& details) OVERRIDE {
215    if (type != NOTIFICATION_WEB_CONTENTS_DISCONNECTED)
216      return;
217
218    // Cancel the drag if it is still in progress.
219    aura::client::DragDropClient* dnd_client =
220        aura::client::GetDragDropClient(window_->GetRootWindow());
221    if (dnd_client && dnd_client->IsDragDropInProgress())
222      dnd_client->DragCancel();
223
224    window_ = NULL;
225    contents_ = NULL;
226  }
227
228  aura::Window* window() const { return window_; }
229
230 private:
231  aura::Window* window_;
232  WebContentsImpl* contents_;
233  NotificationRegistrar registrar_;
234
235  DISALLOW_COPY_AND_ASSIGN(WebDragSourceAura);
236};
237
238// Utility to fill a ui::OSExchangeDataProvider object from DropData.
239void PrepareDragData(const DropData& drop_data,
240                     ui::OSExchangeData::Provider* provider) {
241  if (!drop_data.text.string().empty())
242    provider->SetString(drop_data.text.string());
243  if (drop_data.url.is_valid())
244    provider->SetURL(drop_data.url, drop_data.url_title);
245  if (!drop_data.html.string().empty())
246    provider->SetHtml(drop_data.html.string(), drop_data.html_base_url);
247  if (!drop_data.filenames.empty()) {
248    std::vector<ui::OSExchangeData::FileInfo> filenames;
249    for (std::vector<DropData::FileInfo>::const_iterator it =
250             drop_data.filenames.begin();
251         it != drop_data.filenames.end(); ++it) {
252      filenames.push_back(
253          ui::OSExchangeData::FileInfo(
254              base::FilePath::FromUTF8Unsafe(UTF16ToUTF8(it->path)),
255              base::FilePath::FromUTF8Unsafe(UTF16ToUTF8(it->display_name))));
256    }
257    provider->SetFilenames(filenames);
258  }
259  if (!drop_data.custom_data.empty()) {
260    Pickle pickle;
261    ui::WriteCustomDataToPickle(drop_data.custom_data, &pickle);
262    provider->SetPickledData(ui::Clipboard::GetWebCustomDataFormatType(),
263                             pickle);
264  }
265}
266
267// Utility to fill a DropData object from ui::OSExchangeData.
268void PrepareDropData(DropData* drop_data, const ui::OSExchangeData& data) {
269  string16 plain_text;
270  data.GetString(&plain_text);
271  if (!plain_text.empty())
272    drop_data->text = base::NullableString16(plain_text, false);
273
274  GURL url;
275  string16 url_title;
276  data.GetURLAndTitle(&url, &url_title);
277  if (url.is_valid()) {
278    drop_data->url = url;
279    drop_data->url_title = url_title;
280  }
281
282  string16 html;
283  GURL html_base_url;
284  data.GetHtml(&html, &html_base_url);
285  if (!html.empty())
286    drop_data->html = base::NullableString16(html, false);
287  if (html_base_url.is_valid())
288    drop_data->html_base_url = html_base_url;
289
290  std::vector<ui::OSExchangeData::FileInfo> files;
291  if (data.GetFilenames(&files) && !files.empty()) {
292    for (std::vector<ui::OSExchangeData::FileInfo>::const_iterator
293             it = files.begin(); it != files.end(); ++it) {
294      drop_data->filenames.push_back(
295          DropData::FileInfo(
296              UTF8ToUTF16(it->path.AsUTF8Unsafe()),
297              UTF8ToUTF16(it->display_name.AsUTF8Unsafe())));
298    }
299  }
300
301  Pickle pickle;
302  if (data.GetPickledData(ui::Clipboard::GetWebCustomDataFormatType(), &pickle))
303    ui::ReadCustomDataIntoMap(
304        pickle.data(), pickle.size(), &drop_data->custom_data);
305}
306
307// Utilities to convert between WebKit::WebDragOperationsMask and
308// ui::DragDropTypes.
309int ConvertFromWeb(WebKit::WebDragOperationsMask ops) {
310  int drag_op = ui::DragDropTypes::DRAG_NONE;
311  if (ops & WebKit::WebDragOperationCopy)
312    drag_op |= ui::DragDropTypes::DRAG_COPY;
313  if (ops & WebKit::WebDragOperationMove)
314    drag_op |= ui::DragDropTypes::DRAG_MOVE;
315  if (ops & WebKit::WebDragOperationLink)
316    drag_op |= ui::DragDropTypes::DRAG_LINK;
317  return drag_op;
318}
319
320WebKit::WebDragOperationsMask ConvertToWeb(int drag_op) {
321  int web_drag_op = WebKit::WebDragOperationNone;
322  if (drag_op & ui::DragDropTypes::DRAG_COPY)
323    web_drag_op |= WebKit::WebDragOperationCopy;
324  if (drag_op & ui::DragDropTypes::DRAG_MOVE)
325    web_drag_op |= WebKit::WebDragOperationMove;
326  if (drag_op & ui::DragDropTypes::DRAG_LINK)
327    web_drag_op |= WebKit::WebDragOperationLink;
328  return (WebKit::WebDragOperationsMask) web_drag_op;
329}
330
331int ConvertAuraEventFlagsToWebInputEventModifiers(int aura_event_flags) {
332  int web_input_event_modifiers = 0;
333  if (aura_event_flags & ui::EF_SHIFT_DOWN)
334    web_input_event_modifiers |= WebKit::WebInputEvent::ShiftKey;
335  if (aura_event_flags & ui::EF_CONTROL_DOWN)
336    web_input_event_modifiers |= WebKit::WebInputEvent::ControlKey;
337  if (aura_event_flags & ui::EF_ALT_DOWN)
338    web_input_event_modifiers |= WebKit::WebInputEvent::AltKey;
339  if (aura_event_flags & ui::EF_COMMAND_DOWN)
340    web_input_event_modifiers |= WebKit::WebInputEvent::MetaKey;
341  return web_input_event_modifiers;
342}
343
344// A LayerDelegate that paints an image for the layer.
345class ImageLayerDelegate : public ui::LayerDelegate {
346 public:
347  ImageLayerDelegate() {}
348
349  virtual ~ImageLayerDelegate() {}
350
351  void SetImage(const gfx::Image& image) {
352    image_ = image;
353    image_size_ = image.AsImageSkia().size();
354  }
355  const gfx::Image& image() const { return image_; }
356
357 private:
358  // Overridden from ui::LayerDelegate:
359  virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE {
360    if (image_.IsEmpty()) {
361      canvas->DrawColor(SK_ColorGRAY);
362    } else {
363      SkISize size = canvas->sk_canvas()->getDeviceSize();
364      if (size.width() != image_size_.width() ||
365          size.height() != image_size_.height()) {
366        canvas->DrawColor(SK_ColorWHITE);
367      }
368      canvas->DrawImageInt(image_.AsImageSkia(), 0, 0);
369    }
370  }
371
372  // Called when the layer's device scale factor has changed.
373  virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE {
374  }
375
376  // Invoked prior to the bounds changing. The returned closured is run after
377  // the bounds change.
378  virtual base::Closure PrepareForLayerBoundsChange() OVERRIDE {
379    return base::Closure();
380  }
381
382  gfx::Image image_;
383  gfx::Size image_size_;
384
385  DISALLOW_COPY_AND_ASSIGN(ImageLayerDelegate);
386};
387
388}  // namespace
389
390// When a history navigation is triggered at the end of an overscroll
391// navigation, it is necessary to show the history-screenshot until the page is
392// done navigating and painting. This class accomplishes this by showing the
393// screenshot window on top of the page until the page has completed loading and
394// painting.
395class OverscrollNavigationOverlay :
396    public RenderWidgetHostViewAura::PaintObserver,
397    public WindowSlider::Delegate {
398 public:
399  explicit OverscrollNavigationOverlay(WebContentsImpl* web_contents)
400      : web_contents_(web_contents),
401        image_delegate_(NULL),
402        view_(NULL),
403        loading_complete_(false),
404        received_paint_update_(false),
405        compositor_updated_(false),
406        slide_direction_(SLIDE_UNKNOWN),
407        need_paint_update_(true) {
408  }
409
410  virtual ~OverscrollNavigationOverlay() {
411    if (view_)
412      view_->set_paint_observer(NULL);
413  }
414
415  bool has_window() const { return !!window_.get(); }
416
417  void StartObservingView(RenderWidgetHostViewAura* view) {
418    if (view_)
419      view_->set_paint_observer(NULL);
420
421    loading_complete_ = false;
422    received_paint_update_ = false;
423    compositor_updated_ = false;
424    view_ = view;
425    if (view_)
426      view_->set_paint_observer(this);
427
428    // Make sure the overlay window is on top.
429    if (window_.get() && window_->parent())
430      window_->parent()->StackChildAtTop(window_.get());
431  }
432
433  void SetOverlayWindow(scoped_ptr<aura::Window> window,
434                        ImageWindowDelegate* delegate) {
435    window_ = window.Pass();
436    if (window_.get() && window_->parent())
437      window_->parent()->StackChildAtTop(window_.get());
438    image_delegate_ = delegate;
439
440    if (window_.get() && delegate->has_image()) {
441      window_slider_.reset(new WindowSlider(this,
442                                            window_->parent(),
443                                            window_.get()));
444      slide_direction_ = SLIDE_UNKNOWN;
445    } else {
446      window_slider_.reset();
447    }
448  }
449
450  void SetupForTesting() {
451    need_paint_update_ = false;
452  }
453
454 private:
455  // Stop observing the page if the page-load has completed and the page has
456  // been painted, and a window-slide isn't in progress.
457  void StopObservingIfDone() {
458    // If there is a screenshot displayed in the overlay window, then wait for
459    // the navigated page to complete loading and some paint update before
460    // hiding the overlay.
461    // If there is no screenshot in the overlay window, then hide this view
462    // as soon as there is any new painting notification.
463    if ((need_paint_update_ && !received_paint_update_) ||
464        (image_delegate_->has_image() && !loading_complete_)) {
465      return;
466    }
467
468    // If a slide is in progress, then do not destroy the window or the slide.
469    if (window_slider_.get() && window_slider_->IsSlideInProgress())
470      return;
471
472    window_slider_.reset();
473    window_.reset();
474    image_delegate_ = NULL;
475    if (view_) {
476      view_->set_paint_observer(NULL);
477      view_ = NULL;
478    }
479  }
480
481  // Creates a layer to be used for window-slide. |offset| is the offset of the
482  // NavigationEntry for the screenshot image to display.
483  ui::Layer* CreateSlideLayer(int offset) {
484    const NavigationControllerImpl& controller = web_contents_->GetController();
485    const NavigationEntryImpl* entry = NavigationEntryImpl::FromNavigationEntry(
486        controller.GetEntryAtOffset(offset));
487
488    gfx::Image image;
489    if (entry && entry->screenshot().get()) {
490      std::vector<gfx::ImagePNGRep> image_reps;
491      image_reps.push_back(gfx::ImagePNGRep(entry->screenshot(),
492            ui::GetScaleFactorForNativeView(window_.get())));
493      image = gfx::Image(image_reps);
494    }
495    layer_delegate_.SetImage(image);
496
497    ui::Layer* layer = new ui::Layer(ui::LAYER_TEXTURED);
498    layer->set_delegate(&layer_delegate_);
499    return layer;
500  }
501
502  // Overridden from WindowSlider::Delegate:
503  virtual ui::Layer* CreateBackLayer() OVERRIDE {
504    if (!web_contents_->GetController().CanGoBack())
505      return NULL;
506    slide_direction_ = SLIDE_BACK;
507    return CreateSlideLayer(-1);
508  }
509
510  virtual ui::Layer* CreateFrontLayer() OVERRIDE {
511    if (!web_contents_->GetController().CanGoForward())
512      return NULL;
513    slide_direction_ = SLIDE_FRONT;
514    return CreateSlideLayer(1);
515  }
516
517  virtual void OnWindowSlideComplete() OVERRIDE {
518    if (slide_direction_ == SLIDE_UNKNOWN) {
519      window_slider_.reset();
520      StopObservingIfDone();
521      return;
522    }
523
524    // Change the image used for the overlay window.
525    image_delegate_->SetImage(layer_delegate_.image());
526    window_->layer()->SetTransform(gfx::Transform());
527    window_->SchedulePaintInRect(gfx::Rect(window_->bounds().size()));
528
529    SlideDirection direction = slide_direction_;
530    slide_direction_ = SLIDE_UNKNOWN;
531
532    // Reset state and wait for the new navigation page to complete
533    // loading/painting.
534    StartObservingView(ToRenderWidgetHostViewAura(
535        web_contents_->GetRenderWidgetHostView()));
536
537    // Perform the navigation.
538    if (direction == SLIDE_BACK)
539      web_contents_->GetController().GoBack();
540    else if (direction == SLIDE_FRONT)
541      web_contents_->GetController().GoForward();
542    else
543      NOTREACHED();
544  }
545
546  virtual void OnWindowSlideAborted() OVERRIDE {
547    StopObservingIfDone();
548  }
549
550  virtual void OnWindowSliderDestroyed() OVERRIDE {
551    // The slider has just been destroyed. Release the ownership.
552    WindowSlider* slider ALLOW_UNUSED = window_slider_.release();
553    StopObservingIfDone();
554  }
555
556  // Overridden from RenderWidgetHostViewAura::PaintObserver:
557  virtual void OnPaintComplete() OVERRIDE {
558    received_paint_update_ = true;
559    StopObservingIfDone();
560  }
561
562  virtual void OnCompositingComplete() OVERRIDE {
563    received_paint_update_ = compositor_updated_;
564    StopObservingIfDone();
565  }
566
567  virtual void OnUpdateCompositorContent() OVERRIDE {
568    compositor_updated_ = true;
569  }
570
571  virtual void OnPageLoadComplete() OVERRIDE {
572    loading_complete_ = true;
573    StopObservingIfDone();
574  }
575
576  virtual void OnViewDestroyed() OVERRIDE {
577    DCHECK(view_);
578    view_->set_paint_observer(NULL);
579    view_ = NULL;
580  }
581
582  // The WebContents which is being navigated.
583  WebContentsImpl* web_contents_;
584
585  scoped_ptr<aura::Window> window_;
586
587  // This is the WindowDelegate of |window_|. The delegate manages its own
588  // lifetime (destroys itself when |window_| is destroyed).
589  ImageWindowDelegate* image_delegate_;
590
591  RenderWidgetHostViewAura* view_;
592  bool loading_complete_;
593  bool received_paint_update_;
594  bool compositor_updated_;
595
596  enum SlideDirection {
597    SLIDE_UNKNOWN,
598    SLIDE_BACK,
599    SLIDE_FRONT
600  };
601
602  // The |WindowSlider| that allows sliding history layers while the page is
603  // being reloaded.
604  scoped_ptr<WindowSlider> window_slider_;
605
606  // The direction of the in-progress slide (if any).
607  SlideDirection slide_direction_;
608
609  // The LayerDelegate used for the back/front layers during a slide.
610  ImageLayerDelegate layer_delegate_;
611
612  // During tests, the aura windows don't get any paint updates. So the overlay
613  // container keeps waiting for a paint update it never receives, causing a
614  // timeout. So during tests, disable the wait for paint updates.
615  bool need_paint_update_;
616
617  DISALLOW_COPY_AND_ASSIGN(OverscrollNavigationOverlay);
618};
619
620class WebContentsViewAura::WindowObserver
621    : public aura::WindowObserver, public aura::RootWindowObserver {
622 public:
623  explicit WindowObserver(WebContentsViewAura* view)
624      : view_(view),
625        parent_(NULL) {
626    view_->window_->AddObserver(this);
627  }
628
629  virtual ~WindowObserver() {
630    view_->window_->RemoveObserver(this);
631    if (view_->window_->GetRootWindow())
632      view_->window_->GetRootWindow()->RemoveRootWindowObserver(this);
633    if (parent_)
634      parent_->RemoveObserver(this);
635  }
636
637  // Overridden from aura::WindowObserver:
638  virtual void OnWindowParentChanged(aura::Window* window,
639                                     aura::Window* parent) OVERRIDE {
640    if (window == parent_)
641      return;
642    if (parent_)
643      parent_->RemoveObserver(this);
644    parent_ = parent;
645    if (parent)
646      parent->AddObserver(this);
647  }
648
649  virtual void OnWindowBoundsChanged(aura::Window* window,
650                                     const gfx::Rect& old_bounds,
651                                     const gfx::Rect& new_bounds) OVERRIDE {
652    SendScreenRects();
653    if (view_->touch_editable_)
654      view_->touch_editable_->UpdateEditingController();
655  }
656
657  virtual void OnWindowAddedToRootWindow(aura::Window* window) OVERRIDE {
658    if (window != parent_)
659      window->GetRootWindow()->AddRootWindowObserver(this);
660  }
661
662  virtual void OnWindowRemovingFromRootWindow(aura::Window* window) OVERRIDE {
663    if (window != parent_)
664      window->GetRootWindow()->RemoveRootWindowObserver(this);
665  }
666
667  // Overridden RootWindowObserver:
668  virtual void OnRootWindowHostMoved(const aura::RootWindow* root,
669                                     const gfx::Point& new_origin) OVERRIDE {
670    // This is for the desktop case (i.e. Aura desktop).
671    SendScreenRects();
672  }
673
674 private:
675  void SendScreenRects() {
676    RenderWidgetHostImpl::From(view_->web_contents_->GetRenderViewHost())->
677        SendScreenRects();
678  }
679
680  WebContentsViewAura* view_;
681
682  // We cache the old parent so that we can unregister when it's not the parent
683  // anymore.
684  aura::Window* parent_;
685
686  DISALLOW_COPY_AND_ASSIGN(WindowObserver);
687};
688
689#if defined(OS_WIN)
690// Constrained windows are added as children of the WebContent's view which may
691// overlap with windowed NPAPI plugins. In that case, tell the RWHV so that it
692// can update the plugins' cutout rects accordingly.
693class WebContentsViewAura::ChildWindowObserver : public aura::WindowObserver,
694                                                 public WebContentsObserver {
695 public:
696  explicit ChildWindowObserver(WebContentsViewAura* view)
697      : WebContentsObserver(view->web_contents_),
698        view_(view),
699        web_contents_destroyed_(false) {
700    view_->window_->AddObserver(this);
701  }
702
703  virtual ~ChildWindowObserver() {
704    view_->window_->RemoveObserver(this);
705    const aura::Window::Windows& children = view_->window_->children();
706    for (size_t i = 0; i < children.size(); ++i)
707      children[i]->RemoveObserver(this);
708  }
709
710  // Overridden from aura::WindowObserver:
711  virtual void OnWindowAdded(aura::Window* new_window) OVERRIDE {
712    // If new child windows are added to the WebContent's view, tell the RWHV.
713    // We also start watching them to know when their size is updated. Of
714    // course, ignore the shadow window that contains the RWHV and child windows
715    // of the child windows that we are watching.
716    RenderWidgetHostViewAura* view = ToRenderWidgetHostViewAura(
717        view_->web_contents_->GetRenderWidgetHostView());
718    aura::Window* content_window = view ? view->GetNativeView() : NULL;
719    if (new_window->parent() == view_->window_ &&
720        new_window != content_window) {
721      new_window->AddObserver(this);
722      UpdateConstrainedWindows(NULL);
723    }
724  }
725
726  virtual void OnWillRemoveWindow(aura::Window* window) OVERRIDE {
727    RenderWidgetHostViewAura* view = ToRenderWidgetHostViewAura(
728        view_->web_contents_->GetRenderWidgetHostView());
729    aura::Window* content_window = view ? view->GetNativeView() : NULL;
730    if (window->parent() == view_->window_ &&
731        window != content_window) {
732      window->RemoveObserver(this);
733      UpdateConstrainedWindows(window);
734    }
735  }
736
737  virtual void OnWindowBoundsChanged(aura::Window* window,
738                                     const gfx::Rect& old_bounds,
739                                     const gfx::Rect& new_bounds) OVERRIDE {
740    if (window->parent() == view_->window_ &&
741        window != view_->GetContentNativeView()) {
742      UpdateConstrainedWindows(NULL);
743    }
744  }
745
746  // Overridden from WebContentsObserver:
747  virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE {
748    web_contents_destroyed_ = true;
749  }
750
751 private:
752  void UpdateConstrainedWindows(aura::Window* exclude) {
753    if (web_contents_destroyed_)
754      return;
755
756    RenderWidgetHostViewAura* view = ToRenderWidgetHostViewAura(
757        view_->web_contents_->GetRenderWidgetHostView());
758    if (!view)
759      return;
760
761    std::vector<gfx::Rect> constrained_windows;
762    const aura::Window::Windows& children = view_->window_->children();
763    aura::Window* content = view_->GetContentNativeView();
764    for (size_t i = 0; i < children.size(); ++i) {
765      if (children[i] != content && children[i] != exclude)
766        constrained_windows.push_back(children[i]->GetBoundsInRootWindow());
767    }
768
769    view->UpdateConstrainedWindowRects(constrained_windows);
770  }
771
772  WebContentsViewAura* view_;
773  bool web_contents_destroyed_;
774
775  DISALLOW_COPY_AND_ASSIGN(ChildWindowObserver);
776};
777#endif
778
779////////////////////////////////////////////////////////////////////////////////
780// WebContentsViewAura, public:
781
782WebContentsViewAura::WebContentsViewAura(
783    WebContentsImpl* web_contents,
784    WebContentsViewDelegate* delegate)
785    : web_contents_(web_contents),
786      delegate_(delegate),
787      current_drag_op_(WebKit::WebDragOperationNone),
788      drag_dest_delegate_(NULL),
789      current_rvh_for_drag_(NULL),
790      overscroll_change_brightness_(false),
791      current_overscroll_gesture_(OVERSCROLL_NONE),
792      completed_overscroll_gesture_(OVERSCROLL_NONE),
793      touch_editable_(TouchEditableImplAura::Create()) {
794}
795
796////////////////////////////////////////////////////////////////////////////////
797// WebContentsViewAura, private:
798
799WebContentsViewAura::~WebContentsViewAura() {
800  if (!window_)
801    return;
802
803  window_observer_.reset();
804#if defined(OS_WIN)
805  child_window_observer_.reset();
806#endif
807  // Window needs a valid delegate during its destructor, so we explicitly
808  // delete it here.
809  window_.reset();
810}
811
812void WebContentsViewAura::SetupOverlayWindowForTesting() {
813  if (navigation_overlay_)
814    navigation_overlay_->SetupForTesting();
815}
816
817void WebContentsViewAura::SetTouchEditableForTest(
818    TouchEditableImplAura* touch_editable) {
819  touch_editable_.reset(touch_editable);
820  AttachTouchEditableToRenderView();
821}
822
823void WebContentsViewAura::SizeChangedCommon(const gfx::Size& size) {
824  if (web_contents_->GetInterstitialPage())
825    web_contents_->GetInterstitialPage()->SetSize(size);
826  RenderWidgetHostView* rwhv =
827      web_contents_->GetRenderWidgetHostView();
828  if (rwhv)
829    rwhv->SetSize(size);
830}
831
832void WebContentsViewAura::EndDrag(WebKit::WebDragOperationsMask ops) {
833  aura::RootWindow* root_window = GetNativeView()->GetRootWindow();
834  gfx::Point screen_loc =
835      gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint();
836  gfx::Point client_loc = screen_loc;
837  RenderViewHost* rvh = web_contents_->GetRenderViewHost();
838  aura::Window* window = rvh->GetView()->GetNativeView();
839  aura::Window::ConvertPointToTarget(root_window, window, &client_loc);
840  if (!web_contents_)
841    return;
842  web_contents_->DragSourceEndedAt(client_loc.x(), client_loc.y(),
843      screen_loc.x(), screen_loc.y(), ops);
844}
845
846void WebContentsViewAura::PrepareOverscrollWindow() {
847  // If there is an existing |overscroll_window_| which is in the middle of an
848  // animation, then destroying the window here causes the animation to be
849  // completed immidiately, which triggers |OnImplicitAnimationsCompleted()|
850  // callback, and that tries to reset |overscroll_window_| again, causing a
851  // double-free. So use a temporary variable here.
852  if (overscroll_window_) {
853    base::AutoReset<OverscrollMode> reset_state(&current_overscroll_gesture_,
854                                                current_overscroll_gesture_);
855    scoped_ptr<aura::Window> reset_window(overscroll_window_.release());
856  }
857
858  OverscrollWindowDelegate* overscroll_delegate = new OverscrollWindowDelegate(
859      web_contents_,
860      current_overscroll_gesture_);
861  overscroll_window_.reset(new aura::Window(overscroll_delegate));
862  overscroll_window_->SetType(aura::client::WINDOW_TYPE_CONTROL);
863  overscroll_window_->SetTransparent(true);
864  overscroll_window_->Init(ui::LAYER_TEXTURED);
865  overscroll_window_->layer()->SetMasksToBounds(false);
866  overscroll_window_->SetName("OverscrollOverlay");
867
868  overscroll_change_brightness_ = overscroll_delegate->has_image();
869  window_->AddChild(overscroll_window_.get());
870
871  gfx::Rect bounds = gfx::Rect(window_->bounds().size());
872  if (ShouldNavigateForward(web_contents_->GetController(),
873                            current_overscroll_gesture_)) {
874    // The overlay will be sliding in from the right edge towards the left in
875    // non-RTL, or sliding in from the left edge towards the right in RTL.
876    // So position the overlay window accordingly.
877    bounds.Offset(base::i18n::IsRTL() ? -bounds.width() : bounds.width(), 0);
878  }
879
880  aura::Window* animate_window = GetWindowToAnimateForOverscroll();
881  if (animate_window == overscroll_window_)
882    window_->StackChildAbove(overscroll_window_.get(), GetContentNativeView());
883  else
884    window_->StackChildBelow(overscroll_window_.get(), GetContentNativeView());
885
886  UpdateOverscrollWindowBrightness(0.f);
887
888  overscroll_window_->SetBounds(bounds);
889  overscroll_window_->Show();
890
891  overscroll_shadow_.reset(new ShadowLayerDelegate(animate_window->layer()));
892}
893
894void WebContentsViewAura::PrepareContentWindowForOverscroll() {
895  StopObservingImplicitAnimations();
896  aura::Window* content = GetContentNativeView();
897  content->layer()->GetAnimator()->AbortAllAnimations();
898  content->SetTransform(gfx::Transform());
899  content->layer()->SetLayerBrightness(0.f);
900}
901
902void WebContentsViewAura::ResetOverscrollTransform() {
903  if (!web_contents_->GetRenderWidgetHostView())
904    return;
905  aura::Window* target = GetWindowToAnimateForOverscroll();
906  if (!target)
907    return;
908  {
909    ui::ScopedLayerAnimationSettings settings(target->layer()->GetAnimator());
910    settings.SetPreemptionStrategy(
911        ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
912    settings.SetTweenType(ui::Tween::EASE_OUT);
913    settings.AddObserver(this);
914    target->SetTransform(gfx::Transform());
915  }
916  {
917    ui::ScopedLayerAnimationSettings settings(target->layer()->GetAnimator());
918    settings.SetPreemptionStrategy(
919        ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
920    settings.SetTweenType(ui::Tween::EASE_OUT);
921    UpdateOverscrollWindowBrightness(0.f);
922  }
923}
924
925void WebContentsViewAura::CompleteOverscrollNavigation(OverscrollMode mode) {
926  if (!web_contents_->GetRenderWidgetHostView())
927    return;
928
929  // Animate out the current view first. Navigate to the requested history at
930  // the end of the animation.
931  if (current_overscroll_gesture_ == OVERSCROLL_NONE)
932    return;
933
934  UMA_HISTOGRAM_ENUMERATION("Overscroll.Navigated",
935                            current_overscroll_gesture_, OVERSCROLL_COUNT);
936  OverscrollWindowDelegate* delegate = static_cast<OverscrollWindowDelegate*>(
937      overscroll_window_->delegate());
938  delegate->stop_forwarding_events();
939
940  completed_overscroll_gesture_ = mode;
941  aura::Window* target = GetWindowToAnimateForOverscroll();
942  ui::ScopedLayerAnimationSettings settings(target->layer()->GetAnimator());
943  settings.SetPreemptionStrategy(
944      ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
945  settings.SetTweenType(ui::Tween::EASE_OUT);
946  settings.AddObserver(this);
947  gfx::Transform transform;
948  int content_width =
949      web_contents_->GetRenderWidgetHostView()->GetViewBounds().width();
950  int translate_x = mode == OVERSCROLL_WEST ? -content_width : content_width;
951  transform.Translate(translate_x, 0);
952  target->SetTransform(transform);
953  UpdateOverscrollWindowBrightness(translate_x);
954}
955
956aura::Window* WebContentsViewAura::GetWindowToAnimateForOverscroll() {
957  if (current_overscroll_gesture_ == OVERSCROLL_NONE)
958    return NULL;
959
960  return ShouldNavigateForward(web_contents_->GetController(),
961                               current_overscroll_gesture_) ?
962      overscroll_window_.get() : GetContentNativeView();
963}
964
965gfx::Vector2d WebContentsViewAura::GetTranslationForOverscroll(int delta_x,
966                                                               int delta_y) {
967  if (current_overscroll_gesture_ == OVERSCROLL_NORTH ||
968      current_overscroll_gesture_ == OVERSCROLL_SOUTH) {
969    return gfx::Vector2d(0, delta_y);
970  }
971  // For horizontal overscroll, scroll freely if a navigation is possible. Do a
972  // resistive scroll otherwise.
973  const NavigationControllerImpl& controller = web_contents_->GetController();
974  const gfx::Rect& bounds = GetViewBounds();
975  if (ShouldNavigateForward(controller, current_overscroll_gesture_))
976    return gfx::Vector2d(std::max(-bounds.width(), delta_x), 0);
977  else if (ShouldNavigateBack(controller, current_overscroll_gesture_))
978    return gfx::Vector2d(std::min(bounds.width(), delta_x), 0);
979  return gfx::Vector2d();
980}
981
982void WebContentsViewAura::PrepareOverscrollNavigationOverlay() {
983  OverscrollWindowDelegate* delegate = static_cast<OverscrollWindowDelegate*>(
984      overscroll_window_->delegate());
985  overscroll_window_->SchedulePaintInRect(
986      gfx::Rect(overscroll_window_->bounds().size()));
987  overscroll_window_->SetBounds(gfx::Rect(window_->bounds().size()));
988  overscroll_window_->SetTransform(gfx::Transform());
989  navigation_overlay_->SetOverlayWindow(overscroll_window_.Pass(),
990                                        delegate);
991  navigation_overlay_->StartObservingView(ToRenderWidgetHostViewAura(
992      web_contents_->GetRenderWidgetHostView()));
993}
994
995void WebContentsViewAura::UpdateOverscrollWindowBrightness(float delta_x) {
996  if (!overscroll_change_brightness_)
997    return;
998
999  const float kBrightnessMin = -.1f;
1000  const float kBrightnessMax = -.01f;
1001
1002  float ratio = fabs(delta_x) / GetViewBounds().width();
1003  ratio = std::min(1.f, ratio);
1004  if (base::i18n::IsRTL())
1005    ratio = 1.f - ratio;
1006  float brightness = current_overscroll_gesture_ == OVERSCROLL_WEST ?
1007      kBrightnessMin + ratio * (kBrightnessMax - kBrightnessMin) :
1008      kBrightnessMax - ratio * (kBrightnessMax - kBrightnessMin);
1009  brightness = std::max(kBrightnessMin, brightness);
1010  brightness = std::min(kBrightnessMax, brightness);
1011  aura::Window* window = GetWindowToAnimateForOverscroll();
1012  window->layer()->SetLayerBrightness(brightness);
1013}
1014
1015void WebContentsViewAura::AttachTouchEditableToRenderView() {
1016  if (!touch_editable_)
1017    return;
1018  RenderWidgetHostViewAura* rwhva = ToRenderWidgetHostViewAura(
1019      web_contents_->GetRenderWidgetHostView());
1020  touch_editable_->AttachToView(rwhva);
1021}
1022
1023void WebContentsViewAura::OverscrollUpdateForWebContentsDelegate(int delta_y) {
1024  if (web_contents_->GetDelegate() && IsScrollEndEffectEnabled())
1025    web_contents_->GetDelegate()->OverscrollUpdate(delta_y);
1026}
1027
1028////////////////////////////////////////////////////////////////////////////////
1029// WebContentsViewAura, WebContentsView implementation:
1030
1031gfx::NativeView WebContentsViewAura::GetNativeView() const {
1032  return window_.get();
1033}
1034
1035gfx::NativeView WebContentsViewAura::GetContentNativeView() const {
1036  RenderWidgetHostView* rwhv = web_contents_->GetRenderWidgetHostView();
1037  return rwhv ? rwhv->GetNativeView() : NULL;
1038}
1039
1040gfx::NativeWindow WebContentsViewAura::GetTopLevelNativeWindow() const {
1041  return window_->GetToplevelWindow();
1042}
1043
1044void WebContentsViewAura::GetContainerBounds(gfx::Rect *out) const {
1045  *out = window_->GetBoundsInScreen();
1046}
1047
1048void WebContentsViewAura::OnTabCrashed(base::TerminationStatus status,
1049                                       int error_code) {
1050  // Set the focus to the parent because neither the view window nor this
1051  // window can handle key events.
1052  if (window_->HasFocus() && window_->parent())
1053    window_->parent()->Focus();
1054}
1055
1056void WebContentsViewAura::SizeContents(const gfx::Size& size) {
1057  gfx::Rect bounds = window_->bounds();
1058  if (bounds.size() != size) {
1059    bounds.set_size(size);
1060    window_->SetBounds(bounds);
1061  } else {
1062    // Our size matches what we want but the renderers size may not match.
1063    // Pretend we were resized so that the renderers size is updated too.
1064    SizeChangedCommon(size);
1065  }
1066}
1067
1068void WebContentsViewAura::Focus() {
1069  if (web_contents_->GetInterstitialPage()) {
1070    web_contents_->GetInterstitialPage()->Focus();
1071    return;
1072  }
1073
1074  if (delegate_.get() && delegate_->Focus())
1075    return;
1076
1077  RenderWidgetHostView* rwhv = web_contents_->GetRenderWidgetHostView();
1078  if (rwhv)
1079    rwhv->Focus();
1080}
1081
1082void WebContentsViewAura::SetInitialFocus() {
1083  if (web_contents_->FocusLocationBarByDefault())
1084    web_contents_->SetFocusToLocationBar(false);
1085  else
1086    Focus();
1087}
1088
1089void WebContentsViewAura::StoreFocus() {
1090  if (delegate_)
1091    delegate_->StoreFocus();
1092}
1093
1094void WebContentsViewAura::RestoreFocus() {
1095  if (delegate_)
1096    delegate_->RestoreFocus();
1097}
1098
1099DropData* WebContentsViewAura::GetDropData() const {
1100  return current_drop_data_.get();
1101}
1102
1103gfx::Rect WebContentsViewAura::GetViewBounds() const {
1104  return window_->GetBoundsInScreen();
1105}
1106
1107////////////////////////////////////////////////////////////////////////////////
1108// WebContentsViewAura, WebContentsViewPort implementation:
1109
1110void WebContentsViewAura::CreateView(
1111    const gfx::Size& initial_size, gfx::NativeView context) {
1112  // NOTE: we ignore |initial_size| since in some cases it's wrong (such as
1113  // if the bookmark bar is not shown and you create a new tab). The right
1114  // value is set shortly after this, so its safe to ignore.
1115
1116  window_.reset(new aura::Window(this));
1117  window_->set_owned_by_parent(false);
1118  window_->SetType(aura::client::WINDOW_TYPE_CONTROL);
1119  window_->SetTransparent(false);
1120  window_->Init(ui::LAYER_NOT_DRAWN);
1121  aura::RootWindow* root_window = context ? context->GetRootWindow() : NULL;
1122  if (root_window) {
1123    // There are places where there is no context currently because object
1124    // hierarchies are built before they're attached to a Widget. (See
1125    // views::WebView as an example; GetWidget() returns NULL at the point
1126    // where we are created.)
1127    //
1128    // It should be OK to not set a default parent since such users will
1129    // explicitly add this WebContentsViewAura to their tree after they create
1130    // us.
1131    if (root_window) {
1132      window_->SetDefaultParentByRootWindow(
1133          root_window, root_window->GetBoundsInScreen());
1134    }
1135  }
1136  window_->layer()->SetMasksToBounds(true);
1137  window_->SetName("WebContentsViewAura");
1138
1139  window_observer_.reset(new WindowObserver(this));
1140#if defined(OS_WIN)
1141  child_window_observer_.reset(new ChildWindowObserver(this));
1142#endif
1143
1144  // delegate_->GetDragDestDelegate() creates a new delegate on every call.
1145  // Hence, we save a reference to it locally. Similar model is used on other
1146  // platforms as well.
1147  if (delegate_)
1148    drag_dest_delegate_ = delegate_->GetDragDestDelegate();
1149}
1150
1151RenderWidgetHostView* WebContentsViewAura::CreateViewForWidget(
1152    RenderWidgetHost* render_widget_host) {
1153  if (render_widget_host->GetView()) {
1154    // During testing, the view will already be set up in most cases to the
1155    // test view, so we don't want to clobber it with a real one. To verify that
1156    // this actually is happening (and somebody isn't accidentally creating the
1157    // view twice), we check for the RVH Factory, which will be set when we're
1158    // making special ones (which go along with the special views).
1159    DCHECK(RenderViewHostFactory::has_factory());
1160    return render_widget_host->GetView();
1161  }
1162
1163  RenderWidgetHostView* view =
1164      RenderWidgetHostView::CreateViewForWidget(render_widget_host);
1165  view->InitAsChild(NULL);
1166  GetNativeView()->AddChild(view->GetNativeView());
1167
1168  if (navigation_overlay_.get() && navigation_overlay_->has_window()) {
1169    navigation_overlay_->StartObservingView(ToRenderWidgetHostViewAura(view));
1170  }
1171
1172  view->Show();
1173
1174  // We listen to drag drop events in the newly created view's window.
1175  aura::client::SetDragDropDelegate(view->GetNativeView(), this);
1176
1177  RenderWidgetHostImpl* host_impl =
1178      RenderWidgetHostImpl::From(render_widget_host);
1179  if (host_impl->overscroll_controller() &&
1180      (!web_contents_->GetDelegate() ||
1181       web_contents_->GetDelegate()->CanOverscrollContent())) {
1182    host_impl->overscroll_controller()->set_delegate(this);
1183    if (!navigation_overlay_)
1184      navigation_overlay_.reset(new OverscrollNavigationOverlay(web_contents_));
1185  }
1186
1187  AttachTouchEditableToRenderView();
1188  return view;
1189}
1190
1191RenderWidgetHostView* WebContentsViewAura::CreateViewForPopupWidget(
1192    RenderWidgetHost* render_widget_host) {
1193  return RenderWidgetHostViewPort::CreateViewForWidget(render_widget_host);
1194}
1195
1196void WebContentsViewAura::SetPageTitle(const string16& title) {
1197  window_->set_title(title);
1198}
1199
1200void WebContentsViewAura::RenderViewCreated(RenderViewHost* host) {
1201}
1202
1203void WebContentsViewAura::RenderViewSwappedIn(RenderViewHost* host) {
1204  if (navigation_overlay_.get() && navigation_overlay_->has_window()) {
1205    navigation_overlay_->StartObservingView(
1206        ToRenderWidgetHostViewAura(host->GetView()));
1207  }
1208  AttachTouchEditableToRenderView();
1209}
1210
1211void WebContentsViewAura::SetOverscrollControllerEnabled(bool enabled) {
1212  RenderViewHostImpl* host = static_cast<RenderViewHostImpl*>(
1213      web_contents_->GetRenderViewHost());
1214  if (host) {
1215    host->SetOverscrollControllerEnabled(enabled);
1216    if (enabled)
1217      host->overscroll_controller()->set_delegate(this);
1218  }
1219
1220  if (!enabled)
1221    navigation_overlay_.reset();
1222  else if (!navigation_overlay_)
1223    navigation_overlay_.reset(new OverscrollNavigationOverlay(web_contents_));
1224}
1225
1226////////////////////////////////////////////////////////////////////////////////
1227// WebContentsViewAura, RenderViewHostDelegateView implementation:
1228
1229void WebContentsViewAura::ShowContextMenu(const ContextMenuParams& params) {
1230  if (delegate_)
1231    delegate_->ShowContextMenu(params);
1232  if (touch_editable_)
1233    touch_editable_->EndTouchEditing();
1234
1235}
1236
1237void WebContentsViewAura::ShowPopupMenu(const gfx::Rect& bounds,
1238                                        int item_height,
1239                                        double item_font_size,
1240                                        int selected_item,
1241                                        const std::vector<MenuItem>& items,
1242                                        bool right_aligned,
1243                                        bool allow_multiple_selection) {
1244  // External popup menus are only used on Mac and Android.
1245  NOTIMPLEMENTED();
1246}
1247
1248void WebContentsViewAura::StartDragging(
1249    const DropData& drop_data,
1250    WebKit::WebDragOperationsMask operations,
1251    const gfx::ImageSkia& image,
1252    const gfx::Vector2d& image_offset,
1253    const DragEventSourceInfo& event_info) {
1254  aura::RootWindow* root_window = GetNativeView()->GetRootWindow();
1255  if (!aura::client::GetDragDropClient(root_window)) {
1256    web_contents_->SystemDragEnded();
1257    return;
1258  }
1259
1260  if (touch_editable_)
1261    touch_editable_->EndTouchEditing();
1262
1263  ui::OSExchangeData::Provider* provider = ui::OSExchangeData::CreateProvider();
1264  PrepareDragData(drop_data, provider);
1265
1266  ui::OSExchangeData data(provider);  // takes ownership of |provider|.
1267
1268  if (!image.isNull()) {
1269    drag_utils::SetDragImageOnDataObject(image,
1270        gfx::Size(image.width(), image.height()), image_offset, &data);
1271  }
1272
1273  scoped_ptr<WebDragSourceAura> drag_source(
1274      new WebDragSourceAura(GetNativeView(), web_contents_));
1275
1276  // We need to enable recursive tasks on the message loop so we can get
1277  // updates while in the system DoDragDrop loop.
1278  int result_op = 0;
1279  {
1280    gfx::NativeView content_native_view = GetContentNativeView();
1281    base::MessageLoop::ScopedNestableTaskAllower allow(
1282        base::MessageLoop::current());
1283    result_op = aura::client::GetDragDropClient(root_window)
1284        ->StartDragAndDrop(data,
1285                           root_window,
1286                           content_native_view,
1287                           event_info.event_location,
1288                           ConvertFromWeb(operations),
1289                           event_info.event_source);
1290  }
1291
1292  // Bail out immediately if the contents view window is gone. Note that it is
1293  // not safe to access any class members in this case since |this| may already
1294  // be destroyed. The local variable |drag_source| will still be valid though,
1295  // so we can use it to determine if the window is gone.
1296  if (!drag_source->window()) {
1297    // Note that in this case, we don't need to call SystemDragEnded() since the
1298    // renderer is going away.
1299    return;
1300  }
1301
1302  EndDrag(ConvertToWeb(result_op));
1303  web_contents_->SystemDragEnded();
1304}
1305
1306void WebContentsViewAura::UpdateDragCursor(WebKit::WebDragOperation operation) {
1307  current_drag_op_ = operation;
1308}
1309
1310void WebContentsViewAura::GotFocus() {
1311  if (web_contents_->GetDelegate())
1312    web_contents_->GetDelegate()->WebContentsFocused(web_contents_);
1313}
1314
1315void WebContentsViewAura::TakeFocus(bool reverse) {
1316  if (web_contents_->GetDelegate() &&
1317      !web_contents_->GetDelegate()->TakeFocus(web_contents_, reverse) &&
1318      delegate_.get()) {
1319    delegate_->TakeFocus(reverse);
1320  }
1321}
1322
1323////////////////////////////////////////////////////////////////////////////////
1324// WebContentsViewAura, OverscrollControllerDelegate implementation:
1325
1326void WebContentsViewAura::OnOverscrollUpdate(float delta_x, float delta_y) {
1327  if (current_overscroll_gesture_ == OVERSCROLL_NONE)
1328    return;
1329
1330  aura::Window* target = GetWindowToAnimateForOverscroll();
1331  ui::ScopedLayerAnimationSettings settings(target->layer()->GetAnimator());
1332  settings.SetPreemptionStrategy(ui::LayerAnimator::IMMEDIATELY_SET_NEW_TARGET);
1333  gfx::Vector2d translate = GetTranslationForOverscroll(delta_x, delta_y);
1334  gfx::Transform transform;
1335
1336  // Vertical overscrolls don't participate in the navigation gesture.
1337  if (current_overscroll_gesture_ != OVERSCROLL_NORTH &&
1338      current_overscroll_gesture_ != OVERSCROLL_SOUTH) {
1339    transform.Translate(translate.x(), translate.y());
1340    target->SetTransform(transform);
1341    UpdateOverscrollWindowBrightness(delta_x);
1342  }
1343
1344  OverscrollUpdateForWebContentsDelegate(translate.y());
1345}
1346
1347void WebContentsViewAura::OnOverscrollComplete(OverscrollMode mode) {
1348  UMA_HISTOGRAM_ENUMERATION("Overscroll.Completed", mode, OVERSCROLL_COUNT);
1349  OverscrollUpdateForWebContentsDelegate(0);
1350  NavigationControllerImpl& controller = web_contents_->GetController();
1351  if (ShouldNavigateForward(controller, mode) ||
1352      ShouldNavigateBack(controller, mode)) {
1353    CompleteOverscrollNavigation(mode);
1354    return;
1355  }
1356
1357  ResetOverscrollTransform();
1358}
1359
1360void WebContentsViewAura::OnOverscrollModeChange(OverscrollMode old_mode,
1361                                                 OverscrollMode new_mode) {
1362  // Reset any in-progress overscroll animation first.
1363  ResetOverscrollTransform();
1364
1365  if (new_mode == OVERSCROLL_NONE ||
1366      !GetContentNativeView() ||
1367      ((new_mode == OVERSCROLL_EAST || new_mode == OVERSCROLL_WEST) &&
1368       navigation_overlay_.get() && navigation_overlay_->has_window())) {
1369    current_overscroll_gesture_ = OVERSCROLL_NONE;
1370    OverscrollUpdateForWebContentsDelegate(0);
1371  } else {
1372    aura::Window* target = GetWindowToAnimateForOverscroll();
1373    if (target) {
1374      StopObservingImplicitAnimations();
1375      target->layer()->GetAnimator()->AbortAllAnimations();
1376    }
1377    // Cleanup state of the content window first, because that can reset the
1378    // value of |current_overscroll_gesture_|.
1379    PrepareContentWindowForOverscroll();
1380
1381    current_overscroll_gesture_ = new_mode;
1382    if (current_overscroll_gesture_ == OVERSCROLL_EAST ||
1383        current_overscroll_gesture_ == OVERSCROLL_WEST)
1384      PrepareOverscrollWindow();
1385
1386    UMA_HISTOGRAM_ENUMERATION("Overscroll.Started", new_mode, OVERSCROLL_COUNT);
1387  }
1388  completed_overscroll_gesture_ = OVERSCROLL_NONE;
1389}
1390
1391////////////////////////////////////////////////////////////////////////////////
1392// WebContentsViewAura, ui::ImplicitAnimationObserver implementation:
1393
1394void WebContentsViewAura::OnImplicitAnimationsCompleted() {
1395  overscroll_shadow_.reset();
1396
1397  if (ShouldNavigateForward(web_contents_->GetController(),
1398                            completed_overscroll_gesture_)) {
1399    PrepareOverscrollNavigationOverlay();
1400    web_contents_->GetController().GoForward();
1401  } else if (ShouldNavigateBack(web_contents_->GetController(),
1402                                completed_overscroll_gesture_)) {
1403    PrepareOverscrollNavigationOverlay();
1404    web_contents_->GetController().GoBack();
1405  }
1406
1407  aura::Window* content = GetContentNativeView();
1408  if (content) {
1409    content->SetTransform(gfx::Transform());
1410    content->layer()->SetLayerBrightness(0.f);
1411  }
1412  current_overscroll_gesture_ = OVERSCROLL_NONE;
1413  completed_overscroll_gesture_ = OVERSCROLL_NONE;
1414  overscroll_window_.reset();
1415}
1416
1417////////////////////////////////////////////////////////////////////////////////
1418// WebContentsViewAura, aura::WindowDelegate implementation:
1419
1420gfx::Size WebContentsViewAura::GetMinimumSize() const {
1421  return gfx::Size();
1422}
1423
1424gfx::Size WebContentsViewAura::GetMaximumSize() const {
1425  return gfx::Size();
1426}
1427
1428void WebContentsViewAura::OnBoundsChanged(const gfx::Rect& old_bounds,
1429                                          const gfx::Rect& new_bounds) {
1430  SizeChangedCommon(new_bounds.size());
1431  if (delegate_)
1432    delegate_->SizeChanged(new_bounds.size());
1433
1434  // Constrained web dialogs, need to be kept centered over our content area.
1435  for (size_t i = 0; i < window_->children().size(); i++) {
1436    if (window_->children()[i]->GetProperty(
1437            aura::client::kConstrainedWindowKey)) {
1438      gfx::Rect bounds = window_->children()[i]->bounds();
1439      bounds.set_origin(
1440          gfx::Point((new_bounds.width() - bounds.width()) / 2,
1441                     (new_bounds.height() - bounds.height()) / 2));
1442      window_->children()[i]->SetBounds(bounds);
1443    }
1444  }
1445}
1446
1447gfx::NativeCursor WebContentsViewAura::GetCursor(const gfx::Point& point) {
1448  return gfx::kNullCursor;
1449}
1450
1451int WebContentsViewAura::GetNonClientComponent(const gfx::Point& point) const {
1452  return HTCLIENT;
1453}
1454
1455bool WebContentsViewAura::ShouldDescendIntoChildForEventHandling(
1456    aura::Window* child,
1457    const gfx::Point& location) {
1458  return true;
1459}
1460
1461bool WebContentsViewAura::CanFocus() {
1462  // Do not take the focus if the render widget host view is gone because
1463  // neither the view window nor this window can handle key events.
1464  return web_contents_->GetRenderWidgetHostView() != NULL;
1465}
1466
1467void WebContentsViewAura::OnCaptureLost() {
1468}
1469
1470void WebContentsViewAura::OnPaint(gfx::Canvas* canvas) {
1471}
1472
1473void WebContentsViewAura::OnDeviceScaleFactorChanged(
1474    float device_scale_factor) {
1475}
1476
1477void WebContentsViewAura::OnWindowDestroying() {
1478  // This means the destructor is going to be called soon. If there is an
1479  // overscroll gesture in progress (i.e. |overscroll_window_| is not NULL),
1480  // then destroying it in the WebContentsViewAura destructor can trigger other
1481  // virtual functions to be called (e.g. OnImplicitAnimationsCompleted()). So
1482  // destroy the overscroll window here.
1483  navigation_overlay_.reset();
1484  overscroll_window_.reset();
1485}
1486
1487void WebContentsViewAura::OnWindowDestroyed() {
1488}
1489
1490void WebContentsViewAura::OnWindowTargetVisibilityChanged(bool visible) {
1491  if (visible)
1492    web_contents_->WasShown();
1493  else
1494    web_contents_->WasHidden();
1495}
1496
1497bool WebContentsViewAura::HasHitTestMask() const {
1498  return false;
1499}
1500
1501void WebContentsViewAura::GetHitTestMask(gfx::Path* mask) const {
1502}
1503
1504scoped_refptr<ui::Texture> WebContentsViewAura::CopyTexture() {
1505  // The layer we create doesn't have an external texture, so this should never
1506  // get invoked.
1507  NOTREACHED();
1508  return scoped_refptr<ui::Texture>();
1509}
1510
1511////////////////////////////////////////////////////////////////////////////////
1512// WebContentsViewAura, ui::EventHandler implementation:
1513
1514void WebContentsViewAura::OnKeyEvent(ui::KeyEvent* event) {
1515}
1516
1517void WebContentsViewAura::OnMouseEvent(ui::MouseEvent* event) {
1518  if (!web_contents_->GetDelegate())
1519    return;
1520
1521  switch (event->type()) {
1522    case ui::ET_MOUSE_PRESSED:
1523      web_contents_->GetDelegate()->ActivateContents(web_contents_);
1524      break;
1525    case ui::ET_MOUSE_MOVED:
1526    case ui::ET_MOUSE_EXITED:
1527      web_contents_->GetDelegate()->ContentsMouseEvent(
1528          web_contents_,
1529          gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint(),
1530          event->type() == ui::ET_MOUSE_MOVED);
1531      break;
1532    default:
1533      break;
1534  }
1535}
1536
1537////////////////////////////////////////////////////////////////////////////////
1538// WebContentsViewAura, aura::client::DragDropDelegate implementation:
1539
1540void WebContentsViewAura::OnDragEntered(const ui::DropTargetEvent& event) {
1541  if (drag_dest_delegate_)
1542    drag_dest_delegate_->DragInitialize(web_contents_);
1543
1544  current_drop_data_.reset(new DropData());
1545
1546  PrepareDropData(current_drop_data_.get(), event.data());
1547  WebKit::WebDragOperationsMask op = ConvertToWeb(event.source_operations());
1548
1549  gfx::Point screen_pt =
1550      gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint();
1551  current_rvh_for_drag_ = web_contents_->GetRenderViewHost();
1552  web_contents_->GetRenderViewHost()->DragTargetDragEnter(
1553      *current_drop_data_.get(), event.location(), screen_pt, op,
1554      ConvertAuraEventFlagsToWebInputEventModifiers(event.flags()));
1555
1556  if (drag_dest_delegate_) {
1557    drag_dest_delegate_->OnReceiveDragData(event.data());
1558    drag_dest_delegate_->OnDragEnter();
1559  }
1560}
1561
1562int WebContentsViewAura::OnDragUpdated(const ui::DropTargetEvent& event) {
1563  DCHECK(current_rvh_for_drag_);
1564  if (current_rvh_for_drag_ != web_contents_->GetRenderViewHost())
1565    OnDragEntered(event);
1566
1567  WebKit::WebDragOperationsMask op = ConvertToWeb(event.source_operations());
1568  gfx::Point screen_pt =
1569      gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint();
1570  web_contents_->GetRenderViewHost()->DragTargetDragOver(
1571      event.location(), screen_pt, op,
1572      ConvertAuraEventFlagsToWebInputEventModifiers(event.flags()));
1573
1574  if (drag_dest_delegate_)
1575    drag_dest_delegate_->OnDragOver();
1576
1577  return ConvertFromWeb(current_drag_op_);
1578}
1579
1580void WebContentsViewAura::OnDragExited() {
1581  DCHECK(current_rvh_for_drag_);
1582  if (current_rvh_for_drag_ != web_contents_->GetRenderViewHost())
1583    return;
1584
1585  web_contents_->GetRenderViewHost()->DragTargetDragLeave();
1586  if (drag_dest_delegate_)
1587    drag_dest_delegate_->OnDragLeave();
1588
1589  current_drop_data_.reset();
1590}
1591
1592int WebContentsViewAura::OnPerformDrop(const ui::DropTargetEvent& event) {
1593  DCHECK(current_rvh_for_drag_);
1594  if (current_rvh_for_drag_ != web_contents_->GetRenderViewHost())
1595    OnDragEntered(event);
1596
1597  web_contents_->GetRenderViewHost()->DragTargetDrop(
1598      event.location(),
1599      gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint(),
1600      ConvertAuraEventFlagsToWebInputEventModifiers(event.flags()));
1601  if (drag_dest_delegate_)
1602    drag_dest_delegate_->OnDrop();
1603  current_drop_data_.reset();
1604  return current_drag_op_;
1605}
1606
1607}  // namespace content
1608