| OLD | NEW |
| (Empty) |
| 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/infobars/extension_infobar.h" | |
| 6 | |
| 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/platform_util.h" | |
| 11 #include "chrome/browser/ui/infobar_container_delegate.h" | |
| 12 #include "chrome/browser/ui/views/extensions/extension_view_views.h" | |
| 13 #include "chrome/browser/ui/views/frame/browser_view.h" | |
| 14 #include "extensions/browser/image_loader.h" | |
| 15 #include "extensions/common/constants.h" | |
| 16 #include "extensions/common/extension.h" | |
| 17 #include "extensions/common/extension_icon_set.h" | |
| 18 #include "extensions/common/extension_resource.h" | |
| 19 #include "extensions/common/manifest_handlers/icons_handler.h" | |
| 20 #include "grit/theme_resources.h" | |
| 21 #include "ui/base/resource/resource_bundle.h" | |
| 22 #include "ui/gfx/animation/slide_animation.h" | |
| 23 #include "ui/gfx/canvas.h" | |
| 24 #include "ui/gfx/image/canvas_image_source.h" | |
| 25 #include "ui/gfx/image/image.h" | |
| 26 #include "ui/views/controls/button/menu_button.h" | |
| 27 #include "ui/views/controls/image_view.h" | |
| 28 #include "ui/views/widget/widget.h" | |
| 29 | |
| 30 | |
| 31 // ExtensionInfoBarDelegate ---------------------------------------------------- | |
| 32 | |
| 33 // static | |
| 34 scoped_ptr<infobars::InfoBar> ExtensionInfoBarDelegate::CreateInfoBar( | |
| 35 scoped_ptr<ExtensionInfoBarDelegate> delegate) { | |
| 36 Browser* browser = delegate->browser_; | |
| 37 return scoped_ptr<infobars::InfoBar>( | |
| 38 new ExtensionInfoBar(delegate.Pass(), browser)); | |
| 39 } | |
| 40 | |
| 41 | |
| 42 // ExtensionInfoBar ------------------------------------------------------------ | |
| 43 | |
| 44 namespace { | |
| 45 // The horizontal margin between the infobar icon and the Extension (HTML) view. | |
| 46 const int kIconHorizontalMargin = 1; | |
| 47 | |
| 48 class MenuImageSource: public gfx::CanvasImageSource { | |
| 49 public: | |
| 50 MenuImageSource(const gfx::ImageSkia& icon, const gfx::ImageSkia& drop_image) | |
| 51 : gfx::CanvasImageSource(ComputeSize(drop_image), false), | |
| 52 icon_(icon), | |
| 53 drop_image_(drop_image) { | |
| 54 } | |
| 55 | |
| 56 ~MenuImageSource() override {} | |
| 57 | |
| 58 // Overridden from gfx::CanvasImageSource | |
| 59 void Draw(gfx::Canvas* canvas) override { | |
| 60 int image_size = extension_misc::EXTENSION_ICON_BITTY; | |
| 61 canvas->DrawImageInt(icon_, 0, 0, icon_.width(), icon_.height(), 0, 0, | |
| 62 image_size, image_size, false); | |
| 63 canvas->DrawImageInt(drop_image_, image_size + kDropArrowLeftMargin, | |
| 64 image_size / 2); | |
| 65 } | |
| 66 | |
| 67 private: | |
| 68 gfx::Size ComputeSize(const gfx::ImageSkia& drop_image) const { | |
| 69 int image_size = extension_misc::EXTENSION_ICON_BITTY; | |
| 70 return gfx::Size(image_size + kDropArrowLeftMargin + drop_image.width(), | |
| 71 image_size); | |
| 72 } | |
| 73 | |
| 74 // The margin between the extension icon and the drop-down arrow image. | |
| 75 static const int kDropArrowLeftMargin = 3; | |
| 76 | |
| 77 const gfx::ImageSkia icon_; | |
| 78 const gfx::ImageSkia drop_image_; | |
| 79 | |
| 80 DISALLOW_COPY_AND_ASSIGN(MenuImageSource); | |
| 81 }; | |
| 82 | |
| 83 } // namespace | |
| 84 | |
| 85 ExtensionInfoBar::ExtensionInfoBar( | |
| 86 scoped_ptr<ExtensionInfoBarDelegate> delegate, | |
| 87 Browser* browser) | |
| 88 : InfoBarView(delegate.Pass()), | |
| 89 browser_(browser), | |
| 90 infobar_icon_(NULL), | |
| 91 icon_as_menu_(NULL), | |
| 92 icon_as_image_(NULL), | |
| 93 weak_ptr_factory_(this) { | |
| 94 } | |
| 95 | |
| 96 ExtensionInfoBar::~ExtensionInfoBar() { | |
| 97 } | |
| 98 | |
| 99 void ExtensionInfoBar::Layout() { | |
| 100 InfoBarView::Layout(); | |
| 101 | |
| 102 infobar_icon_->SetPosition(gfx::Point(StartX(), OffsetY(infobar_icon_))); | |
| 103 ExtensionViewViews* extension_view = GetExtensionView(); | |
| 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(gfx::Size( | |
| 110 std::max(0, EndX() - StartX() - NonExtensionViewWidth()), | |
| 111 std::min( | |
| 112 height() - InfoBarContainerDelegate::kSeparatorLineHeight - | |
| 113 arrow_height(), | |
| 114 GetDelegate()->height()))); | |
| 115 // We do SetPosition() separately after SetSize() so OffsetY() will work. | |
| 116 extension_view->SetPosition( | |
| 117 gfx::Point(infobar_icon_->bounds().right() + kIconHorizontalMargin, | |
| 118 std::max(arrow_height(), OffsetY(extension_view)))); | |
| 119 } | |
| 120 | |
| 121 void ExtensionInfoBar::ViewHierarchyChanged( | |
| 122 const ViewHierarchyChangedDetails& details) { | |
| 123 if (!details.is_add || (details.child != this) || (infobar_icon_ != NULL)) { | |
| 124 InfoBarView::ViewHierarchyChanged(details); | |
| 125 return; | |
| 126 } | |
| 127 | |
| 128 extensions::ExtensionViewHost* extension_view_host = | |
| 129 GetDelegate()->extension_view_host(); | |
| 130 | |
| 131 if (extension_view_host->extension()->ShowConfigureContextMenus()) { | |
| 132 icon_as_menu_ = new views::MenuButton(NULL, base::string16(), this, false); | |
| 133 icon_as_menu_->SetFocusable(true); | |
| 134 infobar_icon_ = icon_as_menu_; | |
| 135 } else { | |
| 136 icon_as_image_ = new views::ImageView(); | |
| 137 infobar_icon_ = icon_as_image_; | |
| 138 } | |
| 139 | |
| 140 // Wait until the icon image is loaded before showing it. | |
| 141 infobar_icon_->SetVisible(false); | |
| 142 AddChildView(infobar_icon_); | |
| 143 | |
| 144 // Set the desired height of the ExtensionViewViews, so that when the | |
| 145 // AddChildView() call triggers InfoBarView::ViewHierarchyChanged(), it can | |
| 146 // read the correct height off this object in order to calculate the overall | |
| 147 // desired infobar height. | |
| 148 GetExtensionView()->SetSize(gfx::Size(0, GetDelegate()->height())); | |
| 149 AddChildView(GetExtensionView()); | |
| 150 | |
| 151 // This must happen after adding all other children so InfoBarView can ensure | |
| 152 // the close button is the last child. | |
| 153 InfoBarView::ViewHierarchyChanged(details); | |
| 154 | |
| 155 // This must happen after adding all children because it can trigger layout, | |
| 156 // which assumes that particular children (e.g. the close button) have already | |
| 157 // been added. | |
| 158 const extensions::Extension* extension = extension_view_host->extension(); | |
| 159 extension_misc::ExtensionIcons image_size = | |
| 160 extension_misc::EXTENSION_ICON_BITTY; | |
| 161 extensions::ExtensionResource icon_resource = | |
| 162 extensions::IconsInfo::GetIconResource( | |
| 163 extension, image_size, ExtensionIconSet::MATCH_EXACTLY); | |
| 164 extensions::ImageLoader* loader = | |
| 165 extensions::ImageLoader::Get(extension_view_host->browser_context()); | |
| 166 loader->LoadImageAsync( | |
| 167 extension, | |
| 168 icon_resource, | |
| 169 gfx::Size(image_size, image_size), | |
| 170 base::Bind(&ExtensionInfoBar::OnImageLoaded, | |
| 171 weak_ptr_factory_.GetWeakPtr())); | |
| 172 } | |
| 173 | |
| 174 int ExtensionInfoBar::ContentMinimumWidth() const { | |
| 175 return NonExtensionViewWidth() + static_cast<const ExtensionViewViews*>( | |
| 176 GetDelegate()->extension_view_host()->view())->GetMinimumSize().width(); | |
| 177 } | |
| 178 | |
| 179 void ExtensionInfoBar::OnMenuButtonClicked(views::View* source, | |
| 180 const gfx::Point& point) { | |
| 181 if (!owner()) | |
| 182 return; // We're closing; don't call anything, it might access the owner. | |
| 183 const extensions::Extension* extension = | |
| 184 GetDelegate()->extension_view_host()->extension(); | |
| 185 DCHECK(icon_as_menu_); | |
| 186 | |
| 187 scoped_refptr<ExtensionContextMenuModel> options_menu_contents = | |
| 188 new ExtensionContextMenuModel(extension, browser_); | |
| 189 DCHECK_EQ(icon_as_menu_, source); | |
| 190 RunMenuAt( | |
| 191 options_menu_contents.get(), icon_as_menu_, views::MENU_ANCHOR_TOPLEFT); | |
| 192 } | |
| 193 | |
| 194 void ExtensionInfoBar::OnImageLoaded(const gfx::Image& image) { | |
| 195 if (!GetDelegate()) | |
| 196 return; // The delegate can go away while we asynchronously load images. | |
| 197 | |
| 198 const gfx::ImageSkia* icon = NULL; | |
| 199 // Fall back on the default extension icon on failure. | |
| 200 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | |
| 201 if (image.IsEmpty()) | |
| 202 icon = rb.GetImageNamed(IDR_EXTENSIONS_SECTION).ToImageSkia(); | |
| 203 else | |
| 204 icon = image.ToImageSkia(); | |
| 205 | |
| 206 if (icon_as_menu_) { | |
| 207 const gfx::ImageSkia* drop_image = | |
| 208 rb.GetImageNamed(IDR_APP_DROPARROW).ToImageSkia(); | |
| 209 | |
| 210 gfx::CanvasImageSource* source = new MenuImageSource(*icon, *drop_image); | |
| 211 gfx::ImageSkia menu_image = gfx::ImageSkia(source, source->size()); | |
| 212 icon_as_menu_->SetImage(views::Button::STATE_NORMAL, menu_image); | |
| 213 } else { | |
| 214 icon_as_image_->SetImage(*icon); | |
| 215 } | |
| 216 | |
| 217 infobar_icon_->SizeToPreferredSize(); | |
| 218 infobar_icon_->SetVisible(true); | |
| 219 | |
| 220 Layout(); | |
| 221 } | |
| 222 | |
| 223 ExtensionInfoBarDelegate* ExtensionInfoBar::GetDelegate() { | |
| 224 return delegate()->AsExtensionInfoBarDelegate(); | |
| 225 } | |
| 226 | |
| 227 const ExtensionInfoBarDelegate* ExtensionInfoBar::GetDelegate() const { | |
| 228 return delegate()->AsExtensionInfoBarDelegate(); | |
| 229 } | |
| 230 | |
| 231 ExtensionViewViews* ExtensionInfoBar::GetExtensionView() { | |
| 232 return static_cast<ExtensionViewViews*>( | |
| 233 GetDelegate()->extension_view_host()->view()); | |
| 234 } | |
| 235 | |
| 236 int ExtensionInfoBar::NonExtensionViewWidth() const { | |
| 237 return infobar_icon_->width() + kIconHorizontalMargin; | |
| 238 } | |
| OLD | NEW |