Home | History | Annotate | Download | only in frame
      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