1 // Copyright (c) 2012 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.
5 #include "chrome/browser/ui/views/panels/taskbar_window_thumbnailer_win.h"
9 #include "base/logging.h"
10 #include "base/win/scoped_hdc.h"
11 #include "skia/ext/image_operations.h"
12 #include "ui/gfx/canvas.h"
13 #include "ui/gfx/gdi_util.h"
17 HBITMAP
GetNativeBitmapFromSkBitmap(const SkBitmap
& bitmap
) {
18 int width
= bitmap
.width();
19 int height
= bitmap
.height();
21 BITMAPV4HEADER native_bitmap_header
;
22 gfx::CreateBitmapV4Header(width
, height
, &native_bitmap_header
);
24 HDC dc
= ::GetDC(NULL
);
26 HBITMAP native_bitmap
= ::CreateDIBSection(dc
,
27 reinterpret_cast<BITMAPINFO
*>(&native_bitmap_header
),
32 DCHECK(native_bitmap
);
33 ::ReleaseDC(NULL
, dc
);
34 bitmap
.copyPixelsTo(bits
, width
* height
* 4, width
* 4);
38 void EnableCustomThumbnail(HWND hwnd
, bool enable
) {
39 BOOL enable_value
= enable
;
40 ::DwmSetWindowAttribute(hwnd
,
41 DWMWA_FORCE_ICONIC_REPRESENTATION
,
43 sizeof(enable_value
));
44 ::DwmSetWindowAttribute(hwnd
,
45 DWMWA_HAS_ICONIC_BITMAP
,
47 sizeof(enable_value
));
53 TaskbarWindowThumbnailerWin::TaskbarWindowThumbnailerWin(
54 HWND hwnd
, TaskbarWindowThumbnailerDelegateWin
* delegate
)
57 ui::HWNDSubclass::AddFilterToTarget(hwnd_
, this);
60 TaskbarWindowThumbnailerWin::~TaskbarWindowThumbnailerWin() {
61 ui::HWNDSubclass::RemoveFilterFromAllTargets(this);
64 void TaskbarWindowThumbnailerWin::Start() {
65 EnableCustomThumbnail(hwnd_
, true);
68 void TaskbarWindowThumbnailerWin::Stop() {
69 capture_bitmap_
.reset();
70 EnableCustomThumbnail(hwnd_
, false);
73 void TaskbarWindowThumbnailerWin::CaptureSnapshot() {
75 capture_bitmap_
.reset(CaptureWindowImage());
78 void TaskbarWindowThumbnailerWin::InvalidateSnapshot() {
79 capture_bitmap_
.reset();
81 // The snapshot feeded to the system could be cached. Invalidate it.
82 ::DwmInvalidateIconicBitmaps(hwnd_
);
85 void TaskbarWindowThumbnailerWin::ReplaceWindow(HWND new_hwnd
) {
86 // Stop serving the custom thumbnail for the old window.
87 EnableCustomThumbnail(hwnd_
, false);
88 ui::HWNDSubclass::RemoveFilterFromAllTargets(this);
92 // Start serving the custom thumbnail to the new window.
93 ui::HWNDSubclass::AddFilterToTarget(hwnd_
, this);
94 EnableCustomThumbnail(hwnd_
, true);
97 bool TaskbarWindowThumbnailerWin::FilterMessage(HWND hwnd
,
102 DCHECK_EQ(hwnd_
, hwnd
);
104 case WM_DWMSENDICONICTHUMBNAIL
:
105 return OnDwmSendIconicThumbnail(HIWORD(l_param
),
108 case WM_DWMSENDICONICLIVEPREVIEWBITMAP
:
109 return OnDwmSendIconicLivePreviewBitmap(l_result
);
114 bool TaskbarWindowThumbnailerWin::OnDwmSendIconicThumbnail(
115 int width
, int height
, LRESULT
* l_result
) {
118 SkBitmap
* thumbnail_bitmap
= capture_bitmap_
.get();
120 // Scale the image if needed.
121 SkBitmap scaled_bitmap
;
122 if (capture_bitmap_
->width() != width
||
123 capture_bitmap_
->height() != height
) {
124 double x_scale
= static_cast<double>(width
) / capture_bitmap_
->width();
125 double y_scale
= static_cast<double>(height
) / capture_bitmap_
->height();
126 double scale
= std::min(x_scale
, y_scale
);
127 width
= capture_bitmap_
->width() * scale
;
128 height
= capture_bitmap_
->height() * scale
;
129 scaled_bitmap
= skia::ImageOperations::Resize(
130 *capture_bitmap_
, skia::ImageOperations::RESIZE_GOOD
, width
, height
);
131 thumbnail_bitmap
= &scaled_bitmap
;
134 HBITMAP native_bitmap
= GetNativeBitmapFromSkBitmap(*thumbnail_bitmap
);
135 ::DwmSetIconicThumbnail(hwnd_
, native_bitmap
, 0);
136 ::DeleteObject(native_bitmap
);
142 bool TaskbarWindowThumbnailerWin::OnDwmSendIconicLivePreviewBitmap(
146 HBITMAP native_bitmap
= GetNativeBitmapFromSkBitmap(*capture_bitmap_
);
147 ::DwmSetIconicLivePreviewBitmap(hwnd_
, native_bitmap
, NULL
, 0);
148 ::DeleteObject(native_bitmap
);
153 SkBitmap
* TaskbarWindowThumbnailerWin::CaptureWindowImage() const {
154 std::vector
<HWND
> snapshot_hwnds
;
156 snapshot_hwnds
= delegate_
->GetSnapshotWindowHandles();
157 if (snapshot_hwnds
.empty())
158 snapshot_hwnds
.push_back(hwnd_
);
162 int enclosing_right
= 0;
163 int enclosing_bottom
= 0;
164 for (std::vector
<HWND
>::const_iterator iter
= snapshot_hwnds
.begin();
165 iter
!= snapshot_hwnds
.end(); ++iter
) {
167 if (!::GetWindowRect(*iter
, &bounds
))
169 if (iter
== snapshot_hwnds
.begin()) {
170 enclosing_x
= bounds
.left
;
171 enclosing_y
= bounds
.top
;
172 enclosing_right
= bounds
.right
;
173 enclosing_bottom
= bounds
.bottom
;
175 if (bounds
.left
< enclosing_x
)
176 enclosing_x
= bounds
.left
;
177 if (bounds
.top
< enclosing_y
)
178 enclosing_y
= bounds
.top
;
179 if (bounds
.right
> enclosing_right
)
180 enclosing_right
= bounds
.right
;
181 if (bounds
.bottom
> enclosing_bottom
)
182 enclosing_bottom
= bounds
.bottom
;
186 int width
= enclosing_right
- enclosing_x
;
187 int height
= enclosing_bottom
- enclosing_y
;
188 if (!width
|| !height
)
191 gfx::Canvas
canvas(gfx::Size(width
, height
), 1.0f
, false);
193 skia::ScopedPlatformPaint
scoped_platform_paint(canvas
.sk_canvas());
194 HDC target_dc
= scoped_platform_paint
.GetPlatformSurface();
195 for (std::vector
<HWND
>::const_iterator iter
= snapshot_hwnds
.begin();
196 iter
!= snapshot_hwnds
.end(); ++iter
) {
197 HWND current_hwnd
= *iter
;
199 if (!::GetWindowRect(current_hwnd
, ¤t_bounds
))
201 base::win::ScopedGetDC
source_dc(current_hwnd
);
203 current_bounds
.left
- enclosing_x
,
204 current_bounds
.top
- enclosing_y
,
205 current_bounds
.right
- current_bounds
.left
,
206 current_bounds
.bottom
- current_bounds
.top
,
211 ::ReleaseDC(current_hwnd
, source_dc
);
214 return new SkBitmap(canvas
.ExtractImageRep().sk_bitmap());