| 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..66049a70411faa8455479cd0b99bdbe8a7460ccb
|
| --- /dev/null
|
| +++ b/ui/snapshot/snapshot_win.cc
|
| @@ -0,0 +1,160 @@
|
| +// 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_in_pixels,
|
| + const gfx::Rect& clip_rect_in_pixels,
|
| + gfx::Image* image) {
|
| + gfx::Rect snapshot_bounds_in_window =
|
| + snapshot_bounds_in_pixels + clip_rect_in_pixels.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_in_pixels.size());
|
| + clip_in_bitmap.Offset(-snapshot_bounds_in_pixels.OffsetFromOrigin());
|
| + region.setRect(
|
| + gfx::RectToSkIRect(gfx::Rect(snapshot_bounds_in_pixels.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();
|
| +
|
| + gfx::RectF window_bounds_in_pixels(window_bounds);
|
| + host->GetRootTransform().TransformRect(&window_bounds_in_pixels);
|
| + gfx::RectF snapshot_bounds_in_pixels(snapshot_bounds);
|
| + host->GetRootTransform().TransformRect(&snapshot_bounds_in_pixels);
|
| +
|
| + gfx::Rect expanded_window_bounds_in_pixels =
|
| + gfx::ToEnclosingRect(window_bounds_in_pixels);
|
| + RECT client_area;
|
| + ::GetClientRect(hwnd, &client_area);
|
| + gfx::Rect client_area_rect(client_area);
|
| + client_area_rect.set_origin(gfx::Point());
|
| +
|
| + expanded_window_bounds_in_pixels.Intersect(client_area_rect);
|
| +
|
| + return internal::GrabHwndSnapshot(
|
| + hwnd, gfx::ToEnclosingRect(snapshot_bounds_in_pixels),
|
| + expanded_window_bounds_in_pixels, 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
|
|
|