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 |