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 "third_party/skia/include/core/SkRect.h" 20#include "ui/gfx/icon_util.h" 21#include "ui/gfx/image/image.h" 22#include "ui/views/win/hwnd_util.h" 23 24namespace chrome { 25 26namespace { 27 28// Responsible for invoking TaskbarList::SetOverlayIcon(). The call to 29// TaskbarList::SetOverlayIcon() runs a nested message loop that proves 30// problematic when called on the UI thread. Additionally it seems the call may 31// take a while to complete. For this reason we call it on a worker thread. 32// 33// Docs for TaskbarList::SetOverlayIcon() say it does nothing if the HWND is not 34// valid. 35void SetOverlayIcon(HWND hwnd, scoped_ptr<SkBitmap> bitmap) { 36 base::win::ScopedCOMInitializer com_initializer; 37 base::win::ScopedComPtr<ITaskbarList3> taskbar; 38 HRESULT result = taskbar.CreateInstance(CLSID_TaskbarList, NULL, 39 CLSCTX_INPROC_SERVER); 40 if (FAILED(result) || FAILED(taskbar->HrInit())) 41 return; 42 43 base::win::ScopedGDIObject<HICON> icon; 44 if (bitmap.get()) { 45 const SkBitmap* source_bitmap = NULL; 46 SkBitmap squarer_bitmap; 47 if ((bitmap->width() == profiles::kAvatarIconWidth) && 48 (bitmap->height() == profiles::kAvatarIconHeight)) { 49 // Shave a couple of columns so the bitmap is more square. So when 50 // resized to a square aspect ratio it looks pretty. 51 int x = 2; 52 bitmap->extractSubset(&squarer_bitmap, SkIRect::MakeXYWH(x, 0, 53 profiles::kAvatarIconWidth - x * 2, profiles::kAvatarIconHeight)); 54 source_bitmap = &squarer_bitmap; 55 } else { 56 // The image's size has changed. Resize what we have. 57 source_bitmap = bitmap.get(); 58 } 59 // Since the target size is so small, we use our best resizer. Never pass 60 // windows a different size because it will badly hammer it to 16x16. 61 SkBitmap sk_icon = skia::ImageOperations::Resize( 62 *source_bitmap, 63 skia::ImageOperations::RESIZE_LANCZOS3, 64 16, 16); 65 icon.Set(IconUtil::CreateHICONFromSkBitmap(sk_icon)); 66 if (!icon.Get()) 67 return; 68 } 69 taskbar->SetOverlayIcon(hwnd, icon, L""); 70} 71 72} // namespace 73 74void DrawTaskbarDecoration(gfx::NativeWindow window, const gfx::Image* image) { 75 // HOST_DESKTOP_TYPE_ASH doesn't use the taskbar. 76 if (base::win::GetVersion() < base::win::VERSION_WIN7 || 77 chrome::GetHostDesktopTypeForNativeWindow(window) != 78 chrome::HOST_DESKTOP_TYPE_NATIVE) 79 return; 80 81 HWND hwnd = views::HWNDForNativeWindow(window); 82 83 // SetOverlayIcon() does nothing if the window is not visible so testing here 84 // avoids all the wasted effort of the image resizing. 85 if (!::IsWindowVisible(hwnd)) 86 return; 87 88 // Copy the image since we're going to use it on a separate thread and 89 // gfx::Image isn't thread safe. 90 scoped_ptr<SkBitmap> bitmap( 91 image ? new SkBitmap(*image->ToSkBitmap()) : NULL); 92 // TaskbarList::SetOverlayIcon() may take a while, so we use slow here. 93 base::WorkerPool::PostTask( 94 FROM_HERE, base::Bind(&SetOverlayIcon, hwnd, Passed(&bitmap)), true); 95} 96 97} // namespace chrome 98