// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/ui/panels/taskbar_window_thumbnailer_win.h" #include #include "base/logging.h" #include "skia/ext/image_operations.h" #include "ui/gfx/canvas.h" #include "ui/gfx/gdi_util.h" namespace { HBITMAP GetNativeBitmapFromSkBitmap(const SkBitmap& bitmap) { int width = bitmap.width(); int height = bitmap.height(); BITMAPV4HEADER native_bitmap_header; gfx::CreateBitmapV4Header(width, height, &native_bitmap_header); HDC dc = ::GetDC(NULL); void* bits; HBITMAP native_bitmap = ::CreateDIBSection(dc, reinterpret_cast(&native_bitmap_header), DIB_RGB_COLORS, &bits, NULL, 0); DCHECK(native_bitmap); ::ReleaseDC(NULL, dc); bitmap.copyPixelsTo(bits, width * height * 4, width * 4); return native_bitmap; } void EnableCustomThumbnail(HWND hwnd, bool enable) { BOOL enable_value = enable; ::DwmSetWindowAttribute(hwnd, DWMWA_FORCE_ICONIC_REPRESENTATION, &enable_value, sizeof(enable_value)); ::DwmSetWindowAttribute(hwnd, DWMWA_HAS_ICONIC_BITMAP, &enable_value, sizeof(enable_value)); } } // namespace TaskbarWindowThumbnailerWin::TaskbarWindowThumbnailerWin(HWND hwnd) : hwnd_(hwnd) { } TaskbarWindowThumbnailerWin::~TaskbarWindowThumbnailerWin() { } void TaskbarWindowThumbnailerWin::Start() { capture_bitmap_.reset(CaptureWindowImage()); EnableCustomThumbnail(hwnd_, true); } void TaskbarWindowThumbnailerWin::Stop() { capture_bitmap_.reset(); EnableCustomThumbnail(hwnd_, false); } bool TaskbarWindowThumbnailerWin::FilterMessage(HWND hwnd, UINT message, WPARAM w_param, LPARAM l_param, LRESULT* l_result) { DCHECK_EQ(hwnd_, hwnd); switch (message) { case WM_DWMSENDICONICTHUMBNAIL: return OnDwmSendIconicThumbnail(HIWORD(l_param), LOWORD(l_param), l_result); case WM_DWMSENDICONICLIVEPREVIEWBITMAP: return OnDwmSendIconicLivePreviewBitmap(l_result); } return false; } bool TaskbarWindowThumbnailerWin::OnDwmSendIconicThumbnail( int width, int height, LRESULT* l_result) { DCHECK(capture_bitmap_.get()); SkBitmap* thumbnail_bitmap = capture_bitmap_.get(); // Scale the image if needed. SkBitmap scaled_bitmap; if (capture_bitmap_->width() != width || capture_bitmap_->height() != height) { double x_scale = static_cast(width) / capture_bitmap_->width(); double y_scale = static_cast(height) / capture_bitmap_->height(); double scale = std::min(x_scale, y_scale); width = capture_bitmap_->width() * scale; height = capture_bitmap_->height() * scale; scaled_bitmap = skia::ImageOperations::Resize( *capture_bitmap_, skia::ImageOperations::RESIZE_GOOD, width, height); thumbnail_bitmap = &scaled_bitmap; } HBITMAP native_bitmap = GetNativeBitmapFromSkBitmap(*thumbnail_bitmap); ::DwmSetIconicThumbnail(hwnd_, native_bitmap, 0); ::DeleteObject(native_bitmap); *l_result = 0; return true; } bool TaskbarWindowThumbnailerWin::OnDwmSendIconicLivePreviewBitmap( LRESULT* l_result) { scoped_ptr live_bitmap(CaptureWindowImage()); HBITMAP native_bitmap = GetNativeBitmapFromSkBitmap(*live_bitmap); ::DwmSetIconicLivePreviewBitmap(hwnd_, native_bitmap, NULL, 0); ::DeleteObject(native_bitmap); *l_result = 0; return true; } SkBitmap* TaskbarWindowThumbnailerWin::CaptureWindowImage() const { RECT bounds; ::GetWindowRect(hwnd_, &bounds); int width = bounds.right - bounds.left; int height = bounds.bottom - bounds.top; gfx::Canvas canvas(gfx::Size(width, height), false); HDC target_dc = canvas.BeginPlatformPaint(); HDC source_dc = ::GetDC(hwnd_); ::BitBlt(target_dc, 0, 0, width, height, source_dc, 0, 0, SRCCOPY); ::ReleaseDC(hwnd_, source_dc); canvas.EndPlatformPaint(); return new SkBitmap(canvas.ExtractBitmap()); }