summaryrefslogtreecommitdiff
path: root/chromium/ui/snapshot/snapshot_aura.cc
blob: 10328ee7fc30ba271ad4f0d7d18f74ffe5883b75 (plain)
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// Copyright (c) 2012 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_aura.h"

#include <utility>

#include "base/bind.h"
#include "base/callback.h"
#include "base/memory/ptr_util.h"
#include "base/task_runner_util.h"
#include "cc/output/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/dip_util.h"
#include "ui/compositor/layer.h"
#include "ui/snapshot/snapshot_async.h"

namespace ui {

bool GrabWindowSnapshotAura(aura::Window* window,
                            const gfx::Rect& snapshot_bounds,
                            gfx::Image* image) {
  // Not supported in Aura.  Callers should fall back to the async version.
  return false;
}

static void MakeAsyncCopyRequest(
    Layer* layer,
    const gfx::Rect& source_rect,
    cc::CopyOutputRequest::CopyOutputRequestCallback callback) {
  std::unique_ptr<cc::CopyOutputRequest> request =
      cc::CopyOutputRequest::CreateBitmapRequest(std::move(callback));
  request->set_area(source_rect);
  layer->RequestCopyOfOutput(std::move(request));
}

static void FinishedAsyncCopyRequest(
    std::unique_ptr<aura::WindowTracker> tracker,
    const gfx::Rect& source_rect,
    cc::CopyOutputRequest::CopyOutputRequestCallback callback,
    int retry_count,
    std::unique_ptr<cc::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, base::Passed(&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,
    cc::CopyOutputRequest::CopyOutputRequestCallback callback) {
  auto tracker = base::MakeUnique<aura::WindowTracker>();
  tracker->Add(window);
  MakeAsyncCopyRequest(
      window->layer(), source_rect,
      base::BindOnce(&FinishedAsyncCopyRequest, base::Passed(&tracker),
                     source_rect, std::move(callback), 0));
}

void GrabWindowSnapshotAndScaleAsyncAura(
    aura::Window* window,
    const gfx::Rect& source_rect,
    const gfx::Size& target_size,
    scoped_refptr<base::TaskRunner> background_task_runner,
    const GrabWindowSnapshotAsyncCallback& callback) {
  MakeInitialAsyncCopyRequest(
      window, source_rect,
      base::BindOnce(&SnapshotAsync::ScaleCopyOutputResult, callback,
                     target_size, background_task_runner));
}

void GrabWindowSnapshotAsyncAura(
    aura::Window* window,
    const gfx::Rect& source_rect,
    const GrabWindowSnapshotAsyncCallback& callback) {
  MakeInitialAsyncCopyRequest(
      window, source_rect,
      base::BindOnce(&SnapshotAsync::RunCallbackWithCopyOutputResult,
                     callback));
}

#if !defined(OS_WIN)
bool GrabWindowSnapshot(gfx::NativeWindow window,
                        const gfx::Rect& snapshot_bounds,
                        gfx::Image* image) {
  // Not supported in Aura.  Callers should fall back to the async version.
  return false;
}

bool GrabViewSnapshot(gfx::NativeView view,
                      const gfx::Rect& snapshot_bounds,
                      gfx::Image* image) {
  return GrabWindowSnapshot(view, snapshot_bounds, 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) {
  GrabWindowSnapshotAndScaleAsyncAura(window, source_rect, target_size,
                                      background_task_runner, callback);
}

void GrabWindowSnapshotAsync(gfx::NativeWindow window,
                             const gfx::Rect& source_rect,
                             const GrabWindowSnapshotAsyncCallback& callback) {
  GrabWindowSnapshotAsyncAura(window, source_rect, callback);
}

void GrabViewSnapshotAsync(gfx::NativeView view,
                           const gfx::Rect& source_rect,
                           const GrabWindowSnapshotAsyncCallback& callback) {
  GrabWindowSnapshotAsyncAura(view, source_rect, callback);
}

void GrabLayerSnapshotAsync(ui::Layer* layer,
                            const gfx::Rect& source_rect,
                            const GrabLayerSnapshotCallback& callback) {
  MakeAsyncCopyRequest(
      layer, source_rect,
      base::BindOnce(&SnapshotAsync::RunCallbackWithCopyOutputResult,
                     callback));
}

#endif

}  // namespace ui