summaryrefslogtreecommitdiffstats
path: root/ui/snapshot
diff options
context:
space:
mode:
authorbajones@chromium.org <bajones@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-15 22:20:09 +0000
committerbajones@chromium.org <bajones@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-15 22:20:09 +0000
commitc9bc8f1104914818e054b7f9f2b928ce78bc9dd8 (patch)
tree65db09fb71c6f73383285b406fe25aaf7d206dc9 /ui/snapshot
parentd72acb0dd473cd8dd0d3d420e22a03c766d76623 (diff)
downloadchromium_src-c9bc8f1104914818e054b7f9f2b928ce78bc9dd8.zip
chromium_src-c9bc8f1104914818e054b7f9f2b928ce78bc9dd8.tar.gz
chromium_src-c9bc8f1104914818e054b7f9f2b928ce78bc9dd8.tar.bz2
Implemented GetWindowSnapshot on RenderViewImpl
This necessitated the relocation of the previous chrome::GrabWindowSnapshot code to ui/snapshot, which has been turned into it's own component to avoid circular dependencies with aura. A new variant of GrabWindowSnapshot, GrabViewSnapshot, has been added as well to facilitate easier usage by views. chrome::GrabWindowSnapshotForUser was left in place to accomodate existing calls to the API, but now calls up to the ui/snapshot code. This is a subset of the prior CL 11362023, which has been broken apart to facilitate easier reviews BUG=157479 Review URL: https://chromiumcodereview.appspot.com/11399002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@173329 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/snapshot')
-rw-r--r--ui/snapshot/DEPS7
-rw-r--r--ui/snapshot/snapshot.gyp65
-rw-r--r--ui/snapshot/snapshot.h34
-rw-r--r--ui/snapshot/snapshot_android.cc25
-rw-r--r--ui/snapshot/snapshot_aura.cc58
-rw-r--r--ui/snapshot/snapshot_export.h32
-rw-r--r--ui/snapshot/snapshot_gtk.cc85
-rw-r--r--ui/snapshot/snapshot_ios.mm25
-rw-r--r--ui/snapshot/snapshot_mac.mm73
-rw-r--r--ui/snapshot/snapshot_mac_unittest.mm62
-rw-r--r--ui/snapshot/snapshot_win.cc106
11 files changed, 572 insertions, 0 deletions
diff --git a/ui/snapshot/DEPS b/ui/snapshot/DEPS
new file mode 100644
index 0000000..13c975d
--- /dev/null
+++ b/ui/snapshot/DEPS
@@ -0,0 +1,7 @@
+include_rules = [
+ "+skia",
+ "+ui/aura",
+ "+ui/base",
+ "+ui/compositor",
+ "+ui/gfx",
+] \ No newline at end of file
diff --git a/ui/snapshot/snapshot.gyp b/ui/snapshot/snapshot.gyp
new file mode 100644
index 0000000..40744bf
--- /dev/null
+++ b/ui/snapshot/snapshot.gyp
@@ -0,0 +1,65 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+ 'targets': [
+ {
+ 'target_name': 'snapshot',
+ 'type': '<(component)',
+ 'dependencies': [
+ '../../skia/skia.gyp:skia',
+ '../../base/base.gyp:base',
+ '../ui.gyp:ui',
+ ],
+ 'defines': [
+ 'SNAPSHOT_IMPLEMENTATION',
+ ],
+ 'sources': [
+ 'snapshot.h',
+ 'snapshot_android.cc',
+ 'snapshot_aura.cc',
+ 'snapshot_export.h',
+ 'snapshot_gtk.cc',
+ 'snapshot_ios.mm',
+ 'snapshot_mac.mm',
+ 'snapshot_win.cc',
+ ],
+ 'include_dirs': [
+ '..',
+ ],
+ 'conditions': [
+ ['use_aura==1', {
+ 'dependencies': [
+ '../aura/aura.gyp:aura',
+ '../compositor/compositor.gyp:compositor',
+ ],
+ }],
+ ['use_aura==1 and OS=="win"', {
+ 'sources/': [
+ ['exclude', 'snapshot_win.cc'],
+ ],
+ }],
+ ],
+ },
+ {
+ 'target_name': 'snapshot_unittests',
+ 'type': '<(gtest_target_type)',
+ 'dependencies': [
+ '../../skia/skia.gyp:skia',
+ '../../base/base.gyp:base',
+ '../../testing/gtest.gyp:gtest',
+ '../../testing/gmock.gyp:gmock',
+ '../../testing/gtest.gyp:gtest',
+ '../ui.gyp:ui',
+ 'snapshot'
+ ],
+ 'sources': [
+ 'snapshot_mac_unittest.mm',
+ ]
+ },
+ ],
+}
diff --git a/ui/snapshot/snapshot.h b/ui/snapshot/snapshot.h
new file mode 100644
index 0000000..356309d
--- /dev/null
+++ b/ui/snapshot/snapshot.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_SNAPSHOT_SNAPSHOT_H_
+#define UI_SNAPSHOT_SNAPSHOT_H_
+
+#include <vector>
+
+#include "ui/gfx/native_widget_types.h"
+#include "ui/snapshot/snapshot_export.h"
+
+namespace gfx {
+class Rect;
+}
+
+namespace ui {
+
+// Grabs a snapshot of the window/view. No security checks are done.
+// This is intended to be used for debugging purposes where no BrowserProcess
+// instance is available (ie. tests). DO NOT use in a result of user action.
+SNAPSHOT_EXPORT bool GrabWindowSnapshot(
+ gfx::NativeWindow window,
+ std::vector<unsigned char>* png_representation,
+ const gfx::Rect& snapshot_bounds);
+
+SNAPSHOT_EXPORT bool GrabViewSnapshot(
+ gfx::NativeView view,
+ std::vector<unsigned char>* png_representation,
+ const gfx::Rect& snapshot_bounds);
+
+} // namespace ui
+
+#endif // UI_SNAPSHOT_SNAPSHOT_H_
diff --git a/ui/snapshot/snapshot_android.cc b/ui/snapshot/snapshot_android.cc
new file mode 100644
index 0000000..4e89c9d
--- /dev/null
+++ b/ui/snapshot/snapshot_android.cc
@@ -0,0 +1,25 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/snapshot/snapshot.h"
+
+#include "ui/gfx/rect.h"
+
+namespace ui {
+
+bool GrabViewSnapshot(gfx::NativeView view,
+ std::vector<unsigned char>* png_representation,
+ const gfx::Rect& snapshot_bounds) {
+ // TODO(bajones): Implement Android snapshot functionality
+ return false;
+}
+
+bool GrabWindowSnapshot(gfx::NativeWindow window,
+ std::vector<unsigned char>* png_representation,
+ const gfx::Rect& snapshot_bounds) {
+ // TODO(bajones): Implement Android snapshot functionality
+ return false;
+}
+
+} // namespace ui
diff --git a/ui/snapshot/snapshot_aura.cc b/ui/snapshot/snapshot_aura.cc
new file mode 100644
index 0000000..1eca6d5
--- /dev/null
+++ b/ui/snapshot/snapshot_aura.cc
@@ -0,0 +1,58 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/snapshot/snapshot.h"
+
+#include "base/logging.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/aura/window.h"
+#include "ui/compositor/compositor.h"
+#include "ui/compositor/dip_util.h"
+#include "ui/compositor/layer.h"
+#include "ui/gfx/codec/png_codec.h"
+#include "ui/gfx/rect.h"
+
+namespace ui {
+
+bool GrabViewSnapshot(gfx::NativeView view,
+ std::vector<unsigned char>* png_representation,
+ const gfx::Rect& snapshot_bounds) {
+ return GrabWindowSnapshot(view, png_representation, snapshot_bounds);
+}
+
+bool GrabWindowSnapshot(gfx::NativeWindow window,
+ std::vector<unsigned char>* png_representation,
+ const gfx::Rect& snapshot_bounds) {
+ ui::Compositor* compositor = window->layer()->GetCompositor();
+
+ gfx::Rect read_pixels_bounds = snapshot_bounds;
+
+ // When not in compact mode we must take into account the window's position on
+ // the desktop.
+ read_pixels_bounds.Offset(window->bounds().OffsetFromOrigin());
+ gfx::Rect read_pixels_bounds_in_pixel =
+ ui::ConvertRectToPixel(window->layer(), read_pixels_bounds);
+
+ // Sometimes (i.e. when using Aero on Windows) the compositor's size is
+ // smaller than the window bounds. So trim appropriately.
+ read_pixels_bounds_in_pixel.Intersect(gfx::Rect(compositor->size()));
+
+ DCHECK_LE(0, read_pixels_bounds.x());
+ DCHECK_LE(0, read_pixels_bounds.y());
+
+ SkBitmap bitmap;
+ if (!compositor->ReadPixels(&bitmap, read_pixels_bounds_in_pixel))
+ return false;
+
+ unsigned char* pixels = reinterpret_cast<unsigned char*>(bitmap.getPixels());
+
+ gfx::PNGCodec::Encode(pixels, gfx::PNGCodec::FORMAT_BGRA,
+ read_pixels_bounds_in_pixel.size(),
+ bitmap.rowBytes(), true,
+ std::vector<gfx::PNGCodec::Comment>(),
+ png_representation);
+ return true;
+}
+
+} // namespace ui
diff --git a/ui/snapshot/snapshot_export.h b/ui/snapshot/snapshot_export.h
new file mode 100644
index 0000000..9e27370
--- /dev/null
+++ b/ui/snapshot/snapshot_export.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_SNAPSHOT_SNAPSHOT_EXPORT_H
+#define UI_SNAPSHOT_SNAPSHOT_EXPORT_H
+
+// Defines SNAPSHOT_EXPORT so that functionality implemented by the snapshot
+// module can be exported to consumers.
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(SNAPSHOT_IMPLEMENTATION)
+#define SNAPSHOT_EXPORT __declspec(dllexport)
+#else
+#define SNAPSHOT_EXPORT __declspec(dllimport)
+#endif // defined(SNAPSHOT_IMPLEMENTATION)
+
+#else // defined(WIN32)
+#if defined(SNAPSHOT_IMPLEMENTATION)
+#define SNAPSHOT_EXPORT __attribute__((visibility("default")))
+#else
+#define SNAPSHOT_EXPORT
+#endif
+#endif
+
+#else // defined(COMPONENT_BUILD)
+#define SNAPSHOT_EXPORT
+#endif
+
+#endif // UI_SNAPSHOT_SNAPSHOT_EXPORT_H
diff --git a/ui/snapshot/snapshot_gtk.cc b/ui/snapshot/snapshot_gtk.cc
new file mode 100644
index 0000000..8a2f8c1
--- /dev/null
+++ b/ui/snapshot/snapshot_gtk.cc
@@ -0,0 +1,85 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/snapshot/snapshot.h"
+
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+
+#include "base/logging.h"
+#include "ui/base/x/x11_util.h"
+#include "ui/gfx/rect.h"
+
+namespace {
+
+cairo_status_t SnapshotCallback(void* closure,
+ const unsigned char* data,
+ unsigned int length) {
+ std::vector<unsigned char>* png_representation =
+ static_cast<std::vector<unsigned char>*>(closure);
+
+ size_t old_size = png_representation->size();
+ png_representation->resize(old_size + length);
+ memcpy(&(*png_representation)[old_size], data, length);
+ return CAIRO_STATUS_SUCCESS;
+}
+
+} // namespace
+
+namespace ui {
+
+bool GrabViewSnapshot(gfx::NativeView view_handle,
+ std::vector<unsigned char>* png_representation,
+ const gfx::Rect& snapshot_bounds) {
+ GdkWindow* gdk_window = gtk_widget_get_window(view_handle);
+ Display* display = GDK_WINDOW_XDISPLAY(gdk_window);
+ XID win = GDK_WINDOW_XID(gdk_window);
+
+ gfx::Rect window_bounds;
+ if (ui::GetWindowRect(win, &window_bounds) == 0) {
+ LOG(ERROR) << "Couldn't get window bounds";
+ return false;
+ }
+
+ DCHECK_LE(snapshot_bounds.right(), window_bounds.width());
+ DCHECK_LE(snapshot_bounds.bottom(), window_bounds.height());
+
+ ui::XScopedImage image(XGetImage(
+ display, win, snapshot_bounds.x(), snapshot_bounds.y(),
+ snapshot_bounds.width(), snapshot_bounds.height(), AllPlanes, ZPixmap));
+ if (!image.get()) {
+ LOG(ERROR) << "Couldn't get image";
+ return false;
+ }
+ if (image->depth != 24) {
+ LOG(ERROR)<< "Unsupported image depth " << image->depth;
+ return false;
+ }
+ cairo_surface_t* surface =
+ cairo_image_surface_create_for_data(
+ reinterpret_cast<unsigned char*>(image->data),
+ CAIRO_FORMAT_RGB24,
+ image->width,
+ image->height,
+ image->bytes_per_line);
+
+ if (!surface) {
+ LOG(ERROR) << "Unable to create Cairo surface from XImage data";
+ return false;
+ }
+ cairo_surface_write_to_png_stream(
+ surface, SnapshotCallback, png_representation);
+ cairo_surface_destroy(surface);
+
+ return true;
+}
+
+bool GrabWindowSnapshot(gfx::NativeWindow window_handle,
+ std::vector<unsigned char>* png_representation,
+ const gfx::Rect& snapshot_bounds) {
+ return GrabViewSnapshot(GTK_WIDGET(window_handle), png_representation,
+ snapshot_bounds);
+}
+
+} // namespace ui
diff --git a/ui/snapshot/snapshot_ios.mm b/ui/snapshot/snapshot_ios.mm
new file mode 100644
index 0000000..b373a03
--- /dev/null
+++ b/ui/snapshot/snapshot_ios.mm
@@ -0,0 +1,25 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/snapshot/snapshot.h"
+
+#include "ui/gfx/rect.h"
+
+namespace ui {
+
+bool GrabViewSnapshot(gfx::NativeView view,
+ std::vector<unsigned char>* png_representation,
+ const gfx::Rect& snapshot_bounds) {
+ // TODO(bajones): Implement iOS snapshot functionality
+ return false;
+}
+
+bool GrabWindowSnapshot(gfx::NativeWindow window,
+ std::vector<unsigned char>* png_representation,
+ const gfx::Rect& snapshot_bounds) {
+ // TODO(bajones): Implement iOS snapshot functionality
+ return false;
+}
+
+} // namespace ui
diff --git a/ui/snapshot/snapshot_mac.mm b/ui/snapshot/snapshot_mac.mm
new file mode 100644
index 0000000..5833704
--- /dev/null
+++ b/ui/snapshot/snapshot_mac.mm
@@ -0,0 +1,73 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/snapshot/snapshot.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/logging.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/memory/scoped_nsobject.h"
+#include "ui/gfx/rect.h"
+
+namespace ui {
+
+bool GrabViewSnapshot(gfx::NativeView view,
+ std::vector<unsigned char>* png_representation,
+ const gfx::Rect& snapshot_bounds) {
+ NSWindow* window = [view window];
+ NSScreen* screen = [[NSScreen screens] objectAtIndex:0];
+ gfx::Rect screen_bounds = gfx::Rect(NSRectToCGRect([screen frame]));
+
+
+ // Get the view bounds relative to the screen
+ NSRect frame = [view convertRect:[view bounds] toView:nil];
+ frame.origin = [window convertBaseToScreen:frame.origin];
+
+ gfx::Rect view_bounds = gfx::Rect(NSRectToCGRect(frame));
+
+ // Flip window coordinates based on the primary screen.
+ view_bounds.set_y(
+ screen_bounds.height() - view_bounds.y() - view_bounds.height());
+
+ // Convert snapshot bounds relative to window into bounds relative to
+ // screen.
+ gfx::Rect screen_snapshot_bounds = snapshot_bounds;
+ screen_snapshot_bounds.Offset(view_bounds.OffsetFromOrigin());
+
+ DCHECK_LE(screen_snapshot_bounds.right(), view_bounds.right());
+ DCHECK_LE(screen_snapshot_bounds.bottom(), view_bounds.bottom());
+
+ png_representation->clear();
+
+ base::mac::ScopedCFTypeRef<CGImageRef> windowSnapshot(CGWindowListCreateImage(
+ screen_snapshot_bounds.ToCGRect(), kCGWindowListOptionIncludingWindow,
+ [window windowNumber], kCGWindowImageBoundsIgnoreFraming));
+ if (CGImageGetWidth(windowSnapshot) <= 0)
+ return false;
+
+ scoped_nsobject<NSBitmapImageRep> rep(
+ [[NSBitmapImageRep alloc] initWithCGImage:windowSnapshot]);
+ NSData* data = [rep representationUsingType:NSPNGFileType properties:nil];
+ const unsigned char* buf = static_cast<const unsigned char*>([data bytes]);
+ NSUInteger length = [data length];
+ if (buf == NULL || length == 0)
+ return false;
+
+ png_representation->assign(buf, buf + length);
+ DCHECK(!png_representation->empty());
+
+ return true;
+}
+
+bool GrabWindowSnapshot(gfx::NativeWindow window,
+ std::vector<unsigned char>* png_representation,
+ const gfx::Rect& snapshot_bounds) {
+ // Make sure to grab the "window frame" view so we get current tab +
+ // tabstrip.
+ return GrabViewSnapshot([[window contentView] superview], png_representation,
+ snapshot_bounds);
+}
+
+} // namespace ui
diff --git a/ui/snapshot/snapshot_mac_unittest.mm b/ui/snapshot/snapshot_mac_unittest.mm
new file mode 100644
index 0000000..90061733
--- /dev/null
+++ b/ui/snapshot/snapshot_mac_unittest.mm
@@ -0,0 +1,62 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/snapshot/snapshot.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/memory/scoped_nsobject.h"
+#include "base/memory/scoped_ptr.h"
+#include "testing/platform_test.h"
+#include "ui/gfx/rect.h"
+
+#if !defined(MAC_OS_X_VERSION_10_7) || \
+ MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
+
+@interface NSWindow (LionAPI)
+- (CGFloat)backingScaleFactor;
+@end
+
+#endif // 10.7
+
+namespace ui {
+namespace {
+
+typedef PlatformTest GrabWindowSnapshotTest;
+
+TEST_F(GrabWindowSnapshotTest, TestGrabWindowSnapshot) {
+ // Launch a test window so we can take a snapshot.
+ NSRect frame = NSMakeRect(0, 0, 400, 400);
+ scoped_nsobject<NSWindow> window(
+ [[NSWindow alloc] initWithContentRect:frame
+ styleMask:NSBorderlessWindowMask
+ backing:NSBackingStoreBuffered
+ defer:NO]);
+ [window setBackgroundColor:[NSColor whiteColor]];
+ [window makeKeyAndOrderFront:NSApp];
+
+ scoped_ptr<std::vector<unsigned char> > png_representation(
+ new std::vector<unsigned char>);
+ gfx::Rect bounds = gfx::Rect(0, 0, frame.size.width, frame.size.height);
+ EXPECT_TRUE(ui::GrabWindowSnapshot(window, png_representation.get(),
+ bounds));
+
+ // Copy png back into NSData object so we can make sure we grabbed a png.
+ scoped_nsobject<NSData> image_data(
+ [[NSData alloc] initWithBytes:&(*png_representation)[0]
+ length:png_representation->size()]);
+ NSBitmapImageRep* rep = [NSBitmapImageRep imageRepWithData:image_data.get()];
+ EXPECT_TRUE([rep isKindOfClass:[NSBitmapImageRep class]]);
+ CGFloat scaleFactor = 1.0f;
+ if ([window respondsToSelector:@selector(backingScaleFactor)])
+ scaleFactor = [window backingScaleFactor];
+ EXPECT_EQ(400 * scaleFactor, CGImageGetWidth([rep CGImage]));
+ NSColor* color = [rep colorAtX:200 * scaleFactor y:200 * scaleFactor];
+ CGFloat red = 0, green = 0, blue = 0, alpha = 0;
+ [color getRed:&red green:&green blue:&blue alpha:&alpha];
+ EXPECT_GE(red + green + blue, 3.0);
+}
+
+} // namespace
+} // namespace ui
diff --git a/ui/snapshot/snapshot_win.cc b/ui/snapshot/snapshot_win.cc
new file mode 100644
index 0000000..3a8d1e7
--- /dev/null
+++ b/ui/snapshot/snapshot_win.cc
@@ -0,0 +1,106 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/snapshot/snapshot.h"
+
+#include "base/win/scoped_gdi_object.h"
+#include "base/win/scoped_hdc.h"
+#include "base/win/scoped_select_object.h"
+#include "ui/gfx/codec/png_codec.h"
+#include "ui/gfx/gdi_util.h"
+#include "ui/gfx/rect.h"
+#include "ui/gfx/size.h"
+
+namespace {
+
+gfx::Rect GetWindowBounds(gfx::NativeWindow window_handle) {
+ RECT content_rect = {0, 0, 0, 0};
+ if (window_handle) {
+ ::GetWindowRect(window_handle, &content_rect);
+ } else {
+ MONITORINFO monitor_info = {};
+ monitor_info.cbSize = sizeof(monitor_info);
+ if (GetMonitorInfo(MonitorFromWindow(NULL, MONITOR_DEFAULTTOPRIMARY),
+ &monitor_info)) {
+ content_rect = monitor_info.rcMonitor;
+ }
+ }
+ content_rect.right++; // Match what PrintWindow wants.
+
+ return gfx::Rect(content_rect.right - content_rect.left,
+ content_rect.bottom - content_rect.top);
+}
+
+} // namespace
+
+namespace ui {
+
+bool GrabViewSnapshot(gfx::NativeView view_handle,
+ std::vector<unsigned char>* png_representation,
+ const gfx::Rect& snapshot_bounds) {
+ return GrabWindowSnapshot(view_handle, png_representation, snapshot_bounds);
+}
+
+bool GrabWindowSnapshot(gfx::NativeWindow window_handle,
+ std::vector<unsigned char>* png_representation,
+ const gfx::Rect& snapshot_bounds) {
+ DCHECK(snapshot_bounds.right() <= GetWindowBounds(window_handle).right());
+ DCHECK(snapshot_bounds.bottom() <= GetWindowBounds(window_handle).bottom());
+
+ // Create a memory DC that's compatible with the window.
+ HDC window_hdc = GetWindowDC(window_handle);
+ base::win::ScopedCreateDC mem_hdc(CreateCompatibleDC(window_hdc));
+
+ BITMAPINFOHEADER hdr;
+ gfx::CreateBitmapHeader(snapshot_bounds.width(),
+ snapshot_bounds.height(),
+ &hdr);
+ unsigned char *bit_ptr = NULL;
+ base::win::ScopedBitmap bitmap(
+ CreateDIBSection(mem_hdc,
+ reinterpret_cast<BITMAPINFO*>(&hdr),
+ DIB_RGB_COLORS,
+ reinterpret_cast<void **>(&bit_ptr),
+ NULL, 0));
+
+ base::win::ScopedSelectObject select_bitmap(mem_hdc, bitmap);
+ // Clear the bitmap to white (so that rounded corners on windows
+ // show up on a white background, and strangely-shaped windows
+ // look reasonable). Not capturing an alpha mask saves a
+ // bit of space.
+ PatBlt(mem_hdc, 0, 0, snapshot_bounds.width(), snapshot_bounds.height(),
+ WHITENESS);
+ // Grab a copy of the window
+ // First, see if PrintWindow is defined (it's not in Windows 2000).
+ typedef BOOL (WINAPI *PrintWindowPointer)(HWND, HDC, UINT);
+ PrintWindowPointer print_window =
+ reinterpret_cast<PrintWindowPointer>(
+ GetProcAddress(GetModuleHandle(L"User32.dll"), "PrintWindow"));
+
+ // If PrintWindow is defined, use it. It will work on partially
+ // obscured windows, and works better for out of process sub-windows.
+ // Otherwise grab the bits we can get with BitBlt; it's better
+ // than nothing and will work fine in the average case (window is
+ // completely on screen). Always BitBlt when grabbing the whole screen.
+ if (snapshot_bounds.origin() == gfx::Point() && print_window && window_handle)
+ (*print_window)(window_handle, mem_hdc, 0);
+ else
+ BitBlt(mem_hdc, 0, 0, snapshot_bounds.width(), snapshot_bounds.height(),
+ window_hdc, snapshot_bounds.x(), snapshot_bounds.y(), SRCCOPY);
+
+ // We now have a copy of the window contents in a DIB, so
+ // encode it into a useful format for posting to the bug report
+ // server.
+ gfx::PNGCodec::Encode(bit_ptr, gfx::PNGCodec::FORMAT_BGRA,
+ snapshot_bounds.size(),
+ snapshot_bounds.width() * 4, true,
+ std::vector<gfx::PNGCodec::Comment>(),
+ png_representation);
+
+ ReleaseDC(window_handle, window_hdc);
+
+ return true;
+}
+
+} // namespace ui