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