• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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 "chrome/browser/ui/views/tab_contents/tab_contents_view_views.h"
6 
7 #include <windows.h>
8 
9 #include <vector>
10 
11 #include "base/time.h"
12 #include "chrome/browser/ui/views/sad_tab_view.h"
13 #include "chrome/browser/ui/views/tab_contents/native_tab_contents_view.h"
14 #include "chrome/browser/ui/views/tab_contents/render_view_context_menu_views.h"
15 #include "content/browser/renderer_host/render_process_host.h"
16 #include "content/browser/renderer_host/render_view_host.h"
17 #include "content/browser/renderer_host/render_view_host_factory.h"
18 #include "content/browser/renderer_host/render_widget_host_view.h"
19 #include "content/browser/tab_contents/interstitial_page.h"
20 #include "content/browser/tab_contents/tab_contents.h"
21 #include "content/browser/tab_contents/tab_contents_delegate.h"
22 #include "views/focus/focus_manager.h"
23 #include "views/focus/view_storage.h"
24 #include "views/screen.h"
25 #include "views/widget/native_widget.h"
26 #include "views/widget/root_view.h"
27 #include "views/widget/widget.h"
28 
29 using WebKit::WebDragOperation;
30 using WebKit::WebDragOperationNone;
31 using WebKit::WebDragOperationsMask;
32 using WebKit::WebInputEvent;
33 
34 // static
Create(TabContents * tab_contents)35 TabContentsView* TabContentsView::Create(TabContents* tab_contents) {
36   return new TabContentsViewViews(tab_contents);
37 }
38 
TabContentsViewViews(TabContents * tab_contents)39 TabContentsViewViews::TabContentsViewViews(TabContents* tab_contents)
40     : TabContentsView(tab_contents),
41       ALLOW_THIS_IN_INITIALIZER_LIST(native_tab_contents_view_(
42           NativeTabContentsView::CreateNativeTabContentsView(this))),
43       close_tab_after_drag_ends_(false),
44       sad_tab_(NULL) {
45   last_focused_view_storage_id_ =
46       views::ViewStorage::GetInstance()->CreateStorageID();
47 }
48 
~TabContentsViewViews()49 TabContentsViewViews::~TabContentsViewViews() {
50   // Makes sure to remove any stored view we may still have in the ViewStorage.
51   //
52   // It is possible the view went away before us, so we only do this if the
53   // view is registered.
54   views::ViewStorage* view_storage = views::ViewStorage::GetInstance();
55   if (view_storage->RetrieveView(last_focused_view_storage_id_) != NULL)
56     view_storage->RemoveView(last_focused_view_storage_id_);
57 }
58 
Unparent()59 void TabContentsViewViews::Unparent() {
60   CHECK(native_tab_contents_view_.get());
61   native_tab_contents_view_->Unparent();
62 }
63 
CreateView(const gfx::Size & initial_size)64 void TabContentsViewViews::CreateView(const gfx::Size& initial_size) {
65   native_tab_contents_view_->InitNativeTabContentsView();
66 }
67 
CreateViewForWidget(RenderWidgetHost * render_widget_host)68 RenderWidgetHostView* TabContentsViewViews::CreateViewForWidget(
69     RenderWidgetHost* render_widget_host) {
70   if (render_widget_host->view()) {
71     // During testing, the view will already be set up in most cases to the
72     // test view, so we don't want to clobber it with a real one. To verify that
73     // this actually is happening (and somebody isn't accidentally creating the
74     // view twice), we check for the RVH Factory, which will be set when we're
75     // making special ones (which go along with the special views).
76     DCHECK(RenderViewHostFactory::has_factory());
77     return render_widget_host->view();
78   }
79 
80   // If we were showing sad tab, remove it now.
81   if (sad_tab_) {
82     GetWidget()->SetContentsView(new views::View());
83     sad_tab_ = NULL;
84   }
85 
86   return native_tab_contents_view_->CreateRenderWidgetHostView(
87       render_widget_host);
88 }
89 
GetNativeView() const90 gfx::NativeView TabContentsViewViews::GetNativeView() const {
91   return GetWidget()->GetNativeView();
92 }
93 
GetContentNativeView() const94 gfx::NativeView TabContentsViewViews::GetContentNativeView() const {
95   RenderWidgetHostView* rwhv = tab_contents()->GetRenderWidgetHostView();
96   return rwhv ? rwhv->GetNativeView() : NULL;
97 }
98 
GetTopLevelNativeWindow() const99 gfx::NativeWindow TabContentsViewViews::GetTopLevelNativeWindow() const {
100   return native_tab_contents_view_->GetTopLevelNativeWindow();
101 }
102 
GetContainerBounds(gfx::Rect * out) const103 void TabContentsViewViews::GetContainerBounds(gfx::Rect* out) const {
104   *out = GetWidget()->GetClientAreaScreenBounds();
105 }
106 
StartDragging(const WebDropData & drop_data,WebDragOperationsMask ops,const SkBitmap & image,const gfx::Point & image_offset)107 void TabContentsViewViews::StartDragging(const WebDropData& drop_data,
108                                          WebDragOperationsMask ops,
109                                          const SkBitmap& image,
110                                          const gfx::Point& image_offset) {
111   native_tab_contents_view_->StartDragging(drop_data, ops, image, image_offset);
112 }
113 
SetPageTitle(const std::wstring & title)114 void TabContentsViewViews::SetPageTitle(const std::wstring& title) {
115   native_tab_contents_view_->SetPageTitle(title);
116 }
117 
OnTabCrashed(base::TerminationStatus status,int)118 void TabContentsViewViews::OnTabCrashed(base::TerminationStatus status,
119                                         int /* error_code */) {
120   // Force an invalidation to render sad tab.
121   // Note that it's possible to get this message after the window was destroyed.
122   if (::IsWindow(GetNativeView())) {
123     SadTabView::Kind kind =
124         status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED ?
125         SadTabView::KILLED : SadTabView::CRASHED;
126     sad_tab_ = new SadTabView(tab_contents(), kind);
127     GetWidget()->SetContentsView(sad_tab_);
128     sad_tab_->SchedulePaint();
129   }
130 }
131 
SizeContents(const gfx::Size & size)132 void TabContentsViewViews::SizeContents(const gfx::Size& size) {
133   GetWidget()->SetSize(size);
134 }
135 
Focus()136 void TabContentsViewViews::Focus() {
137   if (tab_contents()->interstitial_page()) {
138     tab_contents()->interstitial_page()->Focus();
139     return;
140   }
141 
142   if (tab_contents()->is_crashed() && sad_tab_ != NULL) {
143     sad_tab_->RequestFocus();
144     return;
145   }
146 
147   if (tab_contents()->constrained_window_count() > 0) {
148     ConstrainedWindow* window = *tab_contents()->constrained_window_begin();
149     DCHECK(window);
150     window->FocusConstrainedWindow();
151     return;
152   }
153 
154   RenderWidgetHostView* rwhv = tab_contents()->GetRenderWidgetHostView();
155   GetWidget()->GetFocusManager()->FocusNativeView(rwhv ? rwhv->GetNativeView()
156                                                        : GetNativeView());
157 }
158 
SetInitialFocus()159 void TabContentsViewViews::SetInitialFocus() {
160   if (tab_contents()->FocusLocationBarByDefault())
161     tab_contents()->SetFocusToLocationBar(false);
162   else
163     Focus();
164 }
165 
StoreFocus()166 void TabContentsViewViews::StoreFocus() {
167   views::ViewStorage* view_storage = views::ViewStorage::GetInstance();
168 
169   if (view_storage->RetrieveView(last_focused_view_storage_id_) != NULL)
170     view_storage->RemoveView(last_focused_view_storage_id_);
171 
172   views::FocusManager* focus_manager =
173       views::FocusManager::GetFocusManagerForNativeView(GetNativeView());
174   if (focus_manager) {
175     // |focus_manager| can be NULL if the tab has been detached but still
176     // exists.
177     views::View* focused_view = focus_manager->GetFocusedView();
178     if (focused_view)
179       view_storage->StoreView(last_focused_view_storage_id_, focused_view);
180   }
181 }
182 
RestoreFocus()183 void TabContentsViewViews::RestoreFocus() {
184   views::ViewStorage* view_storage = views::ViewStorage::GetInstance();
185   views::View* last_focused_view =
186       view_storage->RetrieveView(last_focused_view_storage_id_);
187 
188   if (!last_focused_view) {
189     SetInitialFocus();
190   } else {
191     views::FocusManager* focus_manager =
192         views::FocusManager::GetFocusManagerForNativeView(GetNativeView());
193 
194     // If you hit this DCHECK, please report it to Jay (jcampan).
195     DCHECK(focus_manager != NULL) << "No focus manager when restoring focus.";
196 
197     if (last_focused_view->IsFocusableInRootView() && focus_manager &&
198         focus_manager->ContainsView(last_focused_view)) {
199       last_focused_view->RequestFocus();
200     } else {
201       // The focused view may not belong to the same window hierarchy (e.g.
202       // if the location bar was focused and the tab is dragged out), or it may
203       // no longer be focusable (e.g. if the location bar was focused and then
204       // we switched to fullscreen mode).  In that case we default to the
205       // default focus.
206       SetInitialFocus();
207     }
208     view_storage->RemoveView(last_focused_view_storage_id_);
209   }
210 }
211 
IsDoingDrag() const212 bool TabContentsViewViews::IsDoingDrag() const {
213   return native_tab_contents_view_->IsDoingDrag();
214 }
215 
CancelDragAndCloseTab()216 void TabContentsViewViews::CancelDragAndCloseTab() {
217   DCHECK(IsDoingDrag());
218   // We can't close the tab while we're in the drag and
219   // |drag_handler_->CancelDrag()| is async.  Instead, set a flag to cancel
220   // the drag and when the drag nested message loop ends, close the tab.
221   native_tab_contents_view_->CancelDrag();
222   close_tab_after_drag_ends_ = true;
223 }
224 
GetViewBounds(gfx::Rect * out) const225 void TabContentsViewViews::GetViewBounds(gfx::Rect* out) const {
226   *out = GetWidget()->GetWindowScreenBounds();
227 }
228 
UpdateDragCursor(WebDragOperation operation)229 void TabContentsViewViews::UpdateDragCursor(WebDragOperation operation) {
230   native_tab_contents_view_->SetDragCursor(operation);
231 }
232 
GotFocus()233 void TabContentsViewViews::GotFocus() {
234   if (tab_contents()->delegate())
235     tab_contents()->delegate()->TabContentsFocused(tab_contents());
236 }
237 
TakeFocus(bool reverse)238 void TabContentsViewViews::TakeFocus(bool reverse) {
239   if (!tab_contents()->delegate()->TakeFocus(reverse)) {
240     views::FocusManager* focus_manager =
241         views::FocusManager::GetFocusManagerForNativeView(GetNativeView());
242 
243     // We may not have a focus manager if the tab has been switched before this
244     // message arrived.
245     if (focus_manager)
246       focus_manager->AdvanceFocus(reverse);
247   }
248 }
249 
GetWidget()250 views::Widget* TabContentsViewViews::GetWidget() {
251   return native_tab_contents_view_->AsNativeWidget()->GetWidget();
252 }
253 
GetWidget() const254 const views::Widget* TabContentsViewViews::GetWidget() const {
255   return native_tab_contents_view_->AsNativeWidget()->GetWidget();
256 }
257 
CloseTab()258 void TabContentsViewViews::CloseTab() {
259   tab_contents()->Close(tab_contents()->render_view_host());
260 }
261 
ShowContextMenu(const ContextMenuParams & params)262 void TabContentsViewViews::ShowContextMenu(const ContextMenuParams& params) {
263   // Allow delegates to handle the context menu operation first.
264   if (tab_contents()->delegate()->HandleContextMenu(params))
265     return;
266 
267   context_menu_.reset(new RenderViewContextMenuViews(tab_contents(), params));
268   context_menu_->Init();
269 
270   POINT screen_pt = { params.x, params.y };
271   MapWindowPoints(GetNativeView(), HWND_DESKTOP, &screen_pt, 1);
272 
273   // Enable recursive tasks on the message loop so we can get updates while
274   // the context menu is being displayed.
275   bool old_state = MessageLoop::current()->NestableTasksAllowed();
276   MessageLoop::current()->SetNestableTasksAllowed(true);
277   context_menu_->RunMenuAt(screen_pt.x, screen_pt.y);
278   MessageLoop::current()->SetNestableTasksAllowed(old_state);
279 }
280 
ShowPopupMenu(const gfx::Rect & bounds,int item_height,double item_font_size,int selected_item,const std::vector<WebMenuItem> & items,bool right_aligned)281 void TabContentsViewViews::ShowPopupMenu(const gfx::Rect& bounds,
282                                          int item_height,
283                                          double item_font_size,
284                                          int selected_item,
285                                          const std::vector<WebMenuItem>& items,
286                                          bool right_aligned) {
287   // External popup menus are only used on Mac.
288   NOTREACHED();
289 }
290 
291 ////////////////////////////////////////////////////////////////////////////////
292 // TabContentsViewViews, internal::NativeTabContentsViewDelegate implementation:
293 
GetTabContents()294 TabContents* TabContentsViewViews::GetTabContents() {
295   return tab_contents();
296 }
297 
IsShowingSadTab() const298 bool TabContentsViewViews::IsShowingSadTab() const {
299   return tab_contents()->is_crashed() && sad_tab_;
300 }
301 
OnNativeTabContentsViewShown()302 void TabContentsViewViews::OnNativeTabContentsViewShown() {
303   tab_contents()->ShowContents();
304 }
305 
OnNativeTabContentsViewHidden()306 void TabContentsViewViews::OnNativeTabContentsViewHidden() {
307   tab_contents()->HideContents();
308 }
309 
OnNativeTabContentsViewSized(const gfx::Size & size)310 void TabContentsViewViews::OnNativeTabContentsViewSized(const gfx::Size& size) {
311   if (tab_contents()->interstitial_page())
312     tab_contents()->interstitial_page()->SetSize(size);
313   RenderWidgetHostView* rwhv = tab_contents()->GetRenderWidgetHostView();
314   if (rwhv)
315     rwhv->SetSize(size);
316 }
317 
OnNativeTabContentsViewWheelZoom(int distance)318 void TabContentsViewViews::OnNativeTabContentsViewWheelZoom(int distance) {
319   if (tab_contents()->delegate()) {
320     bool zoom_in = distance > 0;
321     tab_contents()->delegate()->ContentsZoomChange(zoom_in);
322   }
323 }
324 
OnNativeTabContentsViewMouseDown()325 void TabContentsViewViews::OnNativeTabContentsViewMouseDown() {
326   // Make sure this TabContents is activated when it is clicked on.
327   if (tab_contents()->delegate())
328     tab_contents()->delegate()->ActivateContents(tab_contents());
329 }
330 
OnNativeTabContentsViewMouseMove()331 void TabContentsViewViews::OnNativeTabContentsViewMouseMove() {
332   // Let our delegate know that the mouse moved (useful for resetting status
333   // bubble state).
334   if (tab_contents()->delegate()) {
335     tab_contents()->delegate()->ContentsMouseEvent(
336         tab_contents(), views::Screen::GetCursorScreenPoint(), true);
337   }
338 }
339 
OnNativeTabContentsViewDraggingEnded()340 void TabContentsViewViews::OnNativeTabContentsViewDraggingEnded() {
341   if (close_tab_after_drag_ends_) {
342     close_tab_timer_.Start(base::TimeDelta::FromMilliseconds(0), this,
343                            &TabContentsViewViews::CloseTab);
344   }
345   tab_contents()->SystemDragEnded();
346 }
347