普通文本  |  204行  |  6.27 KB

// 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/ui/views/extensions/extension_popup.h"
#include "content/browser/renderer_host/render_view_host.h"
#include "content/browser/renderer_host/render_widget_host_view.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::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();
  AttachToView(view_views);
#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::OnBoundsChanged(const gfx::Rect& previous_bounds) {
  // 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::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);
}