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