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