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