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