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