1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
|
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/snapshot/snapshot_aura.h"
#include <memory>
#include <utility>
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/task/sequenced_task_runner.h"
#include "build/build_config.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tracker.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/layer.h"
#include "ui/snapshot/snapshot_async.h"
namespace ui {
static void MakeAsyncCopyRequest(
Layer* layer,
const gfx::Rect& source_rect,
viz::CopyOutputRequest::CopyOutputRequestCallback callback) {
std::unique_ptr<viz::CopyOutputRequest> request =
std::make_unique<viz::CopyOutputRequest>(
viz::CopyOutputRequest::ResultFormat::RGBA,
viz::CopyOutputRequest::ResultDestination::kSystemMemory,
std::move(callback));
request->set_area(source_rect);
request->set_result_task_runner(
base::SequencedTaskRunner::GetCurrentDefault());
layer->RequestCopyOfOutput(std::move(request));
}
static void 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) {
static const int kMaxRetries = 5;
// Retry the copy request if the previous one failed for some reason.
if (!tracker->windows().empty() && (retry_count < kMaxRetries) &&
result->IsEmpty()) {
// Look up window before calling MakeAsyncRequest. Otherwise, due
// to undefined (favorably right to left) argument evaluation
// order, the tracker might have been passed and set to NULL
// before the window is looked up which results in a NULL pointer
// dereference.
aura::Window* window = tracker->windows()[0];
MakeAsyncCopyRequest(
window->layer(), source_rect,
base::BindOnce(&FinishedAsyncCopyRequest, std::move(tracker),
source_rect, std::move(callback), retry_count + 1));
return;
}
std::move(callback).Run(std::move(result));
}
static void MakeInitialAsyncCopyRequest(
aura::Window* window,
const gfx::Rect& source_rect,
viz::CopyOutputRequest::CopyOutputRequestCallback callback) {
auto tracker = std::make_unique<aura::WindowTracker>();
tracker->Add(window);
MakeAsyncCopyRequest(
window->layer(), source_rect,
base::BindOnce(&FinishedAsyncCopyRequest, std::move(tracker), source_rect,
std::move(callback), 0));
}
void GrabWindowSnapshotAndScaleAura(aura::Window* window,
const gfx::Rect& source_rect,
const gfx::Size& target_size,
GrabSnapshotImageCallback callback) {
MakeInitialAsyncCopyRequest(
window, source_rect,
base::BindOnce(&SnapshotAsync::ScaleCopyOutputResult, std::move(callback),
target_size));
}
void GrabWindowSnapshotAura(aura::Window* window,
const gfx::Rect& source_rect,
GrabSnapshotImageCallback callback) {
MakeInitialAsyncCopyRequest(
window, source_rect,
base::BindOnce(&SnapshotAsync::RunCallbackWithCopyOutputResult,
std::move(callback)));
}
#if !BUILDFLAG(IS_WIN)
void GrabWindowSnapshotAndScale(gfx::NativeWindow window,
const gfx::Rect& source_rect,
const gfx::Size& target_size,
GrabSnapshotImageCallback callback) {
GrabWindowSnapshotAndScaleAura(window, source_rect, target_size,
std::move(callback));
}
void GrabWindowSnapshot(gfx::NativeWindow window,
const gfx::Rect& source_rect,
GrabSnapshotImageCallback callback) {
GrabWindowSnapshotAura(window, source_rect, std::move(callback));
}
void GrabViewSnapshot(gfx::NativeView view,
const gfx::Rect& source_rect,
GrabSnapshotImageCallback callback) {
GrabWindowSnapshotAura(view, source_rect, std::move(callback));
}
void GrabLayerSnapshot(ui::Layer* layer,
const gfx::Rect& source_rect,
GrabSnapshotImageCallback callback) {
MakeAsyncCopyRequest(
layer, source_rect,
base::BindOnce(&SnapshotAsync::RunCallbackWithCopyOutputResult,
std::move(callback)));
}
#endif
} // namespace ui
|