1// 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
5#ifndef FLUTTER_DISPLAY_LIST_DISPLAY_LIST_BUILDER_H_
6#define FLUTTER_DISPLAY_LIST_DISPLAY_LIST_BUILDER_H_
7
8#include "flutter/display_list/display_list.h"
9#include "flutter/display_list/dl_blend_mode.h"
10#include "flutter/display_list/dl_canvas.h"
11#include "flutter/display_list/dl_op_flags.h"
12#include "flutter/display_list/dl_op_receiver.h"
13#include "flutter/display_list/dl_paint.h"
14#include "flutter/display_list/dl_sampling_options.h"
15#include "flutter/display_list/effects/dl_path_effect.h"
16#include "flutter/display_list/image/dl_image.h"
17#include "flutter/display_list/utils/dl_bounds_accumulator.h"
18#include "flutter/display_list/utils/dl_comparable.h"
19#include "flutter/display_list/utils/dl_matrix_clip_tracker.h"
20#include "flutter/fml/macros.h"
21
22namespace flutter {
23
24// The primary class used to build a display list. The list of methods
25// here matches the list of methods invoked on a |DlOpReceiver| combined
26// with the list of methods invoked on a |DlCanvas|.
27class DisplayListBuilder final : public virtual DlCanvas,
28 public SkRefCnt,
29 virtual DlOpReceiver,
30 DisplayListOpFlags {
31 public:
32 static constexpr SkRect kMaxCullRect =
33 SkRect::MakeLTRB(l: -1E9F, t: -1E9F, r: 1E9F, b: 1E9F);
34
35 explicit DisplayListBuilder(bool prepare_rtree)
36 : DisplayListBuilder(kMaxCullRect, prepare_rtree) {}
37
38 explicit DisplayListBuilder(const SkRect& cull_rect = kMaxCullRect,
39 bool prepare_rtree = false);
40
41 ~DisplayListBuilder();
42
43 // |DlCanvas|
44 SkISize GetBaseLayerSize() const override;
45 // |DlCanvas|
46 SkImageInfo GetImageInfo() const override;
47
48 // |DlCanvas|
49 void Save() override;
50
51 // |DlCanvas|
52 void SaveLayer(const SkRect* bounds,
53 const DlPaint* paint = nullptr,
54 const DlImageFilter* backdrop = nullptr) override;
55 // |DlCanvas|
56 void Restore() override;
57 // |DlCanvas|
58 int GetSaveCount() const override { return layer_stack_.size(); }
59 // |DlCanvas|
60 void RestoreToCount(int restore_count) override;
61
62 // |DlCanvas|
63 void Translate(SkScalar tx, SkScalar ty) override;
64 // |DlCanvas|
65 void Scale(SkScalar sx, SkScalar sy) override;
66 // |DlCanvas|
67 void Rotate(SkScalar degrees) override;
68 // |DlCanvas|
69 void Skew(SkScalar sx, SkScalar sy) override;
70
71 // clang-format off
72 // 2x3 2D affine subset of a 4x4 transform in row major order
73 // |DlCanvas|
74 void Transform2DAffine(SkScalar mxx, SkScalar mxy, SkScalar mxt,
75 SkScalar myx, SkScalar myy, SkScalar myt) override;
76 // full 4x4 transform in row major order
77 // |DlCanvas|
78 void TransformFullPerspective(
79 SkScalar mxx, SkScalar mxy, SkScalar mxz, SkScalar mxt,
80 SkScalar myx, SkScalar myy, SkScalar myz, SkScalar myt,
81 SkScalar mzx, SkScalar mzy, SkScalar mzz, SkScalar mzt,
82 SkScalar mwx, SkScalar mwy, SkScalar mwz, SkScalar mwt) override;
83 // clang-format on
84 // |DlCanvas|
85 void TransformReset() override;
86 // |DlCanvas|
87 void Transform(const SkMatrix* matrix) override;
88 // |DlCanvas|
89 void Transform(const SkM44* matrix44) override;
90 // |DlCanvas|
91 void SetTransform(const SkMatrix* matrix) override {
92 TransformReset();
93 Transform(matrix);
94 }
95 // |DlCanvas|
96 void SetTransform(const SkM44* matrix44) override {
97 TransformReset();
98 Transform(matrix44);
99 }
100 using DlCanvas::Transform;
101
102 /// Returns the 4x4 full perspective transform representing all transform
103 /// operations executed so far in this DisplayList within the enclosing
104 /// save stack.
105 // |DlCanvas|
106 SkM44 GetTransformFullPerspective() const override {
107 return tracker_.matrix_4x4();
108 }
109 /// Returns the 3x3 partial perspective transform representing all transform
110 /// operations executed so far in this DisplayList within the enclosing
111 /// save stack.
112 // |DlCanvas|
113 SkMatrix GetTransform() const override { return tracker_.matrix_3x3(); }
114
115 // |DlCanvas|
116 void ClipRect(const SkRect& rect,
117 ClipOp clip_op = ClipOp::kIntersect,
118 bool is_aa = false) override;
119 // |DlCanvas|
120 void ClipRRect(const SkRRect& rrect,
121 ClipOp clip_op = ClipOp::kIntersect,
122 bool is_aa = false) override;
123 // |DlCanvas|
124 void ClipPath(const SkPath& path,
125 ClipOp clip_op = ClipOp::kIntersect,
126 bool is_aa = false) override;
127
128 /// Conservative estimate of the bounds of all outstanding clip operations
129 /// measured in the coordinate space within which this DisplayList will
130 /// be rendered.
131 // |DlCanvas|
132 SkRect GetDestinationClipBounds() const override {
133 return tracker_.device_cull_rect();
134 }
135 /// Conservative estimate of the bounds of all outstanding clip operations
136 /// transformed into the local coordinate space in which currently
137 /// recorded rendering operations are interpreted.
138 // |DlCanvas|
139 SkRect GetLocalClipBounds() const override {
140 return tracker_.local_cull_rect();
141 }
142
143 /// Return true iff the supplied bounds are easily shown to be outside
144 /// of the current clip bounds. This method may conservatively return
145 /// false if it cannot make the determination.
146 // |DlCanvas|
147 bool QuickReject(const SkRect& bounds) const override;
148
149 // |DlCanvas|
150 void DrawPaint(const DlPaint& paint) override;
151 // |DlCanvas|
152 void DrawColor(DlColor color, DlBlendMode mode) override;
153 // |DlCanvas|
154 void DrawLine(const SkPoint& p0,
155 const SkPoint& p1,
156 const DlPaint& paint) override;
157 // |DlCanvas|
158 void DrawRect(const SkRect& rect, const DlPaint& paint) override;
159 // |DlCanvas|
160 void DrawOval(const SkRect& bounds, const DlPaint& paint) override;
161 // |DlCanvas|
162 void DrawCircle(const SkPoint& center,
163 SkScalar radius,
164 const DlPaint& paint) override;
165 // |DlCanvas|
166 void DrawRRect(const SkRRect& rrect, const DlPaint& paint) override;
167 // |DlCanvas|
168 void DrawDRRect(const SkRRect& outer,
169 const SkRRect& inner,
170 const DlPaint& paint) override;
171 // |DlCanvas|
172 void DrawPath(const SkPath& path, const DlPaint& paint) override;
173 // |DlCanvas|
174 void DrawArc(const SkRect& bounds,
175 SkScalar start,
176 SkScalar sweep,
177 bool useCenter,
178 const DlPaint& paint) override;
179 // |DlCanvas|
180 void DrawPoints(PointMode mode,
181 uint32_t count,
182 const SkPoint pts[],
183 const DlPaint& paint) override;
184 // |DlCanvas|
185 void DrawVertices(const DlVertices* vertices,
186 DlBlendMode mode,
187 const DlPaint& paint) override;
188 using DlCanvas::DrawVertices;
189 // |DlCanvas|
190 void DrawImage(const sk_sp<DlImage>& image,
191 const SkPoint point,
192 DlImageSampling sampling,
193 const DlPaint* paint = nullptr) override;
194 // |DlCanvas|
195 void DrawImageRect(
196 const sk_sp<DlImage>& image,
197 const SkRect& src,
198 const SkRect& dst,
199 DlImageSampling sampling,
200 const DlPaint* paint = nullptr,
201 SrcRectConstraint constraint = SrcRectConstraint::kFast) override;
202 using DlCanvas::DrawImageRect;
203 // |DlCanvas|
204 void DrawImageNine(const sk_sp<DlImage>& image,
205 const SkIRect& center,
206 const SkRect& dst,
207 DlFilterMode filter,
208 const DlPaint* paint = nullptr) override;
209 // |DlCanvas|
210 void DrawAtlas(const sk_sp<DlImage>& atlas,
211 const SkRSXform xform[],
212 const SkRect tex[],
213 const DlColor colors[],
214 int count,
215 DlBlendMode mode,
216 DlImageSampling sampling,
217 const SkRect* cullRect,
218 const DlPaint* paint = nullptr) override;
219 // |DlCanvas|
220 void DrawDisplayList(const sk_sp<DisplayList> display_list,
221 SkScalar opacity = SK_Scalar1) override;
222 // |DlCanvas|
223 void DrawTextBlob(const sk_sp<SkTextBlob>& blob,
224 SkScalar x,
225 SkScalar y,
226 const DlPaint& paint) override;
227 // |DlCanvas|
228 void DrawShadow(const SkPath& path,
229 const DlColor color,
230 const SkScalar elevation,
231 bool transparent_occluder,
232 SkScalar dpr) override;
233
234 // |DlCanvas|
235 void Flush() override {}
236
237 sk_sp<DisplayList> Build();
238
239 private:
240 // This method exposes the internal stateful DlOpReceiver implementation
241 // of the DisplayListBuilder, primarily for testing purposes. Its use
242 // is obsolete and forbidden in every other case and is only shared to a
243 // pair of "friend" accessors in the benchmark/unittest files.
244 DlOpReceiver& asReceiver() { return *this; }
245
246 friend DlOpReceiver& DisplayListBuilderBenchmarkAccessor(
247 DisplayListBuilder& builder);
248 friend DlOpReceiver& DisplayListBuilderTestingAccessor(
249 DisplayListBuilder& builder);
250 friend DlPaint DisplayListBuilderTestingAttributes(
251 DisplayListBuilder& builder);
252
253 void SetAttributesFromPaint(const DlPaint& paint,
254 const DisplayListAttributeFlags flags);
255
256 // |DlOpReceiver|
257 void setAntiAlias(bool aa) override {
258 if (current_.isAntiAlias() != aa) {
259 onSetAntiAlias(aa);
260 }
261 }
262 // |DlOpReceiver|
263 void setDither(bool dither) override {
264 if (current_.isDither() != dither) {
265 onSetDither(dither);
266 }
267 }
268 // |DlOpReceiver|
269 void setInvertColors(bool invert) override {
270 if (current_.isInvertColors() != invert) {
271 onSetInvertColors(invert);
272 }
273 }
274 // |DlOpReceiver|
275 void setStrokeCap(DlStrokeCap cap) override {
276 if (current_.getStrokeCap() != cap) {
277 onSetStrokeCap(cap);
278 }
279 }
280 // |DlOpReceiver|
281 void setStrokeJoin(DlStrokeJoin join) override {
282 if (current_.getStrokeJoin() != join) {
283 onSetStrokeJoin(join);
284 }
285 }
286 // |DlOpReceiver|
287 void setDrawStyle(DlDrawStyle style) override {
288 if (current_.getDrawStyle() != style) {
289 onSetDrawStyle(style);
290 }
291 }
292 // |DlOpReceiver|
293 void setStrokeWidth(float width) override {
294 if (current_.getStrokeWidth() != width) {
295 onSetStrokeWidth(width);
296 }
297 }
298 // |DlOpReceiver|
299 void setStrokeMiter(float limit) override {
300 if (current_.getStrokeMiter() != limit) {
301 onSetStrokeMiter(limit);
302 }
303 }
304 // |DlOpReceiver|
305 void setColor(DlColor color) override {
306 if (current_.getColor() != color) {
307 onSetColor(color);
308 }
309 }
310 // |DlOpReceiver|
311 void setBlendMode(DlBlendMode mode) override {
312 if (current_.getBlendMode() != mode) {
313 onSetBlendMode(mode);
314 }
315 }
316 // |DlOpReceiver|
317 void setColorSource(const DlColorSource* source) override {
318 if (NotEquals(a: current_.getColorSource(), b: source)) {
319 onSetColorSource(source);
320 }
321 }
322 // |DlOpReceiver|
323 void setImageFilter(const DlImageFilter* filter) override {
324 if (NotEquals(a: current_.getImageFilter(), b: filter)) {
325 onSetImageFilter(filter);
326 }
327 }
328 // |DlOpReceiver|
329 void setColorFilter(const DlColorFilter* filter) override {
330 if (NotEquals(a: current_.getColorFilter(), b: filter)) {
331 onSetColorFilter(filter);
332 }
333 }
334 // |DlOpReceiver|
335 void setPathEffect(const DlPathEffect* effect) override {
336 if (NotEquals(a: current_.getPathEffect(), b: effect)) {
337 onSetPathEffect(effect);
338 }
339 }
340 // |DlOpReceiver|
341 void setMaskFilter(const DlMaskFilter* filter) override {
342 if (NotEquals(a: current_.getMaskFilter(), b: filter)) {
343 onSetMaskFilter(filter);
344 }
345 }
346
347 DlPaint CurrentAttributes() const { return current_; }
348
349 // |DlOpReceiver|
350 void save() override { Save(); }
351 // Only the |renders_with_attributes()| option will be accepted here. Any
352 // other flags will be ignored and calculated anew as the DisplayList is
353 // built. Alternatively, use the |saveLayer(SkRect, bool)| method.
354 // |DlOpReceiver|
355 void saveLayer(const SkRect* bounds,
356 const SaveLayerOptions options,
357 const DlImageFilter* backdrop) override;
358 // |DlOpReceiver|
359 void restore() override { Restore(); }
360
361 // |DlOpReceiver|
362 void translate(SkScalar tx, SkScalar ty) override { Translate(tx, ty); }
363 // |DlOpReceiver|
364 void scale(SkScalar sx, SkScalar sy) override { Scale(sx, sy); }
365 // |DlOpReceiver|
366 void rotate(SkScalar degrees) override { Rotate(degrees); }
367 // |DlOpReceiver|
368 void skew(SkScalar sx, SkScalar sy) override { Skew(sx, sy); }
369
370 // clang-format off
371 // |DlOpReceiver|
372 void transform2DAffine(SkScalar mxx, SkScalar mxy, SkScalar mxt,
373 SkScalar myx, SkScalar myy, SkScalar myt) override {
374 Transform2DAffine(mxx, mxy, mxt, myx, myy, myt);
375 }
376 // |DlOpReceiver|
377 void transformFullPerspective(
378 SkScalar mxx, SkScalar mxy, SkScalar mxz, SkScalar mxt,
379 SkScalar myx, SkScalar myy, SkScalar myz, SkScalar myt,
380 SkScalar mzx, SkScalar mzy, SkScalar mzz, SkScalar mzt,
381 SkScalar mwx, SkScalar mwy, SkScalar mwz, SkScalar mwt) override {
382 TransformFullPerspective(mxx, mxy, mxz, mxt,
383 myx, myy, myz, myt,
384 mzx, mzy, mzz, mzt,
385 mwx, mwy, mwz, mwt);
386 }
387 // clang-format off
388 // |DlOpReceiver|
389 void transformReset() override { TransformReset(); }
390
391 // |DlOpReceiver|
392 void clipRect(const SkRect& rect, ClipOp clip_op, bool is_aa) override {
393 ClipRect(rect, clip_op, is_aa);
394 }
395 // |DlOpReceiver|
396 void clipRRect(const SkRRect& rrect, ClipOp clip_op, bool is_aa) override {
397 ClipRRect(rrect, clip_op, is_aa);
398 }
399 // |DlOpReceiver|
400 void clipPath(const SkPath& path, ClipOp clip_op, bool is_aa) override {
401 ClipPath(path, clip_op, is_aa);
402 }
403
404 // |DlOpReceiver|
405 void drawPaint() override;
406 // |DlOpReceiver|
407 void drawColor(DlColor color, DlBlendMode mode) override {
408 DrawColor(color, mode);
409 }
410 // |DlOpReceiver|
411 void drawLine(const SkPoint& p0, const SkPoint& p1) override;
412 // |DlOpReceiver|
413 void drawRect(const SkRect& rect) override;
414 // |DlOpReceiver|
415 void drawOval(const SkRect& bounds) override;
416 // |DlOpReceiver|
417 void drawCircle(const SkPoint& center, SkScalar radius) override;
418 // |DlOpReceiver|
419 void drawRRect(const SkRRect& rrect) override;
420 // |DlOpReceiver|
421 void drawDRRect(const SkRRect& outer, const SkRRect& inner) override;
422 // |DlOpReceiver|
423 void drawPath(const SkPath& path) override;
424 // |DlOpReceiver|
425 void drawArc(const SkRect& bounds,
426 SkScalar start,
427 SkScalar sweep,
428 bool useCenter) override;
429 // |DlOpReceiver|
430 void drawPoints(PointMode mode, uint32_t count, const SkPoint pts[]) override;
431 // |DlOpReceiver|
432 void drawVertices(const DlVertices* vertices, DlBlendMode mode) override;
433
434 // |DlOpReceiver|
435 void drawImage(const sk_sp<DlImage> image,
436 const SkPoint point,
437 DlImageSampling sampling,
438 bool render_with_attributes) override;
439 // |DlOpReceiver|
440 void drawImageRect(
441 const sk_sp<DlImage> image,
442 const SkRect& src,
443 const SkRect& dst,
444 DlImageSampling sampling,
445 bool render_with_attributes,
446 SrcRectConstraint constraint = SrcRectConstraint::kFast) override;
447 // |DlOpReceiver|
448 void drawImageNine(const sk_sp<DlImage> image,
449 const SkIRect& center,
450 const SkRect& dst,
451 DlFilterMode filter,
452 bool render_with_attributes) override;
453 // |DlOpReceiver|
454 void drawAtlas(const sk_sp<DlImage> atlas,
455 const SkRSXform xform[],
456 const SkRect tex[],
457 const DlColor colors[],
458 int count,
459 DlBlendMode mode,
460 DlImageSampling sampling,
461 const SkRect* cullRect,
462 bool render_with_attributes) override;
463
464 // |DlOpReceiver|
465 void drawDisplayList(const sk_sp<DisplayList> display_list,
466 SkScalar opacity) override {
467 DrawDisplayList(display_list, opacity);
468 }
469 // |DlOpReceiver|
470 void drawTextBlob(const sk_sp<SkTextBlob> blob,
471 SkScalar x,
472 SkScalar y) override;
473 // |DlOpReceiver|
474 void drawShadow(const SkPath& path,
475 const DlColor color,
476 const SkScalar elevation,
477 bool transparent_occluder,
478 SkScalar dpr) override {
479 DrawShadow(path, color, elevation, transparent_occluder, dpr);
480 }
481
482 void checkForDeferredSave();
483
484 DisplayListStorage storage_;
485 size_t used_ = 0;
486 size_t allocated_ = 0;
487 int render_op_count_ = 0;
488 int op_index_ = 0;
489
490 // bytes and ops from |drawPicture| and |drawDisplayList|
491 size_t nested_bytes_ = 0;
492 int nested_op_count_ = 0;
493
494 bool is_ui_thread_safe_ = true;
495
496 template <typename T, typename... Args>
497 void* Push(size_t extra, int op_inc, Args&&... args);
498
499 void intersect(const SkRect& rect);
500
501 // kInvalidSigma is used to indicate that no MaskBlur is currently set.
502 static constexpr SkScalar kInvalidSigma = 0.0;
503 static bool mask_sigma_valid(SkScalar sigma) {
504 return SkScalarIsFinite(x: sigma) && sigma > 0.0;
505 }
506
507 class LayerInfo {
508 public:
509 explicit LayerInfo(
510 size_t save_offset = 0,
511 bool has_layer = false,
512 const std::shared_ptr<const DlImageFilter>& filter = nullptr)
513 : save_offset_(save_offset),
514 has_layer_(has_layer),
515 filter_(filter) {}
516
517 // The offset into the memory buffer where the saveLayer DLOp record
518 // for this saveLayer() call is placed. This may be needed if the
519 // eventual restore() call has discovered important information about
520 // the records inside the saveLayer that may impact how the saveLayer
521 // is handled (e.g., |cannot_inherit_opacity| == false).
522 // This offset is only valid if |has_layer| is true.
523 size_t save_offset() const { return save_offset_; }
524
525 bool has_layer() const { return has_layer_; }
526 bool cannot_inherit_opacity() const { return cannot_inherit_opacity_; }
527 bool has_compatible_op() const { return has_compatible_op_; }
528 bool affects_transparent_layer() const {
529 return affects_transparent_layer_;
530 }
531
532 bool is_group_opacity_compatible() const {
533 return !cannot_inherit_opacity_;
534 }
535
536 void mark_incompatible() { cannot_inherit_opacity_ = true; }
537
538 // For now this only allows a single compatible op to mark the
539 // layer as being compatible with group opacity. If we start
540 // computing bounds of ops in the Builder methods then we
541 // can upgrade this to checking for overlapping ops.
542 // See https://github.com/flutter/flutter/issues/93899
543 void add_compatible_op() {
544 if (!cannot_inherit_opacity_) {
545 if (has_compatible_op_) {
546 cannot_inherit_opacity_ = true;
547 } else {
548 has_compatible_op_ = true;
549 }
550 }
551 }
552
553 // Records that the current layer contains an op that produces visible
554 // output on a transparent surface.
555 void add_visible_op() {
556 affects_transparent_layer_ = true;
557 }
558
559 // The filter to apply to the layer bounds when it is restored
560 std::shared_ptr<const DlImageFilter> filter() { return filter_; }
561
562 // is_unbounded should be set to true if we ever encounter an operation
563 // on a layer that either is unrestricted (|drawColor| or |drawPaint|)
564 // or cannot compute its bounds (some effects and filters) and there
565 // was no outstanding clip op at the time.
566 // When the layer is restored, the outer layer may then process this
567 // unbounded state by accumulating its own clip or transferring the
568 // unbounded state to its own outer layer.
569 // Typically the DisplayList will have been constructed with a cull
570 // rect which will act as a default clip for the outermost layer and
571 // the unbounded state of all sub layers will eventually be caught by
572 // that cull rect so that the overall unbounded state of the entire
573 // DisplayList will never be true.
574 //
575 // For historical consistency it is worth noting that SkPicture used
576 // to treat these same conditions as a Nop (they accumulate the
577 // SkPicture cull rect, but if no cull rect was specified then it is
578 // an empty Rect and so has no effect on the bounds).
579 //
580 // Flutter is unlikely to ever run into this as the Dart mechanisms
581 // all supply a non-null cull rect for all Dart Picture objects,
582 // even if that cull rect is kGiantRect.
583 void set_unbounded() { is_unbounded_ = true; }
584
585 // |is_unbounded| should be called after |getLayerBounds| in case
586 // a problem was found during the computation of those bounds,
587 // the layer will have one last chance to flag an unbounded state.
588 bool is_unbounded() const { return is_unbounded_; }
589
590 private:
591 size_t save_offset_;
592 bool has_layer_;
593 bool cannot_inherit_opacity_ = false;
594 bool has_compatible_op_ = false;
595 std::shared_ptr<const DlImageFilter> filter_;
596 bool is_unbounded_ = false;
597 bool has_deferred_save_op_ = false;
598 bool is_nop_ = false;
599 bool affects_transparent_layer_ = false;
600
601 friend class DisplayListBuilder;
602 };
603
604 std::vector<LayerInfo> layer_stack_;
605 LayerInfo* current_layer_;
606 DisplayListMatrixClipTracker tracker_;
607 std::unique_ptr<BoundsAccumulator> accumulator_;
608 BoundsAccumulator* accumulator() { return accumulator_.get(); }
609
610 // This flag indicates whether or not the current rendering attributes
611 // are compatible with rendering ops applying an inherited opacity.
612 bool current_opacity_compatibility_ = true;
613
614 // Returns the compatibility of a given blend mode for applying an
615 // inherited opacity value to modulate the visibility of the op.
616 // For now we only accept SrcOver blend modes but this could be expanded
617 // in the future to include other (rarely used) modes that also modulate
618 // the opacity of a rendering operation at the cost of a switch statement
619 // or lookup table.
620 static bool IsOpacityCompatible(DlBlendMode mode) {
621 return (mode == DlBlendMode::kSrcOver);
622 }
623
624 void UpdateCurrentOpacityCompatibility() {
625 current_opacity_compatibility_ = //
626 current_.getColorFilter() == nullptr && //
627 !current_.isInvertColors() && //
628 IsOpacityCompatible(mode: current_.getBlendMode());
629 }
630
631 // Update the opacity compatibility flags of the current layer for an op
632 // that has determined its compatibility as indicated by |compatible|.
633 void UpdateLayerOpacityCompatibility(bool compatible) {
634 if (compatible) {
635 current_layer_->add_compatible_op();
636 } else {
637 current_layer_->mark_incompatible();
638 }
639 }
640
641 // Check for opacity compatibility for an op that may or may not use the
642 // current rendering attributes as indicated by |uses_blend_attribute|.
643 // If the flag is false then the rendering op will be able to substitute
644 // a default Paint object with the opacity applied using the default SrcOver
645 // blend mode which is always compatible with applying an inherited opacity.
646 void CheckLayerOpacityCompatibility(bool uses_blend_attribute = true) {
647 UpdateLayerOpacityCompatibility(compatible: !uses_blend_attribute ||
648 current_opacity_compatibility_);
649 }
650
651 void CheckLayerOpacityHairlineCompatibility() {
652 UpdateLayerOpacityCompatibility(
653 compatible: current_opacity_compatibility_ &&
654 (current_.getDrawStyle() == DlDrawStyle::kFill ||
655 current_.getStrokeWidth() > 0));
656 }
657
658 // Check for opacity compatibility for an op that ignores the current
659 // attributes and uses the indicated blend |mode| to render to the layer.
660 // This is only used by |drawColor| currently.
661 void CheckLayerOpacityCompatibility(DlBlendMode mode) {
662 UpdateLayerOpacityCompatibility(compatible: IsOpacityCompatible(mode));
663 }
664
665 void onSetAntiAlias(bool aa);
666 void onSetDither(bool dither);
667 void onSetInvertColors(bool invert);
668 void onSetStrokeCap(DlStrokeCap cap);
669 void onSetStrokeJoin(DlStrokeJoin join);
670 void onSetDrawStyle(DlDrawStyle style);
671 void onSetStrokeWidth(SkScalar width);
672 void onSetStrokeMiter(SkScalar limit);
673 void onSetColor(DlColor color);
674 void onSetBlendMode(DlBlendMode mode);
675 void onSetColorSource(const DlColorSource* source);
676 void onSetImageFilter(const DlImageFilter* filter);
677 void onSetColorFilter(const DlColorFilter* filter);
678 void onSetPathEffect(const DlPathEffect* effect);
679 void onSetMaskFilter(const DlMaskFilter* filter);
680
681 // The DisplayList had an unbounded call with no cull rect or clip
682 // to contain it. Should only be called after the stream is fully
683 // built.
684 // Unbounded operations are calls like |drawColor| which are defined
685 // to flood the entire surface, or calls that relied on a rendering
686 // attribute which is unable to compute bounds (should be rare).
687 // In those cases the bounds will represent only the accumulation
688 // of the bounded calls and this flag will be set to indicate that
689 // condition.
690 bool is_unbounded() const {
691 FML_DCHECK(layer_stack_.size() == 1);
692 return layer_stack_.front().is_unbounded();
693 }
694
695 SkRect bounds() const {
696 FML_DCHECK(layer_stack_.size() == 1);
697 if (is_unbounded()) {
698 FML_LOG(INFO) << "returning partial bounds for unbounded DisplayList";
699 }
700
701 return accumulator_->bounds();
702 }
703
704 sk_sp<DlRTree> rtree() {
705 FML_DCHECK(layer_stack_.size() == 1);
706 if (is_unbounded()) {
707 FML_LOG(INFO) << "returning partial rtree for unbounded DisplayList";
708 }
709
710 return accumulator_->rtree();
711 }
712
713 static DisplayListAttributeFlags FlagsForPointMode(PointMode mode);
714
715 enum class OpResult {
716 kNoEffect,
717 kPreservesTransparency,
718 kAffectsAll,
719 };
720
721 bool paint_nops_on_transparency();
722 OpResult PaintResult(const DlPaint& paint,
723 DisplayListAttributeFlags flags = kDrawPaintFlags);
724
725 void UpdateLayerResult(OpResult result) {
726 switch (result) {
727 case OpResult::kNoEffect:
728 case OpResult::kPreservesTransparency:
729 break;
730 case OpResult::kAffectsAll:
731 current_layer_->add_visible_op();
732 break;
733 }
734 }
735
736 // kAnyColor is a non-opaque and non-transparent color that will not
737 // trigger any short-circuit tests about the results of a blend.
738 static constexpr DlColor kAnyColor = DlColor::kMidGrey().withAlpha(alpha: 0x80);
739 static_assert(!kAnyColor.isOpaque());
740 static_assert(!kAnyColor.isTransparent());
741 static DlColor GetEffectiveColor(const DlPaint& paint,
742 DisplayListAttributeFlags flags);
743
744 // Computes the bounds of an operation adjusted for a given ImageFilter
745 // and returns whether the computation was possible. If the method
746 // returns false then the caller should assume the worst about the bounds.
747 static bool ComputeFilteredBounds(SkRect& bounds,
748 const DlImageFilter* filter);
749
750 // Adjusts the indicated bounds for the given flags and returns true if
751 // the calculation was possible, or false if it could not be estimated.
752 bool AdjustBoundsForPaint(SkRect& bounds, DisplayListAttributeFlags flags);
753
754 // Records the fact that we encountered an op that either could not
755 // estimate its bounds or that fills all of the destination space.
756 bool AccumulateUnbounded();
757
758 // Records the bounds for an op after modifying them according to the
759 // supplied attribute flags and transforming by the current matrix.
760 bool AccumulateOpBounds(const SkRect& bounds,
761 DisplayListAttributeFlags flags) {
762 SkRect safe_bounds = bounds;
763 return AccumulateOpBounds(bounds&: safe_bounds, flags);
764 }
765
766 // Records the bounds for an op after modifying them according to the
767 // supplied attribute flags and transforming by the current matrix
768 // and clipping against the current clip.
769 bool AccumulateOpBounds(SkRect& bounds, DisplayListAttributeFlags flags);
770
771 // Records the given bounds after transforming by the current matrix
772 // and clipping against the current clip.
773 bool AccumulateBounds(SkRect& bounds);
774
775 DlPaint current_;
776};
777
778} // namespace flutter
779
780#endif // FLUTTER_DISPLAY_LIST_DISPLAY_LIST_BUILDER_H_
781

source code of flutter_engine/flutter/display_list/dl_builder.h