extension_view_views.cc revision a93a17c8d99d686bd4a1511e5504e5e6cc9fcadf
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 "chrome/browser/ui/views/extensions/extension_view_views.h"
6
7#include "chrome/browser/extensions/extension_host.h"
8#include "chrome/browser/ui/views/extensions/extension_popup.h"
9#include "content/public/browser/content_browser_client.h"
10#include "content/public/browser/render_view_host.h"
11#include "content/public/browser/render_widget_host_view.h"
12#include "content/public/browser/web_contents.h"
13#include "content/public/browser/web_contents_view.h"
14#include "extensions/common/view_type.h"
15#include "ui/base/events/event.h"
16#include "ui/views/widget/widget.h"
17
18ExtensionViewViews::ExtensionViewViews(extensions::ExtensionHost* host,
19                                       Browser* browser)
20    : host_(host),
21      browser_(browser),
22      initialized_(false),
23      container_(NULL),
24      is_clipped_(false) {
25  // This view needs to be focusable so it can act as the focused view for the
26  // focus manager. This is required to have SkipDefaultKeyEventProcessing
27  // called so the tab key events are forwarded to the renderer.
28  set_focusable(true);
29}
30
31ExtensionViewViews::~ExtensionViewViews() {
32  if (parent())
33    parent()->RemoveChildView(this);
34  CleanUp();
35}
36
37const extensions::Extension* ExtensionViewViews::extension() const {
38  return host_->extension();
39}
40
41content::RenderViewHost* ExtensionViewViews::render_view_host() const {
42  return host_->render_view_host();
43}
44
45void ExtensionViewViews::DidStopLoading() {
46  ShowIfCompletelyLoaded();
47}
48
49void ExtensionViewViews::SetIsClipped(bool is_clipped) {
50  if (is_clipped_ != is_clipped) {
51    is_clipped_ = is_clipped;
52    if (visible())
53      ShowIfCompletelyLoaded();
54  }
55}
56
57gfx::NativeCursor ExtensionViewViews::GetCursor(const ui::MouseEvent& event) {
58  return gfx::kNullCursor;
59}
60
61void ExtensionViewViews::SetVisible(bool is_visible) {
62  if (is_visible != visible()) {
63    NativeViewHost::SetVisible(is_visible);
64
65    // Also tell RenderWidgetHostView the new visibility. Despite its name, it
66    // is not part of the View hierarchy and does not know about the change
67    // unless we tell it.
68    if (render_view_host()->GetView()) {
69      if (is_visible)
70        render_view_host()->GetView()->Show();
71      else
72        render_view_host()->GetView()->Hide();
73    }
74  }
75}
76
77void ExtensionViewViews::CreateWidgetHostView() {
78  DCHECK(!initialized_);
79  initialized_ = true;
80  Attach(host_->host_contents()->GetView()->GetNativeView());
81  host_->CreateRenderViewSoon();
82  SetVisible(false);
83}
84
85void ExtensionViewViews::ShowIfCompletelyLoaded() {
86  if (visible() || is_clipped_)
87    return;
88
89  // We wait to show the ExtensionViewViews until it has loaded, and the view
90  // has actually been created. These can happen in different orders.
91  if (host_->did_stop_loading()) {
92    SetVisible(true);
93    ResizeDueToAutoResize(pending_preferred_size_);
94  }
95}
96
97void ExtensionViewViews::CleanUp() {
98  if (!initialized_)
99    return;
100  if (native_view())
101    Detach();
102  initialized_ = false;
103}
104
105void ExtensionViewViews::ResizeDueToAutoResize(const gfx::Size& new_size) {
106  // Don't actually do anything with this information until we have been shown.
107  // Size changes will not be honored by lower layers while we are hidden.
108  if (!visible()) {
109    pending_preferred_size_ = new_size;
110    return;
111  }
112
113  gfx::Size preferred_size = GetPreferredSize();
114  if (new_size != preferred_size)
115    SetPreferredSize(new_size);
116}
117
118void ExtensionViewViews::ViewHierarchyChanged(
119    const ViewHierarchyChangedDetails& details) {
120  NativeViewHost::ViewHierarchyChanged(details);
121  if (details.is_add && GetWidget() && !initialized_)
122    CreateWidgetHostView();
123}
124
125bool ExtensionViewViews::SkipDefaultKeyEventProcessing(const ui::KeyEvent& e) {
126  // Let the tab key event be processed by the renderer (instead of moving the
127  // focus to the next focusable view). Also handle Backspace, since otherwise
128  // (on Windows at least), pressing Backspace, when focus is on a text field
129  // within the ExtensionViewViews, will navigate the page back instead of
130  // erasing a character.
131  return (e.key_code() == ui::VKEY_TAB || e.key_code() == ui::VKEY_BACK);
132}
133
134void ExtensionViewViews::OnBoundsChanged(const gfx::Rect& previous_bounds) {
135  // Propagate the new size to RenderWidgetHostView.
136  // We can't send size zero because RenderWidget DCHECKs that.
137  if (render_view_host()->GetView() && !bounds().IsEmpty()) {
138    render_view_host()->GetView()->SetSize(size());
139
140    if (container_)
141      container_->OnViewWasResized();
142  }
143}
144
145void ExtensionViewViews::PreferredSizeChanged() {
146  View::PreferredSizeChanged();
147  if (container_)
148    container_->OnExtensionSizeChanged(this);
149}
150
151void ExtensionViewViews::OnFocus() {
152  host()->host_contents()->GetView()->Focus();
153}
154
155void ExtensionViewViews::RenderViewCreated() {
156  extensions::ViewType host_type = host_->extension_host_type();
157  if (host_type == extensions::VIEW_TYPE_EXTENSION_POPUP) {
158    gfx::Size min_size(ExtensionPopup::kMinWidth,
159                       ExtensionPopup::kMinHeight);
160    gfx::Size max_size(ExtensionPopup::kMaxWidth,
161                       ExtensionPopup::kMaxHeight);
162    render_view_host()->EnableAutoResize(min_size, max_size);
163  }
164
165  if (container_)
166    container_->OnViewWasResized();
167}
168
169void ExtensionViewViews::HandleKeyboardEvent(
170    const content::NativeWebKeyboardEvent& event) {
171  unhandled_keyboard_event_handler_.HandleKeyboardEvent(event,
172                                                        GetFocusManager());
173}
174