Index: ui/snapshot/snapshot_win.cc |
diff --git a/ui/snapshot/snapshot_win.cc b/ui/snapshot/snapshot_win.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..bd150910efa0b1d5f7e2035670749b0de3c74885 |
--- /dev/null |
+++ b/ui/snapshot/snapshot_win.cc |
@@ -0,0 +1,151 @@ |
+// Copyright 2017 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_win.h" |
+ |
+#include "base/callback.h" |
+#include "base/task_runner.h" |
+#include "base/win/windows_version.h" |
+#include "skia/ext/platform_canvas.h" |
+#include "skia/ext/skia_utils_win.h" |
+#include "ui/aura/window.h" |
+#include "ui/aura/window_tree_host.h" |
+#include "ui/gfx/geometry/rect.h" |
+#include "ui/gfx/geometry/size.h" |
+#include "ui/gfx/image/image.h" |
+#include "ui/snapshot/snapshot.h" |
+#include "ui/snapshot/snapshot_aura.h" |
+ |
+namespace { |
+ |
+// Windows 8.1 is the first version that supports PW_RENDERFULLCONTENT. |
+// Without that flag PrintWindow may not correctly capture what's actually |
+// onscreen. |
+bool UseAuraSnapshot() { |
+ return (base::win::GetVersion() < base::win::VERSION_WIN8_1); |
+} |
+ |
+} // namespace |
+ |
+namespace ui { |
+ |
+namespace internal { |
+ |
+bool GrabHwndSnapshot(HWND window_handle, |
+ const gfx::Rect& snapshot_bounds, |
sky
2017/03/23 23:20:33
Please name these in pixels.
|
+ const gfx::Rect& clip_rect, |
+ gfx::Image* image) { |
+ gfx::Rect snapshot_bounds_in_window = |
+ snapshot_bounds + clip_rect.OffsetFromOrigin(); |
+ gfx::Size bitmap_size(snapshot_bounds_in_window.right(), |
+ snapshot_bounds_in_window.bottom()); |
+ |
+ std::unique_ptr<SkCanvas> canvas = skia::CreatePlatformCanvas( |
+ bitmap_size.width(), bitmap_size.height(), false); |
+ HDC mem_hdc = skia::GetNativeDrawingContext(canvas.get()); |
+ |
+ // Grab a copy of the window. Use PrintWindow because it works even when the |
+ // window's partially occluded. The PW_RENDERFULLCONTENT flag is undocumented, |
+ // but works starting in Windows 8.1. It allows for capturing the contents of |
+ // the window that are drawn using DirectComposition. |
+ UINT flags = PW_CLIENTONLY | PW_RENDERFULLCONTENT; |
+ |
+ BOOL result = PrintWindow(window_handle, mem_hdc, flags); |
+ if (!result) { |
+ PLOG(ERROR) << "Failed to print window"; |
+ return false; |
+ } |
+ |
+ SkBitmap bitmap; |
+ canvas->readPixels(gfx::RectToSkIRect(snapshot_bounds_in_window), &bitmap); |
+ |
+ // Clear the region of the bitmap outside the clip rect to white. |
+ SkCanvas image_canvas(bitmap); |
+ SkPaint paint; |
+ paint.setColor(SK_ColorWHITE); |
+ |
+ SkRegion region; |
+ gfx::Rect clip_in_bitmap(clip_rect.size()); |
+ clip_in_bitmap.Offset(-snapshot_bounds.OffsetFromOrigin()); |
+ region.setRect(gfx::RectToSkIRect(gfx::Rect(snapshot_bounds.size()))); |
+ region.op(gfx::RectToSkIRect(clip_in_bitmap), SkRegion::kDifference_Op); |
+ image_canvas.drawRegion(region, paint); |
+ |
+ *image = gfx::Image::CreateFrom1xBitmap(bitmap); |
+ |
+ return true; |
+} |
+ |
+} // namespace internal |
+ |
+bool GrabViewSnapshot(gfx::NativeView view_handle, |
+ const gfx::Rect& snapshot_bounds, |
+ gfx::Image* image) { |
+ return GrabWindowSnapshot(view_handle, snapshot_bounds, image); |
+} |
+ |
+bool GrabWindowSnapshot(gfx::NativeWindow window_handle, |
+ const gfx::Rect& snapshot_bounds, |
+ gfx::Image* image) { |
+ if (UseAuraSnapshot()) { |
+ // Not supported in Aura. Callers should fall back to the async version. |
+ return false; |
+ } |
+ |
+ DCHECK(window_handle); |
+ gfx::Rect window_bounds = window_handle->GetBoundsInRootWindow(); |
+ aura::WindowTreeHost* host = window_handle->GetHost(); |
+ DCHECK(host); |
+ HWND hwnd = host->GetAcceleratedWidget(); |
+ window_bounds.Intersect(host->window()->bounds()); |
sky
2017/03/23 23:20:33
Can you get the bounds directly from the hwnd? I'm
|
+ |
+ gfx::RectF pixel_rect(window_bounds); |
+ host->GetRootTransform().TransformRect(&pixel_rect); |
+ gfx::RectF pixel_snapshot_bounds(snapshot_bounds); |
+ host->GetRootTransform().TransformRect(&pixel_snapshot_bounds); |
+ |
+ return internal::GrabHwndSnapshot(hwnd, |
+ gfx::ToEnclosingRect(pixel_snapshot_bounds), |
+ gfx::ToEnclosingRect(pixel_rect), image); |
+} |
+ |
+void GrabWindowSnapshotAsync(gfx::NativeWindow window, |
+ const gfx::Rect& source_rect, |
+ const GrabWindowSnapshotAsyncCallback& callback) { |
+ if (UseAuraSnapshot()) { |
+ GrabWindowSnapshotAsyncAura(window, source_rect, callback); |
+ return; |
+ } |
+ gfx::Image image; |
+ GrabWindowSnapshot(window, source_rect, &image); |
+ callback.Run(image); |
+} |
+ |
+void GrabViewSnapshotAsync(gfx::NativeView view, |
+ const gfx::Rect& source_rect, |
+ const GrabWindowSnapshotAsyncCallback& callback) { |
+ if (UseAuraSnapshot()) { |
+ GrabWindowSnapshotAsyncAura(view, source_rect, callback); |
+ return; |
+ } |
+ NOTIMPLEMENTED(); |
+ callback.Run(gfx::Image()); |
+} |
+ |
+void GrabWindowSnapshotAndScaleAsync( |
+ gfx::NativeWindow window, |
+ const gfx::Rect& source_rect, |
+ const gfx::Size& target_size, |
+ scoped_refptr<base::TaskRunner> background_task_runner, |
+ const GrabWindowSnapshotAsyncCallback& callback) { |
+ if (UseAuraSnapshot()) { |
+ GrabWindowSnapshotAndScaleAsyncAura(window, source_rect, target_size, |
+ background_task_runner, callback); |
+ return; |
+ } |
+ NOTIMPLEMENTED(); |
+ callback.Run(gfx::Image()); |
+} |
+ |
+} // namespace ui |