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