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