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