1 // Copyright (c) 2012 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_aura.h"
6 
7 #include <memory>
8 #include <utility>
9 
10 #include "base/bind.h"
11 #include "base/callback.h"
12 #include "base/task_runner_util.h"
13 #include "components/viz/common/frame_sinks/copy_output_request.h"
14 #include "third_party/skia/include/core/SkBitmap.h"
15 #include "ui/aura/window.h"
16 #include "ui/aura/window_tracker.h"
17 #include "ui/compositor/compositor.h"
18 #include "ui/compositor/dip_util.h"
19 #include "ui/compositor/layer.h"
20 #include "ui/snapshot/snapshot_async.h"
21 
22 namespace ui {
23 
GrabWindowSnapshotAura(aura::Window * window,const gfx::Rect & snapshot_bounds,gfx::Image * image)24 bool GrabWindowSnapshotAura(aura::Window* window,
25                             const gfx::Rect& snapshot_bounds,
26                             gfx::Image* image) {
27   // Not supported in Aura.  Callers should fall back to the async version.
28   return false;
29 }
30 
MakeAsyncCopyRequest(Layer * layer,const gfx::Rect & source_rect,viz::CopyOutputRequest::CopyOutputRequestCallback callback)31 static void MakeAsyncCopyRequest(
32     Layer* layer,
33     const gfx::Rect& source_rect,
34     viz::CopyOutputRequest::CopyOutputRequestCallback callback) {
35   std::unique_ptr<viz::CopyOutputRequest> request =
36       std::make_unique<viz::CopyOutputRequest>(
37           viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP,
38           std::move(callback));
39   request->set_area(source_rect);
40   layer->RequestCopyOfOutput(std::move(request));
41 }
42 
FinishedAsyncCopyRequest(std::unique_ptr<aura::WindowTracker> tracker,const gfx::Rect & source_rect,viz::CopyOutputRequest::CopyOutputRequestCallback callback,int retry_count,std::unique_ptr<viz::CopyOutputResult> result)43 static void FinishedAsyncCopyRequest(
44     std::unique_ptr<aura::WindowTracker> tracker,
45     const gfx::Rect& source_rect,
46     viz::CopyOutputRequest::CopyOutputRequestCallback callback,
47     int retry_count,
48     std::unique_ptr<viz::CopyOutputResult> result) {
49   static const int kMaxRetries = 5;
50   // Retry the copy request if the previous one failed for some reason.
51   if (!tracker->windows().empty() && (retry_count < kMaxRetries) &&
52       result->IsEmpty()) {
53     // Look up window before calling MakeAsyncRequest. Otherwise, due
54     // to undefined (favorably right to left) argument evaluation
55     // order, the tracker might have been passed and set to NULL
56     // before the window is looked up which results in a NULL pointer
57     // dereference.
58     aura::Window* window = tracker->windows()[0];
59     MakeAsyncCopyRequest(
60         window->layer(), source_rect,
61         base::BindOnce(&FinishedAsyncCopyRequest, std::move(tracker),
62                        source_rect, std::move(callback), retry_count + 1));
63     return;
64   }
65 
66   std::move(callback).Run(std::move(result));
67 }
68 
MakeInitialAsyncCopyRequest(aura::Window * window,const gfx::Rect & source_rect,viz::CopyOutputRequest::CopyOutputRequestCallback callback)69 static void MakeInitialAsyncCopyRequest(
70     aura::Window* window,
71     const gfx::Rect& source_rect,
72     viz::CopyOutputRequest::CopyOutputRequestCallback callback) {
73   auto tracker = std::make_unique<aura::WindowTracker>();
74   tracker->Add(window);
75   MakeAsyncCopyRequest(
76       window->layer(), source_rect,
77       base::BindOnce(&FinishedAsyncCopyRequest, std::move(tracker), source_rect,
78                      std::move(callback), 0));
79 }
80 
GrabWindowSnapshotAndScaleAsyncAura(aura::Window * window,const gfx::Rect & source_rect,const gfx::Size & target_size,GrabWindowSnapshotAsyncCallback callback)81 void GrabWindowSnapshotAndScaleAsyncAura(
82     aura::Window* window,
83     const gfx::Rect& source_rect,
84     const gfx::Size& target_size,
85     GrabWindowSnapshotAsyncCallback callback) {
86   MakeInitialAsyncCopyRequest(
87       window, source_rect,
88       base::BindOnce(&SnapshotAsync::ScaleCopyOutputResult, std::move(callback),
89                      target_size));
90 }
91 
GrabWindowSnapshotAsyncAura(aura::Window * window,const gfx::Rect & source_rect,GrabWindowSnapshotAsyncCallback callback)92 void GrabWindowSnapshotAsyncAura(aura::Window* window,
93                                  const gfx::Rect& source_rect,
94                                  GrabWindowSnapshotAsyncCallback callback) {
95   MakeInitialAsyncCopyRequest(
96       window, source_rect,
97       base::BindOnce(&SnapshotAsync::RunCallbackWithCopyOutputResult,
98                      std::move(callback)));
99 }
100 
101 #if !defined(OS_WIN)
GrabWindowSnapshot(gfx::NativeWindow window,const gfx::Rect & snapshot_bounds,gfx::Image * image)102 bool GrabWindowSnapshot(gfx::NativeWindow window,
103                         const gfx::Rect& snapshot_bounds,
104                         gfx::Image* image) {
105   // Not supported in Aura.  Callers should fall back to the async version.
106   return false;
107 }
108 
GrabViewSnapshot(gfx::NativeView view,const gfx::Rect & snapshot_bounds,gfx::Image * image)109 bool GrabViewSnapshot(gfx::NativeView view,
110                       const gfx::Rect& snapshot_bounds,
111                       gfx::Image* image) {
112   return GrabWindowSnapshot(view, snapshot_bounds, image);
113 }
114 
GrabWindowSnapshotAndScaleAsync(gfx::NativeWindow window,const gfx::Rect & source_rect,const gfx::Size & target_size,GrabWindowSnapshotAsyncCallback callback)115 void GrabWindowSnapshotAndScaleAsync(gfx::NativeWindow window,
116                                      const gfx::Rect& source_rect,
117                                      const gfx::Size& target_size,
118                                      GrabWindowSnapshotAsyncCallback callback) {
119   GrabWindowSnapshotAndScaleAsyncAura(window, source_rect, target_size,
120                                       std::move(callback));
121 }
122 
GrabWindowSnapshotAsync(gfx::NativeWindow window,const gfx::Rect & source_rect,GrabWindowSnapshotAsyncCallback callback)123 void GrabWindowSnapshotAsync(gfx::NativeWindow window,
124                              const gfx::Rect& source_rect,
125                              GrabWindowSnapshotAsyncCallback callback) {
126   GrabWindowSnapshotAsyncAura(window, source_rect, std::move(callback));
127 }
128 
GrabViewSnapshotAsync(gfx::NativeView view,const gfx::Rect & source_rect,GrabWindowSnapshotAsyncCallback callback)129 void GrabViewSnapshotAsync(gfx::NativeView view,
130                            const gfx::Rect& source_rect,
131                            GrabWindowSnapshotAsyncCallback callback) {
132   GrabWindowSnapshotAsyncAura(view, source_rect, std::move(callback));
133 }
134 
GrabLayerSnapshotAsync(ui::Layer * layer,const gfx::Rect & source_rect,GrabWindowSnapshotAsyncCallback callback)135 void GrabLayerSnapshotAsync(ui::Layer* layer,
136                             const gfx::Rect& source_rect,
137                             GrabWindowSnapshotAsyncCallback callback) {
138   MakeAsyncCopyRequest(
139       layer, source_rect,
140       base::BindOnce(&SnapshotAsync::RunCallbackWithCopyOutputResult,
141                      std::move(callback)));
142 }
143 
144 #endif
145 
146 }  // namespace ui
147