- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / views / frame / taskbar_decorator_win.cc
1 // Copyright (c) 2013 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/frame/taskbar_decorator.h"
6
7 #include <shobjidl.h>
8
9 #include "base/bind.h"
10 #include "base/location.h"
11 #include "base/threading/worker_pool.h"
12 #include "base/win/scoped_com_initializer.h"
13 #include "base/win/scoped_comptr.h"
14 #include "base/win/scoped_gdi_object.h"
15 #include "base/win/windows_version.h"
16 #include "chrome/browser/profiles/profile_info_util.h"
17 #include "chrome/browser/ui/host_desktop.h"
18 #include "skia/ext/image_operations.h"
19 #include "skia/ext/platform_canvas.h"
20 #include "third_party/skia/include/core/SkRect.h"
21 #include "ui/gfx/icon_util.h"
22 #include "ui/gfx/image/image.h"
23 #include "ui/views/win/hwnd_util.h"
24
25 namespace chrome {
26
27 namespace {
28
29 // Responsible for invoking TaskbarList::SetOverlayIcon(). The call to
30 // TaskbarList::SetOverlayIcon() runs a nested message loop that proves
31 // problematic when called on the UI thread. Additionally it seems the call may
32 // take a while to complete. For this reason we call it on a worker thread.
33 //
34 // Docs for TaskbarList::SetOverlayIcon() say it does nothing if the HWND is not
35 // valid.
36 void SetOverlayIcon(HWND hwnd, scoped_ptr<SkBitmap> bitmap) {
37   base::win::ScopedCOMInitializer com_initializer;
38   base::win::ScopedComPtr<ITaskbarList3> taskbar;
39   HRESULT result = taskbar.CreateInstance(CLSID_TaskbarList, NULL,
40                                           CLSCTX_INPROC_SERVER);
41   if (FAILED(result) || FAILED(taskbar->HrInit()))
42     return;
43
44   base::win::ScopedGDIObject<HICON> icon;
45   if (bitmap.get()) {
46     const SkBitmap* source_bitmap = NULL;
47     SkBitmap squarer_bitmap;
48     if ((bitmap->width() == profiles::kAvatarIconWidth) &&
49         (bitmap->height() == profiles::kAvatarIconHeight)) {
50       // Shave a couple of columns so the bitmap is more square. So when
51       // resized to a square aspect ratio it looks pretty.
52       int x = 2;
53       bitmap->extractSubset(&squarer_bitmap, SkIRect::MakeXYWH(x, 0,
54           profiles::kAvatarIconWidth - x * 2, profiles::kAvatarIconHeight));
55       source_bitmap = &squarer_bitmap;
56     } else {
57       // The image's size has changed. Resize what we have.
58       source_bitmap = bitmap.get();
59     }
60
61     // Maintain aspect ratio on resize. It is assumed that the image is wider
62     // than it is tall.
63     const size_t kOverlayIconSize = 16;
64     size_t resized_height =
65         source_bitmap->height() * kOverlayIconSize / source_bitmap->width();
66     DCHECK_GE(kOverlayIconSize, resized_height);
67     // Since the target size is so small, we use our best resizer.
68     SkBitmap sk_icon = skia::ImageOperations::Resize(
69         *source_bitmap,
70         skia::ImageOperations::RESIZE_LANCZOS3,
71         kOverlayIconSize, resized_height);
72
73     // Paint the resized icon onto a 16x16 canvas otherwise Windows will badly
74     // hammer it to 16x16.
75     scoped_ptr<SkCanvas> offscreen_canvas(
76         skia::CreateBitmapCanvas(kOverlayIconSize, kOverlayIconSize, false));
77     DCHECK(offscreen_canvas);
78     offscreen_canvas->drawBitmap(sk_icon, 0, kOverlayIconSize - resized_height);
79
80     icon.Set(IconUtil::CreateHICONFromSkBitmap(
81         offscreen_canvas->getDevice()->accessBitmap(false)));
82     if (!icon.Get())
83       return;
84   }
85   taskbar->SetOverlayIcon(hwnd, icon, L"");
86 }
87
88 }  // namespace
89
90 void DrawTaskbarDecoration(gfx::NativeWindow window, const gfx::Image* image) {
91   // HOST_DESKTOP_TYPE_ASH doesn't use the taskbar.
92   if (base::win::GetVersion() < base::win::VERSION_WIN7 ||
93       chrome::GetHostDesktopTypeForNativeWindow(window) !=
94       chrome::HOST_DESKTOP_TYPE_NATIVE)
95     return;
96
97   HWND hwnd = views::HWNDForNativeWindow(window);
98
99   // SetOverlayIcon() does nothing if the window is not visible so testing here
100   // avoids all the wasted effort of the image resizing.
101   if (!::IsWindowVisible(hwnd))
102     return;
103
104   // Copy the image since we're going to use it on a separate thread and
105   // gfx::Image isn't thread safe.
106   scoped_ptr<SkBitmap> bitmap(
107       image ? new SkBitmap(*image->ToSkBitmap()) : NULL);
108   // TaskbarList::SetOverlayIcon() may take a while, so we use slow here.
109   base::WorkerPool::PostTask(
110       FROM_HERE, base::Bind(&SetOverlayIcon, hwnd, Passed(&bitmap)), true);
111 }
112
113 }  // namespace chrome