NaCl: Update revision in DEPS, r12770 -> r12773
[chromium-blink-merge.git] / chrome / browser / ui / views / infobars / extension_infobar.cc
blob877fcc81581dd52cbf77730ef071d22c070eec54
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.
5 #include "chrome/browser/ui/views/infobars/extension_infobar.h"
7 #include "chrome/browser/extensions/extension_context_menu_model.h"
8 #include "chrome/browser/extensions/extension_infobar_delegate.h"
9 #include "chrome/browser/extensions/extension_view_host.h"
10 #include "chrome/browser/extensions/image_loader.h"
11 #include "chrome/browser/platform_util.h"
12 #include "chrome/browser/ui/views/frame/browser_view.h"
13 #include "chrome/common/extensions/extension_constants.h"
14 #include "chrome/common/extensions/extension_icon_set.h"
15 #include "chrome/common/extensions/manifest_handlers/icons_handler.h"
16 #include "extensions/common/extension.h"
17 #include "extensions/common/extension_resource.h"
18 #include "grit/theme_resources.h"
19 #include "ui/base/resource/resource_bundle.h"
20 #include "ui/gfx/animation/slide_animation.h"
21 #include "ui/gfx/canvas.h"
22 #include "ui/gfx/image/canvas_image_source.h"
23 #include "ui/gfx/image/image.h"
24 #include "ui/views/controls/button/menu_button.h"
25 #include "ui/views/controls/image_view.h"
26 #include "ui/views/controls/menu/menu_item_view.h"
27 #include "ui/views/widget/widget.h"
30 // ExtensionInfoBarDelegate ----------------------------------------------------
32 // static
33 scoped_ptr<InfoBar> ExtensionInfoBarDelegate::CreateInfoBar(
34 scoped_ptr<ExtensionInfoBarDelegate> delegate) {
35 Browser* browser = delegate->browser_;
36 return scoped_ptr<InfoBar>(new ExtensionInfoBar(delegate.Pass(), browser));
40 // ExtensionInfoBar ------------------------------------------------------------
42 namespace {
43 // The horizontal margin between the infobar icon and the Extension (HTML) view.
44 const int kIconHorizontalMargin = 1;
46 class MenuImageSource: public gfx::CanvasImageSource {
47 public:
48 MenuImageSource(const gfx::ImageSkia& icon, const gfx::ImageSkia& drop_image)
49 : gfx::CanvasImageSource(ComputeSize(drop_image), false),
50 icon_(icon),
51 drop_image_(drop_image) {
54 virtual ~MenuImageSource() {
57 // Overridden from gfx::CanvasImageSource
58 virtual void Draw(gfx::Canvas* canvas) OVERRIDE {
59 int image_size = extension_misc::EXTENSION_ICON_BITTY;
60 canvas->DrawImageInt(icon_, 0, 0, icon_.width(), icon_.height(), 0, 0,
61 image_size, image_size, false);
62 canvas->DrawImageInt(drop_image_, image_size + kDropArrowLeftMargin,
63 image_size / 2);
66 private:
67 gfx::Size ComputeSize(const gfx::ImageSkia& drop_image) const {
68 int image_size = extension_misc::EXTENSION_ICON_BITTY;
69 return gfx::Size(image_size + kDropArrowLeftMargin + drop_image.width(),
70 image_size);
73 // The margin between the extension icon and the drop-down arrow image.
74 static const int kDropArrowLeftMargin = 3;
76 const gfx::ImageSkia icon_;
77 const gfx::ImageSkia drop_image_;
79 DISALLOW_COPY_AND_ASSIGN(MenuImageSource);
82 } // namespace
84 ExtensionInfoBar::ExtensionInfoBar(
85 scoped_ptr<ExtensionInfoBarDelegate> delegate,
86 Browser* browser)
87 : InfoBarView(delegate.PassAs<InfoBarDelegate>()),
88 browser_(browser),
89 infobar_icon_(NULL),
90 icon_as_menu_(NULL),
91 icon_as_image_(NULL),
92 weak_ptr_factory_(this) {
95 ExtensionInfoBar::~ExtensionInfoBar() {
98 void ExtensionInfoBar::Layout() {
99 InfoBarView::Layout();
101 infobar_icon_->SetPosition(gfx::Point(StartX(), OffsetY(infobar_icon_)));
102 ExtensionViewViews* extension_view =
103 GetDelegate()->extension_view_host()->view();
104 // TODO(pkasting): We'd like to simply set the extension view's desired height
105 // at creation time and position using OffsetY() like for other infobar items,
106 // but the NativeViewHost inside does not seem to be clipped by the ClipRect()
107 // call in InfoBarView::PaintChildren(), so we have to manually clamp the size
108 // here.
109 extension_view->SetSize(
110 gfx::Size(std::max(0, EndX() - StartX() - NonExtensionViewWidth()),
111 std::min(height() - kSeparatorLineHeight - arrow_height(),
112 GetDelegate()->height())));
113 // We do SetPosition() separately after SetSize() so OffsetY() will work.
114 extension_view->SetPosition(
115 gfx::Point(infobar_icon_->bounds().right() + kIconHorizontalMargin,
116 std::max(arrow_height(), OffsetY(extension_view))));
119 void ExtensionInfoBar::ViewHierarchyChanged(
120 const ViewHierarchyChangedDetails& details) {
121 if (!details.is_add || (details.child != this) || (infobar_icon_ != NULL)) {
122 InfoBarView::ViewHierarchyChanged(details);
123 return;
126 extensions::ExtensionViewHost* extension_view_host =
127 GetDelegate()->extension_view_host();
129 if (extension_view_host->extension()->ShowConfigureContextMenus()) {
130 icon_as_menu_ = new views::MenuButton(NULL, base::string16(), this, false);
131 icon_as_menu_->SetFocusable(true);
132 infobar_icon_ = icon_as_menu_;
133 } else {
134 icon_as_image_ = new views::ImageView();
135 infobar_icon_ = icon_as_image_;
138 // Wait until the icon image is loaded before showing it.
139 infobar_icon_->SetVisible(false);
140 AddChildView(infobar_icon_);
142 // Set the desired height of the ExtensionViewViews, so that when the
143 // AddChildView() call triggers InfoBarView::ViewHierarchyChanged(), it can
144 // read the correct height off this object in order to calculate the overall
145 // desired infobar height.
146 extension_view_host->view()->SetSize(gfx::Size(0, GetDelegate()->height()));
147 AddChildView(extension_view_host->view());
149 // This must happen after adding all other children so InfoBarView can ensure
150 // the close button is the last child.
151 InfoBarView::ViewHierarchyChanged(details);
153 // This must happen after adding all children because it can trigger layout,
154 // which assumes that particular children (e.g. the close button) have already
155 // been added.
156 const extensions::Extension* extension = extension_view_host->extension();
157 extension_misc::ExtensionIcons image_size =
158 extension_misc::EXTENSION_ICON_BITTY;
159 extensions::ExtensionResource icon_resource =
160 extensions::IconsInfo::GetIconResource(
161 extension, image_size, ExtensionIconSet::MATCH_EXACTLY);
162 extensions::ImageLoader* loader =
163 extensions::ImageLoader::Get(extension_view_host->browser_context());
164 loader->LoadImageAsync(
165 extension,
166 icon_resource,
167 gfx::Size(image_size, image_size),
168 base::Bind(&ExtensionInfoBar::OnImageLoaded,
169 weak_ptr_factory_.GetWeakPtr()));
172 int ExtensionInfoBar::ContentMinimumWidth() {
173 return NonExtensionViewWidth() +
174 GetDelegate()->extension_view_host()->view()->GetMinimumSize().width();
177 void ExtensionInfoBar::OnMenuButtonClicked(views::View* source,
178 const gfx::Point& point) {
179 if (!owner())
180 return; // We're closing; don't call anything, it might access the owner.
181 const extensions::Extension* extension =
182 GetDelegate()->extension_view_host()->extension();
183 DCHECK(icon_as_menu_);
185 scoped_refptr<ExtensionContextMenuModel> options_menu_contents =
186 new ExtensionContextMenuModel(extension, browser_);
187 DCHECK_EQ(icon_as_menu_, source);
188 RunMenuAt(options_menu_contents.get(),
189 icon_as_menu_,
190 views::MenuItemView::TOPLEFT);
193 void ExtensionInfoBar::OnImageLoaded(const gfx::Image& image) {
194 if (!GetDelegate())
195 return; // The delegate can go away while we asynchronously load images.
197 const gfx::ImageSkia* icon = NULL;
198 // Fall back on the default extension icon on failure.
199 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
200 if (image.IsEmpty())
201 icon = rb.GetImageNamed(IDR_EXTENSIONS_SECTION).ToImageSkia();
202 else
203 icon = image.ToImageSkia();
205 if (icon_as_menu_) {
206 const gfx::ImageSkia* drop_image =
207 rb.GetImageNamed(IDR_APP_DROPARROW).ToImageSkia();
209 gfx::CanvasImageSource* source = new MenuImageSource(*icon, *drop_image);
210 gfx::ImageSkia menu_image = gfx::ImageSkia(source, source->size());
211 icon_as_menu_->SetIcon(menu_image);
212 } else {
213 icon_as_image_->SetImage(*icon);
216 infobar_icon_->SizeToPreferredSize();
217 infobar_icon_->SetVisible(true);
219 Layout();
222 ExtensionInfoBarDelegate* ExtensionInfoBar::GetDelegate() {
223 return delegate()->AsExtensionInfoBarDelegate();
226 int ExtensionInfoBar::NonExtensionViewWidth() const {
227 return infobar_icon_->width() + kIconHorizontalMargin;