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