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