15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/snapshot/snapshot_win.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/callback.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_gdi_object.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_hdc.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_select_object.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/codec/png_codec.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/gdi_util.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/rect.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/size.h"
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/snapshot/snapshot.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)gfx::Rect GetWindowBounds(HWND window_handle) {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RECT content_rect = {0, 0, 0, 0};
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (window_handle) {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ::GetWindowRect(window_handle, &content_rect);
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MONITORINFO monitor_info = {};
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    monitor_info.cbSize = sizeof(monitor_info);
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (GetMonitorInfo(MonitorFromWindow(NULL, MONITOR_DEFAULTTOPRIMARY),
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       &monitor_info)) {
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content_rect = monitor_info.rcMonitor;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content_rect.right++;  // Match what PrintWindow wants.
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return gfx::Rect(content_rect.right - content_rect.left,
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   content_rect.bottom - content_rect.top);
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace ui {
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace internal {
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool GrabHwndSnapshot(HWND window_handle,
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                      const gfx::Rect& snapshot_bounds,
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                      std::vector<unsigned char>* png_representation) {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(snapshot_bounds.right() <= GetWindowBounds(window_handle).right());
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(snapshot_bounds.bottom() <= GetWindowBounds(window_handle).bottom());
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create a memory DC that's compatible with the window.
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HDC window_hdc = GetWindowDC(window_handle);
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedCreateDC mem_hdc(CreateCompatibleDC(window_hdc));
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BITMAPINFOHEADER hdr;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::CreateBitmapHeader(snapshot_bounds.width(),
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          snapshot_bounds.height(),
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          &hdr);
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char *bit_ptr = NULL;
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedBitmap bitmap(
591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      CreateDIBSection(mem_hdc.Get(),
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       reinterpret_cast<BITMAPINFO*>(&hdr),
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       DIB_RGB_COLORS,
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       reinterpret_cast<void **>(&bit_ptr),
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       NULL, 0));
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  base::win::ScopedSelectObject select_bitmap(mem_hdc.Get(), bitmap);
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Clear the bitmap to white (so that rounded corners on windows
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // show up on a white background, and strangely-shaped windows
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // look reasonable). Not capturing an alpha mask saves a
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // bit of space.
701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  PatBlt(mem_hdc.Get(), 0, 0, snapshot_bounds.width(), snapshot_bounds.height(),
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         WHITENESS);
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Grab a copy of the window
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First, see if PrintWindow is defined (it's not in Windows 2000).
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef BOOL (WINAPI *PrintWindowPointer)(HWND, HDC, UINT);
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PrintWindowPointer print_window =
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<PrintWindowPointer>(
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GetProcAddress(GetModuleHandle(L"User32.dll"), "PrintWindow"));
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If PrintWindow is defined, use it.  It will work on partially
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // obscured windows, and works better for out of process sub-windows.
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Otherwise grab the bits we can get with BitBlt; it's better
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // than nothing and will work fine in the average case (window is
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // completely on screen).  Always BitBlt when grabbing the whole screen.
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (snapshot_bounds.origin() == gfx::Point() && print_window && window_handle)
851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    (*print_window)(window_handle, mem_hdc.Get(), 0);
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    BitBlt(mem_hdc.Get(), 0, 0, snapshot_bounds.width(),
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci           snapshot_bounds.height(), window_hdc, snapshot_bounds.x(),
891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci           snapshot_bounds.y(), SRCCOPY);
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We now have a copy of the window contents in a DIB, so
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // encode it into a useful format for posting to the bug report
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // server.
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::PNGCodec::Encode(bit_ptr, gfx::PNGCodec::FORMAT_BGRA,
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        snapshot_bounds.size(),
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        snapshot_bounds.width() * 4, true,
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        std::vector<gfx::PNGCodec::Comment>(),
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        png_representation);
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReleaseDC(window_handle, window_hdc);
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace internal
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#if !defined(USE_AURA)
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool GrabViewSnapshot(gfx::NativeView view_handle,
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                      std::vector<unsigned char>* png_representation,
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                      const gfx::Rect& snapshot_bounds) {
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return GrabWindowSnapshot(view_handle, png_representation, snapshot_bounds);
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
115c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool GrabWindowSnapshot(gfx::NativeWindow window_handle,
116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        std::vector<unsigned char>* png_representation,
117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        const gfx::Rect& snapshot_bounds) {
118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(window_handle);
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return internal::GrabHwndSnapshot(window_handle, snapshot_bounds,
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                    png_representation);
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GrapWindowSnapshotAsync(
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    gfx::NativeWindow window,
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const gfx::Rect& snapshot_bounds,
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const gfx::Size& target_size,
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_refptr<base::TaskRunner> background_task_runner,
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    GrabWindowSnapshotAsyncCallback callback) {
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  callback.Run(gfx::Image());
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GrabViewSnapshotAsync(
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    gfx::NativeView view,
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const gfx::Rect& source_rect,
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_refptr<base::TaskRunner> background_task_runner,
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const GrabWindowSnapshotAsyncPNGCallback& callback) {
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  callback.Run(scoped_refptr<base::RefCountedBytes>());
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GrabWindowSnapshotAsync(
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    gfx::NativeWindow window,
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const gfx::Rect& source_rect,
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_refptr<base::TaskRunner> background_task_runner,
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const GrabWindowSnapshotAsyncPNGCallback& callback) {
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  callback.Run(scoped_refptr<base::RefCountedBytes>());
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif  // !defined(USE_AURA)
150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace ui
152