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