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/win/scoped_comptr.h" 12 #include "base/win/scoped_gdi_object.h" 13 #include "base/win/windows_version.h" 14 #include "chrome/browser/profiles/profile_avatar_icon_util.h" 15 #include "chrome/browser/ui/host_desktop.h" 16 #include "content/public/browser/browser_thread.h" 17 #include "skia/ext/image_operations.h" 18 #include "skia/ext/platform_canvas.h" 19 #include "ui/gfx/icon_util.h" 20 #include "ui/gfx/image/image.h" 21 #include "ui/views/win/hwnd_util.h" 22 23 namespace chrome { 24 25 namespace { 26 27 // Responsible for invoking TaskbarList::SetOverlayIcon(). The call to 28 // TaskbarList::SetOverlayIcon() runs a nested message loop that proves 29 // problematic when called on the UI thread. Additionally it seems the call may 30 // take a while to complete. For this reason we call it on a worker thread. 31 // 32 // Docs for TaskbarList::SetOverlayIcon() say it does nothing if the HWND is not 33 // valid. 34 void SetOverlayIcon(HWND hwnd, scoped_ptr<SkBitmap> bitmap) { 35 base::win::ScopedComPtr<ITaskbarList3> taskbar; 36 HRESULT result = taskbar.CreateInstance(CLSID_TaskbarList, NULL, 37 CLSCTX_INPROC_SERVER); 38 if (FAILED(result) || FAILED(taskbar->HrInit())) 39 return; 40 41 base::win::ScopedGDIObject<HICON> icon; 42 if (bitmap.get()) { 43 DCHECK_GE(bitmap.get()->width(), bitmap.get()->height()); 44 // Maintain aspect ratio on resize. 45 const int kOverlayIconSize = 16; 46 int resized_height = 47 bitmap.get()->height() * kOverlayIconSize / bitmap.get()->width(); 48 DCHECK_GE(kOverlayIconSize, resized_height); 49 // Since the target size is so small, we use our best resizer. 50 SkBitmap sk_icon = skia::ImageOperations::Resize( 51 *bitmap.get(), 52 skia::ImageOperations::RESIZE_LANCZOS3, 53 kOverlayIconSize, resized_height); 54 55 // Paint the resized icon onto a 16x16 canvas otherwise Windows will badly 56 // hammer it to 16x16. 57 SkBitmap offscreen_bitmap; 58 offscreen_bitmap.allocN32Pixels(kOverlayIconSize, kOverlayIconSize); 59 SkCanvas offscreen_canvas(offscreen_bitmap); 60 offscreen_canvas.clear(SK_ColorTRANSPARENT); 61 offscreen_canvas.drawBitmap(sk_icon, 0, kOverlayIconSize - resized_height); 62 icon.Set(IconUtil::CreateHICONFromSkBitmap(offscreen_bitmap)); 63 if (!icon.Get()) 64 return; 65 } 66 taskbar->SetOverlayIcon(hwnd, icon, L""); 67 } 68 69 } // namespace 70 71 void DrawTaskbarDecoration(gfx::NativeWindow window, const gfx::Image* image) { 72 // HOST_DESKTOP_TYPE_ASH doesn't use the taskbar. 73 if (base::win::GetVersion() < base::win::VERSION_WIN7 || 74 chrome::GetHostDesktopTypeForNativeWindow(window) != 75 chrome::HOST_DESKTOP_TYPE_NATIVE) 76 return; 77 78 HWND hwnd = views::HWNDForNativeWindow(window); 79 80 // SetOverlayIcon() does nothing if the window is not visible so testing here 81 // avoids all the wasted effort of the image resizing. 82 if (!::IsWindowVisible(hwnd)) 83 return; 84 85 // Copy the image since we're going to use it on a separate thread and 86 // gfx::Image isn't thread safe. 87 scoped_ptr<SkBitmap> bitmap; 88 if (image) { 89 bitmap.reset(new SkBitmap( 90 profiles::GetAvatarIconAsSquare(*image->ToSkBitmap(), 1))); 91 } 92 content::BrowserThread::GetBlockingPool()->PostWorkerTaskWithShutdownBehavior( 93 FROM_HERE, base::Bind(&SetOverlayIcon, hwnd, Passed(&bitmap)), 94 base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN); 95 } 96 97 } // namespace chrome 98