1// Copyright 2014 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 "athena/content/public/web_contents_view_delegate_creator.h"
6
7#include "athena/content/render_view_context_menu_impl.h"
8#include "components/web_modal/popup_manager.h"
9#include "components/web_modal/single_web_contents_dialog_manager.h"
10#include "components/web_modal/web_contents_modal_dialog_host.h"
11#include "components/web_modal/web_contents_modal_dialog_manager.h"
12#include "content/public/browser/render_widget_host_view.h"
13#include "content/public/browser/web_contents.h"
14#include "content/public/browser/web_contents_delegate.h"
15#include "content/public/browser/web_contents_view_delegate.h"
16#include "ui/aura/client/screen_position_client.h"
17#include "ui/aura/window.h"
18#include "ui/views/widget/widget.h"
19
20namespace athena {
21namespace {
22
23class WebContentsViewDelegateImpl : public content::WebContentsViewDelegate {
24 public:
25  explicit WebContentsViewDelegateImpl(content::WebContents* web_contents)
26      : web_contents_(web_contents) {}
27  virtual ~WebContentsViewDelegateImpl() {}
28
29  virtual content::WebDragDestDelegate* GetDragDestDelegate() OVERRIDE {
30    // TODO(oshima): crbug.com/401610
31    return NULL;
32  }
33
34  virtual bool Focus() OVERRIDE {
35    web_modal::PopupManager* popup_manager =
36        web_modal::PopupManager::FromWebContents(web_contents_);
37    if (popup_manager)
38      popup_manager->WasFocused(web_contents_);
39    return false;
40  }
41
42  virtual void ShowContextMenu(
43      content::RenderFrameHost* render_frame_host,
44      const content::ContextMenuParams& params) OVERRIDE {
45    ShowMenu(BuildMenu(
46        content::WebContents::FromRenderFrameHost(render_frame_host), params));
47  }
48
49  virtual void SizeChanged(const gfx::Size& size) OVERRIDE {
50    // TODO(oshima|sadrul): Implement this when sad_tab is componentized.
51    // See c/b/ui/views/tab_contents/chrome_web_contents_view_delegate_views.cc
52  }
53
54  virtual void ShowDisambiguationPopup(
55      const gfx::Rect& target_rect,
56      const SkBitmap& zoomed_bitmap,
57      const gfx::NativeView content,
58      const base::Callback<void(ui::GestureEvent*)>& gesture_cb,
59      const base::Callback<void(ui::MouseEvent*)>& mouse_cb) OVERRIDE {
60  }
61
62  virtual void HideDisambiguationPopup() OVERRIDE {
63  }
64
65  scoped_ptr<RenderViewContextMenuImpl> BuildMenu(
66      content::WebContents* web_contents,
67      const content::ContextMenuParams& params) {
68    scoped_ptr<RenderViewContextMenuImpl> menu;
69    content::RenderFrameHost* focused_frame = web_contents->GetFocusedFrame();
70    // If the frame tree does not have a focused frame at this point, do not
71    // bother creating RenderViewContextMenuViews.
72    // This happens if the frame has navigated to a different page before
73    // ContextMenu message was received by the current RenderFrameHost.
74    if (focused_frame) {
75      menu.reset(new RenderViewContextMenuImpl(focused_frame, params));
76      menu->Init();
77    }
78    return menu.Pass();
79  }
80
81  void ShowMenu(scoped_ptr<RenderViewContextMenuImpl> menu) {
82    context_menu_.reset(menu.release());
83
84    if (!context_menu_.get())
85      return;
86
87    // Menus need a Widget to work. If we're not the active tab we won't
88    // necessarily be in a widget.
89    views::Widget* top_level_widget = GetTopLevelWidget();
90    if (!top_level_widget)
91      return;
92
93    const content::ContextMenuParams& params = context_menu_->params();
94    // Don't show empty menus.
95    if (context_menu_->menu_model().GetItemCount() == 0)
96      return;
97
98    gfx::Point screen_point(params.x, params.y);
99
100    // Convert from target window coordinates to root window coordinates.
101    aura::Window* target_window = GetActiveNativeView();
102    aura::Window* root_window = target_window->GetRootWindow();
103    aura::client::ScreenPositionClient* screen_position_client =
104        aura::client::GetScreenPositionClient(root_window);
105    if (screen_position_client) {
106      screen_position_client->ConvertPointToScreen(target_window,
107                                                   &screen_point);
108    }
109    // Enable recursive tasks on the message loop so we can get updates while
110    // the context menu is being displayed.
111    base::MessageLoop::ScopedNestableTaskAllower allow(
112        base::MessageLoop::current());
113    context_menu_->RunMenuAt(
114        top_level_widget, screen_point, params.source_type);
115  }
116
117  aura::Window* GetActiveNativeView() {
118    return web_contents_->GetFullscreenRenderWidgetHostView()
119               ? web_contents_->GetFullscreenRenderWidgetHostView()
120                     ->GetNativeView()
121               : web_contents_->GetNativeView();
122  }
123
124  views::Widget* GetTopLevelWidget() {
125    return views::Widget::GetTopLevelWidgetForNativeView(GetActiveNativeView());
126  }
127
128  views::FocusManager* GetFocusManager() {
129    views::Widget* toplevel_widget = GetTopLevelWidget();
130    return toplevel_widget ? toplevel_widget->GetFocusManager() : NULL;
131  }
132
133  void SetInitialFocus() {
134    if (web_contents_->FocusLocationBarByDefault()) {
135      if (web_contents_->GetDelegate())
136        web_contents_->GetDelegate()->SetFocusToLocationBar(false);
137    } else {
138      web_contents_->Focus();
139    }
140  }
141  scoped_ptr<RenderViewContextMenuImpl> context_menu_;
142  content::WebContents* web_contents_;
143  DISALLOW_COPY_AND_ASSIGN(WebContentsViewDelegateImpl);
144};
145
146}  // namespace
147
148content::WebContentsViewDelegate* CreateWebContentsViewDelegate(
149    content::WebContents* web_contents) {
150  return new WebContentsViewDelegateImpl(web_contents);
151}
152
153}  // namespace athena
154