OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "ui/snapshot/snapshot_win.h" | |
6 | |
7 #include "base/callback.h" | |
8 #include "base/task_runner.h" | |
9 #include "base/win/windows_version.h" | |
10 #include "skia/ext/platform_canvas.h" | |
11 #include "skia/ext/skia_utils_win.h" | |
12 #include "ui/aura/window.h" | |
13 #include "ui/aura/window_tree_host.h" | |
14 #include "ui/gfx/geometry/rect.h" | |
15 #include "ui/gfx/geometry/size.h" | |
16 #include "ui/gfx/image/image.h" | |
17 #include "ui/snapshot/snapshot.h" | |
18 #include "ui/snapshot/snapshot_aura.h" | |
19 | |
20 namespace { | |
21 | |
22 // Windows 8.1 is the first version that supports PW_RENDERFULLCONTENT. | |
23 // Without that flag PrintWindow may not correctly capture what's actually | |
24 // onscreen. | |
25 bool UseAuraSnapshot() { | |
26 return (base::win::GetVersion() < base::win::VERSION_WIN8_1); | |
27 } | |
28 | |
29 } // namespace | |
30 | |
31 namespace ui { | |
32 | |
33 namespace internal { | |
34 | |
35 bool GrabHwndSnapshot(HWND window_handle, | |
36 const gfx::Rect& snapshot_bounds, | |
sky
2017/03/23 23:20:33
Please name these in pixels.
| |
37 const gfx::Rect& clip_rect, | |
38 gfx::Image* image) { | |
39 gfx::Rect snapshot_bounds_in_window = | |
40 snapshot_bounds + clip_rect.OffsetFromOrigin(); | |
41 gfx::Size bitmap_size(snapshot_bounds_in_window.right(), | |
42 snapshot_bounds_in_window.bottom()); | |
43 | |
44 std::unique_ptr<SkCanvas> canvas = skia::CreatePlatformCanvas( | |
45 bitmap_size.width(), bitmap_size.height(), false); | |
46 HDC mem_hdc = skia::GetNativeDrawingContext(canvas.get()); | |
47 | |
48 // Grab a copy of the window. Use PrintWindow because it works even when the | |
49 // window's partially occluded. The PW_RENDERFULLCONTENT flag is undocumented, | |
50 // but works starting in Windows 8.1. It allows for capturing the contents of | |
51 // the window that are drawn using DirectComposition. | |
52 UINT flags = PW_CLIENTONLY | PW_RENDERFULLCONTENT; | |
53 | |
54 BOOL result = PrintWindow(window_handle, mem_hdc, flags); | |
55 if (!result) { | |
56 PLOG(ERROR) << "Failed to print window"; | |
57 return false; | |
58 } | |
59 | |
60 SkBitmap bitmap; | |
61 canvas->readPixels(gfx::RectToSkIRect(snapshot_bounds_in_window), &bitmap); | |
62 | |
63 // Clear the region of the bitmap outside the clip rect to white. | |
64 SkCanvas image_canvas(bitmap); | |
65 SkPaint paint; | |
66 paint.setColor(SK_ColorWHITE); | |
67 | |
68 SkRegion region; | |
69 gfx::Rect clip_in_bitmap(clip_rect.size()); | |
70 clip_in_bitmap.Offset(-snapshot_bounds.OffsetFromOrigin()); | |
71 region.setRect(gfx::RectToSkIRect(gfx::Rect(snapshot_bounds.size()))); | |
72 region.op(gfx::RectToSkIRect(clip_in_bitmap), SkRegion::kDifference_Op); | |
73 image_canvas.drawRegion(region, paint); | |
74 | |
75 *image = gfx::Image::CreateFrom1xBitmap(bitmap); | |
76 | |
77 return true; | |
78 } | |
79 | |
80 } // namespace internal | |
81 | |
82 bool GrabViewSnapshot(gfx::NativeView view_handle, | |
83 const gfx::Rect& snapshot_bounds, | |
84 gfx::Image* image) { | |
85 return GrabWindowSnapshot(view_handle, snapshot_bounds, image); | |
86 } | |
87 | |
88 bool GrabWindowSnapshot(gfx::NativeWindow window_handle, | |
89 const gfx::Rect& snapshot_bounds, | |
90 gfx::Image* image) { | |
91 if (UseAuraSnapshot()) { | |
92 // Not supported in Aura. Callers should fall back to the async version. | |
93 return false; | |
94 } | |
95 | |
96 DCHECK(window_handle); | |
97 gfx::Rect window_bounds = window_handle->GetBoundsInRootWindow(); | |
98 aura::WindowTreeHost* host = window_handle->GetHost(); | |
99 DCHECK(host); | |
100 HWND hwnd = host->GetAcceleratedWidget(); | |
101 window_bounds.Intersect(host->window()->bounds()); | |
sky
2017/03/23 23:20:33
Can you get the bounds directly from the hwnd? I'm
| |
102 | |
103 gfx::RectF pixel_rect(window_bounds); | |
104 host->GetRootTransform().TransformRect(&pixel_rect); | |
105 gfx::RectF pixel_snapshot_bounds(snapshot_bounds); | |
106 host->GetRootTransform().TransformRect(&pixel_snapshot_bounds); | |
107 | |
108 return internal::GrabHwndSnapshot(hwnd, | |
109 gfx::ToEnclosingRect(pixel_snapshot_bounds), | |
110 gfx::ToEnclosingRect(pixel_rect), image); | |
111 } | |
112 | |
113 void GrabWindowSnapshotAsync(gfx::NativeWindow window, | |
114 const gfx::Rect& source_rect, | |
115 const GrabWindowSnapshotAsyncCallback& callback) { | |
116 if (UseAuraSnapshot()) { | |
117 GrabWindowSnapshotAsyncAura(window, source_rect, callback); | |
118 return; | |
119 } | |
120 gfx::Image image; | |
121 GrabWindowSnapshot(window, source_rect, &image); | |
122 callback.Run(image); | |
123 } | |
124 | |
125 void GrabViewSnapshotAsync(gfx::NativeView view, | |
126 const gfx::Rect& source_rect, | |
127 const GrabWindowSnapshotAsyncCallback& callback) { | |
128 if (UseAuraSnapshot()) { | |
129 GrabWindowSnapshotAsyncAura(view, source_rect, callback); | |
130 return; | |
131 } | |
132 NOTIMPLEMENTED(); | |
133 callback.Run(gfx::Image()); | |
134 } | |
135 | |
136 void GrabWindowSnapshotAndScaleAsync( | |
137 gfx::NativeWindow window, | |
138 const gfx::Rect& source_rect, | |
139 const gfx::Size& target_size, | |
140 scoped_refptr<base::TaskRunner> background_task_runner, | |
141 const GrabWindowSnapshotAsyncCallback& callback) { | |
142 if (UseAuraSnapshot()) { | |
143 GrabWindowSnapshotAndScaleAsyncAura(window, source_rect, target_size, | |
144 background_task_runner, callback); | |
145 return; | |
146 } | |
147 NOTIMPLEMENTED(); | |
148 callback.Run(gfx::Image()); | |
149 } | |
150 | |
151 } // namespace ui | |
OLD | NEW |