blob: ea2a13258078017891a159cafd0c67150d318051 [file] [log] [blame]
Chinmay Garde41869f62021-12-28 15:19:35 -08001// Copyright 2013 The Flutter 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
Jim Grahamee6969d2023-03-20 19:34:48 -07005#include "flutter/display_list/dl_builder.h"
Chinmay Garde41869f62021-12-28 15:19:35 -08006
JsouLiangac817502022-08-11 15:48:40 +08007#include "flutter/display_list/display_list.h"
Jim Grahamee6969d2023-03-20 19:34:48 -07008#include "flutter/display_list/dl_blend_mode.h"
9#include "flutter/display_list/dl_op_records.h"
10#include "flutter/display_list/effects/dl_color_source.h"
11#include "flutter/display_list/utils/dl_bounds_accumulator.h"
Brandon DeRosier716bb912023-01-09 20:25:59 -080012#include "fml/logging.h"
Chinmay Garde41869f62021-12-28 15:19:35 -080013
14namespace flutter {
15
16#define DL_BUILDER_PAGE 4096
17
18// CopyV(dst, src,n, src,n, ...) copies any number of typed srcs into dst.
19static void CopyV(void* dst) {}
20
21template <typename S, typename... Rest>
22static void CopyV(void* dst, const S* src, int n, Rest&&... rest) {
23 FML_DCHECK(((uintptr_t)dst & (alignof(S) - 1)) == 0)
24 << "Expected " << dst << " to be aligned for at least " << alignof(S)
25 << " bytes.";
Kevin Lubick2722c542023-01-18 12:58:59 -050026 // If n is 0, there is nothing to copy into dst from src.
27 if (n > 0) {
28 memcpy(dst, src, n * sizeof(S));
29 dst = reinterpret_cast<void*>(reinterpret_cast<uint8_t*>(dst) +
30 n * sizeof(S));
31 }
32 // Repeat for the next items, if any
33 CopyV(dst, std::forward<Rest>(rest)...);
Chinmay Garde41869f62021-12-28 15:19:35 -080034}
35
Kevin Lubick4f0cdcd2023-01-09 19:22:33 -060036static constexpr inline bool is_power_of_two(int value) {
37 return (value & (value - 1)) == 0;
38}
39
Chinmay Garde41869f62021-12-28 15:19:35 -080040template <typename T, typename... Args>
Jim Graham147ac7d2022-12-22 02:16:25 -080041void* DisplayListBuilder::Push(size_t pod, int render_op_inc, Args&&... args) {
Chinmay Garde41869f62021-12-28 15:19:35 -080042 size_t size = SkAlignPtr(sizeof(T) + pod);
43 FML_DCHECK(size < (1 << 24));
44 if (used_ + size > allocated_) {
Kevin Lubick4f0cdcd2023-01-09 19:22:33 -060045 static_assert(is_power_of_two(DL_BUILDER_PAGE),
Chinmay Garde41869f62021-12-28 15:19:35 -080046 "This math needs updating for non-pow2.");
47 // Next greater multiple of DL_BUILDER_PAGE.
48 allocated_ = (used_ + size + DL_BUILDER_PAGE) & ~(DL_BUILDER_PAGE - 1);
49 storage_.realloc(allocated_);
50 FML_DCHECK(storage_.get());
51 memset(storage_.get() + used_, 0, allocated_ - used_);
52 }
53 FML_DCHECK(used_ + size <= allocated_);
54 auto op = reinterpret_cast<T*>(storage_.get() + used_);
55 used_ += size;
56 new (op) T{std::forward<Args>(args)...};
57 op->type = T::kType;
58 op->size = size;
Jim Graham147ac7d2022-12-22 02:16:25 -080059 render_op_count_ += render_op_inc;
60 op_index_++;
Chinmay Garde41869f62021-12-28 15:19:35 -080061 return op + 1;
62}
63
64sk_sp<DisplayList> DisplayListBuilder::Build() {
65 while (layer_stack_.size() > 1) {
66 restore();
67 }
Jim Grahamff04d2f2023-05-25 14:56:25 -070068
Chinmay Garde41869f62021-12-28 15:19:35 -080069 size_t bytes = used_;
Jim Graham147ac7d2022-12-22 02:16:25 -080070 int count = render_op_count_;
Chinmay Garde41869f62021-12-28 15:19:35 -080071 size_t nested_bytes = nested_bytes_;
72 int nested_count = nested_op_count_;
Zachary Anderson886a14e2023-07-15 07:14:10 -070073 bool compatible = layer_stack_.back().is_group_opacity_compatible();
Jim Grahamff04d2f2023-05-25 14:56:25 -070074 bool is_safe = is_ui_thread_safe_;
75
Jim Graham147ac7d2022-12-22 02:16:25 -080076 used_ = allocated_ = render_op_count_ = op_index_ = 0;
Chinmay Garde41869f62021-12-28 15:19:35 -080077 nested_bytes_ = nested_op_count_ = 0;
78 storage_.realloc(bytes);
Jim Grahamff04d2f2023-05-25 14:56:25 -070079 layer_stack_.pop_back();
80 layer_stack_.emplace_back();
81 tracker_.reset();
82 current_ = DlPaint();
83
Zachary Anderson886a14e2023-07-15 07:14:10 -070084 return sk_sp<DisplayList>(
85 new DisplayList(std::move(storage_), bytes, count, nested_bytes,
86 nested_count, bounds(), compatible, is_safe, rtree()));
Chinmay Garde41869f62021-12-28 15:19:35 -080087}
88
ColdPaleLight948699b2022-12-15 19:52:52 +080089DisplayListBuilder::DisplayListBuilder(const SkRect& cull_rect,
ColdPaleLight6b7ed782022-12-20 18:05:40 +080090 bool prepare_rtree)
91 : tracker_(cull_rect, SkMatrix::I()) {
ColdPaleLight948699b2022-12-15 19:52:52 +080092 if (prepare_rtree) {
93 accumulator_ = std::make_unique<RTreeBoundsAccumulator>();
94 } else {
95 accumulator_ = std::make_unique<RectBoundsAccumulator>();
96 }
97
ColdPaleLight6b7ed782022-12-20 18:05:40 +080098 layer_stack_.emplace_back();
Chinmay Garde41869f62021-12-28 15:19:35 -080099 current_layer_ = &layer_stack_.back();
100}
101
102DisplayListBuilder::~DisplayListBuilder() {
103 uint8_t* ptr = storage_.get();
104 if (ptr) {
105 DisplayList::DisposeOps(ptr, ptr + used_);
106 }
107}
108
Jim Graham0d5b7802023-02-23 22:09:35 -0800109SkISize DisplayListBuilder::GetBaseLayerSize() const {
110 return tracker_.base_device_cull_rect().roundOut().size();
111}
112
113SkImageInfo DisplayListBuilder::GetImageInfo() const {
114 SkISize size = GetBaseLayerSize();
115 return SkImageInfo::MakeUnknown(size.width(), size.height());
116}
117
Chinmay Garde41869f62021-12-28 15:19:35 -0800118void DisplayListBuilder::onSetAntiAlias(bool aa) {
Jim Grahamd45b9112022-04-29 13:59:06 -0700119 current_.setAntiAlias(aa);
120 Push<SetAntiAliasOp>(0, 0, aa);
Chinmay Garde41869f62021-12-28 15:19:35 -0800121}
122void DisplayListBuilder::onSetDither(bool dither) {
Jim Grahamd45b9112022-04-29 13:59:06 -0700123 current_.setDither(dither);
124 Push<SetDitherOp>(0, 0, dither);
Chinmay Garde41869f62021-12-28 15:19:35 -0800125}
126void DisplayListBuilder::onSetInvertColors(bool invert) {
Jim Grahamd45b9112022-04-29 13:59:06 -0700127 current_.setInvertColors(invert);
128 Push<SetInvertColorsOp>(0, 0, invert);
Chinmay Garde41869f62021-12-28 15:19:35 -0800129 UpdateCurrentOpacityCompatibility();
130}
Jim Grahamd45b9112022-04-29 13:59:06 -0700131void DisplayListBuilder::onSetStrokeCap(DlStrokeCap cap) {
132 current_.setStrokeCap(cap);
133 Push<SetStrokeCapOp>(0, 0, cap);
Chinmay Garde41869f62021-12-28 15:19:35 -0800134}
Jim Grahamd45b9112022-04-29 13:59:06 -0700135void DisplayListBuilder::onSetStrokeJoin(DlStrokeJoin join) {
136 current_.setStrokeJoin(join);
137 Push<SetStrokeJoinOp>(0, 0, join);
Chinmay Garde41869f62021-12-28 15:19:35 -0800138}
Jim Grahamff04d2f2023-05-25 14:56:25 -0700139void DisplayListBuilder::onSetDrawStyle(DlDrawStyle style) {
Jim Grahamd45b9112022-04-29 13:59:06 -0700140 current_.setDrawStyle(style);
141 Push<SetStyleOp>(0, 0, style);
Chinmay Garde41869f62021-12-28 15:19:35 -0800142}
Jim Grahamd45b9112022-04-29 13:59:06 -0700143void DisplayListBuilder::onSetStrokeWidth(float width) {
144 current_.setStrokeWidth(width);
145 Push<SetStrokeWidthOp>(0, 0, width);
Chinmay Garde41869f62021-12-28 15:19:35 -0800146}
Jim Grahamd45b9112022-04-29 13:59:06 -0700147void DisplayListBuilder::onSetStrokeMiter(float limit) {
148 current_.setStrokeMiter(limit);
149 Push<SetStrokeMiterOp>(0, 0, limit);
Chinmay Garde41869f62021-12-28 15:19:35 -0800150}
Jim Grahamd45b9112022-04-29 13:59:06 -0700151void DisplayListBuilder::onSetColor(DlColor color) {
152 current_.setColor(color);
153 Push<SetColorOp>(0, 0, color);
Chinmay Garde41869f62021-12-28 15:19:35 -0800154}
JsouLiang1aa52552022-03-20 05:10:07 +0800155void DisplayListBuilder::onSetBlendMode(DlBlendMode mode) {
Jim Grahamd45b9112022-04-29 13:59:06 -0700156 current_.setBlendMode(mode);
157 Push<SetBlendModeOp>(0, 0, mode);
Chinmay Garde41869f62021-12-28 15:19:35 -0800158 UpdateCurrentOpacityCompatibility();
159}
ColdPaleLight948699b2022-12-15 19:52:52 +0800160
Jim Grahamdc22c4c2022-03-15 16:55:04 -0700161void DisplayListBuilder::onSetColorSource(const DlColorSource* source) {
162 if (source == nullptr) {
Jim Grahamd45b9112022-04-29 13:59:06 -0700163 current_.setColorSource(nullptr);
Jim Grahamdc22c4c2022-03-15 16:55:04 -0700164 Push<ClearColorSourceOp>(0, 0);
165 } else {
Jim Grahamd45b9112022-04-29 13:59:06 -0700166 current_.setColorSource(source->shared());
Jim Graham35833e72023-04-17 16:47:20 -0700167 is_ui_thread_safe_ = is_ui_thread_safe_ && source->isUIThreadSafe();
Jim Grahamdc22c4c2022-03-15 16:55:04 -0700168 switch (source->type()) {
169 case DlColorSourceType::kColor: {
170 const DlColorColorSource* color_source = source->asColor();
Jim Grahamd45b9112022-04-29 13:59:06 -0700171 current_.setColorSource(nullptr);
Jim Grahamdc22c4c2022-03-15 16:55:04 -0700172 setColor(color_source->color());
173 break;
174 }
175 case DlColorSourceType::kImage: {
176 const DlImageColorSource* image_source = source->asImage();
177 FML_DCHECK(image_source);
178 Push<SetImageColorSourceOp>(0, 0, image_source);
179 break;
180 }
181 case DlColorSourceType::kLinearGradient: {
182 const DlLinearGradientColorSource* linear = source->asLinearGradient();
183 FML_DCHECK(linear);
184 void* pod = Push<SetPodColorSourceOp>(linear->size(), 0);
185 new (pod) DlLinearGradientColorSource(linear);
186 break;
187 }
188 case DlColorSourceType::kRadialGradient: {
189 const DlRadialGradientColorSource* radial = source->asRadialGradient();
190 FML_DCHECK(radial);
191 void* pod = Push<SetPodColorSourceOp>(radial->size(), 0);
192 new (pod) DlRadialGradientColorSource(radial);
193 break;
194 }
195 case DlColorSourceType::kConicalGradient: {
196 const DlConicalGradientColorSource* conical =
197 source->asConicalGradient();
198 FML_DCHECK(conical);
199 void* pod = Push<SetPodColorSourceOp>(conical->size(), 0);
200 new (pod) DlConicalGradientColorSource(conical);
201 break;
202 }
203 case DlColorSourceType::kSweepGradient: {
204 const DlSweepGradientColorSource* sweep = source->asSweepGradient();
205 FML_DCHECK(sweep);
206 void* pod = Push<SetPodColorSourceOp>(sweep->size(), 0);
207 new (pod) DlSweepGradientColorSource(sweep);
208 break;
209 }
Dan Field4fbe41d2022-08-18 16:12:11 -0700210 case DlColorSourceType::kRuntimeEffect: {
211 const DlRuntimeEffectColorSource* effect = source->asRuntimeEffect();
212 FML_DCHECK(effect);
213 Push<SetRuntimeEffectColorSourceOp>(0, 0, effect);
214 break;
215 }
Brandon DeRosier716bb912023-01-09 20:25:59 -0800216#ifdef IMPELLER_ENABLE_3D
217 case DlColorSourceType::kScene: {
218 const DlSceneColorSource* scene = source->asScene();
219 FML_DCHECK(scene);
220 Push<SetSceneColorSourceOp>(0, 0, scene);
221 break;
222 }
223#endif // IMPELLER_ENABLE_3D
Jim Grahamdc22c4c2022-03-15 16:55:04 -0700224 }
225 }
Chinmay Garde41869f62021-12-28 15:19:35 -0800226}
Jim Graham3f2750c2022-03-21 13:55:08 -0700227void DisplayListBuilder::onSetImageFilter(const DlImageFilter* filter) {
228 if (filter == nullptr) {
Jim Grahamd45b9112022-04-29 13:59:06 -0700229 current_.setImageFilter(nullptr);
Jim Graham3f2750c2022-03-21 13:55:08 -0700230 Push<ClearImageFilterOp>(0, 0);
231 } else {
Jim Grahamd45b9112022-04-29 13:59:06 -0700232 current_.setImageFilter(filter->shared());
Jim Graham3f2750c2022-03-21 13:55:08 -0700233 switch (filter->type()) {
234 case DlImageFilterType::kBlur: {
235 const DlBlurImageFilter* blur_filter = filter->asBlur();
236 FML_DCHECK(blur_filter);
237 void* pod = Push<SetPodImageFilterOp>(blur_filter->size(), 0);
238 new (pod) DlBlurImageFilter(blur_filter);
239 break;
240 }
fzyzcjy9b3117a2022-04-05 04:01:02 +0800241 case DlImageFilterType::kDilate: {
242 const DlDilateImageFilter* dilate_filter = filter->asDilate();
243 FML_DCHECK(dilate_filter);
244 void* pod = Push<SetPodImageFilterOp>(dilate_filter->size(), 0);
245 new (pod) DlDilateImageFilter(dilate_filter);
246 break;
247 }
248 case DlImageFilterType::kErode: {
249 const DlErodeImageFilter* erode_filter = filter->asErode();
250 FML_DCHECK(erode_filter);
251 void* pod = Push<SetPodImageFilterOp>(erode_filter->size(), 0);
252 new (pod) DlErodeImageFilter(erode_filter);
253 break;
254 }
Jim Graham3f2750c2022-03-21 13:55:08 -0700255 case DlImageFilterType::kMatrix: {
256 const DlMatrixImageFilter* matrix_filter = filter->asMatrix();
257 FML_DCHECK(matrix_filter);
258 void* pod = Push<SetPodImageFilterOp>(matrix_filter->size(), 0);
259 new (pod) DlMatrixImageFilter(matrix_filter);
260 break;
261 }
Jim Graham25514ec2023-03-19 15:59:17 -0700262 case DlImageFilterType::kCompose:
263 case DlImageFilterType::kLocalMatrix:
Jim Graham3f2750c2022-03-21 13:55:08 -0700264 case DlImageFilterType::kColorFilter: {
265 Push<SetSharedImageFilterOp>(0, 0, filter);
266 break;
267 }
Jim Graham3f2750c2022-03-21 13:55:08 -0700268 }
269 }
Chinmay Garde41869f62021-12-28 15:19:35 -0800270}
Jim Graham70c11732022-02-17 11:19:11 -0800271void DisplayListBuilder::onSetColorFilter(const DlColorFilter* filter) {
272 if (filter == nullptr) {
Jim Grahamd45b9112022-04-29 13:59:06 -0700273 current_.setColorFilter(nullptr);
Jim Graham70c11732022-02-17 11:19:11 -0800274 Push<ClearColorFilterOp>(0, 0);
275 } else {
Jim Grahamd45b9112022-04-29 13:59:06 -0700276 current_.setColorFilter(filter->shared());
Jim Graham70c11732022-02-17 11:19:11 -0800277 switch (filter->type()) {
Jim Grahameef4f8e2022-02-25 11:51:02 -0800278 case DlColorFilterType::kBlend: {
Jim Graham70c11732022-02-17 11:19:11 -0800279 const DlBlendColorFilter* blend_filter = filter->asBlend();
280 FML_DCHECK(blend_filter);
Jim Grahamdc22c4c2022-03-15 16:55:04 -0700281 void* pod = Push<SetPodColorFilterOp>(blend_filter->size(), 0);
Jim Graham70c11732022-02-17 11:19:11 -0800282 new (pod) DlBlendColorFilter(blend_filter);
283 break;
284 }
Jim Grahameef4f8e2022-02-25 11:51:02 -0800285 case DlColorFilterType::kMatrix: {
Jim Graham70c11732022-02-17 11:19:11 -0800286 const DlMatrixColorFilter* matrix_filter = filter->asMatrix();
287 FML_DCHECK(matrix_filter);
Jim Grahamdc22c4c2022-03-15 16:55:04 -0700288 void* pod = Push<SetPodColorFilterOp>(matrix_filter->size(), 0);
Jim Graham70c11732022-02-17 11:19:11 -0800289 new (pod) DlMatrixColorFilter(matrix_filter);
290 break;
291 }
Jim Grahameef4f8e2022-02-25 11:51:02 -0800292 case DlColorFilterType::kSrgbToLinearGamma: {
Jim Grahamdc22c4c2022-03-15 16:55:04 -0700293 void* pod = Push<SetPodColorFilterOp>(filter->size(), 0);
Jim Graham70c11732022-02-17 11:19:11 -0800294 new (pod) DlSrgbToLinearGammaColorFilter();
295 break;
296 }
Jim Grahameef4f8e2022-02-25 11:51:02 -0800297 case DlColorFilterType::kLinearToSrgbGamma: {
Jim Grahamdc22c4c2022-03-15 16:55:04 -0700298 void* pod = Push<SetPodColorFilterOp>(filter->size(), 0);
Jim Graham70c11732022-02-17 11:19:11 -0800299 new (pod) DlLinearToSrgbGammaColorFilter();
300 break;
301 }
Jim Graham70c11732022-02-17 11:19:11 -0800302 }
303 }
Chinmay Garde41869f62021-12-28 15:19:35 -0800304 UpdateCurrentOpacityCompatibility();
305}
JsouLiangb8ca6a52022-05-12 09:45:30 +0800306void DisplayListBuilder::onSetPathEffect(const DlPathEffect* effect) {
307 if (effect == nullptr) {
308 current_.setPathEffect(nullptr);
309 Push<ClearPathEffectOp>(0, 0);
310 } else {
311 current_.setPathEffect(effect->shared());
312 switch (effect->type()) {
313 case DlPathEffectType::kDash: {
314 const DlDashPathEffect* dash_effect = effect->asDash();
315 void* pod = Push<SetPodPathEffectOp>(dash_effect->size(), 0);
316 new (pod) DlDashPathEffect(dash_effect);
317 break;
318 }
JsouLiangb8ca6a52022-05-12 09:45:30 +0800319 }
320 }
Chinmay Garde41869f62021-12-28 15:19:35 -0800321}
Jim Grahamd1fbb632022-02-18 09:19:09 -0800322void DisplayListBuilder::onSetMaskFilter(const DlMaskFilter* filter) {
323 if (filter == nullptr) {
Jim Grahamd45b9112022-04-29 13:59:06 -0700324 current_.setMaskFilter(nullptr);
Jim Grahamd1fbb632022-02-18 09:19:09 -0800325 Push<ClearMaskFilterOp>(0, 0);
326 } else {
Jim Grahamd45b9112022-04-29 13:59:06 -0700327 current_.setMaskFilter(filter->shared());
Jim Grahamd1fbb632022-02-18 09:19:09 -0800328 switch (filter->type()) {
Jim Grahameef4f8e2022-02-25 11:51:02 -0800329 case DlMaskFilterType::kBlur: {
Jim Grahamd1fbb632022-02-18 09:19:09 -0800330 const DlBlurMaskFilter* blur_filter = filter->asBlur();
331 FML_DCHECK(blur_filter);
Jim Grahamdc22c4c2022-03-15 16:55:04 -0700332 void* pod = Push<SetPodMaskFilterOp>(blur_filter->size(), 0);
Jim Grahamd1fbb632022-02-18 09:19:09 -0800333 new (pod) DlBlurMaskFilter(blur_filter);
334 break;
335 }
Jim Grahamd1fbb632022-02-18 09:19:09 -0800336 }
Chinmay Garde41869f62021-12-28 15:19:35 -0800337 }
338}
339
Jim Grahamde9093d2023-02-24 17:42:20 -0800340void DisplayListBuilder::SetAttributesFromPaint(
Jim Grahame8812252022-04-22 15:54:03 -0700341 const DlPaint& paint,
342 const DisplayListAttributeFlags flags) {
343 if (flags.applies_anti_alias()) {
344 setAntiAlias(paint.isAntiAlias());
345 }
346 if (flags.applies_dither()) {
347 setDither(paint.isDither());
348 }
349 if (flags.applies_alpha_or_color()) {
350 setColor(paint.getColor().argb);
351 }
352 if (flags.applies_blend()) {
353 setBlendMode(paint.getBlendMode());
354 }
355 if (flags.applies_style()) {
Jim Grahamff04d2f2023-05-25 14:56:25 -0700356 setDrawStyle(paint.getDrawStyle());
Jim Grahame8812252022-04-22 15:54:03 -0700357 }
Jim Grahamd45b9112022-04-29 13:59:06 -0700358 if (flags.is_stroked(paint.getDrawStyle())) {
Jim Grahame8812252022-04-22 15:54:03 -0700359 setStrokeWidth(paint.getStrokeWidth());
360 setStrokeMiter(paint.getStrokeMiter());
Jim Grahamd45b9112022-04-29 13:59:06 -0700361 setStrokeCap(paint.getStrokeCap());
362 setStrokeJoin(paint.getStrokeJoin());
Jim Grahame8812252022-04-22 15:54:03 -0700363 }
364 if (flags.applies_shader()) {
365 setColorSource(paint.getColorSource().get());
366 }
367 if (flags.applies_color_filter()) {
368 setInvertColors(paint.isInvertColors());
369 setColorFilter(paint.getColorFilter().get());
370 }
371 if (flags.applies_image_filter()) {
372 setImageFilter(paint.getImageFilter().get());
373 }
Jason Simmons623d2d92022-10-10 15:29:19 -0700374 if (flags.applies_path_effect()) {
375 setPathEffect(paint.getPathEffect().get());
376 }
Jim Grahame8812252022-04-22 15:54:03 -0700377 if (flags.applies_mask_filter()) {
378 setMaskFilter(paint.getMaskFilter().get());
379 }
380}
381
JsouLiangac817502022-08-11 15:48:40 +0800382void DisplayListBuilder::checkForDeferredSave() {
383 if (current_layer_->has_deferred_save_op_) {
Jim Graham147ac7d2022-12-22 02:16:25 -0800384 size_t save_offset_ = used_;
JsouLiangac817502022-08-11 15:48:40 +0800385 Push<SaveOp>(0, 1);
Jim Graham147ac7d2022-12-22 02:16:25 -0800386 current_layer_->save_offset_ = save_offset_;
JsouLiangac817502022-08-11 15:48:40 +0800387 current_layer_->has_deferred_save_op_ = false;
388 }
389}
390
Jim Graham0d5b7802023-02-23 22:09:35 -0800391void DisplayListBuilder::Save() {
ColdPaleLight6b7ed782022-12-20 18:05:40 +0800392 layer_stack_.emplace_back();
Chinmay Garde41869f62021-12-28 15:19:35 -0800393 current_layer_ = &layer_stack_.back();
JsouLiangac817502022-08-11 15:48:40 +0800394 current_layer_->has_deferred_save_op_ = true;
ColdPaleLight6b7ed782022-12-20 18:05:40 +0800395 tracker_.save();
ColdPaleLight948699b2022-12-15 19:52:52 +0800396 accumulator()->save();
Chinmay Garde41869f62021-12-28 15:19:35 -0800397}
JsouLiangac817502022-08-11 15:48:40 +0800398
Jim Graham0d5b7802023-02-23 22:09:35 -0800399void DisplayListBuilder::Restore() {
Chinmay Garde41869f62021-12-28 15:19:35 -0800400 if (layer_stack_.size() > 1) {
Jim Graham147ac7d2022-12-22 02:16:25 -0800401 SaveOpBase* op = reinterpret_cast<SaveOpBase*>(
402 storage_.get() + current_layer_->save_offset());
JsouLiangac817502022-08-11 15:48:40 +0800403 if (!current_layer_->has_deferred_save_op_) {
Jim Graham147ac7d2022-12-22 02:16:25 -0800404 op->restore_index = op_index_;
JsouLiangac817502022-08-11 15:48:40 +0800405 Push<RestoreOp>(0, 1);
406 }
Chinmay Garde41869f62021-12-28 15:19:35 -0800407 // Grab the current layer info before we push the restore
408 // on the stack.
409 LayerInfo layer_info = layer_stack_.back();
ColdPaleLight948699b2022-12-15 19:52:52 +0800410
ColdPaleLight6b7ed782022-12-20 18:05:40 +0800411 tracker_.restore();
Chinmay Garde41869f62021-12-28 15:19:35 -0800412 layer_stack_.pop_back();
413 current_layer_ = &layer_stack_.back();
ColdPaleLight948699b2022-12-15 19:52:52 +0800414 bool is_unbounded = layer_info.is_unbounded();
415
416 // Before we pop_back we will get the current layer bounds from the
417 // current accumulator and adjust it as required based on the filter.
418 std::shared_ptr<const DlImageFilter> filter = layer_info.filter();
419 if (filter) {
ColdPaleLight6b7ed782022-12-20 18:05:40 +0800420 const SkRect clip = tracker_.device_cull_rect();
ColdPaleLight948699b2022-12-15 19:52:52 +0800421 if (!accumulator()->restore(
Jim Graham0d5b7802023-02-23 22:09:35 -0800422 [filter = filter, matrix = GetTransform()](const SkRect& input,
ColdPaleLight948699b2022-12-15 19:52:52 +0800423 SkRect& output) {
424 SkIRect output_bounds;
425 bool ret = filter->map_device_bounds(input.roundOut(), matrix,
426 output_bounds);
427 output.set(output_bounds);
428 return ret;
429 },
ColdPaleLight6b7ed782022-12-20 18:05:40 +0800430 &clip)) {
ColdPaleLight948699b2022-12-15 19:52:52 +0800431 is_unbounded = true;
432 }
433 } else {
434 accumulator()->restore();
435 }
436
437 if (is_unbounded) {
438 AccumulateUnbounded();
439 }
440
441 if (layer_info.has_layer()) {
Jim Graham147ac7d2022-12-22 02:16:25 -0800442 // Layers are never deferred for now, we need to update the
443 // following code if we ever do saveLayer culling...
444 FML_DCHECK(!layer_info.has_deferred_save_op_);
Jim Grahamdbe4cc82022-02-04 00:45:10 -0800445 if (layer_info.is_group_opacity_compatible()) {
446 // We are now going to go back and modify the matching saveLayer
447 // call to add the option indicating it can distribute an opacity
448 // value to its children.
449 //
450 // Note that this operation cannot and does not change the size
451 // or structure of the SaveLayerOp record. It only sets an option
452 // flag on an existing field.
453 //
454 // Note that these kinds of modification operations on data already
455 // in the DisplayList are only allowed *during* the build phase.
456 // Once built, the DisplayList records must remain read only to
457 // ensure consistency of rendering and |Equals()| behavior.
Jim Grahamdbe4cc82022-02-04 00:45:10 -0800458 op->options = op->options.with_can_distribute_opacity();
459 }
460 } else {
Chinmay Garde41869f62021-12-28 15:19:35 -0800461 // For regular save() ops there was no protecting layer so we have to
462 // accumulate the values into the enclosing layer.
ColdPaleLight948699b2022-12-15 19:52:52 +0800463 if (layer_info.cannot_inherit_opacity()) {
Chinmay Garde41869f62021-12-28 15:19:35 -0800464 current_layer_->mark_incompatible();
ColdPaleLight948699b2022-12-15 19:52:52 +0800465 } else if (layer_info.has_compatible_op()) {
Chinmay Garde41869f62021-12-28 15:19:35 -0800466 current_layer_->add_compatible_op();
467 }
468 }
469 }
470}
Jim Graham0d5b7802023-02-23 22:09:35 -0800471void DisplayListBuilder::RestoreToCount(int restore_count) {
472 FML_DCHECK(restore_count <= GetSaveCount());
473 while (restore_count < GetSaveCount() && GetSaveCount() > 1) {
Jim Graham8ab41242022-04-22 16:19:04 -0700474 restore();
475 }
476}
Chinmay Garde41869f62021-12-28 15:19:35 -0800477void DisplayListBuilder::saveLayer(const SkRect* bounds,
Jim Graham0f2870c2022-06-06 15:23:06 -0700478 const SaveLayerOptions in_options,
479 const DlImageFilter* backdrop) {
Jim Grahamdbe4cc82022-02-04 00:45:10 -0800480 SaveLayerOptions options = in_options.without_optimizations();
Jim Grahameb57d702023-07-14 15:34:50 -0700481 size_t save_layer_offset = used_;
Zachary Anderson886a14e2023-07-15 07:14:10 -0700482 if (backdrop) {
483 bounds //
484 ? Push<SaveLayerBackdropBoundsOp>(0, 1, options, *bounds, backdrop)
485 : Push<SaveLayerBackdropOp>(0, 1, options, backdrop);
486 } else {
487 bounds //
488 ? Push<SaveLayerBoundsOp>(0, 1, options, *bounds)
489 : Push<SaveLayerOp>(0, 1, options);
490 }
491 CheckLayerOpacityCompatibility(options.renders_with_attributes());
492
ColdPaleLight948699b2022-12-15 19:52:52 +0800493 if (options.renders_with_attributes()) {
494 // The actual flood of the outer layer clip will occur after the
495 // (eventual) corresponding restore is called, but rather than
496 // remember this information in the LayerInfo until the restore
497 // method is processed, we just mark the unbounded state up front.
Jim Graham147ac7d2022-12-22 02:16:25 -0800498 // Another reason to accumulate the clip here rather than in
499 // restore is so that this savelayer will be tagged in the rtree
500 // with its full bounds and the right op_index so that it doesn't
501 // get culled during rendering.
ColdPaleLight948699b2022-12-15 19:52:52 +0800502 if (!paint_nops_on_transparency()) {
Zachary Anderson886a14e2023-07-15 07:14:10 -0700503 // We will fill the clip of the outer layer when we restore
504 AccumulateUnbounded();
ColdPaleLight948699b2022-12-15 19:52:52 +0800505 }
ColdPaleLight6b7ed782022-12-20 18:05:40 +0800506 layer_stack_.emplace_back(save_layer_offset, true,
ColdPaleLight948699b2022-12-15 19:52:52 +0800507 current_.getImageFilter());
508 } else {
ColdPaleLight6b7ed782022-12-20 18:05:40 +0800509 layer_stack_.emplace_back(save_layer_offset, true, nullptr);
ColdPaleLight948699b2022-12-15 19:52:52 +0800510 }
ColdPaleLight6b7ed782022-12-20 18:05:40 +0800511 tracker_.save();
ColdPaleLight948699b2022-12-15 19:52:52 +0800512 accumulator()->save();
Zachary Anderson886a14e2023-07-15 07:14:10 -0700513 current_layer_ = &layer_stack_.back();
Jim Grahamdbe4cc82022-02-04 00:45:10 -0800514 if (options.renders_with_attributes()) {
515 // |current_opacity_compatibility_| does not take an ImageFilter into
516 // account because an individual primitive with an ImageFilter can apply
517 // opacity on top of it. But, if the layer is applying the ImageFilter
518 // then it cannot pass the opacity on.
Jim Grahamd45b9112022-04-29 13:59:06 -0700519 if (!current_opacity_compatibility_ ||
520 current_.getImageFilter() != nullptr) {
Jim Grahamdbe4cc82022-02-04 00:45:10 -0800521 UpdateLayerOpacityCompatibility(false);
522 }
523 }
ColdPaleLight948699b2022-12-15 19:52:52 +0800524
525 // Even though Skia claims that the bounds are only a hint, they actually
526 // use them as the temporary layer bounds during rendering the layer, so
527 // we set them as if a clip operation were performed.
528 if (bounds) {
Jim Graham0d5b7802023-02-23 22:09:35 -0800529 tracker_.clipRect(*bounds, ClipOp::kIntersect, false);
ColdPaleLight948699b2022-12-15 19:52:52 +0800530 }
Zachary Anderson886a14e2023-07-15 07:14:10 -0700531 if (backdrop) {
532 // A backdrop will affect up to the entire surface, bounded by the clip
533 AccumulateUnbounded();
534 }
Chinmay Garde41869f62021-12-28 15:19:35 -0800535}
Jim Graham0d5b7802023-02-23 22:09:35 -0800536void DisplayListBuilder::SaveLayer(const SkRect* bounds,
Jim Graham0f2870c2022-06-06 15:23:06 -0700537 const DlPaint* paint,
538 const DlImageFilter* backdrop) {
Jim Grahame8812252022-04-22 15:54:03 -0700539 if (paint != nullptr) {
Jim Grahamde9093d2023-02-24 17:42:20 -0800540 SetAttributesFromPaint(*paint,
541 DisplayListOpFlags::kSaveLayerWithPaintFlags);
Jim Graham0f2870c2022-06-06 15:23:06 -0700542 saveLayer(bounds, SaveLayerOptions::kWithAttributes, backdrop);
Jim Grahame8812252022-04-22 15:54:03 -0700543 } else {
Jim Graham0f2870c2022-06-06 15:23:06 -0700544 saveLayer(bounds, SaveLayerOptions::kNoAttributes, backdrop);
Jim Grahame8812252022-04-22 15:54:03 -0700545 }
546}
Chinmay Garde41869f62021-12-28 15:19:35 -0800547
Jim Graham0d5b7802023-02-23 22:09:35 -0800548void DisplayListBuilder::Translate(SkScalar tx, SkScalar ty) {
Chinmay Garde41869f62021-12-28 15:19:35 -0800549 if (SkScalarIsFinite(tx) && SkScalarIsFinite(ty) &&
550 (tx != 0.0 || ty != 0.0)) {
JsouLiangac817502022-08-11 15:48:40 +0800551 checkForDeferredSave();
Chinmay Garde41869f62021-12-28 15:19:35 -0800552 Push<TranslateOp>(0, 1, tx, ty);
ColdPaleLight6b7ed782022-12-20 18:05:40 +0800553 tracker_.translate(tx, ty);
Chinmay Garde41869f62021-12-28 15:19:35 -0800554 }
555}
Jim Graham0d5b7802023-02-23 22:09:35 -0800556void DisplayListBuilder::Scale(SkScalar sx, SkScalar sy) {
Chinmay Garde41869f62021-12-28 15:19:35 -0800557 if (SkScalarIsFinite(sx) && SkScalarIsFinite(sy) &&
558 (sx != 1.0 || sy != 1.0)) {
JsouLiangac817502022-08-11 15:48:40 +0800559 checkForDeferredSave();
Chinmay Garde41869f62021-12-28 15:19:35 -0800560 Push<ScaleOp>(0, 1, sx, sy);
ColdPaleLight6b7ed782022-12-20 18:05:40 +0800561 tracker_.scale(sx, sy);
Chinmay Garde41869f62021-12-28 15:19:35 -0800562 }
563}
Jim Graham0d5b7802023-02-23 22:09:35 -0800564void DisplayListBuilder::Rotate(SkScalar degrees) {
Chinmay Garde41869f62021-12-28 15:19:35 -0800565 if (SkScalarMod(degrees, 360.0) != 0.0) {
JsouLiangac817502022-08-11 15:48:40 +0800566 checkForDeferredSave();
Chinmay Garde41869f62021-12-28 15:19:35 -0800567 Push<RotateOp>(0, 1, degrees);
ColdPaleLight6b7ed782022-12-20 18:05:40 +0800568 tracker_.rotate(degrees);
Chinmay Garde41869f62021-12-28 15:19:35 -0800569 }
570}
Jim Graham0d5b7802023-02-23 22:09:35 -0800571void DisplayListBuilder::Skew(SkScalar sx, SkScalar sy) {
Chinmay Garde41869f62021-12-28 15:19:35 -0800572 if (SkScalarIsFinite(sx) && SkScalarIsFinite(sy) &&
573 (sx != 0.0 || sy != 0.0)) {
JsouLiangac817502022-08-11 15:48:40 +0800574 checkForDeferredSave();
Chinmay Garde41869f62021-12-28 15:19:35 -0800575 Push<SkewOp>(0, 1, sx, sy);
ColdPaleLight6b7ed782022-12-20 18:05:40 +0800576 tracker_.skew(sx, sy);
Chinmay Garde41869f62021-12-28 15:19:35 -0800577 }
578}
579
580// clang-format off
581
582// 2x3 2D affine subset of a 4x4 transform in row major order
Jim Graham0d5b7802023-02-23 22:09:35 -0800583void DisplayListBuilder::Transform2DAffine(
Chinmay Garde41869f62021-12-28 15:19:35 -0800584 SkScalar mxx, SkScalar mxy, SkScalar mxt,
585 SkScalar myx, SkScalar myy, SkScalar myt) {
586 if (SkScalarsAreFinite(mxx, myx) &&
587 SkScalarsAreFinite(mxy, myy) &&
Jim Graham8dbffe52023-05-10 12:00:18 -0700588 SkScalarsAreFinite(mxt, myt)) {
589 if (mxx == 1 && mxy == 0 &&
590 myx == 0 && myy == 1) {
591 Translate(mxt, myt);
592 } else {
593 checkForDeferredSave();
594 Push<Transform2DAffineOp>(0, 1,
595 mxx, mxy, mxt,
596 myx, myy, myt);
597 tracker_.transform2DAffine(mxx, mxy, mxt,
598 myx, myy, myt);
599 }
Chinmay Garde41869f62021-12-28 15:19:35 -0800600 }
601}
602// full 4x4 transform in row major order
Jim Graham0d5b7802023-02-23 22:09:35 -0800603void DisplayListBuilder::TransformFullPerspective(
Chinmay Garde41869f62021-12-28 15:19:35 -0800604 SkScalar mxx, SkScalar mxy, SkScalar mxz, SkScalar mxt,
605 SkScalar myx, SkScalar myy, SkScalar myz, SkScalar myt,
606 SkScalar mzx, SkScalar mzy, SkScalar mzz, SkScalar mzt,
607 SkScalar mwx, SkScalar mwy, SkScalar mwz, SkScalar mwt) {
608 if ( mxz == 0 &&
609 myz == 0 &&
610 mzx == 0 && mzy == 0 && mzz == 1 && mzt == 0 &&
611 mwx == 0 && mwy == 0 && mwz == 0 && mwt == 1) {
Jim Graham0d5b7802023-02-23 22:09:35 -0800612 Transform2DAffine(mxx, mxy, mxt,
Chinmay Garde41869f62021-12-28 15:19:35 -0800613 myx, myy, myt);
614 } else if (SkScalarsAreFinite(mxx, mxy) && SkScalarsAreFinite(mxz, mxt) &&
615 SkScalarsAreFinite(myx, myy) && SkScalarsAreFinite(myz, myt) &&
616 SkScalarsAreFinite(mzx, mzy) && SkScalarsAreFinite(mzz, mzt) &&
617 SkScalarsAreFinite(mwx, mwy) && SkScalarsAreFinite(mwz, mwt)) {
JsouLiangac817502022-08-11 15:48:40 +0800618 checkForDeferredSave();
Chinmay Garde41869f62021-12-28 15:19:35 -0800619 Push<TransformFullPerspectiveOp>(0, 1,
620 mxx, mxy, mxz, mxt,
621 myx, myy, myz, myt,
622 mzx, mzy, mzz, mzt,
623 mwx, mwy, mwz, mwt);
ColdPaleLight6b7ed782022-12-20 18:05:40 +0800624 tracker_.transformFullPerspective(mxx, mxy, mxz, mxt,
625 myx, myy, myz, myt,
626 mzx, mzy, mzz, mzt,
627 mwx, mwy, mwz, mwt);
Chinmay Garde41869f62021-12-28 15:19:35 -0800628 }
629}
Chinmay Garde41869f62021-12-28 15:19:35 -0800630// clang-format on
Jim Graham0d5b7802023-02-23 22:09:35 -0800631void DisplayListBuilder::TransformReset() {
JsouLiangac817502022-08-11 15:48:40 +0800632 checkForDeferredSave();
Chinmay Garde81547d12022-03-16 12:40:24 -0700633 Push<TransformResetOp>(0, 0);
ColdPaleLight6b7ed782022-12-20 18:05:40 +0800634 tracker_.setIdentity();
Chinmay Garde81547d12022-03-16 12:40:24 -0700635}
Jim Graham0d5b7802023-02-23 22:09:35 -0800636void DisplayListBuilder::Transform(const SkMatrix* matrix) {
Jim Graham1ef3f752022-04-19 23:04:03 -0700637 if (matrix != nullptr) {
Jim Graham0d5b7802023-02-23 22:09:35 -0800638 Transform(SkM44(*matrix));
Jim Graham1ef3f752022-04-19 23:04:03 -0700639 }
640}
Jim Graham0d5b7802023-02-23 22:09:35 -0800641void DisplayListBuilder::Transform(const SkM44* m44) {
Jim Graham1ef3f752022-04-19 23:04:03 -0700642 if (m44 != nullptr) {
643 transformFullPerspective(
644 m44->rc(0, 0), m44->rc(0, 1), m44->rc(0, 2), m44->rc(0, 3),
645 m44->rc(1, 0), m44->rc(1, 1), m44->rc(1, 2), m44->rc(1, 3),
646 m44->rc(2, 0), m44->rc(2, 1), m44->rc(2, 2), m44->rc(2, 3),
647 m44->rc(3, 0), m44->rc(3, 1), m44->rc(3, 2), m44->rc(3, 3));
648 }
649}
Chinmay Garde41869f62021-12-28 15:19:35 -0800650
Jim Graham0d5b7802023-02-23 22:09:35 -0800651void DisplayListBuilder::ClipRect(const SkRect& rect,
652 ClipOp clip_op,
Chinmay Garde41869f62021-12-28 15:19:35 -0800653 bool is_aa) {
JsouLiangac817502022-08-11 15:48:40 +0800654 if (!rect.isFinite()) {
655 return;
656 }
657 checkForDeferredSave();
Jim Graham45de0992022-06-14 18:53:06 -0700658 switch (clip_op) {
Jim Graham0d5b7802023-02-23 22:09:35 -0800659 case ClipOp::kIntersect:
Jim Graham45de0992022-06-14 18:53:06 -0700660 Push<ClipIntersectRectOp>(0, 1, rect, is_aa);
Jim Graham45de0992022-06-14 18:53:06 -0700661 break;
Jim Graham0d5b7802023-02-23 22:09:35 -0800662 case ClipOp::kDifference:
Jim Graham45de0992022-06-14 18:53:06 -0700663 Push<ClipDifferenceRectOp>(0, 1, rect, is_aa);
664 break;
665 }
Zachary Anderson886a14e2023-07-15 07:14:10 -0700666 tracker_.clipRect(rect, clip_op, is_aa);
Chinmay Garde41869f62021-12-28 15:19:35 -0800667}
Jim Graham0d5b7802023-02-23 22:09:35 -0800668void DisplayListBuilder::ClipRRect(const SkRRect& rrect,
669 ClipOp clip_op,
Chinmay Garde41869f62021-12-28 15:19:35 -0800670 bool is_aa) {
671 if (rrect.isRect()) {
672 clipRect(rrect.rect(), clip_op, is_aa);
673 } else {
JsouLiangac817502022-08-11 15:48:40 +0800674 checkForDeferredSave();
Jim Graham45de0992022-06-14 18:53:06 -0700675 switch (clip_op) {
Jim Graham0d5b7802023-02-23 22:09:35 -0800676 case ClipOp::kIntersect:
Jim Graham45de0992022-06-14 18:53:06 -0700677 Push<ClipIntersectRRectOp>(0, 1, rrect, is_aa);
Jim Graham45de0992022-06-14 18:53:06 -0700678 break;
Jim Graham0d5b7802023-02-23 22:09:35 -0800679 case ClipOp::kDifference:
Jim Graham45de0992022-06-14 18:53:06 -0700680 Push<ClipDifferenceRRectOp>(0, 1, rrect, is_aa);
681 break;
682 }
Zachary Anderson886a14e2023-07-15 07:14:10 -0700683 tracker_.clipRRect(rrect, clip_op, is_aa);
Chinmay Garde41869f62021-12-28 15:19:35 -0800684 }
685}
Jim Graham0d5b7802023-02-23 22:09:35 -0800686void DisplayListBuilder::ClipPath(const SkPath& path,
687 ClipOp clip_op,
Chinmay Garde41869f62021-12-28 15:19:35 -0800688 bool is_aa) {
689 if (!path.isInverseFillType()) {
690 SkRect rect;
691 if (path.isRect(&rect)) {
692 this->clipRect(rect, clip_op, is_aa);
693 return;
694 }
695 SkRRect rrect;
696 if (path.isOval(&rect)) {
697 rrect.setOval(rect);
698 this->clipRRect(rrect, clip_op, is_aa);
699 return;
700 }
701 if (path.isRRect(&rrect)) {
702 this->clipRRect(rrect, clip_op, is_aa);
703 return;
704 }
705 }
JsouLiangac817502022-08-11 15:48:40 +0800706 checkForDeferredSave();
Jim Graham45de0992022-06-14 18:53:06 -0700707 switch (clip_op) {
Jim Graham0d5b7802023-02-23 22:09:35 -0800708 case ClipOp::kIntersect:
Jim Graham45de0992022-06-14 18:53:06 -0700709 Push<ClipIntersectPathOp>(0, 1, path, is_aa);
Jim Graham45de0992022-06-14 18:53:06 -0700710 break;
Jim Graham0d5b7802023-02-23 22:09:35 -0800711 case ClipOp::kDifference:
Jim Graham45de0992022-06-14 18:53:06 -0700712 Push<ClipDifferencePathOp>(0, 1, path, is_aa);
713 break;
714 }
Zachary Anderson886a14e2023-07-15 07:14:10 -0700715 tracker_.clipPath(path, clip_op, is_aa);
Jim Graham5b31f4f2022-11-17 11:34:19 -0800716}
717
Jim Graham0d5b7802023-02-23 22:09:35 -0800718bool DisplayListBuilder::QuickReject(const SkRect& bounds) const {
ColdPaleLight6b7ed782022-12-20 18:05:40 +0800719 return tracker_.content_culled(bounds);
Chinmay Garde41869f62021-12-28 15:19:35 -0800720}
721
722void DisplayListBuilder::drawPaint() {
Zachary Anderson886a14e2023-07-15 07:14:10 -0700723 Push<DrawPaintOp>(0, 1);
724 CheckLayerOpacityCompatibility();
725 AccumulateUnbounded();
Chinmay Garde41869f62021-12-28 15:19:35 -0800726}
Jim Graham0d5b7802023-02-23 22:09:35 -0800727void DisplayListBuilder::DrawPaint(const DlPaint& paint) {
Jim Grahamde9093d2023-02-24 17:42:20 -0800728 SetAttributesFromPaint(paint, DisplayListOpFlags::kDrawPaintFlags);
Jim Grahame8812252022-04-22 15:54:03 -0700729 drawPaint();
730}
Jim Graham0d5b7802023-02-23 22:09:35 -0800731void DisplayListBuilder::DrawColor(DlColor color, DlBlendMode mode) {
Zachary Anderson886a14e2023-07-15 07:14:10 -0700732 Push<DrawColorOp>(0, 1, color, mode);
733 CheckLayerOpacityCompatibility(mode);
734 AccumulateUnbounded();
Chinmay Garde41869f62021-12-28 15:19:35 -0800735}
736void DisplayListBuilder::drawLine(const SkPoint& p0, const SkPoint& p1) {
Zachary Anderson886a14e2023-07-15 07:14:10 -0700737 Push<DrawLineOp>(0, 1, p0, p1);
738 CheckLayerOpacityCompatibility();
ColdPaleLight948699b2022-12-15 19:52:52 +0800739 SkRect bounds = SkRect::MakeLTRB(p0.fX, p0.fY, p1.fX, p1.fY).makeSorted();
740 DisplayListAttributeFlags flags =
741 (bounds.width() > 0.0f && bounds.height() > 0.0f) ? kDrawLineFlags
742 : kDrawHVLineFlags;
Zachary Anderson886a14e2023-07-15 07:14:10 -0700743 AccumulateOpBounds(bounds, flags);
Chinmay Garde41869f62021-12-28 15:19:35 -0800744}
Jim Graham0d5b7802023-02-23 22:09:35 -0800745void DisplayListBuilder::DrawLine(const SkPoint& p0,
Jim Grahame8812252022-04-22 15:54:03 -0700746 const SkPoint& p1,
747 const DlPaint& paint) {
Jim Grahamde9093d2023-02-24 17:42:20 -0800748 SetAttributesFromPaint(paint, DisplayListOpFlags::kDrawLineFlags);
Jim Grahame8812252022-04-22 15:54:03 -0700749 drawLine(p0, p1);
750}
Chinmay Garde41869f62021-12-28 15:19:35 -0800751void DisplayListBuilder::drawRect(const SkRect& rect) {
Zachary Anderson886a14e2023-07-15 07:14:10 -0700752 Push<DrawRectOp>(0, 1, rect);
753 CheckLayerOpacityCompatibility();
754 AccumulateOpBounds(rect.makeSorted(), kDrawRectFlags);
Chinmay Garde41869f62021-12-28 15:19:35 -0800755}
Jim Graham0d5b7802023-02-23 22:09:35 -0800756void DisplayListBuilder::DrawRect(const SkRect& rect, const DlPaint& paint) {
Jim Grahamde9093d2023-02-24 17:42:20 -0800757 SetAttributesFromPaint(paint, DisplayListOpFlags::kDrawRectFlags);
Jim Grahame8812252022-04-22 15:54:03 -0700758 drawRect(rect);
759}
Chinmay Garde41869f62021-12-28 15:19:35 -0800760void DisplayListBuilder::drawOval(const SkRect& bounds) {
Zachary Anderson886a14e2023-07-15 07:14:10 -0700761 Push<DrawOvalOp>(0, 1, bounds);
762 CheckLayerOpacityCompatibility();
763 AccumulateOpBounds(bounds.makeSorted(), kDrawOvalFlags);
Chinmay Garde41869f62021-12-28 15:19:35 -0800764}
Jim Graham0d5b7802023-02-23 22:09:35 -0800765void DisplayListBuilder::DrawOval(const SkRect& bounds, const DlPaint& paint) {
Jim Grahamde9093d2023-02-24 17:42:20 -0800766 SetAttributesFromPaint(paint, DisplayListOpFlags::kDrawOvalFlags);
Jim Grahame8812252022-04-22 15:54:03 -0700767 drawOval(bounds);
768}
Chinmay Garde41869f62021-12-28 15:19:35 -0800769void DisplayListBuilder::drawCircle(const SkPoint& center, SkScalar radius) {
Zachary Anderson886a14e2023-07-15 07:14:10 -0700770 Push<DrawCircleOp>(0, 1, center, radius);
771 CheckLayerOpacityCompatibility();
772 AccumulateOpBounds(SkRect::MakeLTRB(center.fX - radius, center.fY - radius,
773 center.fX + radius, center.fY + radius),
774 kDrawCircleFlags);
Chinmay Garde41869f62021-12-28 15:19:35 -0800775}
Jim Graham0d5b7802023-02-23 22:09:35 -0800776void DisplayListBuilder::DrawCircle(const SkPoint& center,
Jim Grahame8812252022-04-22 15:54:03 -0700777 SkScalar radius,
778 const DlPaint& paint) {
Jim Grahamde9093d2023-02-24 17:42:20 -0800779 SetAttributesFromPaint(paint, DisplayListOpFlags::kDrawCircleFlags);
Jim Grahame8812252022-04-22 15:54:03 -0700780 drawCircle(center, radius);
781}
Chinmay Garde41869f62021-12-28 15:19:35 -0800782void DisplayListBuilder::drawRRect(const SkRRect& rrect) {
783 if (rrect.isRect()) {
784 drawRect(rrect.rect());
785 } else if (rrect.isOval()) {
786 drawOval(rrect.rect());
787 } else {
Zachary Anderson886a14e2023-07-15 07:14:10 -0700788 Push<DrawRRectOp>(0, 1, rrect);
789 CheckLayerOpacityCompatibility();
790 AccumulateOpBounds(rrect.getBounds(), kDrawRRectFlags);
Chinmay Garde41869f62021-12-28 15:19:35 -0800791 }
792}
Jim Graham0d5b7802023-02-23 22:09:35 -0800793void DisplayListBuilder::DrawRRect(const SkRRect& rrect, const DlPaint& paint) {
Jim Grahamde9093d2023-02-24 17:42:20 -0800794 SetAttributesFromPaint(paint, DisplayListOpFlags::kDrawRRectFlags);
Jim Grahame8812252022-04-22 15:54:03 -0700795 drawRRect(rrect);
796}
Chinmay Garde41869f62021-12-28 15:19:35 -0800797void DisplayListBuilder::drawDRRect(const SkRRect& outer,
798 const SkRRect& inner) {
Zachary Anderson886a14e2023-07-15 07:14:10 -0700799 Push<DrawDRRectOp>(0, 1, outer, inner);
800 CheckLayerOpacityCompatibility();
801 AccumulateOpBounds(outer.getBounds(), kDrawDRRectFlags);
Chinmay Garde41869f62021-12-28 15:19:35 -0800802}
Jim Graham0d5b7802023-02-23 22:09:35 -0800803void DisplayListBuilder::DrawDRRect(const SkRRect& outer,
Jim Grahame8812252022-04-22 15:54:03 -0700804 const SkRRect& inner,
805 const DlPaint& paint) {
Jim Grahamde9093d2023-02-24 17:42:20 -0800806 SetAttributesFromPaint(paint, DisplayListOpFlags::kDrawDRRectFlags);
Jim Grahame8812252022-04-22 15:54:03 -0700807 drawDRRect(outer, inner);
808}
Chinmay Garde41869f62021-12-28 15:19:35 -0800809void DisplayListBuilder::drawPath(const SkPath& path) {
Zachary Anderson886a14e2023-07-15 07:14:10 -0700810 Push<DrawPathOp>(0, 1, path);
811 CheckLayerOpacityHairlineCompatibility();
812 if (path.isInverseFillType()) {
813 AccumulateUnbounded();
814 } else {
815 AccumulateOpBounds(path.getBounds(), kDrawPathFlags);
ColdPaleLight948699b2022-12-15 19:52:52 +0800816 }
Chinmay Garde41869f62021-12-28 15:19:35 -0800817}
Jim Graham0d5b7802023-02-23 22:09:35 -0800818void DisplayListBuilder::DrawPath(const SkPath& path, const DlPaint& paint) {
Jim Grahamde9093d2023-02-24 17:42:20 -0800819 SetAttributesFromPaint(paint, DisplayListOpFlags::kDrawPathFlags);
Jim Grahame8812252022-04-22 15:54:03 -0700820 drawPath(path);
821}
Chinmay Garde41869f62021-12-28 15:19:35 -0800822
823void DisplayListBuilder::drawArc(const SkRect& bounds,
824 SkScalar start,
825 SkScalar sweep,
826 bool useCenter) {
Zachary Anderson886a14e2023-07-15 07:14:10 -0700827 Push<DrawArcOp>(0, 1, bounds, start, sweep, useCenter);
828 if (useCenter) {
829 CheckLayerOpacityHairlineCompatibility();
830 } else {
831 CheckLayerOpacityCompatibility();
832 }
ColdPaleLight948699b2022-12-15 19:52:52 +0800833 // This could be tighter if we compute where the start and end
834 // angles are and then also consider the quadrants swept and
835 // the center if specified.
Zachary Anderson886a14e2023-07-15 07:14:10 -0700836 AccumulateOpBounds(bounds,
837 useCenter //
838 ? kDrawArcWithCenterFlags
839 : kDrawArcNoCenterFlags);
Chinmay Garde41869f62021-12-28 15:19:35 -0800840}
Jim Graham0d5b7802023-02-23 22:09:35 -0800841void DisplayListBuilder::DrawArc(const SkRect& bounds,
Jim Grahame8812252022-04-22 15:54:03 -0700842 SkScalar start,
843 SkScalar sweep,
844 bool useCenter,
845 const DlPaint& paint) {
Jim Grahamde9093d2023-02-24 17:42:20 -0800846 SetAttributesFromPaint(
Jim Grahame8812252022-04-22 15:54:03 -0700847 paint, useCenter ? kDrawArcWithCenterFlags : kDrawArcNoCenterFlags);
848 drawArc(bounds, start, sweep, useCenter);
849}
Jim Graham0d5b7802023-02-23 22:09:35 -0800850void DisplayListBuilder::drawPoints(PointMode mode,
Chinmay Garde41869f62021-12-28 15:19:35 -0800851 uint32_t count,
852 const SkPoint pts[]) {
ColdPaleLight948699b2022-12-15 19:52:52 +0800853 if (count == 0) {
854 return;
855 }
856
Zachary Anderson886a14e2023-07-15 07:14:10 -0700857 void* data_ptr;
Jim Graham25514ec2023-03-19 15:59:17 -0700858 FML_DCHECK(count < DlOpReceiver::kMaxDrawPointsCount);
Chinmay Garde41869f62021-12-28 15:19:35 -0800859 int bytes = count * sizeof(SkPoint);
ColdPaleLight948699b2022-12-15 19:52:52 +0800860 RectBoundsAccumulator ptBounds;
861 for (size_t i = 0; i < count; i++) {
862 ptBounds.accumulate(pts[i]);
863 }
864 SkRect point_bounds = ptBounds.bounds();
Chinmay Garde41869f62021-12-28 15:19:35 -0800865 switch (mode) {
Jim Graham0d5b7802023-02-23 22:09:35 -0800866 case PointMode::kPoints:
Chinmay Garde41869f62021-12-28 15:19:35 -0800867 data_ptr = Push<DrawPointsOp>(bytes, 1, count);
Zachary Anderson886a14e2023-07-15 07:14:10 -0700868 AccumulateOpBounds(point_bounds, kDrawPointsAsPointsFlags);
Chinmay Garde41869f62021-12-28 15:19:35 -0800869 break;
Jim Graham0d5b7802023-02-23 22:09:35 -0800870 case PointMode::kLines:
Chinmay Garde41869f62021-12-28 15:19:35 -0800871 data_ptr = Push<DrawLinesOp>(bytes, 1, count);
Zachary Anderson886a14e2023-07-15 07:14:10 -0700872 AccumulateOpBounds(point_bounds, kDrawPointsAsLinesFlags);
Chinmay Garde41869f62021-12-28 15:19:35 -0800873 break;
Jim Graham0d5b7802023-02-23 22:09:35 -0800874 case PointMode::kPolygon:
Chinmay Garde41869f62021-12-28 15:19:35 -0800875 data_ptr = Push<DrawPolygonOp>(bytes, 1, count);
Zachary Anderson886a14e2023-07-15 07:14:10 -0700876 AccumulateOpBounds(point_bounds, kDrawPointsAsPolygonFlags);
Chinmay Garde41869f62021-12-28 15:19:35 -0800877 break;
878 default:
Zachary Anderson886a14e2023-07-15 07:14:10 -0700879 FML_DCHECK(false);
Chinmay Garde41869f62021-12-28 15:19:35 -0800880 return;
881 }
882 CopyV(data_ptr, pts, count);
883 // drawPoints treats every point or line (or segment of a polygon)
884 // as a completely separate operation meaning we cannot ensure
885 // distribution of group opacity without analyzing the mode and the
886 // bounds of every sub-primitive.
887 // See: https://fiddle.skia.org/c/228459001d2de8db117ce25ef5cedb0c
888 UpdateLayerOpacityCompatibility(false);
889}
Jim Graham0d5b7802023-02-23 22:09:35 -0800890void DisplayListBuilder::DrawPoints(PointMode mode,
Jim Grahame8812252022-04-22 15:54:03 -0700891 uint32_t count,
892 const SkPoint pts[],
893 const DlPaint& paint) {
Zachary Anderson886a14e2023-07-15 07:14:10 -0700894 const DisplayListAttributeFlags* flags;
895 switch (mode) {
896 case PointMode::kPoints:
897 flags = &DisplayListOpFlags::kDrawPointsAsPointsFlags;
898 break;
899 case PointMode::kLines:
900 flags = &DisplayListOpFlags::kDrawPointsAsLinesFlags;
901 break;
902 case PointMode::kPolygon:
903 flags = &DisplayListOpFlags::kDrawPointsAsPolygonFlags;
904 break;
905 default:
906 FML_DCHECK(false);
907 return;
908 }
909 SetAttributesFromPaint(paint, *flags);
Jim Grahame8812252022-04-22 15:54:03 -0700910 drawPoints(mode, count, pts);
911}
Jim Grahame4f9ee12022-03-31 00:15:04 -0700912void DisplayListBuilder::drawVertices(const DlVertices* vertices,
JsouLiang1aa52552022-03-20 05:10:07 +0800913 DlBlendMode mode) {
Zachary Anderson886a14e2023-07-15 07:14:10 -0700914 void* pod = Push<DrawVerticesOp>(vertices->size(), 1, mode);
915 new (pod) DlVertices(vertices);
916 // DrawVertices applies its colors to the paint so we have no way
917 // of controlling opacity using the current paint attributes.
918 // Although, examination of the |mode| might find some predictable
919 // cases.
920 UpdateLayerOpacityCompatibility(false);
921 AccumulateOpBounds(vertices->bounds(), kDrawVerticesFlags);
Chinmay Garde41869f62021-12-28 15:19:35 -0800922}
Jim Graham0d5b7802023-02-23 22:09:35 -0800923void DisplayListBuilder::DrawVertices(const DlVertices* vertices,
Jim Grahame8812252022-04-22 15:54:03 -0700924 DlBlendMode mode,
925 const DlPaint& paint) {
Jim Grahamde9093d2023-02-24 17:42:20 -0800926 SetAttributesFromPaint(paint, DisplayListOpFlags::kDrawVerticesFlags);
Jim Grahame8812252022-04-22 15:54:03 -0700927 drawVertices(vertices, mode);
928}
Chinmay Garde41869f62021-12-28 15:19:35 -0800929
Chinmay Garde6dd43e62022-03-30 13:31:37 -0700930void DisplayListBuilder::drawImage(const sk_sp<DlImage> image,
Chinmay Garde41869f62021-12-28 15:19:35 -0800931 const SkPoint point,
JsouLiange25d1ce2022-06-18 03:26:04 +0800932 DlImageSampling sampling,
Chinmay Garde41869f62021-12-28 15:19:35 -0800933 bool render_with_attributes) {
Zachary Anderson886a14e2023-07-15 07:14:10 -0700934 render_with_attributes
935 ? Push<DrawImageWithAttrOp>(0, 1, image, point, sampling)
936 : Push<DrawImageOp>(0, 1, image, point, sampling);
937 CheckLayerOpacityCompatibility(render_with_attributes);
938 is_ui_thread_safe_ = is_ui_thread_safe_ && image->isUIThreadSafe();
939 SkRect bounds = SkRect::MakeXYWH(point.fX, point.fY, //
940 image->width(), image->height());
ColdPaleLight948699b2022-12-15 19:52:52 +0800941 DisplayListAttributeFlags flags = render_with_attributes //
942 ? kDrawImageWithPaintFlags
943 : kDrawImageFlags;
Zachary Anderson886a14e2023-07-15 07:14:10 -0700944 AccumulateOpBounds(bounds, flags);
Chinmay Garde41869f62021-12-28 15:19:35 -0800945}
Jim Graham0d5b7802023-02-23 22:09:35 -0800946void DisplayListBuilder::DrawImage(const sk_sp<DlImage>& image,
Jim Grahame8812252022-04-22 15:54:03 -0700947 const SkPoint point,
JsouLiange25d1ce2022-06-18 03:26:04 +0800948 DlImageSampling sampling,
Jim Grahame8812252022-04-22 15:54:03 -0700949 const DlPaint* paint) {
950 if (paint != nullptr) {
Jim Grahamde9093d2023-02-24 17:42:20 -0800951 SetAttributesFromPaint(*paint,
952 DisplayListOpFlags::kDrawImageWithPaintFlags);
Jim Grahame8812252022-04-22 15:54:03 -0700953 drawImage(image, point, sampling, true);
954 } else {
955 drawImage(image, point, sampling, false);
956 }
957}
Chinmay Garde6dd43e62022-03-30 13:31:37 -0700958void DisplayListBuilder::drawImageRect(const sk_sp<DlImage> image,
Chinmay Garde41869f62021-12-28 15:19:35 -0800959 const SkRect& src,
960 const SkRect& dst,
JsouLiange25d1ce2022-06-18 03:26:04 +0800961 DlImageSampling sampling,
Chinmay Garde41869f62021-12-28 15:19:35 -0800962 bool render_with_attributes,
Jim Graham25514ec2023-03-19 15:59:17 -0700963 SrcRectConstraint constraint) {
Zachary Anderson886a14e2023-07-15 07:14:10 -0700964 Push<DrawImageRectOp>(0, 1, image, src, dst, sampling, render_with_attributes,
965 constraint);
966 CheckLayerOpacityCompatibility(render_with_attributes);
967 is_ui_thread_safe_ = is_ui_thread_safe_ && image->isUIThreadSafe();
ColdPaleLight948699b2022-12-15 19:52:52 +0800968 DisplayListAttributeFlags flags = render_with_attributes
969 ? kDrawImageRectWithPaintFlags
970 : kDrawImageRectFlags;
Zachary Anderson886a14e2023-07-15 07:14:10 -0700971 AccumulateOpBounds(dst, flags);
Chinmay Garde41869f62021-12-28 15:19:35 -0800972}
Jim Graham0d5b7802023-02-23 22:09:35 -0800973void DisplayListBuilder::DrawImageRect(const sk_sp<DlImage>& image,
Jim Grahame8812252022-04-22 15:54:03 -0700974 const SkRect& src,
975 const SkRect& dst,
JsouLiange25d1ce2022-06-18 03:26:04 +0800976 DlImageSampling sampling,
Jim Grahame8812252022-04-22 15:54:03 -0700977 const DlPaint* paint,
Jim Graham25514ec2023-03-19 15:59:17 -0700978 SrcRectConstraint constraint) {
Jim Grahame8812252022-04-22 15:54:03 -0700979 if (paint != nullptr) {
Jim Grahamde9093d2023-02-24 17:42:20 -0800980 SetAttributesFromPaint(*paint,
981 DisplayListOpFlags::kDrawImageRectWithPaintFlags);
Jason Simmonsb3e314e2023-03-06 18:58:49 -0800982 drawImageRect(image, src, dst, sampling, true, constraint);
Jim Grahame8812252022-04-22 15:54:03 -0700983 } else {
Jason Simmonsb3e314e2023-03-06 18:58:49 -0800984 drawImageRect(image, src, dst, sampling, false, constraint);
Jim Grahame8812252022-04-22 15:54:03 -0700985 }
986}
Chinmay Garde6dd43e62022-03-30 13:31:37 -0700987void DisplayListBuilder::drawImageNine(const sk_sp<DlImage> image,
Chinmay Garde41869f62021-12-28 15:19:35 -0800988 const SkIRect& center,
989 const SkRect& dst,
JsouLiange25d1ce2022-06-18 03:26:04 +0800990 DlFilterMode filter,
Chinmay Garde41869f62021-12-28 15:19:35 -0800991 bool render_with_attributes) {
Zachary Anderson886a14e2023-07-15 07:14:10 -0700992 render_with_attributes
993 ? Push<DrawImageNineWithAttrOp>(0, 1, image, center, dst, filter)
994 : Push<DrawImageNineOp>(0, 1, image, center, dst, filter);
995 CheckLayerOpacityCompatibility(render_with_attributes);
996 is_ui_thread_safe_ = is_ui_thread_safe_ && image->isUIThreadSafe();
ColdPaleLight948699b2022-12-15 19:52:52 +0800997 DisplayListAttributeFlags flags = render_with_attributes
998 ? kDrawImageNineWithPaintFlags
999 : kDrawImageNineFlags;
Zachary Anderson886a14e2023-07-15 07:14:10 -07001000 AccumulateOpBounds(dst, flags);
Chinmay Garde41869f62021-12-28 15:19:35 -08001001}
Jim Graham0d5b7802023-02-23 22:09:35 -08001002void DisplayListBuilder::DrawImageNine(const sk_sp<DlImage>& image,
Jim Grahame8812252022-04-22 15:54:03 -07001003 const SkIRect& center,
1004 const SkRect& dst,
JsouLiange25d1ce2022-06-18 03:26:04 +08001005 DlFilterMode filter,
Jim Grahame8812252022-04-22 15:54:03 -07001006 const DlPaint* paint) {
1007 if (paint != nullptr) {
Jim Grahamde9093d2023-02-24 17:42:20 -08001008 SetAttributesFromPaint(*paint,
1009 DisplayListOpFlags::kDrawImageNineWithPaintFlags);
Jim Grahame8812252022-04-22 15:54:03 -07001010 drawImageNine(image, center, dst, filter, true);
1011 } else {
1012 drawImageNine(image, center, dst, filter, false);
1013 }
1014}
Chinmay Garde6dd43e62022-03-30 13:31:37 -07001015void DisplayListBuilder::drawAtlas(const sk_sp<DlImage> atlas,
Chinmay Garde41869f62021-12-28 15:19:35 -08001016 const SkRSXform xform[],
1017 const SkRect tex[],
Jim Grahamd45b9112022-04-29 13:59:06 -07001018 const DlColor colors[],
Chinmay Garde41869f62021-12-28 15:19:35 -08001019 int count,
JsouLiang1aa52552022-03-20 05:10:07 +08001020 DlBlendMode mode,
JsouLiange25d1ce2022-06-18 03:26:04 +08001021 DlImageSampling sampling,
Chinmay Garde41869f62021-12-28 15:19:35 -08001022 const SkRect* cull_rect,
1023 bool render_with_attributes) {
1024 int bytes = count * (sizeof(SkRSXform) + sizeof(SkRect));
1025 void* data_ptr;
1026 if (colors != nullptr) {
Jim Grahamd45b9112022-04-29 13:59:06 -07001027 bytes += count * sizeof(DlColor);
Chinmay Garde41869f62021-12-28 15:19:35 -08001028 if (cull_rect != nullptr) {
gaaclarke56841d42022-10-26 01:19:12 -07001029 data_ptr =
1030 Push<DrawAtlasCulledOp>(bytes, 1, atlas, count, mode, sampling, true,
1031 *cull_rect, render_with_attributes);
Chinmay Garde41869f62021-12-28 15:19:35 -08001032 } else {
gaaclarke56841d42022-10-26 01:19:12 -07001033 data_ptr = Push<DrawAtlasOp>(bytes, 1, atlas, count, mode, sampling, true,
1034 render_with_attributes);
Chinmay Garde41869f62021-12-28 15:19:35 -08001035 }
1036 CopyV(data_ptr, xform, count, tex, count, colors, count);
1037 } else {
1038 if (cull_rect != nullptr) {
gaaclarke56841d42022-10-26 01:19:12 -07001039 data_ptr =
1040 Push<DrawAtlasCulledOp>(bytes, 1, atlas, count, mode, sampling, false,
1041 *cull_rect, render_with_attributes);
Chinmay Garde41869f62021-12-28 15:19:35 -08001042 } else {
gaaclarke56841d42022-10-26 01:19:12 -07001043 data_ptr = Push<DrawAtlasOp>(bytes, 1, atlas, count, mode, sampling,
1044 false, render_with_attributes);
Chinmay Garde41869f62021-12-28 15:19:35 -08001045 }
1046 CopyV(data_ptr, xform, count, tex, count);
1047 }
1048 // drawAtlas treats each image as a separate operation so we cannot rely
1049 // on it to distribute the opacity without overlap without checking all
1050 // of the transforms and texture rectangles.
1051 UpdateLayerOpacityCompatibility(false);
Jim Graham35833e72023-04-17 16:47:20 -07001052 is_ui_thread_safe_ = is_ui_thread_safe_ && atlas->isUIThreadSafe();
Zachary Anderson886a14e2023-07-15 07:14:10 -07001053
1054 SkPoint quad[4];
1055 RectBoundsAccumulator atlasBounds;
1056 for (int i = 0; i < count; i++) {
1057 const SkRect& src = tex[i];
1058 xform[i].toQuad(src.width(), src.height(), quad);
1059 for (int j = 0; j < 4; j++) {
1060 atlasBounds.accumulate(quad[j]);
1061 }
1062 }
1063 if (atlasBounds.is_not_empty()) {
1064 DisplayListAttributeFlags flags = render_with_attributes //
1065 ? kDrawAtlasWithPaintFlags
1066 : kDrawAtlasFlags;
1067 AccumulateOpBounds(atlasBounds.bounds(), flags);
1068 }
Chinmay Garde41869f62021-12-28 15:19:35 -08001069}
Jim Graham0d5b7802023-02-23 22:09:35 -08001070void DisplayListBuilder::DrawAtlas(const sk_sp<DlImage>& atlas,
Jim Grahame8812252022-04-22 15:54:03 -07001071 const SkRSXform xform[],
1072 const SkRect tex[],
Jim Grahamd45b9112022-04-29 13:59:06 -07001073 const DlColor colors[],
Jim Grahame8812252022-04-22 15:54:03 -07001074 int count,
1075 DlBlendMode mode,
JsouLiange25d1ce2022-06-18 03:26:04 +08001076 DlImageSampling sampling,
Jim Grahame8812252022-04-22 15:54:03 -07001077 const SkRect* cull_rect,
1078 const DlPaint* paint) {
1079 if (paint != nullptr) {
Jim Grahamde9093d2023-02-24 17:42:20 -08001080 SetAttributesFromPaint(*paint,
1081 DisplayListOpFlags::kDrawAtlasWithPaintFlags);
Jim Grahame8812252022-04-22 15:54:03 -07001082 drawAtlas(atlas, xform, tex, colors, count, mode, sampling, cull_rect,
1083 true);
1084 } else {
1085 drawAtlas(atlas, xform, tex, colors, count, mode, sampling, cull_rect,
1086 false);
1087 }
1088}
Chinmay Garde41869f62021-12-28 15:19:35 -08001089
Jim Graham0d5b7802023-02-23 22:09:35 -08001090void DisplayListBuilder::DrawDisplayList(const sk_sp<DisplayList> display_list,
1091 SkScalar opacity) {
1092 DlPaint current_paint = current_;
Zachary Anderson886a14e2023-07-15 07:14:10 -07001093 Push<DrawDisplayListOp>(0, 1, display_list, opacity);
Jim Graham35833e72023-04-17 16:47:20 -07001094 is_ui_thread_safe_ = is_ui_thread_safe_ && display_list->isUIThreadSafe();
Jim Graham25514ec2023-03-19 15:59:17 -07001095 // Not really necessary if the developer is interacting with us via
1096 // our attribute-state-less DlCanvas methods, but this avoids surprises
1097 // for those who may have been using the stateful Dispatcher methods.
1098 SetAttributesFromPaint(current_paint,
1099 DisplayListOpFlags::kSaveLayerWithPaintFlags);
Jim Graham147ac7d2022-12-22 02:16:25 -08001100
Zachary Anderson886a14e2023-07-15 07:14:10 -07001101 const SkRect bounds = display_list->bounds();
1102 switch (accumulator()->type()) {
1103 case BoundsAccumulatorType::kRect:
1104 AccumulateOpBounds(bounds, kDrawDisplayListFlags);
1105 break;
1106 case BoundsAccumulatorType::kRTree:
1107 auto rtree = display_list->rtree();
1108 if (rtree) {
1109 std::list<SkRect> rects =
1110 rtree->searchAndConsolidateRects(bounds, false);
1111 for (const SkRect& rect : rects) {
1112 // TODO (https://github.com/flutter/flutter/issues/114919): Attributes
1113 // are not necessarily `kDrawDisplayListFlags`.
1114 AccumulateOpBounds(rect, kDrawDisplayListFlags);
1115 }
1116 } else {
1117 AccumulateOpBounds(bounds, kDrawDisplayListFlags);
1118 }
1119 break;
1120 }
Chinmay Garde41869f62021-12-28 15:19:35 -08001121 // The non-nested op count accumulated in the |Push| method will include
1122 // this call to |drawDisplayList| for non-nested op count metrics.
1123 // But, for nested op count metrics we want the |drawDisplayList| call itself
1124 // to be transparent. So we subtract 1 from our accumulated nested count to
1125 // balance out against the 1 that was accumulated into the regular count.
Jim Grahamde9093d2023-02-24 17:42:20 -08001126 // This behavior is identical to the way SkPicture computed nested op counts.
Chinmay Garde41869f62021-12-28 15:19:35 -08001127 nested_op_count_ += display_list->op_count(true) - 1;
1128 nested_bytes_ += display_list->bytes(true);
1129 UpdateLayerOpacityCompatibility(display_list->can_apply_group_opacity());
1130}
1131void DisplayListBuilder::drawTextBlob(const sk_sp<SkTextBlob> blob,
1132 SkScalar x,
1133 SkScalar y) {
Zachary Anderson886a14e2023-07-15 07:14:10 -07001134 Push<DrawTextBlobOp>(0, 1, blob, x, y);
1135 AccumulateOpBounds(blob->bounds().makeOffset(x, y), kDrawTextBlobFlags);
1136 // There is no way to query if the glyphs of a text blob overlap and
1137 // there are no current guarantees from either Skia or Impeller that
1138 // they will protect overlapping glyphs from the effects of overdraw
1139 // so we must make the conservative assessment that this DL layer is
1140 // not compatible with group opacity inheritance.
1141 UpdateLayerOpacityCompatibility(false);
Chinmay Garde41869f62021-12-28 15:19:35 -08001142}
Jim Graham0d5b7802023-02-23 22:09:35 -08001143void DisplayListBuilder::DrawTextBlob(const sk_sp<SkTextBlob>& blob,
Jason Simmons4cbfe422022-11-11 08:39:23 -08001144 SkScalar x,
1145 SkScalar y,
1146 const DlPaint& paint) {
Jim Grahamde9093d2023-02-24 17:42:20 -08001147 SetAttributesFromPaint(paint, DisplayListOpFlags::kDrawTextBlobFlags);
Jason Simmons4cbfe422022-11-11 08:39:23 -08001148 drawTextBlob(blob, x, y);
1149}
Jim Graham0d5b7802023-02-23 22:09:35 -08001150void DisplayListBuilder::DrawShadow(const SkPath& path,
Jim Grahamd45b9112022-04-29 13:59:06 -07001151 const DlColor color,
Chinmay Garde41869f62021-12-28 15:19:35 -08001152 const SkScalar elevation,
1153 bool transparent_occluder,
1154 SkScalar dpr) {
Zachary Anderson886a14e2023-07-15 07:14:10 -07001155 transparent_occluder //
1156 ? Push<DrawShadowTransparentOccluderOp>(0, 1, path, color, elevation, dpr)
1157 : Push<DrawShadowOp>(0, 1, path, color, elevation, dpr);
1158
1159 SkRect shadow_bounds =
1160 DlCanvas::ComputeShadowBounds(path, elevation, dpr, GetTransform());
1161 AccumulateOpBounds(shadow_bounds, kDrawShadowFlags);
1162 UpdateLayerOpacityCompatibility(false);
Chinmay Garde41869f62021-12-28 15:19:35 -08001163}
1164
ColdPaleLight948699b2022-12-15 19:52:52 +08001165bool DisplayListBuilder::ComputeFilteredBounds(SkRect& bounds,
1166 const DlImageFilter* filter) {
1167 if (filter) {
1168 if (!filter->map_local_bounds(bounds, bounds)) {
1169 return false;
1170 }
1171 }
1172 return true;
1173}
1174
1175bool DisplayListBuilder::AdjustBoundsForPaint(SkRect& bounds,
1176 DisplayListAttributeFlags flags) {
1177 if (flags.ignores_paint()) {
1178 return true;
1179 }
1180
1181 if (flags.is_geometric()) {
Jim Grahamf73ac7d2023-03-01 19:49:18 -08001182 bool is_stroked = flags.is_stroked(current_.getDrawStyle());
1183
ColdPaleLight948699b2022-12-15 19:52:52 +08001184 // Path effect occurs before stroking...
1185 DisplayListSpecialGeometryFlags special_flags =
Jim Grahamf73ac7d2023-03-01 19:49:18 -08001186 flags.WithPathEffect(current_.getPathEffectPtr(), is_stroked);
ColdPaleLight948699b2022-12-15 19:52:52 +08001187 if (current_.getPathEffect()) {
1188 auto effect_bounds = current_.getPathEffect()->effect_bounds(bounds);
1189 if (!effect_bounds.has_value()) {
1190 return false;
1191 }
1192 bounds = effect_bounds.value();
1193 }
1194
Jim Grahamf73ac7d2023-03-01 19:49:18 -08001195 if (is_stroked) {
ColdPaleLight948699b2022-12-15 19:52:52 +08001196 // Determine the max multiplier to the stroke width first.
1197 SkScalar pad = 1.0f;
1198 if (current_.getStrokeJoin() == DlStrokeJoin::kMiter &&
1199 special_flags.may_have_acute_joins()) {
1200 pad = std::max(pad, current_.getStrokeMiter());
1201 }
1202 if (current_.getStrokeCap() == DlStrokeCap::kSquare &&
1203 special_flags.may_have_diagonal_caps()) {
1204 pad = std::max(pad, SK_ScalarSqrt2);
1205 }
1206 SkScalar min_stroke_width = 0.01;
Jim Graham25514ec2023-03-19 15:59:17 -07001207 pad *= std::max(current_.getStrokeWidth() * 0.5f, min_stroke_width);
ColdPaleLight948699b2022-12-15 19:52:52 +08001208 bounds.outset(pad, pad);
1209 }
1210 }
1211
1212 if (flags.applies_mask_filter()) {
Jim Grahamf73ac7d2023-03-01 19:49:18 -08001213 auto filter = current_.getMaskFilter();
1214 if (filter) {
1215 switch (filter->type()) {
1216 case DlMaskFilterType::kBlur: {
1217 FML_DCHECK(filter->asBlur());
1218 SkScalar mask_sigma_pad = filter->asBlur()->sigma() * 3.0;
1219 bounds.outset(mask_sigma_pad, mask_sigma_pad);
ColdPaleLight948699b2022-12-15 19:52:52 +08001220 }
ColdPaleLight948699b2022-12-15 19:52:52 +08001221 }
1222 }
1223 }
1224
1225 if (flags.applies_image_filter()) {
1226 return ComputeFilteredBounds(bounds, current_.getImageFilter().get());
1227 }
1228
1229 return true;
1230}
1231
Zachary Anderson886a14e2023-07-15 07:14:10 -07001232void DisplayListBuilder::AccumulateUnbounded() {
1233 accumulator()->accumulate(tracker_.device_cull_rect(), op_index_ - 1);
ColdPaleLight948699b2022-12-15 19:52:52 +08001234}
1235
Zachary Anderson886a14e2023-07-15 07:14:10 -07001236void DisplayListBuilder::AccumulateOpBounds(SkRect& bounds,
ColdPaleLight948699b2022-12-15 19:52:52 +08001237 DisplayListAttributeFlags flags) {
1238 if (AdjustBoundsForPaint(bounds, flags)) {
Zachary Anderson886a14e2023-07-15 07:14:10 -07001239 AccumulateBounds(bounds);
ColdPaleLight948699b2022-12-15 19:52:52 +08001240 } else {
Zachary Anderson886a14e2023-07-15 07:14:10 -07001241 AccumulateUnbounded();
ColdPaleLight948699b2022-12-15 19:52:52 +08001242 }
1243}
Zachary Anderson886a14e2023-07-15 07:14:10 -07001244void DisplayListBuilder::AccumulateBounds(SkRect& bounds) {
1245 tracker_.mapRect(&bounds);
1246 if (bounds.intersect(tracker_.device_cull_rect())) {
1247 accumulator()->accumulate(bounds, op_index_ - 1);
ColdPaleLight948699b2022-12-15 19:52:52 +08001248 }
1249}
1250
1251bool DisplayListBuilder::paint_nops_on_transparency() {
1252 // SkImageFilter::canComputeFastBounds tests for transparency behavior
1253 // This test assumes that the blend mode checked down below will
1254 // NOP on transparent black.
Zachary Anderson886a14e2023-07-15 07:14:10 -07001255 if (current_.getImageFilter() &&
1256 current_.getImageFilter()->modifies_transparent_black()) {
ColdPaleLight948699b2022-12-15 19:52:52 +08001257 return false;
1258 }
1259
1260 // We filter the transparent black that is used for the background of a
1261 // saveLayer and make sure it returns transparent black. If it does, then
1262 // the color filter will leave all area surrounding the contents of the
1263 // save layer untouched out to the edge of the output surface.
1264 // This test assumes that the blend mode checked down below will
1265 // NOP on transparent black.
Zachary Anderson886a14e2023-07-15 07:14:10 -07001266 if (current_.getColorFilter() &&
1267 current_.getColorFilter()->modifies_transparent_black()) {
ColdPaleLight948699b2022-12-15 19:52:52 +08001268 return false;
1269 }
1270
ColdPaleLight948699b2022-12-15 19:52:52 +08001271 // Unusual blendmodes require us to process a saved layer
Jim Grahamee6969d2023-03-20 19:34:48 -07001272 // even with operations outside the clip.
ColdPaleLight948699b2022-12-15 19:52:52 +08001273 // For example, DstIn is used by masking layers.
1274 // https://code.google.com/p/skia/issues/detail?id=1291
1275 // https://crbug.com/401593
Jim Graham25514ec2023-03-19 15:59:17 -07001276 switch (current_.getBlendMode()) {
ColdPaleLight948699b2022-12-15 19:52:52 +08001277 // For each of the following transfer modes, if the source
1278 // alpha is zero (our transparent black), the resulting
1279 // blended pixel is not necessarily equal to the original
1280 // destination pixel.
1281 // Mathematically, any time in the following equations where
1282 // the result is not d assuming source is 0
1283 case DlBlendMode::kClear: // r = 0
1284 case DlBlendMode::kSrc: // r = s
1285 case DlBlendMode::kSrcIn: // r = s * da
1286 case DlBlendMode::kDstIn: // r = d * sa
1287 case DlBlendMode::kSrcOut: // r = s * (1-da)
1288 case DlBlendMode::kDstATop: // r = d*sa + s*(1-da)
1289 case DlBlendMode::kModulate: // r = s*d
1290 return false;
1291 break;
1292
1293 // And in these equations, the result must be d if the
1294 // source is 0
1295 case DlBlendMode::kDst: // r = d
1296 case DlBlendMode::kSrcOver: // r = s + (1-sa)*d
1297 case DlBlendMode::kDstOver: // r = d + (1-da)*s
1298 case DlBlendMode::kDstOut: // r = d * (1-sa)
1299 case DlBlendMode::kSrcATop: // r = s*da + d*(1-sa)
1300 case DlBlendMode::kXor: // r = s*(1-da) + d*(1-sa)
1301 case DlBlendMode::kPlus: // r = min(s + d, 1)
1302 case DlBlendMode::kScreen: // r = s + d - s*d
1303 case DlBlendMode::kOverlay: // multiply or screen, depending on dest
1304 case DlBlendMode::kDarken: // rc = s + d - max(s*da, d*sa),
1305 // ra = kSrcOver
1306 case DlBlendMode::kLighten: // rc = s + d - min(s*da, d*sa),
1307 // ra = kSrcOver
1308 case DlBlendMode::kColorDodge: // brighten destination to reflect source
1309 case DlBlendMode::kColorBurn: // darken destination to reflect source
1310 case DlBlendMode::kHardLight: // multiply or screen, depending on source
1311 case DlBlendMode::kSoftLight: // lighten or darken, depending on source
1312 case DlBlendMode::kDifference: // rc = s + d - 2*(min(s*da, d*sa)),
1313 // ra = kSrcOver
1314 case DlBlendMode::kExclusion: // rc = s + d - two(s*d), ra = kSrcOver
1315 case DlBlendMode::kMultiply: // r = s*(1-da) + d*(1-sa) + s*d
1316 case DlBlendMode::kHue: // ra = kSrcOver
1317 case DlBlendMode::kSaturation: // ra = kSrcOver
1318 case DlBlendMode::kColor: // ra = kSrcOver
1319 case DlBlendMode::kLuminosity: // ra = kSrcOver
1320 return true;
1321 break;
1322 }
1323}
Chinmay Garde41869f62021-12-28 15:19:35 -08001324} // namespace flutter