| // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ui/views/extensions/extension_view.h" |
| |
| #include "chrome/browser/extensions/extension_host.h" |
| #include "chrome/browser/renderer_host/render_view_host.h" |
| #include "chrome/browser/renderer_host/render_widget_host_view.h" |
| #include "chrome/browser/ui/views/extensions/extension_popup.h" |
| #include "views/widget/widget.h" |
| |
| #if defined(OS_WIN) |
| #include "chrome/browser/renderer_host/render_widget_host_view_win.h" |
| #elif defined(TOUCH_UI) |
| #include "chrome/browser/renderer_host/render_widget_host_view_views.h" |
| #elif defined(OS_LINUX) |
| #include "chrome/browser/renderer_host/render_widget_host_view_gtk.h" |
| #endif |
| |
| ExtensionView::ExtensionView(ExtensionHost* host, Browser* browser) |
| : host_(host), |
| browser_(browser), |
| initialized_(false), |
| container_(NULL), |
| is_clipped_(false) { |
| host_->set_view(this); |
| |
| // This view needs to be focusable so it can act as the focused view for the |
| // focus manager. This is required to have SkipDefaultKeyEventProcessing |
| // called so the tab key events are forwarded to the renderer. |
| SetFocusable(true); |
| } |
| |
| ExtensionView::~ExtensionView() { |
| if (parent()) |
| parent()->RemoveChildView(this); |
| CleanUp(); |
| } |
| |
| const Extension* ExtensionView::extension() const { |
| return host_->extension(); |
| } |
| |
| RenderViewHost* ExtensionView::render_view_host() const { |
| return host_->render_view_host(); |
| } |
| |
| void ExtensionView::DidStopLoading() { |
| ShowIfCompletelyLoaded(); |
| } |
| |
| void ExtensionView::SetIsClipped(bool is_clipped) { |
| if (is_clipped_ != is_clipped) { |
| is_clipped_ = is_clipped; |
| if (IsVisible()) |
| ShowIfCompletelyLoaded(); |
| } |
| } |
| |
| void ExtensionView::SetVisible(bool is_visible) { |
| if (is_visible != IsVisible()) { |
| NativeViewHost::SetVisible(is_visible); |
| |
| // Also tell RenderWidgetHostView the new visibility. Despite its name, it |
| // is not part of the View hierarchy and does not know about the change |
| // unless we tell it. |
| if (render_view_host()->view()) { |
| if (is_visible) |
| render_view_host()->view()->Show(); |
| else |
| render_view_host()->view()->Hide(); |
| } |
| } |
| } |
| |
| void ExtensionView::OnBoundsChanged() { |
| View::OnBoundsChanged(); |
| // Propagate the new size to RenderWidgetHostView. |
| // We can't send size zero because RenderWidget DCHECKs that. |
| if (render_view_host()->view() && !bounds().IsEmpty()) |
| render_view_host()->view()->SetSize(size()); |
| } |
| |
| void ExtensionView::CreateWidgetHostView() { |
| DCHECK(!initialized_); |
| initialized_ = true; |
| RenderWidgetHostView* view = |
| RenderWidgetHostView::CreateViewForWidget(render_view_host()); |
| |
| // TODO(mpcomplete): RWHV needs a cross-platform Init function. |
| #if defined(OS_WIN) |
| // Create the HWND. Note: |
| // RenderWidgetHostHWND supports windowed plugins, but if we ever also |
| // wanted to support constrained windows with this, we would need an |
| // additional HWND to parent off of because windowed plugin HWNDs cannot |
| // exist in the same z-order as constrained windows. |
| RenderWidgetHostViewWin* view_win = |
| static_cast<RenderWidgetHostViewWin*>(view); |
| HWND hwnd = view_win->Create(GetWidget()->GetNativeView()); |
| view_win->ShowWindow(SW_SHOW); |
| Attach(hwnd); |
| #elif defined(TOUCH_UI) |
| RenderWidgetHostViewViews* view_views = |
| static_cast<RenderWidgetHostViewViews*>(view); |
| view_views->InitAsChild(); |
| Attach(view_views->GetNativeView()); |
| #elif defined(OS_LINUX) |
| RenderWidgetHostViewGtk* view_gtk = |
| static_cast<RenderWidgetHostViewGtk*>(view); |
| view_gtk->InitAsChild(); |
| Attach(view_gtk->GetNativeView()); |
| #else |
| NOTIMPLEMENTED(); |
| #endif |
| |
| host_->CreateRenderViewSoon(view); |
| SetVisible(false); |
| } |
| |
| void ExtensionView::ShowIfCompletelyLoaded() { |
| if (IsVisible() || is_clipped_) |
| return; |
| |
| // We wait to show the ExtensionView until it has loaded, and the view has |
| // actually been created. These can happen in different orders. |
| if (host_->did_stop_loading()) { |
| SetVisible(true); |
| UpdatePreferredSize(pending_preferred_size_); |
| } |
| } |
| |
| void ExtensionView::CleanUp() { |
| if (!initialized_) |
| return; |
| if (native_view()) |
| Detach(); |
| initialized_ = false; |
| } |
| |
| void ExtensionView::SetBackground(const SkBitmap& background) { |
| if (render_view_host()->IsRenderViewLive() && render_view_host()->view()) { |
| render_view_host()->view()->SetBackground(background); |
| } else { |
| pending_background_ = background; |
| } |
| ShowIfCompletelyLoaded(); |
| } |
| |
| void ExtensionView::UpdatePreferredSize(const gfx::Size& new_size) { |
| // Don't actually do anything with this information until we have been shown. |
| // Size changes will not be honored by lower layers while we are hidden. |
| if (!IsVisible()) { |
| pending_preferred_size_ = new_size; |
| return; |
| } |
| |
| gfx::Size preferred_size = GetPreferredSize(); |
| if (new_size != preferred_size) |
| SetPreferredSize(new_size); |
| } |
| |
| void ExtensionView::ViewHierarchyChanged(bool is_add, |
| views::View *parent, |
| views::View *child) { |
| NativeViewHost::ViewHierarchyChanged(is_add, parent, child); |
| if (is_add && GetWidget() && !initialized_) |
| CreateWidgetHostView(); |
| } |
| |
| void ExtensionView::PreferredSizeChanged() { |
| View::PreferredSizeChanged(); |
| if (container_) |
| container_->OnExtensionPreferredSizeChanged(this); |
| } |
| |
| bool ExtensionView::SkipDefaultKeyEventProcessing(const views::KeyEvent& e) { |
| // Let the tab key event be processed by the renderer (instead of moving the |
| // focus to the next focusable view). |
| return (e.key_code() == ui::VKEY_TAB); |
| } |
| |
| void ExtensionView::HandleMouseMove() { |
| if (container_) |
| container_->OnExtensionMouseMove(this); |
| } |
| |
| void ExtensionView::HandleMouseLeave() { |
| if (container_) |
| container_->OnExtensionMouseLeave(this); |
| } |
| |
| void ExtensionView::RenderViewCreated() { |
| if (!pending_background_.empty() && render_view_host()->view()) { |
| render_view_host()->view()->SetBackground(pending_background_); |
| pending_background_.reset(); |
| } |
| |
| // Tell the renderer not to draw scroll bars in popups unless the |
| // popups are at the maximum allowed size. |
| gfx::Size largest_popup_size(ExtensionPopup::kMaxWidth, |
| ExtensionPopup::kMaxHeight); |
| host_->DisableScrollbarsForSmallWindows(largest_popup_size); |
| } |