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