Add a FrameHostMsg_BeginNavigation IPC
[chromium-blink-merge.git] / content / browser / web_contents / web_contents_view_aura.cc
blobd04508ecd4cd6cf81ba68380725524958f605a5d
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.
5 #include "content/browser/web_contents/web_contents_view_aura.h"
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"
73 namespace content {
74 WebContentsView* 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;
83 namespace {
85 bool IsScrollEndEffectEnabled() {
86 return CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
87 switches::kScrollEndEffect) == "1";
90 bool ShouldNavigateForward(const NavigationController& controller,
91 OverscrollMode mode) {
92 return mode == (base::i18n::IsRTL() ? OVERSCROLL_EAST : OVERSCROLL_WEST) &&
93 controller.CanGoForward();
96 bool ShouldNavigateBack(const NavigationController& controller,
97 OverscrollMode mode) {
98 return mode == (base::i18n::IsRTL() ? OVERSCROLL_WEST : OVERSCROLL_EAST) &&
99 controller.CanGoBack();
102 RenderWidgetHostViewAura* ToRenderWidgetHostViewAura(
103 RenderWidgetHostView* view) {
104 if (!view || RenderViewHostFactory::has_factory())
105 return NULL; // Can't cast to RenderWidgetHostViewAura in unit tests.
107 RenderViewHost* rvh = RenderViewHost::From(view->GetRenderWidgetHost());
108 WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
109 rvh ? WebContents::FromRenderViewHost(rvh) : NULL);
110 if (BrowserPluginGuest::IsGuest(web_contents))
111 return NULL;
112 return static_cast<RenderWidgetHostViewAura*>(view);
115 // The window delegate for the overscroll window. This redirects trackpad events
116 // to the web-contents window. The delegate destroys itself when the window is
117 // destroyed.
118 class OverscrollWindowDelegate : public ImageWindowDelegate {
119 public:
120 OverscrollWindowDelegate(WebContentsImpl* web_contents,
121 OverscrollMode overscroll_mode)
122 : web_contents_(web_contents),
123 forward_events_(true) {
124 const NavigationControllerImpl& controller = web_contents->GetController();
125 const NavigationEntryImpl* entry = NULL;
126 if (ShouldNavigateForward(controller, overscroll_mode)) {
127 entry = NavigationEntryImpl::FromNavigationEntry(
128 controller.GetEntryAtOffset(1));
129 } else if (ShouldNavigateBack(controller, overscroll_mode)) {
130 entry = NavigationEntryImpl::FromNavigationEntry(
131 controller.GetEntryAtOffset(-1));
134 gfx::Image image;
135 if (entry && entry->screenshot().get()) {
136 std::vector<gfx::ImagePNGRep> image_reps;
137 image_reps.push_back(gfx::ImagePNGRep(entry->screenshot(),
138 ui::GetScaleFactorForNativeView(web_contents_window())));
139 image = gfx::Image(image_reps);
141 SetImage(image);
144 void stop_forwarding_events() { forward_events_ = false; }
146 private:
147 virtual ~OverscrollWindowDelegate() {}
149 aura::Window* web_contents_window() {
150 return web_contents_->GetView()->GetContentNativeView();
153 // Overridden from ui::EventHandler.
154 virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE {
155 if (forward_events_ && web_contents_window())
156 web_contents_window()->delegate()->OnScrollEvent(event);
159 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
160 if (forward_events_ && web_contents_window())
161 web_contents_window()->delegate()->OnGestureEvent(event);
164 WebContentsImpl* web_contents_;
166 // The window is displayed both during the gesture, and after the gesture
167 // while the navigation is in progress. During the gesture, it is necessary to
168 // forward input events to the content page (e.g. when the overscroll window
169 // slides under the cursor and starts receiving scroll events). However, once
170 // the gesture is complete, and the window is being displayed as an overlay
171 // window during navigation, events should not be forwarded anymore.
172 bool forward_events_;
174 DISALLOW_COPY_AND_ASSIGN(OverscrollWindowDelegate);
177 // Listens to all mouse drag events during a drag and drop and sends them to
178 // the renderer.
179 class WebDragSourceAura : public NotificationObserver {
180 public:
181 WebDragSourceAura(aura::Window* window, WebContentsImpl* contents)
182 : window_(window),
183 contents_(contents) {
184 registrar_.Add(this,
185 NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
186 Source<WebContents>(contents));
189 virtual ~WebDragSourceAura() {
192 // NotificationObserver:
193 virtual void Observe(int type,
194 const NotificationSource& source,
195 const NotificationDetails& details) OVERRIDE {
196 if (type != NOTIFICATION_WEB_CONTENTS_DISCONNECTED)
197 return;
199 // Cancel the drag if it is still in progress.
200 aura::client::DragDropClient* dnd_client =
201 aura::client::GetDragDropClient(window_->GetRootWindow());
202 if (dnd_client && dnd_client->IsDragDropInProgress())
203 dnd_client->DragCancel();
205 window_ = NULL;
206 contents_ = NULL;
209 aura::Window* window() const { return window_; }
211 private:
212 aura::Window* window_;
213 WebContentsImpl* contents_;
214 NotificationRegistrar registrar_;
216 DISALLOW_COPY_AND_ASSIGN(WebDragSourceAura);
219 #if (!defined(OS_CHROMEOS) && defined(USE_X11)) || defined(OS_WIN)
220 // Fill out the OSExchangeData with a file contents, synthesizing a name if
221 // necessary.
222 void PrepareDragForFileContents(const DropData& drop_data,
223 ui::OSExchangeData::Provider* provider) {
224 base::FilePath file_name =
225 base::FilePath::FromUTF16Unsafe(drop_data.file_description_filename);
226 // Images without ALT text will only have a file extension so we need to
227 // synthesize one from the provided extension and URL.
228 if (file_name.BaseName().RemoveExtension().empty()) {
229 const base::FilePath::StringType extension = file_name.Extension();
230 // Retrieve the name from the URL.
231 file_name = net::GenerateFileName(drop_data.url, "", "", "", "", "")
232 .ReplaceExtension(extension);
234 provider->SetFileContents(file_name, drop_data.file_contents);
236 #endif
238 #if defined(OS_WIN)
239 void PrepareDragForDownload(
240 const DropData& drop_data,
241 ui::OSExchangeData::Provider* provider,
242 WebContentsImpl* web_contents) {
243 const GURL& page_url = web_contents->GetLastCommittedURL();
244 const std::string& page_encoding = web_contents->GetEncoding();
246 // Parse the download metadata.
247 base::string16 mime_type;
248 base::FilePath file_name;
249 GURL download_url;
250 if (!ParseDownloadMetadata(drop_data.download_metadata,
251 &mime_type,
252 &file_name,
253 &download_url))
254 return;
256 // Generate the file name based on both mime type and proposed file name.
257 std::string default_name =
258 GetContentClient()->browser()->GetDefaultDownloadName();
259 base::FilePath generated_download_file_name =
260 net::GenerateFileName(download_url,
261 std::string(),
262 std::string(),
263 base::UTF16ToUTF8(file_name.value()),
264 base::UTF16ToUTF8(mime_type),
265 default_name);
267 // http://crbug.com/332579
268 base::ThreadRestrictions::ScopedAllowIO allow_file_operations;
270 base::FilePath temp_dir_path;
271 if (!base::CreateNewTempDirectory(FILE_PATH_LITERAL("chrome_drag"),
272 &temp_dir_path))
273 return;
275 base::FilePath download_path =
276 temp_dir_path.Append(generated_download_file_name);
278 // We cannot know when the target application will be done using the temporary
279 // file, so schedule it to be deleted after rebooting.
280 base::DeleteFileAfterReboot(download_path);
281 base::DeleteFileAfterReboot(temp_dir_path);
283 // Provide the data as file (CF_HDROP). A temporary download file with the
284 // Zone.Identifier ADS (Alternate Data Stream) attached will be created.
285 scoped_refptr<DragDownloadFile> download_file =
286 new DragDownloadFile(
287 download_path,
288 base::File(),
289 download_url,
290 Referrer(page_url, drop_data.referrer_policy),
291 page_encoding,
292 web_contents);
293 ui::OSExchangeData::DownloadFileInfo file_download(base::FilePath(),
294 download_file.get());
295 provider->SetDownloadFileInfo(file_download);
297 #endif // defined(OS_WIN)
299 // Returns the CustomFormat to store file system files.
300 const ui::OSExchangeData::CustomFormat& GetFileSystemFileCustomFormat() {
301 static const char kFormatString[] = "chromium/x-file-system-files";
302 CR_DEFINE_STATIC_LOCAL(ui::OSExchangeData::CustomFormat,
303 format,
304 (ui::Clipboard::GetFormatType(kFormatString)));
305 return format;
308 // Writes file system files to the pickle.
309 void WriteFileSystemFilesToPickle(
310 const std::vector<DropData::FileSystemFileInfo>& file_system_files,
311 Pickle* pickle) {
312 pickle->WriteUInt64(file_system_files.size());
313 for (size_t i = 0; i < file_system_files.size(); ++i) {
314 pickle->WriteString(file_system_files[i].url.spec());
315 pickle->WriteInt64(file_system_files[i].size);
319 // Reads file system files from the pickle.
320 bool ReadFileSystemFilesFromPickle(
321 const Pickle& pickle,
322 std::vector<DropData::FileSystemFileInfo>* file_system_files) {
323 PickleIterator iter(pickle);
325 uint64 num_files = 0;
326 if (!pickle.ReadUInt64(&iter, &num_files))
327 return false;
328 file_system_files->resize(num_files);
330 for (uint64 i = 0; i < num_files; ++i) {
331 std::string url_string;
332 int64 size = 0;
333 if (!pickle.ReadString(&iter, &url_string) ||
334 !pickle.ReadInt64(&iter, &size))
335 return false;
337 GURL url(url_string);
338 if (!url.is_valid())
339 return false;
341 (*file_system_files)[i].url = url;
342 (*file_system_files)[i].size = size;
344 return true;
347 // Utility to fill a ui::OSExchangeDataProvider object from DropData.
348 void PrepareDragData(const DropData& drop_data,
349 ui::OSExchangeData::Provider* provider,
350 WebContentsImpl* web_contents) {
351 provider->MarkOriginatedFromRenderer();
352 #if defined(OS_WIN)
353 // Put download before file contents to prefer the download of a image over
354 // its thumbnail link.
355 if (!drop_data.download_metadata.empty())
356 PrepareDragForDownload(drop_data, provider, web_contents);
357 #endif
358 #if (!defined(OS_CHROMEOS) && defined(USE_X11)) || defined(OS_WIN)
359 // We set the file contents before the URL because the URL also sets file
360 // contents (to a .URL shortcut). We want to prefer file content data over
361 // a shortcut so we add it first.
362 if (!drop_data.file_contents.empty())
363 PrepareDragForFileContents(drop_data, provider);
364 #endif
365 // Call SetString() before SetURL() when we actually have a custom string.
366 // SetURL() will itself do SetString() when a string hasn't been set yet,
367 // but we want to prefer drop_data.text.string() over the URL string if it
368 // exists.
369 if (!drop_data.text.string().empty())
370 provider->SetString(drop_data.text.string());
371 if (drop_data.url.is_valid())
372 provider->SetURL(drop_data.url, drop_data.url_title);
373 if (!drop_data.html.string().empty())
374 provider->SetHtml(drop_data.html.string(), drop_data.html_base_url);
375 if (!drop_data.filenames.empty())
376 provider->SetFilenames(drop_data.filenames);
377 if (!drop_data.file_system_files.empty()) {
378 Pickle pickle;
379 WriteFileSystemFilesToPickle(drop_data.file_system_files, &pickle);
380 provider->SetPickledData(GetFileSystemFileCustomFormat(), pickle);
382 if (!drop_data.custom_data.empty()) {
383 Pickle pickle;
384 ui::WriteCustomDataToPickle(drop_data.custom_data, &pickle);
385 provider->SetPickledData(ui::Clipboard::GetWebCustomDataFormatType(),
386 pickle);
390 // Utility to fill a DropData object from ui::OSExchangeData.
391 void PrepareDropData(DropData* drop_data, const ui::OSExchangeData& data) {
392 drop_data->did_originate_from_renderer = data.DidOriginateFromRenderer();
394 base::string16 plain_text;
395 data.GetString(&plain_text);
396 if (!plain_text.empty())
397 drop_data->text = base::NullableString16(plain_text, false);
399 GURL url;
400 base::string16 url_title;
401 data.GetURLAndTitle(
402 ui::OSExchangeData::DO_NOT_CONVERT_FILENAMES, &url, &url_title);
403 if (url.is_valid()) {
404 drop_data->url = url;
405 drop_data->url_title = url_title;
408 base::string16 html;
409 GURL html_base_url;
410 data.GetHtml(&html, &html_base_url);
411 if (!html.empty())
412 drop_data->html = base::NullableString16(html, false);
413 if (html_base_url.is_valid())
414 drop_data->html_base_url = html_base_url;
416 data.GetFilenames(&drop_data->filenames);
418 Pickle pickle;
419 std::vector<DropData::FileSystemFileInfo> file_system_files;
420 if (data.GetPickledData(GetFileSystemFileCustomFormat(), &pickle) &&
421 ReadFileSystemFilesFromPickle(pickle, &file_system_files))
422 drop_data->file_system_files = file_system_files;
424 if (data.GetPickledData(ui::Clipboard::GetWebCustomDataFormatType(), &pickle))
425 ui::ReadCustomDataIntoMap(
426 pickle.data(), pickle.size(), &drop_data->custom_data);
429 // Utilities to convert between blink::WebDragOperationsMask and
430 // ui::DragDropTypes.
431 int ConvertFromWeb(blink::WebDragOperationsMask ops) {
432 int drag_op = ui::DragDropTypes::DRAG_NONE;
433 if (ops & blink::WebDragOperationCopy)
434 drag_op |= ui::DragDropTypes::DRAG_COPY;
435 if (ops & blink::WebDragOperationMove)
436 drag_op |= ui::DragDropTypes::DRAG_MOVE;
437 if (ops & blink::WebDragOperationLink)
438 drag_op |= ui::DragDropTypes::DRAG_LINK;
439 return drag_op;
442 blink::WebDragOperationsMask ConvertToWeb(int drag_op) {
443 int web_drag_op = blink::WebDragOperationNone;
444 if (drag_op & ui::DragDropTypes::DRAG_COPY)
445 web_drag_op |= blink::WebDragOperationCopy;
446 if (drag_op & ui::DragDropTypes::DRAG_MOVE)
447 web_drag_op |= blink::WebDragOperationMove;
448 if (drag_op & ui::DragDropTypes::DRAG_LINK)
449 web_drag_op |= blink::WebDragOperationLink;
450 return (blink::WebDragOperationsMask) web_drag_op;
453 int ConvertAuraEventFlagsToWebInputEventModifiers(int aura_event_flags) {
454 int web_input_event_modifiers = 0;
455 if (aura_event_flags & ui::EF_SHIFT_DOWN)
456 web_input_event_modifiers |= blink::WebInputEvent::ShiftKey;
457 if (aura_event_flags & ui::EF_CONTROL_DOWN)
458 web_input_event_modifiers |= blink::WebInputEvent::ControlKey;
459 if (aura_event_flags & ui::EF_ALT_DOWN)
460 web_input_event_modifiers |= blink::WebInputEvent::AltKey;
461 if (aura_event_flags & ui::EF_COMMAND_DOWN)
462 web_input_event_modifiers |= blink::WebInputEvent::MetaKey;
463 return web_input_event_modifiers;
466 } // namespace
468 class WebContentsViewAura::WindowObserver
469 : public aura::WindowObserver, public aura::WindowTreeHostObserver {
470 public:
471 explicit WindowObserver(WebContentsViewAura* view)
472 : view_(view),
473 host_window_(NULL) {
474 view_->window_->AddObserver(this);
476 #if defined(OS_WIN)
477 if (view_->window_->GetRootWindow())
478 view_->window_->GetRootWindow()->AddObserver(this);
479 #endif
482 virtual ~WindowObserver() {
483 view_->window_->RemoveObserver(this);
484 if (view_->window_->GetHost())
485 view_->window_->GetHost()->RemoveObserver(this);
486 if (host_window_)
487 host_window_->RemoveObserver(this);
488 #if defined(OS_WIN)
489 if (host_window_) {
490 const aura::Window::Windows& children = host_window_->children();
491 for (size_t i = 0; i < children.size(); ++i)
492 children[i]->RemoveObserver(this);
495 aura::Window* root_window = view_->window_->GetRootWindow();
496 if (root_window) {
497 root_window->RemoveObserver(this);
498 const aura::Window::Windows& root_children = root_window->children();
499 for (size_t i = 0; i < root_children.size(); ++i)
500 root_children[i]->RemoveObserver(this);
502 #endif
505 // Overridden from aura::WindowObserver:
506 #if defined(OS_WIN)
507 // Constrained windows are added as children of the parent's parent's view
508 // which may overlap with windowed NPAPI plugins. In that case, tell the RWHV
509 // so that it can update the plugins' cutout rects accordingly.
510 // Note: this is hard coding how Chrome layer adds its dialogs. Since NPAPI is
511 // going to be deprecated in a year, this is ok for now. The test for this is
512 // PrintPreviewTest.WindowedNPAPIPluginHidden.
513 virtual void OnWindowAdded(aura::Window* new_window) OVERRIDE {
514 if (!new_window->Contains(view_->window_.get())) {
515 // Skip the case when the parent moves to the root window.
516 if (new_window != host_window_) {
517 // Observe sibling windows of the WebContents, or children of the root
518 // window.
519 if (new_window->parent() == host_window_ ||
520 new_window->parent() == view_->window_->GetRootWindow()) {
521 new_window->AddObserver(this);
526 if (new_window->parent() == host_window_) {
527 UpdateConstrainedWindows(NULL);
531 virtual void OnWillRemoveWindow(aura::Window* window) OVERRIDE {
532 if (window == view_->window_)
533 return;
535 window->RemoveObserver(this);
536 UpdateConstrainedWindows(window);
539 virtual void OnWindowVisibilityChanged(aura::Window* window,
540 bool visible) OVERRIDE {
541 if (window == view_->window_ ||
542 window->parent() == host_window_ ||
543 window->parent() == view_->window_->GetRootWindow()) {
544 UpdateConstrainedWindows(NULL);
547 #endif
549 virtual void OnWindowParentChanged(aura::Window* window,
550 aura::Window* parent) OVERRIDE {
551 if (window != view_->window_)
552 return;
554 // Use the new parent's root window for calculating HiDPI subpixel offset.
555 RenderWidgetHostViewAura* rwhv = ToRenderWidgetHostViewAura(
556 view_->web_contents_->GetRenderWidgetHostView());
557 if (rwhv)
558 rwhv->SnapToPhysicalPixelBoundary();
560 aura::Window* host_window =
561 window->GetProperty(aura::client::kHostWindowKey);
562 if (!host_window)
563 host_window = parent;
565 if (host_window_)
566 host_window_->RemoveObserver(this);
568 #if defined(OS_WIN)
569 if (host_window_) {
570 const aura::Window::Windows& children = host_window_->children();
571 for (size_t i = 0; i < children.size(); ++i)
572 children[i]->RemoveObserver(this);
574 if (rwhv)
575 rwhv->UpdateConstrainedWindowRects(std::vector<gfx::Rect>());
578 // When we get parented to the root window, the code below will watch the
579 // host window, aka root window. Since we already watch the root window on
580 // Windows, unregister first so that the debug check doesn't fire.
581 if (host_window && host_window == window->GetRootWindow())
582 host_window->RemoveObserver(this);
584 // We need to undo the above if we were parented to the root window and then
585 // got parented to another window. At that point, the code before the ifdef
586 // would have stopped watching the root window.
587 if (window->GetRootWindow() &&
588 host_window != window->GetRootWindow() &&
589 !window->GetRootWindow()->HasObserver(this)) {
590 window->GetRootWindow()->AddObserver(this);
592 #endif
594 host_window_ = host_window;
595 if (host_window) {
596 host_window->AddObserver(this);
597 #if defined(OS_WIN)
598 if (host_window != window->GetRootWindow()) {
599 const aura::Window::Windows& children = host_window->children();
600 for (size_t i = 0; i < children.size(); ++i) {
601 if (!children[i]->Contains(view_->window_.get()))
602 children[i]->AddObserver(this);
605 #endif
609 virtual void OnWindowBoundsChanged(aura::Window* window,
610 const gfx::Rect& old_bounds,
611 const gfx::Rect& new_bounds) OVERRIDE {
612 if (window == host_window_ || window == view_->window_) {
613 SendScreenRects();
614 if (view_->touch_editable_)
615 view_->touch_editable_->UpdateEditingController();
616 #if defined(OS_WIN)
617 } else {
618 UpdateConstrainedWindows(NULL);
619 #endif
623 virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {
624 if (window == host_window_) {
625 host_window_->RemoveObserver(this);
626 host_window_ = NULL;
630 virtual void OnWindowAddedToRootWindow(aura::Window* window) OVERRIDE {
631 if (window == view_->window_) {
632 window->GetHost()->AddObserver(this);
633 #if defined(OS_WIN)
634 if (!window->GetRootWindow()->HasObserver(this))
635 window->GetRootWindow()->AddObserver(this);
636 #endif
640 virtual void OnWindowRemovingFromRootWindow(aura::Window* window,
641 aura::Window* new_root) OVERRIDE {
642 if (window == view_->window_) {
643 window->GetHost()->RemoveObserver(this);
644 #if defined(OS_WIN)
645 window->GetRootWindow()->RemoveObserver(this);
647 const aura::Window::Windows& root_children =
648 window->GetRootWindow()->children();
649 for (size_t i = 0; i < root_children.size(); ++i) {
650 if (root_children[i] != view_->window_ &&
651 root_children[i] != host_window_) {
652 root_children[i]->RemoveObserver(this);
655 #endif
659 // Overridden WindowTreeHostObserver:
660 virtual void OnHostMoved(const aura::WindowTreeHost* host,
661 const gfx::Point& new_origin) OVERRIDE {
662 TRACE_EVENT1("ui",
663 "WebContentsViewAura::WindowObserver::OnHostMoved",
664 "new_origin", new_origin.ToString());
666 // This is for the desktop case (i.e. Aura desktop).
667 SendScreenRects();
670 private:
671 void SendScreenRects() {
672 RenderWidgetHostImpl::From(view_->web_contents_->GetRenderViewHost())->
673 SendScreenRects();
676 #if defined(OS_WIN)
677 void UpdateConstrainedWindows(aura::Window* exclude) {
678 RenderWidgetHostViewAura* view = ToRenderWidgetHostViewAura(
679 view_->web_contents_->GetRenderWidgetHostView());
680 if (!view)
681 return;
683 std::vector<gfx::Rect> constrained_windows;
684 if (host_window_) {
685 const aura::Window::Windows& children = host_window_->children();
686 for (size_t i = 0; i < children.size(); ++i) {
687 if (!children[i]->Contains(view_->window_.get()) &&
688 children[i] != exclude &&
689 children[i]->IsVisible()) {
690 constrained_windows.push_back(children[i]->GetBoundsInRootWindow());
695 aura::Window* root_window = view_->window_->GetRootWindow();
696 const aura::Window::Windows& root_children = root_window->children();
697 if (root_window) {
698 for (size_t i = 0; i < root_children.size(); ++i) {
699 if (root_children[i]->IsVisible() &&
700 !root_children[i]->Contains(view_->window_.get())) {
701 constrained_windows.push_back(
702 root_children[i]->GetBoundsInRootWindow());
707 view->UpdateConstrainedWindowRects(constrained_windows);
709 #endif
711 WebContentsViewAura* view_;
713 // The parent window that hosts the constrained windows. We cache the old host
714 // view so that we can unregister when it's not the parent anymore.
715 aura::Window* host_window_;
717 DISALLOW_COPY_AND_ASSIGN(WindowObserver);
720 ////////////////////////////////////////////////////////////////////////////////
721 // WebContentsViewAura, public:
723 WebContentsViewAura::WebContentsViewAura(
724 WebContentsImpl* web_contents,
725 WebContentsViewDelegate* delegate)
726 : web_contents_(web_contents),
727 delegate_(delegate),
728 current_drag_op_(blink::WebDragOperationNone),
729 drag_dest_delegate_(NULL),
730 current_rvh_for_drag_(NULL),
731 overscroll_change_brightness_(false),
732 current_overscroll_gesture_(OVERSCROLL_NONE),
733 completed_overscroll_gesture_(OVERSCROLL_NONE),
734 touch_editable_(TouchEditableImplAura::Create()),
735 is_or_was_visible_(false) {
738 ////////////////////////////////////////////////////////////////////////////////
739 // WebContentsViewAura, private:
741 WebContentsViewAura::~WebContentsViewAura() {
742 if (!window_)
743 return;
745 window_observer_.reset();
746 window_->RemoveObserver(this);
748 // Window needs a valid delegate during its destructor, so we explicitly
749 // delete it here.
750 window_.reset();
753 void WebContentsViewAura::SetTouchEditableForTest(
754 TouchEditableImplAura* touch_editable) {
755 touch_editable_.reset(touch_editable);
756 AttachTouchEditableToRenderView();
759 void WebContentsViewAura::SizeChangedCommon(const gfx::Size& size) {
760 if (web_contents_->GetInterstitialPage())
761 web_contents_->GetInterstitialPage()->SetSize(size);
762 RenderWidgetHostView* rwhv =
763 web_contents_->GetRenderWidgetHostView();
764 if (rwhv)
765 rwhv->SetSize(size);
768 void WebContentsViewAura::EndDrag(blink::WebDragOperationsMask ops) {
769 aura::Window* root_window = GetNativeView()->GetRootWindow();
770 gfx::Point screen_loc =
771 gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint();
772 gfx::Point client_loc = screen_loc;
773 RenderViewHost* rvh = web_contents_->GetRenderViewHost();
774 aura::Window* window = rvh->GetView()->GetNativeView();
775 aura::Window::ConvertPointToTarget(root_window, window, &client_loc);
776 if (!web_contents_)
777 return;
778 web_contents_->DragSourceEndedAt(client_loc.x(), client_loc.y(),
779 screen_loc.x(), screen_loc.y(), ops);
782 void WebContentsViewAura::InstallOverscrollControllerDelegate(
783 RenderWidgetHostViewAura* view) {
784 const std::string value = CommandLine::ForCurrentProcess()->
785 GetSwitchValueASCII(switches::kOverscrollHistoryNavigation);
786 if (value == "0") {
787 navigation_overlay_.reset();
788 return;
790 if (value == "2") {
791 navigation_overlay_.reset();
792 if (!gesture_nav_simple_)
793 gesture_nav_simple_.reset(new GestureNavSimple(web_contents_));
794 view->overscroll_controller()->set_delegate(gesture_nav_simple_.get());
795 return;
797 view->overscroll_controller()->set_delegate(this);
798 if (!navigation_overlay_)
799 navigation_overlay_.reset(new OverscrollNavigationOverlay(web_contents_));
802 void WebContentsViewAura::PrepareOverscrollWindow() {
803 // If there is an existing |overscroll_window_| which is in the middle of an
804 // animation, then destroying the window here causes the animation to be
805 // completed immidiately, which triggers |OnImplicitAnimationsCompleted()|
806 // callback, and that tries to reset |overscroll_window_| again, causing a
807 // double-free. So use a temporary variable here.
808 if (overscroll_window_) {
809 base::AutoReset<OverscrollMode> reset_state(&current_overscroll_gesture_,
810 current_overscroll_gesture_);
811 scoped_ptr<aura::Window> reset_window(overscroll_window_.release());
814 OverscrollWindowDelegate* overscroll_delegate = new OverscrollWindowDelegate(
815 web_contents_,
816 current_overscroll_gesture_);
817 overscroll_window_.reset(new aura::Window(overscroll_delegate));
818 overscroll_window_->SetType(ui::wm::WINDOW_TYPE_CONTROL);
819 overscroll_window_->SetTransparent(true);
820 overscroll_window_->Init(aura::WINDOW_LAYER_TEXTURED);
821 overscroll_window_->layer()->SetMasksToBounds(false);
822 overscroll_window_->SetName("OverscrollOverlay");
824 overscroll_change_brightness_ = overscroll_delegate->has_image();
825 window_->AddChild(overscroll_window_.get());
827 gfx::Rect bounds = gfx::Rect(window_->bounds().size());
828 if (ShouldNavigateForward(web_contents_->GetController(),
829 current_overscroll_gesture_)) {
830 // The overlay will be sliding in from the right edge towards the left in
831 // non-RTL, or sliding in from the left edge towards the right in RTL.
832 // So position the overlay window accordingly.
833 bounds.Offset(base::i18n::IsRTL() ? -bounds.width() : bounds.width(), 0);
836 aura::Window* animate_window = GetWindowToAnimateForOverscroll();
837 if (animate_window == overscroll_window_)
838 window_->StackChildAbove(overscroll_window_.get(), GetContentNativeView());
839 else
840 window_->StackChildBelow(overscroll_window_.get(), GetContentNativeView());
842 UpdateOverscrollWindowBrightness(0.f);
844 overscroll_window_->SetBounds(bounds);
845 overscroll_window_->Show();
847 overscroll_shadow_.reset(new ShadowLayerDelegate(animate_window->layer()));
850 void WebContentsViewAura::PrepareContentWindowForOverscroll() {
851 StopObservingImplicitAnimations();
852 aura::Window* content = GetContentNativeView();
853 content->layer()->GetAnimator()->AbortAllAnimations();
854 content->SetTransform(gfx::Transform());
855 content->layer()->SetLayerBrightness(0.f);
858 void WebContentsViewAura::ResetOverscrollTransform() {
859 if (!web_contents_->GetRenderWidgetHostView())
860 return;
861 aura::Window* target = GetWindowToAnimateForOverscroll();
862 if (!target)
863 return;
865 ui::ScopedLayerAnimationSettings settings(target->layer()->GetAnimator());
866 settings.SetPreemptionStrategy(
867 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
868 settings.SetTweenType(gfx::Tween::EASE_OUT);
869 settings.AddObserver(this);
870 target->SetTransform(gfx::Transform());
873 ui::ScopedLayerAnimationSettings settings(target->layer()->GetAnimator());
874 settings.SetPreemptionStrategy(
875 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
876 settings.SetTweenType(gfx::Tween::EASE_OUT);
877 UpdateOverscrollWindowBrightness(0.f);
881 void WebContentsViewAura::CompleteOverscrollNavigation(OverscrollMode mode) {
882 if (!web_contents_->GetRenderWidgetHostView())
883 return;
885 // Animate out the current view first. Navigate to the requested history at
886 // the end of the animation.
887 if (current_overscroll_gesture_ == OVERSCROLL_NONE)
888 return;
890 UMA_HISTOGRAM_ENUMERATION("Overscroll.Navigated",
891 current_overscroll_gesture_, OVERSCROLL_COUNT);
892 OverscrollWindowDelegate* delegate = static_cast<OverscrollWindowDelegate*>(
893 overscroll_window_->delegate());
894 delegate->stop_forwarding_events();
896 completed_overscroll_gesture_ = mode;
897 aura::Window* target = GetWindowToAnimateForOverscroll();
898 ui::ScopedLayerAnimationSettings settings(target->layer()->GetAnimator());
899 settings.SetPreemptionStrategy(
900 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
901 settings.SetTweenType(gfx::Tween::EASE_OUT);
902 settings.AddObserver(this);
903 gfx::Transform transform;
904 int content_width =
905 web_contents_->GetRenderWidgetHostView()->GetViewBounds().width();
906 int translate_x = mode == OVERSCROLL_WEST ? -content_width : content_width;
907 transform.Translate(translate_x, 0);
908 target->SetTransform(transform);
909 UpdateOverscrollWindowBrightness(translate_x);
912 aura::Window* WebContentsViewAura::GetWindowToAnimateForOverscroll() {
913 if (current_overscroll_gesture_ == OVERSCROLL_NONE)
914 return NULL;
916 return ShouldNavigateForward(web_contents_->GetController(),
917 current_overscroll_gesture_) ?
918 overscroll_window_.get() : GetContentNativeView();
921 gfx::Vector2d WebContentsViewAura::GetTranslationForOverscroll(int delta_x,
922 int delta_y) {
923 if (current_overscroll_gesture_ == OVERSCROLL_NORTH ||
924 current_overscroll_gesture_ == OVERSCROLL_SOUTH) {
925 return gfx::Vector2d(0, delta_y);
927 // For horizontal overscroll, scroll freely if a navigation is possible. Do a
928 // resistive scroll otherwise.
929 const NavigationControllerImpl& controller = web_contents_->GetController();
930 const gfx::Rect& bounds = GetViewBounds();
931 if (ShouldNavigateForward(controller, current_overscroll_gesture_))
932 return gfx::Vector2d(std::max(-bounds.width(), delta_x), 0);
933 else if (ShouldNavigateBack(controller, current_overscroll_gesture_))
934 return gfx::Vector2d(std::min(bounds.width(), delta_x), 0);
935 return gfx::Vector2d();
938 void WebContentsViewAura::PrepareOverscrollNavigationOverlay() {
939 OverscrollWindowDelegate* delegate = static_cast<OverscrollWindowDelegate*>(
940 overscroll_window_->delegate());
941 overscroll_window_->SchedulePaintInRect(
942 gfx::Rect(overscroll_window_->bounds().size()));
943 overscroll_window_->SetBounds(gfx::Rect(window_->bounds().size()));
944 overscroll_window_->SetTransform(gfx::Transform());
945 navigation_overlay_->SetOverlayWindow(overscroll_window_.Pass(),
946 delegate);
947 navigation_overlay_->StartObserving();
950 void WebContentsViewAura::UpdateOverscrollWindowBrightness(float delta_x) {
951 if (!overscroll_change_brightness_)
952 return;
954 const float kBrightnessMin = -.1f;
955 const float kBrightnessMax = -.01f;
957 float ratio = fabs(delta_x) / GetViewBounds().width();
958 ratio = std::min(1.f, ratio);
959 if (base::i18n::IsRTL())
960 ratio = 1.f - ratio;
961 float brightness = current_overscroll_gesture_ == OVERSCROLL_WEST ?
962 kBrightnessMin + ratio * (kBrightnessMax - kBrightnessMin) :
963 kBrightnessMax - ratio * (kBrightnessMax - kBrightnessMin);
964 brightness = std::max(kBrightnessMin, brightness);
965 brightness = std::min(kBrightnessMax, brightness);
966 aura::Window* window = GetWindowToAnimateForOverscroll();
967 window->layer()->SetLayerBrightness(brightness);
970 void WebContentsViewAura::AttachTouchEditableToRenderView() {
971 if (!touch_editable_)
972 return;
973 RenderWidgetHostViewAura* rwhva = ToRenderWidgetHostViewAura(
974 web_contents_->GetRenderWidgetHostView());
975 touch_editable_->AttachToView(rwhva);
978 void WebContentsViewAura::OverscrollUpdateForWebContentsDelegate(int delta_y) {
979 if (web_contents_->GetDelegate() && IsScrollEndEffectEnabled())
980 web_contents_->GetDelegate()->OverscrollUpdate(delta_y);
983 ////////////////////////////////////////////////////////////////////////////////
984 // WebContentsViewAura, WebContentsView implementation:
986 gfx::NativeView WebContentsViewAura::GetNativeView() const {
987 return window_.get();
990 gfx::NativeView WebContentsViewAura::GetContentNativeView() const {
991 RenderWidgetHostView* rwhv = web_contents_->GetRenderWidgetHostView();
992 return rwhv ? rwhv->GetNativeView() : NULL;
995 gfx::NativeWindow WebContentsViewAura::GetTopLevelNativeWindow() const {
996 return window_->GetToplevelWindow();
999 void WebContentsViewAura::GetContainerBounds(gfx::Rect *out) const {
1000 *out = window_->GetBoundsInScreen();
1003 void WebContentsViewAura::SizeContents(const gfx::Size& size) {
1004 gfx::Rect bounds = window_->bounds();
1005 if (bounds.size() != size) {
1006 bounds.set_size(size);
1007 window_->SetBounds(bounds);
1008 } else {
1009 // Our size matches what we want but the renderers size may not match.
1010 // Pretend we were resized so that the renderers size is updated too.
1011 SizeChangedCommon(size);
1015 void WebContentsViewAura::Focus() {
1016 if (web_contents_->GetInterstitialPage()) {
1017 web_contents_->GetInterstitialPage()->Focus();
1018 return;
1021 if (delegate_.get() && delegate_->Focus())
1022 return;
1024 RenderWidgetHostView* rwhv = web_contents_->GetRenderWidgetHostView();
1025 if (rwhv)
1026 rwhv->Focus();
1029 void WebContentsViewAura::SetInitialFocus() {
1030 if (web_contents_->FocusLocationBarByDefault())
1031 web_contents_->SetFocusToLocationBar(false);
1032 else
1033 Focus();
1036 void WebContentsViewAura::StoreFocus() {
1037 if (delegate_)
1038 delegate_->StoreFocus();
1041 void WebContentsViewAura::RestoreFocus() {
1042 if (delegate_)
1043 delegate_->RestoreFocus();
1046 DropData* WebContentsViewAura::GetDropData() const {
1047 return current_drop_data_.get();
1050 gfx::Rect WebContentsViewAura::GetViewBounds() const {
1051 return window_->GetBoundsInScreen();
1054 ////////////////////////////////////////////////////////////////////////////////
1055 // WebContentsViewAura, WebContentsView implementation:
1057 void WebContentsViewAura::CreateView(
1058 const gfx::Size& initial_size, gfx::NativeView context) {
1059 // NOTE: we ignore |initial_size| since in some cases it's wrong (such as
1060 // if the bookmark bar is not shown and you create a new tab). The right
1061 // value is set shortly after this, so its safe to ignore.
1063 aura::Env::CreateInstance(true);
1064 window_.reset(new aura::Window(this));
1065 window_->set_owned_by_parent(false);
1066 window_->SetType(ui::wm::WINDOW_TYPE_CONTROL);
1067 window_->SetTransparent(false);
1068 window_->Init(aura::WINDOW_LAYER_NOT_DRAWN);
1069 window_->AddObserver(this);
1070 aura::Window* root_window = context ? context->GetRootWindow() : NULL;
1071 if (root_window) {
1072 // There are places where there is no context currently because object
1073 // hierarchies are built before they're attached to a Widget. (See
1074 // views::WebView as an example; GetWidget() returns NULL at the point
1075 // where we are created.)
1077 // It should be OK to not set a default parent since such users will
1078 // explicitly add this WebContentsViewAura to their tree after they create
1079 // us.
1080 if (root_window) {
1081 aura::client::ParentWindowWithContext(
1082 window_.get(), root_window, root_window->GetBoundsInScreen());
1085 window_->layer()->SetMasksToBounds(true);
1086 window_->SetName("WebContentsViewAura");
1088 // WindowObserver is not interesting and is problematic for Browser Plugin
1089 // guests.
1090 // The use cases for WindowObserver do not apply to Browser Plugins:
1091 // 1) guests do not support NPAPI plugins.
1092 // 2) guests' window bounds are supposed to come from its embedder.
1093 if (!BrowserPluginGuest::IsGuest(web_contents_))
1094 window_observer_.reset(new WindowObserver(this));
1096 // delegate_->GetDragDestDelegate() creates a new delegate on every call.
1097 // Hence, we save a reference to it locally. Similar model is used on other
1098 // platforms as well.
1099 if (delegate_)
1100 drag_dest_delegate_ = delegate_->GetDragDestDelegate();
1103 RenderWidgetHostViewBase* WebContentsViewAura::CreateViewForWidget(
1104 RenderWidgetHost* render_widget_host) {
1105 if (render_widget_host->GetView()) {
1106 // During testing, the view will already be set up in most cases to the
1107 // test view, so we don't want to clobber it with a real one. To verify that
1108 // this actually is happening (and somebody isn't accidentally creating the
1109 // view twice), we check for the RVH Factory, which will be set when we're
1110 // making special ones (which go along with the special views).
1111 DCHECK(RenderViewHostFactory::has_factory());
1112 return static_cast<RenderWidgetHostViewBase*>(
1113 render_widget_host->GetView());
1116 RenderWidgetHostViewAura* view =
1117 new RenderWidgetHostViewAura(render_widget_host);
1118 view->InitAsChild(NULL);
1119 GetNativeView()->AddChild(view->GetNativeView());
1121 if (navigation_overlay_.get() && navigation_overlay_->has_window()) {
1122 navigation_overlay_->StartObserving();
1125 RenderWidgetHostImpl* host_impl =
1126 RenderWidgetHostImpl::From(render_widget_host);
1128 if (!host_impl->is_hidden())
1129 view->Show();
1131 // We listen to drag drop events in the newly created view's window.
1132 aura::client::SetDragDropDelegate(view->GetNativeView(), this);
1134 if (view->overscroll_controller() &&
1135 (!web_contents_->GetDelegate() ||
1136 web_contents_->GetDelegate()->CanOverscrollContent())) {
1137 InstallOverscrollControllerDelegate(view);
1140 AttachTouchEditableToRenderView();
1141 return view;
1144 RenderWidgetHostViewBase* WebContentsViewAura::CreateViewForPopupWidget(
1145 RenderWidgetHost* render_widget_host) {
1146 return new RenderWidgetHostViewAura(render_widget_host);
1149 void WebContentsViewAura::SetPageTitle(const base::string16& title) {
1150 window_->SetTitle(title);
1153 void WebContentsViewAura::RenderViewCreated(RenderViewHost* host) {
1156 void WebContentsViewAura::RenderViewSwappedIn(RenderViewHost* host) {
1157 if (navigation_overlay_.get() && navigation_overlay_->has_window())
1158 navigation_overlay_->StartObserving();
1159 AttachTouchEditableToRenderView();
1162 void WebContentsViewAura::SetOverscrollControllerEnabled(bool enabled) {
1163 RenderWidgetHostViewAura* view =
1164 ToRenderWidgetHostViewAura(web_contents_->GetRenderWidgetHostView());
1165 if (view) {
1166 view->SetOverscrollControllerEnabled(enabled);
1167 if (enabled)
1168 InstallOverscrollControllerDelegate(view);
1171 if (!enabled)
1172 navigation_overlay_.reset();
1173 else if (!navigation_overlay_)
1174 navigation_overlay_.reset(new OverscrollNavigationOverlay(web_contents_));
1177 ////////////////////////////////////////////////////////////////////////////////
1178 // WebContentsViewAura, RenderViewHostDelegateView implementation:
1180 void WebContentsViewAura::ShowContextMenu(RenderFrameHost* render_frame_host,
1181 const ContextMenuParams& params) {
1182 if (touch_editable_) {
1183 touch_editable_->EndTouchEditing(false);
1185 if (delegate_) {
1186 delegate_->ShowContextMenu(render_frame_host, params);
1187 // WARNING: we may have been deleted during the call to ShowContextMenu().
1191 void WebContentsViewAura::StartDragging(
1192 const DropData& drop_data,
1193 blink::WebDragOperationsMask operations,
1194 const gfx::ImageSkia& image,
1195 const gfx::Vector2d& image_offset,
1196 const DragEventSourceInfo& event_info) {
1197 aura::Window* root_window = GetNativeView()->GetRootWindow();
1198 if (!aura::client::GetDragDropClient(root_window)) {
1199 web_contents_->SystemDragEnded();
1200 return;
1203 if (touch_editable_)
1204 touch_editable_->EndTouchEditing(false);
1206 ui::OSExchangeData::Provider* provider = ui::OSExchangeData::CreateProvider();
1207 PrepareDragData(drop_data, provider, web_contents_);
1209 ui::OSExchangeData data(provider); // takes ownership of |provider|.
1211 if (!image.isNull())
1212 drag_utils::SetDragImageOnDataObject(image, image_offset, &data);
1214 scoped_ptr<WebDragSourceAura> drag_source(
1215 new WebDragSourceAura(GetNativeView(), web_contents_));
1217 // We need to enable recursive tasks on the message loop so we can get
1218 // updates while in the system DoDragDrop loop.
1219 int result_op = 0;
1221 gfx::NativeView content_native_view = GetContentNativeView();
1222 base::MessageLoop::ScopedNestableTaskAllower allow(
1223 base::MessageLoop::current());
1224 result_op = aura::client::GetDragDropClient(root_window)
1225 ->StartDragAndDrop(data,
1226 root_window,
1227 content_native_view,
1228 event_info.event_location,
1229 ConvertFromWeb(operations),
1230 event_info.event_source);
1233 // Bail out immediately if the contents view window is gone. Note that it is
1234 // not safe to access any class members in this case since |this| may already
1235 // be destroyed. The local variable |drag_source| will still be valid though,
1236 // so we can use it to determine if the window is gone.
1237 if (!drag_source->window()) {
1238 // Note that in this case, we don't need to call SystemDragEnded() since the
1239 // renderer is going away.
1240 return;
1243 EndDrag(ConvertToWeb(result_op));
1244 web_contents_->SystemDragEnded();
1247 void WebContentsViewAura::UpdateDragCursor(blink::WebDragOperation operation) {
1248 current_drag_op_ = operation;
1251 void WebContentsViewAura::GotFocus() {
1252 if (web_contents_->GetDelegate())
1253 web_contents_->GetDelegate()->WebContentsFocused(web_contents_);
1256 void WebContentsViewAura::TakeFocus(bool reverse) {
1257 if (web_contents_->GetDelegate() &&
1258 !web_contents_->GetDelegate()->TakeFocus(web_contents_, reverse) &&
1259 delegate_.get()) {
1260 delegate_->TakeFocus(reverse);
1264 ////////////////////////////////////////////////////////////////////////////////
1265 // WebContentsViewAura, OverscrollControllerDelegate implementation:
1267 gfx::Rect WebContentsViewAura::GetVisibleBounds() const {
1268 RenderWidgetHostView* rwhv = web_contents_->GetRenderWidgetHostView();
1269 if (!rwhv || !rwhv->IsShowing())
1270 return gfx::Rect();
1272 return rwhv->GetViewBounds();
1275 void WebContentsViewAura::OnOverscrollUpdate(float delta_x, float delta_y) {
1276 if (current_overscroll_gesture_ == OVERSCROLL_NONE)
1277 return;
1279 aura::Window* target = GetWindowToAnimateForOverscroll();
1280 gfx::Vector2d translate = GetTranslationForOverscroll(delta_x, delta_y);
1281 gfx::Transform transform;
1283 // Vertical overscrolls don't participate in the navigation gesture.
1284 if (current_overscroll_gesture_ != OVERSCROLL_NORTH &&
1285 current_overscroll_gesture_ != OVERSCROLL_SOUTH) {
1286 transform.Translate(translate.x(), translate.y());
1287 target->SetTransform(transform);
1288 UpdateOverscrollWindowBrightness(delta_x);
1291 OverscrollUpdateForWebContentsDelegate(translate.y());
1294 void WebContentsViewAura::OnOverscrollComplete(OverscrollMode mode) {
1295 UMA_HISTOGRAM_ENUMERATION("Overscroll.Completed", mode, OVERSCROLL_COUNT);
1296 OverscrollUpdateForWebContentsDelegate(0);
1297 NavigationControllerImpl& controller = web_contents_->GetController();
1298 if (ShouldNavigateForward(controller, mode) ||
1299 ShouldNavigateBack(controller, mode)) {
1300 CompleteOverscrollNavigation(mode);
1301 return;
1304 ResetOverscrollTransform();
1307 void WebContentsViewAura::OnOverscrollModeChange(OverscrollMode old_mode,
1308 OverscrollMode new_mode) {
1309 // Reset any in-progress overscroll animation first.
1310 ResetOverscrollTransform();
1312 if (new_mode != OVERSCROLL_NONE && touch_editable_)
1313 touch_editable_->OverscrollStarted();
1315 if (new_mode == OVERSCROLL_NONE ||
1316 !GetContentNativeView() ||
1317 ((new_mode == OVERSCROLL_EAST || new_mode == OVERSCROLL_WEST) &&
1318 navigation_overlay_.get() && navigation_overlay_->has_window())) {
1319 current_overscroll_gesture_ = OVERSCROLL_NONE;
1320 OverscrollUpdateForWebContentsDelegate(0);
1321 } else {
1322 aura::Window* target = GetWindowToAnimateForOverscroll();
1323 if (target) {
1324 StopObservingImplicitAnimations();
1325 target->layer()->GetAnimator()->AbortAllAnimations();
1327 // Cleanup state of the content window first, because that can reset the
1328 // value of |current_overscroll_gesture_|.
1329 PrepareContentWindowForOverscroll();
1331 current_overscroll_gesture_ = new_mode;
1332 if (current_overscroll_gesture_ == OVERSCROLL_EAST ||
1333 current_overscroll_gesture_ == OVERSCROLL_WEST)
1334 PrepareOverscrollWindow();
1336 UMA_HISTOGRAM_ENUMERATION("Overscroll.Started", new_mode, OVERSCROLL_COUNT);
1338 completed_overscroll_gesture_ = OVERSCROLL_NONE;
1341 ////////////////////////////////////////////////////////////////////////////////
1342 // WebContentsViewAura, ui::ImplicitAnimationObserver implementation:
1344 void WebContentsViewAura::OnImplicitAnimationsCompleted() {
1345 overscroll_shadow_.reset();
1347 if (ShouldNavigateForward(web_contents_->GetController(),
1348 completed_overscroll_gesture_)) {
1349 web_contents_->GetController().GoForward();
1350 PrepareOverscrollNavigationOverlay();
1351 } else if (ShouldNavigateBack(web_contents_->GetController(),
1352 completed_overscroll_gesture_)) {
1353 web_contents_->GetController().GoBack();
1354 PrepareOverscrollNavigationOverlay();
1355 } else {
1356 if (touch_editable_)
1357 touch_editable_->OverscrollCompleted();
1360 aura::Window* content = GetContentNativeView();
1361 if (content) {
1362 content->SetTransform(gfx::Transform());
1363 content->layer()->SetLayerBrightness(0.f);
1365 current_overscroll_gesture_ = OVERSCROLL_NONE;
1366 completed_overscroll_gesture_ = OVERSCROLL_NONE;
1367 overscroll_window_.reset();
1370 ////////////////////////////////////////////////////////////////////////////////
1371 // WebContentsViewAura, aura::WindowDelegate implementation:
1373 gfx::Size WebContentsViewAura::GetMinimumSize() const {
1374 return gfx::Size();
1377 gfx::Size WebContentsViewAura::GetMaximumSize() const {
1378 return gfx::Size();
1381 void WebContentsViewAura::OnBoundsChanged(const gfx::Rect& old_bounds,
1382 const gfx::Rect& new_bounds) {
1383 SizeChangedCommon(new_bounds.size());
1384 if (delegate_)
1385 delegate_->SizeChanged(new_bounds.size());
1387 // Constrained web dialogs, need to be kept centered over our content area.
1388 for (size_t i = 0; i < window_->children().size(); i++) {
1389 if (window_->children()[i]->GetProperty(
1390 aura::client::kConstrainedWindowKey)) {
1391 gfx::Rect bounds = window_->children()[i]->bounds();
1392 bounds.set_origin(
1393 gfx::Point((new_bounds.width() - bounds.width()) / 2,
1394 (new_bounds.height() - bounds.height()) / 2));
1395 window_->children()[i]->SetBounds(bounds);
1400 gfx::NativeCursor WebContentsViewAura::GetCursor(const gfx::Point& point) {
1401 return gfx::kNullCursor;
1404 int WebContentsViewAura::GetNonClientComponent(const gfx::Point& point) const {
1405 return HTCLIENT;
1408 bool WebContentsViewAura::ShouldDescendIntoChildForEventHandling(
1409 aura::Window* child,
1410 const gfx::Point& location) {
1411 return true;
1414 bool WebContentsViewAura::CanFocus() {
1415 // Do not take the focus if the render widget host view aura is gone or
1416 // is in the process of shutting down because neither the view window nor
1417 // this window can handle key events.
1418 RenderWidgetHostViewAura* view = ToRenderWidgetHostViewAura(
1419 web_contents_->GetRenderWidgetHostView());
1420 if (view != NULL && !view->IsClosing())
1421 return true;
1423 return false;
1426 void WebContentsViewAura::OnCaptureLost() {
1429 void WebContentsViewAura::OnPaint(gfx::Canvas* canvas) {
1432 void WebContentsViewAura::OnDeviceScaleFactorChanged(
1433 float device_scale_factor) {
1436 void WebContentsViewAura::OnWindowDestroying(aura::Window* window) {
1437 // This means the destructor is going to be called soon. If there is an
1438 // overscroll gesture in progress (i.e. |overscroll_window_| is not NULL),
1439 // then destroying it in the WebContentsViewAura destructor can trigger other
1440 // virtual functions to be called (e.g. OnImplicitAnimationsCompleted()). So
1441 // destroy the overscroll window here.
1442 navigation_overlay_.reset();
1443 overscroll_window_.reset();
1446 void WebContentsViewAura::OnWindowDestroyed(aura::Window* window) {
1449 void WebContentsViewAura::OnWindowTargetVisibilityChanged(bool visible) {
1452 bool WebContentsViewAura::HasHitTestMask() const {
1453 return false;
1456 void WebContentsViewAura::GetHitTestMask(gfx::Path* mask) const {
1459 ////////////////////////////////////////////////////////////////////////////////
1460 // WebContentsViewAura, ui::EventHandler implementation:
1462 void WebContentsViewAura::OnKeyEvent(ui::KeyEvent* event) {
1465 void WebContentsViewAura::OnMouseEvent(ui::MouseEvent* event) {
1466 if (!web_contents_->GetDelegate())
1467 return;
1469 switch (event->type()) {
1470 case ui::ET_MOUSE_PRESSED:
1471 web_contents_->GetDelegate()->ActivateContents(web_contents_);
1472 break;
1473 case ui::ET_MOUSE_MOVED:
1474 case ui::ET_MOUSE_EXITED:
1475 web_contents_->GetDelegate()->ContentsMouseEvent(
1476 web_contents_,
1477 gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint(),
1478 event->type() == ui::ET_MOUSE_MOVED);
1479 break;
1480 default:
1481 break;
1485 ////////////////////////////////////////////////////////////////////////////////
1486 // WebContentsViewAura, aura::client::DragDropDelegate implementation:
1488 void WebContentsViewAura::OnDragEntered(const ui::DropTargetEvent& event) {
1489 current_rvh_for_drag_ = web_contents_->GetRenderViewHost();
1490 current_drop_data_.reset(new DropData());
1492 PrepareDropData(current_drop_data_.get(), event.data());
1493 blink::WebDragOperationsMask op = ConvertToWeb(event.source_operations());
1495 // Give the delegate an opportunity to cancel the drag.
1496 if (!web_contents_->GetDelegate()->CanDragEnter(web_contents_,
1497 *current_drop_data_.get(),
1498 op)) {
1499 current_drop_data_.reset(NULL);
1500 return;
1503 if (drag_dest_delegate_)
1504 drag_dest_delegate_->DragInitialize(web_contents_);
1506 gfx::Point screen_pt =
1507 gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint();
1508 web_contents_->GetRenderViewHost()->DragTargetDragEnter(
1509 *current_drop_data_.get(), event.location(), screen_pt, op,
1510 ConvertAuraEventFlagsToWebInputEventModifiers(event.flags()));
1512 if (drag_dest_delegate_) {
1513 drag_dest_delegate_->OnReceiveDragData(event.data());
1514 drag_dest_delegate_->OnDragEnter();
1518 int WebContentsViewAura::OnDragUpdated(const ui::DropTargetEvent& event) {
1519 DCHECK(current_rvh_for_drag_);
1520 if (current_rvh_for_drag_ != web_contents_->GetRenderViewHost())
1521 OnDragEntered(event);
1523 if (!current_drop_data_)
1524 return ui::DragDropTypes::DRAG_NONE;
1526 blink::WebDragOperationsMask op = ConvertToWeb(event.source_operations());
1527 gfx::Point screen_pt =
1528 gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint();
1529 web_contents_->GetRenderViewHost()->DragTargetDragOver(
1530 event.location(), screen_pt, op,
1531 ConvertAuraEventFlagsToWebInputEventModifiers(event.flags()));
1533 if (drag_dest_delegate_)
1534 drag_dest_delegate_->OnDragOver();
1536 return ConvertFromWeb(current_drag_op_);
1539 void WebContentsViewAura::OnDragExited() {
1540 DCHECK(current_rvh_for_drag_);
1541 if (current_rvh_for_drag_ != web_contents_->GetRenderViewHost())
1542 return;
1544 if (!current_drop_data_)
1545 return;
1547 web_contents_->GetRenderViewHost()->DragTargetDragLeave();
1548 if (drag_dest_delegate_)
1549 drag_dest_delegate_->OnDragLeave();
1551 current_drop_data_.reset();
1554 int WebContentsViewAura::OnPerformDrop(const ui::DropTargetEvent& event) {
1555 DCHECK(current_rvh_for_drag_);
1556 if (current_rvh_for_drag_ != web_contents_->GetRenderViewHost())
1557 OnDragEntered(event);
1559 if (!current_drop_data_)
1560 return ui::DragDropTypes::DRAG_NONE;
1562 web_contents_->GetRenderViewHost()->DragTargetDrop(
1563 event.location(),
1564 gfx::Screen::GetScreenFor(GetNativeView())->GetCursorScreenPoint(),
1565 ConvertAuraEventFlagsToWebInputEventModifiers(event.flags()));
1566 if (drag_dest_delegate_)
1567 drag_dest_delegate_->OnDrop();
1568 current_drop_data_.reset();
1569 return ConvertFromWeb(current_drag_op_);
1572 void WebContentsViewAura::OnWindowParentChanged(aura::Window* window,
1573 aura::Window* parent) {
1574 // Ignore any visibility changes in the hierarchy below.
1575 if (window != window_.get() && window_->Contains(window))
1576 return;
1578 // On Windows we will get called with a parent of NULL as part of the shut
1579 // down process. As such we do only change the visibility when a parent gets
1580 // set.
1581 if (parent)
1582 UpdateWebContentsVisibility(window->IsVisible());
1585 void WebContentsViewAura::OnWindowVisibilityChanged(aura::Window* window,
1586 bool visible) {
1587 // Ignore any visibility changes in the hierarchy below.
1588 if (window != window_.get() && window_->Contains(window))
1589 return;
1591 UpdateWebContentsVisibility(visible);
1594 void WebContentsViewAura::UpdateWebContentsVisibility(bool visible) {
1595 if (!is_or_was_visible_) {
1596 // We should not hide the web contents before it was shown the first time,
1597 // since resources would immediately be destroyed and only re-created after
1598 // content got loaded. In this state the window content is undefined and can
1599 // show garbage.
1600 // However - the page load mechanism requires an activation call through a
1601 // visibility call to (re)load.
1602 if (visible) {
1603 is_or_was_visible_ = true;
1604 web_contents_->WasShown();
1606 return;
1608 if (visible) {
1609 if (!web_contents_->should_normally_be_visible())
1610 web_contents_->WasShown();
1611 } else {
1612 if (web_contents_->should_normally_be_visible())
1613 web_contents_->WasHidden();
1617 } // namespace content