- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / views / panels / taskbar_window_thumbnailer_win.cc
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.
4
5 #include "chrome/browser/ui/views/panels/taskbar_window_thumbnailer_win.h"
6
7 #include <dwmapi.h>
8
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"
14
15 namespace {
16
17 HBITMAP GetNativeBitmapFromSkBitmap(const SkBitmap& bitmap) {
18   int width = bitmap.width();
19   int height = bitmap.height();
20
21   BITMAPV4HEADER native_bitmap_header;
22   gfx::CreateBitmapV4Header(width, height, &native_bitmap_header);
23
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;
36 }
37
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));
48 }
49
50 }  // namespace
51
52
53 TaskbarWindowThumbnailerWin::TaskbarWindowThumbnailerWin(
54     HWND hwnd, TaskbarWindowThumbnailerDelegateWin* delegate)
55     : hwnd_(hwnd),
56       delegate_(delegate) {
57   ui::HWNDSubclass::AddFilterToTarget(hwnd_, this);
58 }
59
60 TaskbarWindowThumbnailerWin::~TaskbarWindowThumbnailerWin() {
61   ui::HWNDSubclass::RemoveFilterFromAllTargets(this);
62 }
63
64 void TaskbarWindowThumbnailerWin::Start() {
65   EnableCustomThumbnail(hwnd_, true);
66 }
67
68 void TaskbarWindowThumbnailerWin::Stop() {
69   capture_bitmap_.reset();
70   EnableCustomThumbnail(hwnd_, false);
71 }
72
73 void TaskbarWindowThumbnailerWin::CaptureSnapshot() {
74   if (!capture_bitmap_)
75     capture_bitmap_.reset(CaptureWindowImage());
76 }
77
78 void TaskbarWindowThumbnailerWin::InvalidateSnapshot() {
79   capture_bitmap_.reset();
80
81   // The snapshot feeded to the system could be cached. Invalidate it.
82   ::DwmInvalidateIconicBitmaps(hwnd_);
83 }
84
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);
89
90   hwnd_ = new_hwnd;
91
92   // Start serving the custom thumbnail to the new window.
93   ui::HWNDSubclass::AddFilterToTarget(hwnd_, this);
94   EnableCustomThumbnail(hwnd_, true);
95 }
96
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);
110   }
111   return false;
112 }
113
114 bool TaskbarWindowThumbnailerWin::OnDwmSendIconicThumbnail(
115     int width, int height, LRESULT* l_result) {
116   CaptureSnapshot();
117
118   SkBitmap* thumbnail_bitmap = capture_bitmap_.get();
119
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;
132   }
133
134   HBITMAP native_bitmap = GetNativeBitmapFromSkBitmap(*thumbnail_bitmap);
135   ::DwmSetIconicThumbnail(hwnd_, native_bitmap, 0);
136   ::DeleteObject(native_bitmap);
137
138   *l_result = 0;
139   return true;
140 }
141
142 bool TaskbarWindowThumbnailerWin::OnDwmSendIconicLivePreviewBitmap(
143     LRESULT* l_result) {
144   CaptureSnapshot();
145
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;
151 }
152
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_);
159
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;
183     }
184   }
185
186   int width = enclosing_right - enclosing_x;
187   int height = enclosing_bottom - enclosing_y;
188   if (!width || !height)
189     return NULL;
190
191   gfx::Canvas canvas(gfx::Size(width, height), 1.0f, false);
192   {
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,
208                0,
209                0,
210                SRCCOPY);
211       ::ReleaseDC(current_hwnd, source_dc);
212     }
213   }
214   return new SkBitmap(canvas.ExtractImageRep().sk_bitmap());
215 }