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