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