1// Copyright (c) 2011 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.h" 6 7#include "chrome/browser/extensions/extension_host.h" 8#include "chrome/browser/ui/views/extensions/extension_popup.h" 9#include "content/browser/renderer_host/render_view_host.h" 10#include "content/browser/renderer_host/render_widget_host_view.h" 11#include "views/widget/widget.h" 12 13#if defined(OS_WIN) 14#include "chrome/browser/renderer_host/render_widget_host_view_win.h" 15#elif defined(TOUCH_UI) 16#include "chrome/browser/renderer_host/render_widget_host_view_views.h" 17#elif defined(OS_LINUX) 18#include "chrome/browser/renderer_host/render_widget_host_view_gtk.h" 19#endif 20 21ExtensionView::ExtensionView(ExtensionHost* host, Browser* browser) 22 : host_(host), 23 browser_(browser), 24 initialized_(false), 25 container_(NULL), 26 is_clipped_(false) { 27 host_->set_view(this); 28 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 SetFocusable(true); 33} 34 35ExtensionView::~ExtensionView() { 36 if (parent()) 37 parent()->RemoveChildView(this); 38 CleanUp(); 39} 40 41const Extension* ExtensionView::extension() const { 42 return host_->extension(); 43} 44 45RenderViewHost* ExtensionView::render_view_host() const { 46 return host_->render_view_host(); 47} 48 49void ExtensionView::DidStopLoading() { 50 ShowIfCompletelyLoaded(); 51} 52 53void ExtensionView::SetIsClipped(bool is_clipped) { 54 if (is_clipped_ != is_clipped) { 55 is_clipped_ = is_clipped; 56 if (IsVisible()) 57 ShowIfCompletelyLoaded(); 58 } 59} 60 61void ExtensionView::SetVisible(bool is_visible) { 62 if (is_visible != IsVisible()) { 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()->view()) { 69 if (is_visible) 70 render_view_host()->view()->Show(); 71 else 72 render_view_host()->view()->Hide(); 73 } 74 } 75} 76 77void ExtensionView::CreateWidgetHostView() { 78 DCHECK(!initialized_); 79 initialized_ = true; 80 RenderWidgetHostView* view = 81 RenderWidgetHostView::CreateViewForWidget(render_view_host()); 82 83 // TODO(mpcomplete): RWHV needs a cross-platform Init function. 84#if defined(OS_WIN) 85 // Create the HWND. Note: 86 // RenderWidgetHostHWND supports windowed plugins, but if we ever also 87 // wanted to support constrained windows with this, we would need an 88 // additional HWND to parent off of because windowed plugin HWNDs cannot 89 // exist in the same z-order as constrained windows. 90 RenderWidgetHostViewWin* view_win = 91 static_cast<RenderWidgetHostViewWin*>(view); 92 HWND hwnd = view_win->Create(GetWidget()->GetNativeView()); 93 view_win->ShowWindow(SW_SHOW); 94 Attach(hwnd); 95#elif defined(TOUCH_UI) 96 RenderWidgetHostViewViews* view_views = 97 static_cast<RenderWidgetHostViewViews*>(view); 98 view_views->InitAsChild(); 99 AttachToView(view_views); 100#elif defined(OS_LINUX) 101 RenderWidgetHostViewGtk* view_gtk = 102 static_cast<RenderWidgetHostViewGtk*>(view); 103 view_gtk->InitAsChild(); 104 Attach(view_gtk->GetNativeView()); 105#else 106 NOTIMPLEMENTED(); 107#endif 108 109 host_->CreateRenderViewSoon(view); 110 SetVisible(false); 111} 112 113void ExtensionView::ShowIfCompletelyLoaded() { 114 if (IsVisible() || is_clipped_) 115 return; 116 117 // We wait to show the ExtensionView until it has loaded, and the view has 118 // actually been created. These can happen in different orders. 119 if (host_->did_stop_loading()) { 120 SetVisible(true); 121 UpdatePreferredSize(pending_preferred_size_); 122 } 123} 124 125void ExtensionView::CleanUp() { 126 if (!initialized_) 127 return; 128 if (native_view()) 129 Detach(); 130 initialized_ = false; 131} 132 133void ExtensionView::SetBackground(const SkBitmap& background) { 134 if (render_view_host()->IsRenderViewLive() && render_view_host()->view()) { 135 render_view_host()->view()->SetBackground(background); 136 } else { 137 pending_background_ = background; 138 } 139 ShowIfCompletelyLoaded(); 140} 141 142void ExtensionView::UpdatePreferredSize(const gfx::Size& new_size) { 143 // Don't actually do anything with this information until we have been shown. 144 // Size changes will not be honored by lower layers while we are hidden. 145 if (!IsVisible()) { 146 pending_preferred_size_ = new_size; 147 return; 148 } 149 150 gfx::Size preferred_size = GetPreferredSize(); 151 if (new_size != preferred_size) 152 SetPreferredSize(new_size); 153} 154 155void ExtensionView::ViewHierarchyChanged(bool is_add, 156 views::View *parent, 157 views::View *child) { 158 NativeViewHost::ViewHierarchyChanged(is_add, parent, child); 159 if (is_add && GetWidget() && !initialized_) 160 CreateWidgetHostView(); 161} 162 163void ExtensionView::PreferredSizeChanged() { 164 View::PreferredSizeChanged(); 165 if (container_) 166 container_->OnExtensionPreferredSizeChanged(this); 167} 168 169bool ExtensionView::SkipDefaultKeyEventProcessing(const views::KeyEvent& e) { 170 // Let the tab key event be processed by the renderer (instead of moving the 171 // focus to the next focusable view). 172 return (e.key_code() == ui::VKEY_TAB); 173} 174 175void ExtensionView::OnBoundsChanged(const gfx::Rect& previous_bounds) { 176 // Propagate the new size to RenderWidgetHostView. 177 // We can't send size zero because RenderWidget DCHECKs that. 178 if (render_view_host()->view() && !bounds().IsEmpty()) 179 render_view_host()->view()->SetSize(size()); 180} 181 182void ExtensionView::HandleMouseMove() { 183 if (container_) 184 container_->OnExtensionMouseMove(this); 185} 186 187void ExtensionView::HandleMouseLeave() { 188 if (container_) 189 container_->OnExtensionMouseLeave(this); 190} 191 192void ExtensionView::RenderViewCreated() { 193 if (!pending_background_.empty() && render_view_host()->view()) { 194 render_view_host()->view()->SetBackground(pending_background_); 195 pending_background_.reset(); 196 } 197 198 // Tell the renderer not to draw scroll bars in popups unless the 199 // popups are at the maximum allowed size. 200 gfx::Size largest_popup_size(ExtensionPopup::kMaxWidth, 201 ExtensionPopup::kMaxHeight); 202 host_->DisableScrollbarsForSmallWindows(largest_popup_size); 203} 204