[Metrics] Make MetricsStateManager take a callback param to check if UMA is enabled.
[chromium-blink-merge.git] / chrome / browser / ui / views / panels / taskbar_window_thumbnailer_win.cc
blob29c2a5f98691187e194122120d9d241099e199a3
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"
7 #include <dwmapi.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"
15 namespace {
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);
25 void* bits;
26 HBITMAP native_bitmap = ::CreateDIBSection(dc,
27 reinterpret_cast<BITMAPINFO*>(&native_bitmap_header),
28 DIB_RGB_COLORS,
29 &bits,
30 NULL,
31 0);
32 DCHECK(native_bitmap);
33 ::ReleaseDC(NULL, dc);
34 bitmap.copyPixelsTo(bits, width * height * 4, width * 4);
35 return native_bitmap;
38 void EnableCustomThumbnail(HWND hwnd, bool enable) {
39 BOOL enable_value = enable;
40 ::DwmSetWindowAttribute(hwnd,
41 DWMWA_FORCE_ICONIC_REPRESENTATION,
42 &enable_value,
43 sizeof(enable_value));
44 ::DwmSetWindowAttribute(hwnd,
45 DWMWA_HAS_ICONIC_BITMAP,
46 &enable_value,
47 sizeof(enable_value));
50 } // namespace
53 TaskbarWindowThumbnailerWin::TaskbarWindowThumbnailerWin(
54 HWND hwnd, TaskbarWindowThumbnailerDelegateWin* delegate)
55 : hwnd_(hwnd),
56 delegate_(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() {
74 if (!capture_bitmap_)
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);
90 hwnd_ = new_hwnd;
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,
98 UINT message,
99 WPARAM w_param,
100 LPARAM l_param,
101 LRESULT* l_result) {
102 DCHECK_EQ(hwnd_, hwnd);
103 switch (message) {
104 case WM_DWMSENDICONICTHUMBNAIL:
105 return OnDwmSendIconicThumbnail(HIWORD(l_param),
106 LOWORD(l_param),
107 l_result);
108 case WM_DWMSENDICONICLIVEPREVIEWBITMAP:
109 return OnDwmSendIconicLivePreviewBitmap(l_result);
111 return false;
114 bool TaskbarWindowThumbnailerWin::OnDwmSendIconicThumbnail(
115 int width, int height, LRESULT* l_result) {
116 CaptureSnapshot();
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);
138 *l_result = 0;
139 return true;
142 bool TaskbarWindowThumbnailerWin::OnDwmSendIconicLivePreviewBitmap(
143 LRESULT* l_result) {
144 CaptureSnapshot();
146 HBITMAP native_bitmap = GetNativeBitmapFromSkBitmap(*capture_bitmap_);
147 ::DwmSetIconicLivePreviewBitmap(hwnd_, native_bitmap, NULL, 0);
148 ::DeleteObject(native_bitmap);
149 *l_result = 0;
150 return true;
153 SkBitmap* TaskbarWindowThumbnailerWin::CaptureWindowImage() const {
154 std::vector<HWND> snapshot_hwnds;
155 if (delegate_)
156 snapshot_hwnds = delegate_->GetSnapshotWindowHandles();
157 if (snapshot_hwnds.empty())
158 snapshot_hwnds.push_back(hwnd_);
160 int enclosing_x = 0;
161 int enclosing_y = 0;
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) {
166 RECT bounds;
167 if (!::GetWindowRect(*iter, &bounds))
168 continue;
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;
174 } else {
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)
189 return NULL;
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;
198 RECT current_bounds;
199 if (!::GetWindowRect(current_hwnd, &current_bounds))
200 continue;
201 base::win::ScopedGetDC source_dc(current_hwnd);
202 ::BitBlt(target_dc,
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,
207 source_dc,
210 SRCCOPY);
211 ::ReleaseDC(current_hwnd, source_dc);
214 return new SkBitmap(canvas.ExtractImageRep().sk_bitmap());