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