1 // Copyright 2020 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 "components/paint_preview/browser/paint_preview_compositor_client_impl.h"
6 
7 #include <utility>
8 
9 #include "base/callback.h"
10 
11 namespace paint_preview {
12 
13 namespace {
14 
15 // These methods bind a callback to a task runner. This simplifies situations
16 // where a caller provides a callback which should be passed to |compositor_|
17 // verbatim, but should be run on the caller's task runner rather than
18 // |compositor_task_runner_|.
19 //
20 // Based on the implementation in: chromecast/base/bind_to_task_runner.h
21 
22 template <typename Sig>
23 struct BindToTaskRunnerTrampoline;
24 
25 template <typename... Args>
26 struct BindToTaskRunnerTrampoline<void(Args...)> {
Runpaint_preview::__anone5fcb3470111::BindToTaskRunnerTrampoline27   static void Run(base::TaskRunner* task_runner,
28                   base::OnceCallback<void(Args...)> callback,
29                   Args... args) {
30     task_runner->PostTask(
31         FROM_HERE,
32         base::BindOnce(std::move(callback), std::forward<Args>(args)...));
33   }
34 };
35 
36 template <typename T>
BindToTaskRunner(scoped_refptr<base::TaskRunner> task_runner,base::OnceCallback<T> callback)37 base::OnceCallback<T> BindToTaskRunner(
38     scoped_refptr<base::TaskRunner> task_runner,
39     base::OnceCallback<T> callback) {
40   return base::BindOnce(&BindToTaskRunnerTrampoline<T>::Run,
41                         base::RetainedRef(std::move(task_runner)),
42                         std::move(callback));
43 }
44 
45 }  // namespace
46 
PaintPreviewCompositorClientImpl(scoped_refptr<base::SequencedTaskRunner> compositor_task_runner,base::WeakPtr<PaintPreviewCompositorServiceImpl> service)47 PaintPreviewCompositorClientImpl::PaintPreviewCompositorClientImpl(
48     scoped_refptr<base::SequencedTaskRunner> compositor_task_runner,
49     base::WeakPtr<PaintPreviewCompositorServiceImpl> service)
50     : compositor_task_runner_(compositor_task_runner),
51       default_task_runner_(base::SequencedTaskRunnerHandle::Get()),
52       service_(service),
53       compositor_(new mojo::Remote<mojom::PaintPreviewCompositor>(),
54                   base::OnTaskRunnerDeleter(compositor_task_runner_)) {}
55 
~PaintPreviewCompositorClientImpl()56 PaintPreviewCompositorClientImpl::~PaintPreviewCompositorClientImpl() {
57   DCHECK(default_task_runner_->RunsTasksInCurrentSequence());
58   NotifyServiceOfInvalidation();
59 }
60 
61 const base::Optional<base::UnguessableToken>&
Token() const62 PaintPreviewCompositorClientImpl::Token() const {
63   DCHECK(default_task_runner_->RunsTasksInCurrentSequence());
64   return token_;
65 }
66 
SetDisconnectHandler(base::OnceClosure closure)67 void PaintPreviewCompositorClientImpl::SetDisconnectHandler(
68     base::OnceClosure closure) {
69   DCHECK(default_task_runner_->RunsTasksInCurrentSequence());
70   user_disconnect_closure_ = std::move(closure);
71 }
72 
73 // For the following methods the use of base::Unretained for |compositor_| and
74 // things |compositor_| owns is safe as:
75 // 1. |compositor_| is deleted on the |compositor_task_runner_| after other
76 //    non-delayed tasks in the current sequence are run.
77 // 2. New tasks cannot be created that reference |compositor_| once it is
78 //    deleted as its lifetime is tied to that of the
79 //    PaintPreviewCompositorClient.
80 //
81 // NOTE: This is only safe as no delayed tasks are posted and there are no
82 // cases of base::Unretained(this) or other class members passed as pointers.
83 
BeginSeparatedFrameComposite(mojom::PaintPreviewBeginCompositeRequestPtr request,mojom::PaintPreviewCompositor::BeginSeparatedFrameCompositeCallback callback)84 void PaintPreviewCompositorClientImpl::BeginSeparatedFrameComposite(
85     mojom::PaintPreviewBeginCompositeRequestPtr request,
86     mojom::PaintPreviewCompositor::BeginSeparatedFrameCompositeCallback
87         callback) {
88   DCHECK(default_task_runner_->RunsTasksInCurrentSequence());
89   compositor_task_runner_->PostTask(
90       FROM_HERE,
91       base::BindOnce(
92           &mojom::PaintPreviewCompositor::BeginSeparatedFrameComposite,
93           base::Unretained(compositor_.get()->get()), std::move(request),
94           BindToTaskRunner(default_task_runner_, std::move(callback))));
95 }
96 
BitmapForSeparatedFrame(const base::UnguessableToken & frame_guid,const gfx::Rect & clip_rect,float scale_factor,mojom::PaintPreviewCompositor::BitmapForSeparatedFrameCallback callback)97 void PaintPreviewCompositorClientImpl::BitmapForSeparatedFrame(
98     const base::UnguessableToken& frame_guid,
99     const gfx::Rect& clip_rect,
100     float scale_factor,
101     mojom::PaintPreviewCompositor::BitmapForSeparatedFrameCallback callback) {
102   DCHECK(default_task_runner_->RunsTasksInCurrentSequence());
103 
104   auto validate_bitmap = base::BindOnce(
105       [](mojom::PaintPreviewCompositor::BitmapForSeparatedFrameCallback
106              callback,
107          mojom::PaintPreviewCompositor::BitmapStatus status,
108          const SkBitmap& bitmap) {
109         // The paint preview service should be sending us N32 32bpp bitmaps in
110         // reply, otherwise this can lead to out-of-bounds mistakes when
111         // transferring the pixels out of the bitmap into other buffers.
112         CHECK_EQ(bitmap.colorType(), kN32_SkColorType);
113         std::move(callback).Run(status, bitmap);
114       },
115       BindToTaskRunner(default_task_runner_, std::move(callback)));
116 
117   compositor_task_runner_->PostTask(
118       FROM_HERE,
119       base::BindOnce(&mojom::PaintPreviewCompositor::BitmapForSeparatedFrame,
120                      base::Unretained(compositor_.get()->get()), frame_guid,
121                      clip_rect, scale_factor, std::move(validate_bitmap)));
122 }
123 
BeginMainFrameComposite(mojom::PaintPreviewBeginCompositeRequestPtr request,mojom::PaintPreviewCompositor::BeginMainFrameCompositeCallback callback)124 void PaintPreviewCompositorClientImpl::BeginMainFrameComposite(
125     mojom::PaintPreviewBeginCompositeRequestPtr request,
126     mojom::PaintPreviewCompositor::BeginMainFrameCompositeCallback callback) {
127   DCHECK(default_task_runner_->RunsTasksInCurrentSequence());
128   compositor_task_runner_->PostTask(
129       FROM_HERE,
130       base::BindOnce(
131           &mojom::PaintPreviewCompositor::BeginMainFrameComposite,
132           base::Unretained(compositor_.get()->get()), std::move(request),
133           BindToTaskRunner(default_task_runner_, std::move(callback))));
134 }
135 
BitmapForMainFrame(const gfx::Rect & clip_rect,float scale_factor,mojom::PaintPreviewCompositor::BitmapForMainFrameCallback callback)136 void PaintPreviewCompositorClientImpl::BitmapForMainFrame(
137     const gfx::Rect& clip_rect,
138     float scale_factor,
139     mojom::PaintPreviewCompositor::BitmapForMainFrameCallback callback) {
140   DCHECK(default_task_runner_->RunsTasksInCurrentSequence());
141   compositor_task_runner_->PostTask(
142       FROM_HERE,
143       base::BindOnce(
144           &mojom::PaintPreviewCompositor::BitmapForMainFrame,
145           base::Unretained(compositor_.get()->get()), clip_rect, scale_factor,
146           BindToTaskRunner(default_task_runner_, std::move(callback))));
147 }
148 
SetRootFrameUrl(const GURL & url)149 void PaintPreviewCompositorClientImpl::SetRootFrameUrl(const GURL& url) {
150   DCHECK(default_task_runner_->RunsTasksInCurrentSequence());
151   compositor_task_runner_->PostTask(
152       FROM_HERE,
153       base::BindOnce(&mojom::PaintPreviewCompositor::SetRootFrameUrl,
154                      base::Unretained(compositor_.get()->get()), url));
155 }
156 
IsBoundAndConnected(base::OnceCallback<void (bool)> callback)157 void PaintPreviewCompositorClientImpl::IsBoundAndConnected(
158     base::OnceCallback<void(bool)> callback) {
159   DCHECK(default_task_runner_->RunsTasksInCurrentSequence());
160   compositor_task_runner_->PostTask(
161       FROM_HERE, base::BindOnce(
162                      [](mojo::Remote<mojom::PaintPreviewCompositor>* compositor,
163                         scoped_refptr<base::SequencedTaskRunner> task_runner,
164                         base::OnceCallback<void(bool)> callback) {
165                        task_runner->PostTask(
166                            FROM_HERE,
167                            base::BindOnce(std::move(callback),
168                                           compositor->is_bound() &&
169                                               compositor->is_connected()));
170                      },
171                      base::Unretained(compositor_.get()), default_task_runner_,
172                      std::move(callback)));
173 }
174 
175 mojo::PendingReceiver<mojom::PaintPreviewCompositor>
BindNewPipeAndPassReceiver()176 PaintPreviewCompositorClientImpl::BindNewPipeAndPassReceiver() {
177   DCHECK(compositor_task_runner_->RunsTasksInCurrentSequence());
178   return compositor_->BindNewPipeAndPassReceiver();
179 }
180 
181 PaintPreviewCompositorClientImpl::OnCompositorCreatedCallback
BuildCompositorCreatedCallback(base::OnceClosure user_closure,OnCompositorCreatedCallback service_callback)182 PaintPreviewCompositorClientImpl::BuildCompositorCreatedCallback(
183     base::OnceClosure user_closure,
184     OnCompositorCreatedCallback service_callback) {
185   DCHECK(default_task_runner_->RunsTasksInCurrentSequence());
186   return BindToTaskRunner(
187       default_task_runner_,
188       base::BindOnce(&PaintPreviewCompositorClientImpl::OnCompositorCreated,
189                      weak_ptr_factory_.GetWeakPtr(), std::move(user_closure),
190                      std::move(service_callback)));
191 }
192 
OnCompositorCreated(base::OnceClosure user_closure,OnCompositorCreatedCallback service_callback,const base::UnguessableToken & token)193 void PaintPreviewCompositorClientImpl::OnCompositorCreated(
194     base::OnceClosure user_closure,
195     OnCompositorCreatedCallback service_callback,
196     const base::UnguessableToken& token) {
197   DCHECK(default_task_runner_->RunsTasksInCurrentSequence());
198   token_ = token;
199   std::move(user_closure).Run();
200   std::move(service_callback).Run(token);
201   compositor_task_runner_->PostTask(
202       FROM_HERE,
203       base::BindOnce(
204           &mojo::Remote<mojom::PaintPreviewCompositor>::set_disconnect_handler,
205           base::Unretained(compositor_.get()),
206           BindToTaskRunner(
207               default_task_runner_,
208               base::BindOnce(
209                   &PaintPreviewCompositorClientImpl::DisconnectHandler,
210                   weak_ptr_factory_.GetWeakPtr()))));
211 }
212 
NotifyServiceOfInvalidation()213 void PaintPreviewCompositorClientImpl::NotifyServiceOfInvalidation() {
214   DCHECK(default_task_runner_->RunsTasksInCurrentSequence());
215   if (service_ && token_.has_value())
216     service_->MarkCompositorAsDeleted(token_.value());
217 }
218 
DisconnectHandler()219 void PaintPreviewCompositorClientImpl::DisconnectHandler() {
220   DCHECK(default_task_runner_->RunsTasksInCurrentSequence());
221   if (user_disconnect_closure_)
222     std::move(user_disconnect_closure_).Run();
223   NotifyServiceOfInvalidation();
224   compositor_task_runner_->PostTask(
225       FROM_HERE,
226       base::BindOnce(&mojo::Remote<mojom::PaintPreviewCompositor>::reset,
227                      base::Unretained(compositor_.get())));
228 }
229 
230 }  // namespace paint_preview
231