Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/views/avatar_menu_button.h" | 5 #include "chrome/browser/ui/views/avatar_menu_button.h" |
| 6 | 6 |
| 7 #include "chrome/browser/profiles/profile_metrics.h" | 7 #include "chrome/browser/profiles/profile_metrics.h" |
| 8 #include "chrome/browser/profiles/profile_info_util.h" | |
| 8 #include "chrome/browser/ui/browser.h" | 9 #include "chrome/browser/ui/browser.h" |
| 9 #include "chrome/browser/ui/views/avatar_menu_bubble_view.h" | 10 #include "chrome/browser/ui/views/avatar_menu_bubble_view.h" |
| 10 #include "chrome/browser/ui/views/frame/browser_view.h" | 11 #include "chrome/browser/ui/views/frame/browser_view.h" |
| 11 #include "chrome/browser/ui/views/window.h" | 12 #include "chrome/browser/ui/views/window.h" |
| 12 #include "ui/gfx/canvas_skia.h" | 13 #include "ui/gfx/canvas_skia.h" |
| 13 #include "ui/views/widget/widget.h" | 14 #include "ui/views/widget/widget.h" |
| 14 | 15 |
| 15 | 16 |
| 16 #if defined(OS_WIN) | 17 #if defined(OS_WIN) |
| 17 #include <shobjidl.h> | 18 #include <shobjidl.h> |
| 18 #include "base/win/scoped_comptr.h" | 19 #include "base/win/scoped_comptr.h" |
| 19 #include "base/win/windows_version.h" | 20 #include "base/win/windows_version.h" |
| 20 #include "skia/ext/image_operations.h" | 21 #include "skia/ext/image_operations.h" |
| 21 #include "ui/gfx/icon_util.h" | 22 #include "ui/gfx/icon_util.h" |
| 22 #endif | 23 #endif |
| 23 | 24 |
| 24 static inline int Round(double x) { | 25 static inline int Round(double x) { |
| 25 return static_cast<int>(x + 0.5); | 26 return static_cast<int>(x + 0.5); |
| 26 } | 27 } |
| 27 | 28 |
| 28 // The Windows 7 taskbar supports dynamic overlays and effects, we use this | 29 // The Windows 7 taskbar supports dynamic overlays and effects, we use this |
| 29 // to ovelay the avatar icon there. The overlay only applies if the taskbar | 30 // to ovelay the avatar icon there. The overlay only applies if the taskbar |
| 30 // is in "default large icon mode". This function is a best effort deal so | 31 // is in "default large icon mode". This function is a best effort deal so |
| 31 // we bail out silently at any error condition. | 32 // we bail out silently at any error condition. |
| 32 // See http://msdn.microsoft.com/en-us/library/dd391696(VS.85).aspx for | 33 // See http://msdn.microsoft.com/en-us/library/dd391696(VS.85).aspx for |
| 33 // more information. | 34 // more information. |
| 34 void DrawTaskBarDecoration(const Browser* browser, const SkBitmap* bitmap) { | 35 void DrawTaskBarDecoration(const Browser* browser, const gfx::Image* image) { |
| 35 #if defined(OS_WIN) && !defined(USE_AURA) | 36 #if defined(OS_WIN) && !defined(USE_AURA) |
| 36 if (base::win::GetVersion() < base::win::VERSION_WIN7) | 37 if (base::win::GetVersion() < base::win::VERSION_WIN7) |
| 37 return; | 38 return; |
| 38 BrowserWindow* bw = browser->window(); | 39 BrowserWindow* bw = browser->window(); |
| 39 if (!bw) | 40 if (!bw) |
| 40 return; | 41 return; |
| 41 gfx::NativeWindow window = bw->GetNativeHandle(); | 42 gfx::NativeWindow window = bw->GetNativeHandle(); |
| 42 if (!window) | 43 if (!window) |
| 43 return; | 44 return; |
| 44 | 45 |
| 45 base::win::ScopedComPtr<ITaskbarList3> taskbar; | 46 base::win::ScopedComPtr<ITaskbarList3> taskbar; |
| 46 HRESULT result = taskbar.CreateInstance(CLSID_TaskbarList, NULL, | 47 HRESULT result = taskbar.CreateInstance(CLSID_TaskbarList, NULL, |
| 47 CLSCTX_INPROC_SERVER); | 48 CLSCTX_INPROC_SERVER); |
| 48 if (FAILED(result) || FAILED(taskbar->HrInit())) | 49 if (FAILED(result) || FAILED(taskbar->HrInit())) |
| 49 return; | 50 return; |
| 50 HICON icon = NULL; | 51 HICON icon = NULL; |
| 51 if (bitmap) { | 52 if (image) { |
| 53 const SkBitmap* bitmap = image->ToSkBitmap(); | |
| 52 const SkBitmap* source_bitmap = NULL; | 54 const SkBitmap* source_bitmap = NULL; |
| 53 SkBitmap squarer_bitmap; | 55 SkBitmap squarer_bitmap; |
| 54 if ((bitmap->width() == 38) && (bitmap->height() == 31)) { | 56 if ((bitmap->width() == profiles::kAvatarIconWidth) && |
| 57 (bitmap->height() == profiles::kAvatarIconHeight)) { | |
| 55 // Shave a couple of columns so the bitmap is more square. So when | 58 // Shave a couple of columns so the bitmap is more square. So when |
| 56 // resized to a square aspect ratio it looks pretty. | 59 // resized to a square aspect ratio it looks pretty. |
| 57 bitmap->extractSubset(&squarer_bitmap, SkIRect::MakeXYWH(2, 0, 34, 31)); | 60 int x = 2; |
|
Peter Kasting
2011/11/28 22:01:36
Nit: Wouldn't it make more sense to do something l
sail
2011/11/28 23:09:36
I think that's a good idea. I'm working on a separ
| |
| 61 bitmap->extractSubset(&squarer_bitmap, SkIRect::MakeXYWH(x, 0, | |
| 62 profiles::kAvatarIconWidth - x * 2, profiles::kAvatarIconHeight)); | |
| 58 source_bitmap = &squarer_bitmap; | 63 source_bitmap = &squarer_bitmap; |
| 59 } else { | 64 } else { |
| 60 // The bitmaps size has changed. Resize what we have. | 65 // The bitmaps size has changed. Resize what we have. |
| 61 source_bitmap = bitmap; | 66 source_bitmap = bitmap; |
| 62 } | 67 } |
| 63 // Since the target size is so small, we use our best resizer. Never pass | 68 // Since the target size is so small, we use our best resizer. Never pass |
| 64 // windows a different size because it will badly hammer it to 16x16. | 69 // windows a different size because it will badly hammer it to 16x16. |
| 65 SkBitmap sk_icon = skia::ImageOperations::Resize( | 70 SkBitmap sk_icon = skia::ImageOperations::Resize( |
| 66 *source_bitmap, | 71 *source_bitmap, |
| 67 skia::ImageOperations::RESIZE_LANCZOS3, | 72 skia::ImageOperations::RESIZE_LANCZOS3, |
| 68 16, 16); | 73 16, 16); |
| 69 icon = IconUtil::CreateHICONFromSkBitmap(sk_icon); | 74 icon = IconUtil::CreateHICONFromSkBitmap(sk_icon); |
| 70 if (!icon) | 75 if (!icon) |
| 71 return; | 76 return; |
| 72 } | 77 } |
| 73 taskbar->SetOverlayIcon(window, icon, L""); | 78 taskbar->SetOverlayIcon(window, icon, L""); |
| 74 if (icon) | 79 if (icon) |
| 75 DestroyIcon(icon); | 80 DestroyIcon(icon); |
| 76 #endif | 81 #endif |
| 77 } | 82 } |
| 78 | 83 |
| 79 AvatarMenuButton::AvatarMenuButton(Browser* browser, bool has_menu) | 84 AvatarMenuButton::AvatarMenuButton(Browser* browser, bool has_menu) |
| 80 : MenuButton(NULL, string16(), this, false), | 85 : MenuButton(NULL, string16(), this, false), |
| 81 browser_(browser), | 86 browser_(browser), |
| 82 has_menu_(has_menu), | 87 has_menu_(has_menu), |
| 83 set_taskbar_decoration_(false) { | 88 set_taskbar_decoration_(false), |
| 89 is_gaia_picture_(false), | |
| 90 old_height_(0) { | |
| 84 // In RTL mode, the avatar icon should be looking the opposite direction. | 91 // In RTL mode, the avatar icon should be looking the opposite direction. |
| 85 EnableCanvasFlippingForRTLUI(true); | 92 EnableCanvasFlippingForRTLUI(true); |
| 86 } | 93 } |
| 87 | 94 |
| 88 AvatarMenuButton::~AvatarMenuButton() { | 95 AvatarMenuButton::~AvatarMenuButton() { |
| 89 // During destruction of the browser frame, we might not have a window | 96 // During destruction of the browser frame, we might not have a window |
| 90 // so the taskbar button will be removed by windows anyway. | 97 // so the taskbar button will be removed by windows anyway. |
| 91 if (browser_->IsAttemptingToCloseBrowser()) | 98 if (browser_->IsAttemptingToCloseBrowser()) |
| 92 return; | 99 return; |
| 93 DrawTaskBarDecoration(browser_, NULL); | 100 DrawTaskBarDecoration(browser_, NULL); |
| 94 } | 101 } |
| 95 | 102 |
| 96 void AvatarMenuButton::OnPaint(gfx::Canvas* canvas) { | 103 void AvatarMenuButton::OnPaint(gfx::Canvas* canvas) { |
| 97 const SkBitmap& icon = GetImageToPaint(); | 104 if (!icon_.get()) |
| 98 if (icon.isNull()) | |
| 99 return; | 105 return; |
| 100 | 106 |
| 107 if (old_height_ != height() || button_icon_.isNull()) { | |
| 108 old_height_ = height(); | |
| 109 button_icon_ = profiles::GetAvatarIconForTitleBar( | |
| 110 *icon_, is_gaia_picture_, width(), height()); | |
| 111 } | |
| 112 | |
| 101 // Scale the image to fit the width of the button. | 113 // Scale the image to fit the width of the button. |
| 102 int dst_width = std::min(icon.width(), width()); | 114 int dst_width = std::min(button_icon_.width(), width()); |
| 103 // Truncate rather than rounding, so that for odd widths we put the extra | 115 // Truncate rather than rounding, so that for odd widths we put the extra |
| 104 // pixel on the left. | 116 // pixel on the left. |
| 105 int dst_x = (width() - dst_width) / 2; | 117 int dst_x = (width() - dst_width) / 2; |
| 106 | 118 |
| 107 // Scale the height and maintain aspect ratio. This means that the | 119 // Scale the height and maintain aspect ratio. This means that the |
| 108 // icon may not fit in the view. That's ok, we just vertically center it. | 120 // icon may not fit in the view. That's ok, we just vertically center it. |
| 109 float scale = | 121 float scale = |
| 110 static_cast<float>(dst_width) / static_cast<float>(icon.width()); | 122 static_cast<float>(dst_width) / static_cast<float>(button_icon_.width()); |
| 111 // Round here so that we minimize the aspect ratio drift. | 123 // Round here so that we minimize the aspect ratio drift. |
| 112 int dst_height = Round(icon.height() * scale); | 124 int dst_height = Round(button_icon_.height() * scale); |
| 113 // Round rather than truncating, so that for odd heights we select an extra | 125 // Round rather than truncating, so that for odd heights we select an extra |
| 114 // pixel below the image center rather than above. This is because the | 126 // pixel below the image center rather than above. This is because the |
| 115 // incognito image has shadows at the top that make the apparent center below | 127 // incognito image has shadows at the top that make the apparent center below |
| 116 // the real center. | 128 // the real center. |
| 117 int dst_y = Round((height() - dst_height) / 2.0); | 129 int dst_y = Round((height() - dst_height) / 2.0); |
| 118 | 130 canvas->DrawBitmapInt(button_icon_, 0, 0, button_icon_.width(), |
| 119 canvas->DrawBitmapInt(icon, 0, 0, icon.width(), icon.height(), | 131 button_icon_.height(), dst_x, dst_y, dst_width, dst_height, false); |
| 120 dst_x, dst_y, dst_width, dst_height, false); | |
| 121 | 132 |
| 122 if (set_taskbar_decoration_) { | 133 if (set_taskbar_decoration_) { |
| 123 // Drawing the taskbar decoration uses lanczos resizing so we really | 134 // Drawing the taskbar decoration uses lanczos resizing so we really |
| 124 // want to do it only once. | 135 // want to do it only once. |
| 125 DrawTaskBarDecoration(browser_, &icon); | 136 DrawTaskBarDecoration(browser_, icon_.get()); |
| 126 set_taskbar_decoration_ = false; | 137 set_taskbar_decoration_ = false; |
| 127 } | 138 } |
| 128 } | 139 } |
| 129 | 140 |
| 130 bool AvatarMenuButton::HitTest(const gfx::Point& point) const { | 141 bool AvatarMenuButton::HitTest(const gfx::Point& point) const { |
| 131 if (!has_menu_) | 142 if (!has_menu_) |
| 132 return false; | 143 return false; |
| 133 return views::MenuButton::HitTest(point); | 144 return views::MenuButton::HitTest(point); |
| 134 } | 145 } |
| 135 | 146 |
| 136 // If the icon changes, we need to set the taskbar decoration again. | 147 void AvatarMenuButton::SetIcon(const gfx::Image& icon, bool is_gaia_picture) { |
| 137 void AvatarMenuButton::SetIcon(const SkBitmap& icon) { | 148 icon_.reset(new gfx::Image(icon)); |
|
Peter Kasting
2011/11/28 22:01:36
Nit: Why use a scoped_ptr here? Why not just use
sail
2011/11/28 23:09:36
gfx::Image doesn't have a default constructor so i
| |
| 138 views::MenuButton::SetIcon(icon); | 149 button_icon_ = SkBitmap(); |
| 150 is_gaia_picture_ = is_gaia_picture; | |
| 151 // If the icon changes, we need to set the taskbar decoration again. | |
| 139 set_taskbar_decoration_ = true; | 152 set_taskbar_decoration_ = true; |
| 140 } | 153 } |
| 141 | 154 |
| 142 // views::ViewMenuDelegate implementation | 155 // views::ViewMenuDelegate implementation |
| 143 void AvatarMenuButton::RunMenu(views::View* source, const gfx::Point& pt) { | 156 void AvatarMenuButton::RunMenu(views::View* source, const gfx::Point& pt) { |
| 144 ShowAvatarBubble(); | 157 ShowAvatarBubble(); |
| 145 } | 158 } |
| 146 | 159 |
| 147 void AvatarMenuButton::ShowAvatarBubble() { | 160 void AvatarMenuButton::ShowAvatarBubble() { |
| 148 if (!has_menu_) | 161 if (!has_menu_) |
| 149 return; | 162 return; |
| 150 | 163 |
| 151 gfx::Point origin; | 164 gfx::Point origin; |
| 152 views::View::ConvertPointToScreen(this, &origin); | 165 views::View::ConvertPointToScreen(this, &origin); |
| 153 gfx::Rect bounds(origin, size()); | 166 gfx::Rect bounds(origin, size()); |
| 154 | 167 |
| 155 AvatarMenuBubbleView* bubble = new AvatarMenuBubbleView(this, | 168 AvatarMenuBubbleView* bubble = new AvatarMenuBubbleView(this, |
| 156 views::BubbleBorder::TOP_LEFT, bounds, browser_); | 169 views::BubbleBorder::TOP_LEFT, bounds, browser_); |
| 157 browser::CreateViewsBubble(bubble); | 170 browser::CreateViewsBubble(bubble); |
| 158 bubble->Show(); | 171 bubble->Show(); |
| 159 | 172 |
| 160 ProfileMetrics::LogProfileOpenMethod(ProfileMetrics::ICON_AVATAR_BUBBLE); | 173 ProfileMetrics::LogProfileOpenMethod(ProfileMetrics::ICON_AVATAR_BUBBLE); |
| 161 } | 174 } |
| OLD | NEW |