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 |