diff --git a/display_list/benchmarking/dl_complexity_unittests.cc b/display_list/benchmarking/dl_complexity_unittests.cc index eee77ac9bdf55..4ec6111485d88 100644 --- a/display_list/benchmarking/dl_complexity_unittests.cc +++ b/display_list/benchmarking/dl_complexity_unittests.cc @@ -423,7 +423,7 @@ TEST(DisplayListComplexity, DrawAtlas) { std::vector xforms; for (int i = 0; i < 10; i++) { rects.push_back(SkRect::MakeXYWH(0, 0, 10, 10)); - xforms.push_back(SkRSXform::Make(1, 0, 0, 0)); + xforms.push_back(SkRSXform::Make(0, 0, 0, 0)); } DisplayListBuilder builder; diff --git a/display_list/display_list.cc b/display_list/display_list.cc index 53707b4c272d9..378f86804f260 100644 --- a/display_list/display_list.cc +++ b/display_list/display_list.cc @@ -22,8 +22,7 @@ DisplayList::DisplayList() unique_id_(0), bounds_({0, 0, 0, 0}), can_apply_group_opacity_(true), - is_ui_thread_safe_(true), - affects_transparent_surface_(false) {} + is_ui_thread_safe_(true) {} DisplayList::DisplayList(DisplayListStorage&& storage, size_t byte_count, @@ -33,7 +32,6 @@ DisplayList::DisplayList(DisplayListStorage&& storage, const SkRect& bounds, bool can_apply_group_opacity, bool is_ui_thread_safe, - bool affects_transparent_surface, sk_sp rtree) : storage_(std::move(storage)), byte_count_(byte_count), @@ -44,7 +42,6 @@ DisplayList::DisplayList(DisplayListStorage&& storage, bounds_(bounds), can_apply_group_opacity_(can_apply_group_opacity), is_ui_thread_safe_(is_ui_thread_safe), - affects_transparent_surface_(affects_transparent_surface), rtree_(std::move(rtree)) {} DisplayList::~DisplayList() { diff --git a/display_list/display_list.h b/display_list/display_list.h index 5e49d2bead06f..4a6f339fdea0d 100644 --- a/display_list/display_list.h +++ b/display_list/display_list.h @@ -263,9 +263,6 @@ class DisplayList : public SkRefCnt { } bool can_apply_group_opacity() const { return can_apply_group_opacity_; } - bool affects_transparent_surface() const { - return affects_transparent_surface_; - } bool isUIThreadSafe() const { return is_ui_thread_safe_; } private: @@ -277,7 +274,6 @@ class DisplayList : public SkRefCnt { const SkRect& bounds, bool can_apply_group_opacity, bool is_ui_thread_safe, - bool affects_transparent_surface, sk_sp rtree); static uint32_t next_unique_id(); @@ -296,8 +292,6 @@ class DisplayList : public SkRefCnt { const bool can_apply_group_opacity_; const bool is_ui_thread_safe_; - const bool affects_transparent_surface_; - const sk_sp rtree_; void Dispatch(DlOpReceiver& ctx, diff --git a/display_list/display_list_unittests.cc b/display_list/display_list_unittests.cc index 291fb1281456a..42f9064e0d7dd 100644 --- a/display_list/display_list_unittests.cc +++ b/display_list/display_list_unittests.cc @@ -22,7 +22,6 @@ #include "flutter/testing/testing.h" #include "third_party/skia/include/core/SkPictureRecorder.h" -#include "third_party/skia/include/core/SkRSXform.h" #include "third_party/skia/include/core/SkSurface.h" namespace flutter { @@ -2640,164 +2639,5 @@ TEST_F(DisplayListTest, DrawSaveDrawCannotInheritOpacity) { ASSERT_FALSE(display_list->can_apply_group_opacity()); } -TEST_F(DisplayListTest, NopOperationsOmittedFromRecords) { - auto run_tests = [](const std::string& name, - void init(DisplayListBuilder & builder, DlPaint & paint), - uint32_t expected_op_count = 0u) { - auto run_one_test = - [init](const std::string& name, - void build(DisplayListBuilder & builder, DlPaint & paint), - uint32_t expected_op_count = 0u) { - DisplayListBuilder builder; - DlPaint paint; - init(builder, paint); - build(builder, paint); - auto list = builder.Build(); - if (list->op_count() != expected_op_count) { - FML_LOG(ERROR) << *list; - } - ASSERT_EQ(list->op_count(), expected_op_count) << name; - ASSERT_TRUE(list->bounds().isEmpty()) << name; - }; - run_one_test( - name + " DrawColor", - [](DisplayListBuilder& builder, DlPaint& paint) { - builder.DrawColor(paint.getColor(), paint.getBlendMode()); - }, - expected_op_count); - run_one_test( - name + " DrawPaint", - [](DisplayListBuilder& builder, DlPaint& paint) { - builder.DrawPaint(paint); - }, - expected_op_count); - run_one_test( - name + " DrawRect", - [](DisplayListBuilder& builder, DlPaint& paint) { - builder.DrawRect({10, 10, 20, 20}, paint); - }, - expected_op_count); - run_one_test( - name + " Other Draw Ops", - [](DisplayListBuilder& builder, DlPaint& paint) { - builder.DrawLine({10, 10}, {20, 20}, paint); - builder.DrawOval({10, 10, 20, 20}, paint); - builder.DrawCircle({50, 50}, 20, paint); - builder.DrawRRect(SkRRect::MakeRectXY({10, 10, 20, 20}, 5, 5), paint); - builder.DrawDRRect(SkRRect::MakeRectXY({5, 5, 100, 100}, 5, 5), - SkRRect::MakeRectXY({10, 10, 20, 20}, 5, 5), - paint); - builder.DrawPath(kTestPath1, paint); - builder.DrawArc({10, 10, 20, 20}, 45, 90, true, paint); - SkPoint pts[] = {{10, 10}, {20, 20}}; - builder.DrawPoints(PointMode::kLines, 2, pts, paint); - builder.DrawVertices(TestVertices1, DlBlendMode::kSrcOver, paint); - builder.DrawImage(TestImage1, {10, 10}, DlImageSampling::kLinear, - &paint); - builder.DrawImageRect(TestImage1, SkRect{0.0f, 0.0f, 10.0f, 10.0f}, - SkRect{10.0f, 10.0f, 25.0f, 25.0f}, - DlImageSampling::kLinear, &paint); - builder.DrawImageNine(TestImage1, {10, 10, 20, 20}, - {10, 10, 100, 100}, DlFilterMode::kLinear, - &paint); - SkRSXform xforms[] = {{1, 0, 10, 10}, {0, 1, 10, 10}}; - SkRect rects[] = {{10, 10, 20, 20}, {10, 20, 30, 20}}; - builder.DrawAtlas(TestImage1, xforms, rects, nullptr, 2, - DlBlendMode::kSrcOver, DlImageSampling::kLinear, - nullptr, &paint); - builder.DrawTextBlob(TestBlob1, 10, 10, paint); - - // Dst mode eliminates most rendering ops except for - // the following two, so we'll prune those manually... - if (paint.getBlendMode() != DlBlendMode::kDst) { - builder.DrawDisplayList(TestDisplayList1, paint.getOpacity()); - builder.DrawShadow(kTestPath1, paint.getColor(), 1, true, 1); - } - }, - expected_op_count); - run_one_test( - name + " SaveLayer", - [](DisplayListBuilder& builder, DlPaint& paint) { - builder.SaveLayer(nullptr, &paint, nullptr); - builder.DrawRect({10, 10, 20, 20}, DlPaint()); - builder.Restore(); - }, - expected_op_count); - run_one_test( - name + " inside Save", - [](DisplayListBuilder& builder, DlPaint& paint) { - builder.Save(); - builder.DrawRect({10, 10, 20, 20}, paint); - builder.Restore(); - }, - expected_op_count); - }; - run_tests("transparent color", // - [](DisplayListBuilder& builder, DlPaint& paint) { - paint.setColor(DlColor::kTransparent()); - }); - run_tests("0 alpha", // - [](DisplayListBuilder& builder, DlPaint& paint) { - // The transparent test above already tested transparent - // black (all 0s), we set White color here so we can test - // the case of all 1s with a 0 alpha - paint.setColor(DlColor::kWhite()); - paint.setAlpha(0); - }); - run_tests("BlendMode::kDst", // - [](DisplayListBuilder& builder, DlPaint& paint) { - paint.setBlendMode(DlBlendMode::kDst); - }); - run_tests("Empty rect clip", // - [](DisplayListBuilder& builder, DlPaint& paint) { - builder.ClipRect(SkRect::MakeEmpty(), ClipOp::kIntersect, false); - }); - run_tests("Empty rrect clip", // - [](DisplayListBuilder& builder, DlPaint& paint) { - builder.ClipRRect(SkRRect::MakeEmpty(), ClipOp::kIntersect, - false); - }); - run_tests("Empty path clip", // - [](DisplayListBuilder& builder, DlPaint& paint) { - builder.ClipPath(SkPath(), ClipOp::kIntersect, false); - }); - run_tests("Transparent SaveLayer", // - [](DisplayListBuilder& builder, DlPaint& paint) { - DlPaint save_paint; - save_paint.setColor(DlColor::kTransparent()); - builder.SaveLayer(nullptr, &save_paint); - }); - run_tests("0 alpha SaveLayer", // - [](DisplayListBuilder& builder, DlPaint& paint) { - DlPaint save_paint; - // The transparent test above already tested transparent - // black (all 0s), we set White color here so we can test - // the case of all 1s with a 0 alpha - save_paint.setColor(DlColor::kWhite()); - save_paint.setAlpha(0); - builder.SaveLayer(nullptr, &save_paint); - }); - run_tests("Dst blended SaveLayer", // - [](DisplayListBuilder& builder, DlPaint& paint) { - DlPaint save_paint; - save_paint.setBlendMode(DlBlendMode::kDst); - builder.SaveLayer(nullptr, &save_paint); - }); - run_tests( - "Nop inside SaveLayer", - [](DisplayListBuilder& builder, DlPaint& paint) { - builder.SaveLayer(nullptr, nullptr); - paint.setBlendMode(DlBlendMode::kDst); - }, - 2u); - run_tests("DrawImage inside Culled SaveLayer", // - [](DisplayListBuilder& builder, DlPaint& paint) { - DlPaint save_paint; - save_paint.setColor(DlColor::kTransparent()); - builder.SaveLayer(nullptr, &save_paint); - builder.DrawImage(TestImage1, {10, 10}, DlImageSampling::kLinear); - }); -} - } // namespace testing } // namespace flutter diff --git a/display_list/dl_builder.cc b/display_list/dl_builder.cc index c728b81aa6b5c..731ac6307bc9c 100644 --- a/display_list/dl_builder.cc +++ b/display_list/dl_builder.cc @@ -6,12 +6,10 @@ #include "flutter/display_list/display_list.h" #include "flutter/display_list/dl_blend_mode.h" -#include "flutter/display_list/dl_op_flags.h" #include "flutter/display_list/dl_op_records.h" #include "flutter/display_list/effects/dl_color_source.h" #include "flutter/display_list/utils/dl_bounds_accumulator.h" #include "fml/logging.h" -#include "third_party/skia/include/core/SkScalar.h" namespace flutter { @@ -74,12 +72,11 @@ sk_sp DisplayListBuilder::Build() { used_ = allocated_ = render_op_count_ = op_index_ = 0; nested_bytes_ = nested_op_count_ = 0; storage_.realloc(bytes); - bool compatible = current_layer_->is_group_opacity_compatible(); + bool compatible = layer_stack_.back().is_group_opacity_compatible(); bool is_safe = is_ui_thread_safe_; - bool affects_transparency = current_layer_->affects_transparent_layer(); - return sk_sp(new DisplayList( - std::move(storage_), bytes, count, nested_bytes, nested_count, bounds(), - compatible, is_safe, affects_transparency, rtree())); + return sk_sp( + new DisplayList(std::move(storage_), bytes, count, nested_bytes, + nested_count, bounds(), compatible, is_safe, rtree())); } DisplayListBuilder::DisplayListBuilder(const SkRect& cull_rect, @@ -385,11 +382,9 @@ void DisplayListBuilder::checkForDeferredSave() { } void DisplayListBuilder::Save() { - bool is_nop = current_layer_->is_nop_; layer_stack_.emplace_back(); current_layer_ = &layer_stack_.back(); current_layer_->has_deferred_save_op_ = true; - current_layer_->is_nop_ = is_nop; tracker_.save(); accumulator()->save(); } @@ -476,16 +471,18 @@ void DisplayListBuilder::saveLayer(const SkRect* bounds, const SaveLayerOptions in_options, const DlImageFilter* backdrop) { SaveLayerOptions options = in_options.without_optimizations(); - DisplayListAttributeFlags flags = options.renders_with_attributes() - ? kSaveLayerWithPaintFlags - : kSaveLayerFlags; - OpResult result = PaintResult(current_, flags); - if (result == OpResult::kNoEffect) { - save(); - current_layer_->is_nop_ = true; - return; - } size_t save_layer_offset = used_; + if (backdrop) { + bounds // + ? Push(0, 1, options, *bounds, backdrop) + : Push(0, 1, options, backdrop); + } else { + bounds // + ? Push(0, 1, options, *bounds) + : Push(0, 1, options); + } + CheckLayerOpacityCompatibility(options.renders_with_attributes()); + if (options.renders_with_attributes()) { // The actual flood of the outer layer clip will occur after the // (eventual) corresponding restore is called, but rather than @@ -496,41 +493,17 @@ void DisplayListBuilder::saveLayer(const SkRect* bounds, // with its full bounds and the right op_index so that it doesn't // get culled during rendering. if (!paint_nops_on_transparency()) { - // We will fill the clip of the outer layer when we restore. - // Accumulate should always return true here because if the - // clip was empty then that would have been caught up above - // when we tested the PaintResult. - [[maybe_unused]] bool unclipped = AccumulateUnbounded(); - FML_DCHECK(unclipped); + // We will fill the clip of the outer layer when we restore + AccumulateUnbounded(); } - CheckLayerOpacityCompatibility(true); layer_stack_.emplace_back(save_layer_offset, true, current_.getImageFilter()); } else { - CheckLayerOpacityCompatibility(false); layer_stack_.emplace_back(save_layer_offset, true, nullptr); } - current_layer_ = &layer_stack_.back(); - tracker_.save(); accumulator()->save(); - - if (backdrop) { - // A backdrop will affect up to the entire surface, bounded by the clip - // Accumulate should always return true here because if the - // clip was empty then that would have been caught up above - // when we tested the PaintResult. - [[maybe_unused]] bool unclipped = AccumulateUnbounded(); - FML_DCHECK(unclipped); - bounds // - ? Push(0, 1, options, *bounds, backdrop) - : Push(0, 1, options, backdrop); - } else { - bounds // - ? Push(0, 1, options, *bounds) - : Push(0, 1, options); - } - + current_layer_ = &layer_stack_.back(); if (options.renders_with_attributes()) { // |current_opacity_compatibility_| does not take an ImageFilter into // account because an individual primitive with an ImageFilter can apply @@ -541,7 +514,6 @@ void DisplayListBuilder::saveLayer(const SkRect* bounds, UpdateLayerOpacityCompatibility(false); } } - UpdateLayerResult(result); // Even though Skia claims that the bounds are only a hint, they actually // use them as the temporary layer bounds during rendering the layer, so @@ -549,6 +521,10 @@ void DisplayListBuilder::saveLayer(const SkRect* bounds, if (bounds) { tracker_.clipRect(*bounds, ClipOp::kIntersect, false); } + if (backdrop) { + // A backdrop will affect up to the entire surface, bounded by the clip + AccumulateUnbounded(); + } } void DisplayListBuilder::SaveLayer(const SkRect* bounds, const DlPaint* paint, @@ -671,11 +647,6 @@ void DisplayListBuilder::ClipRect(const SkRect& rect, if (!rect.isFinite()) { return; } - tracker_.clipRect(rect, clip_op, is_aa); - if (current_layer_->is_nop_ || tracker_.is_cull_rect_empty()) { - current_layer_->is_nop_ = true; - return; - } checkForDeferredSave(); switch (clip_op) { case ClipOp::kIntersect: @@ -685,6 +656,7 @@ void DisplayListBuilder::ClipRect(const SkRect& rect, Push(0, 1, rect, is_aa); break; } + tracker_.clipRect(rect, clip_op, is_aa); } void DisplayListBuilder::ClipRRect(const SkRRect& rrect, ClipOp clip_op, @@ -692,11 +664,6 @@ void DisplayListBuilder::ClipRRect(const SkRRect& rrect, if (rrect.isRect()) { clipRect(rrect.rect(), clip_op, is_aa); } else { - tracker_.clipRRect(rrect, clip_op, is_aa); - if (current_layer_->is_nop_ || tracker_.is_cull_rect_empty()) { - current_layer_->is_nop_ = true; - return; - } checkForDeferredSave(); switch (clip_op) { case ClipOp::kIntersect: @@ -706,6 +673,7 @@ void DisplayListBuilder::ClipRRect(const SkRRect& rrect, Push(0, 1, rrect, is_aa); break; } + tracker_.clipRRect(rrect, clip_op, is_aa); } } void DisplayListBuilder::ClipPath(const SkPath& path, @@ -728,11 +696,6 @@ void DisplayListBuilder::ClipPath(const SkPath& path, return; } } - tracker_.clipPath(path, clip_op, is_aa); - if (current_layer_->is_nop_ || tracker_.is_cull_rect_empty()) { - current_layer_->is_nop_ = true; - return; - } checkForDeferredSave(); switch (clip_op) { case ClipOp::kIntersect: @@ -742,6 +705,7 @@ void DisplayListBuilder::ClipPath(const SkPath& path, Push(0, 1, path, is_aa); break; } + tracker_.clipPath(path, clip_op, is_aa); } bool DisplayListBuilder::QuickReject(const SkRect& bounds) const { @@ -749,36 +713,27 @@ bool DisplayListBuilder::QuickReject(const SkRect& bounds) const { } void DisplayListBuilder::drawPaint() { - OpResult result = PaintResult(current_, kDrawPaintFlags); - if (result != OpResult::kNoEffect && AccumulateUnbounded()) { - Push(0, 1); - CheckLayerOpacityCompatibility(); - UpdateLayerResult(result); - } + Push(0, 1); + CheckLayerOpacityCompatibility(); + AccumulateUnbounded(); } void DisplayListBuilder::DrawPaint(const DlPaint& paint) { SetAttributesFromPaint(paint, DisplayListOpFlags::kDrawPaintFlags); drawPaint(); } void DisplayListBuilder::DrawColor(DlColor color, DlBlendMode mode) { - OpResult result = PaintResult(DlPaint(color).setBlendMode(mode)); - if (result != OpResult::kNoEffect && AccumulateUnbounded()) { - Push(0, 1, color, mode); - CheckLayerOpacityCompatibility(mode); - UpdateLayerResult(result); - } + Push(0, 1, color, mode); + CheckLayerOpacityCompatibility(mode); + AccumulateUnbounded(); } void DisplayListBuilder::drawLine(const SkPoint& p0, const SkPoint& p1) { + Push(0, 1, p0, p1); + CheckLayerOpacityCompatibility(); SkRect bounds = SkRect::MakeLTRB(p0.fX, p0.fY, p1.fX, p1.fY).makeSorted(); DisplayListAttributeFlags flags = (bounds.width() > 0.0f && bounds.height() > 0.0f) ? kDrawLineFlags : kDrawHVLineFlags; - OpResult result = PaintResult(current_, flags); - if (result != OpResult::kNoEffect && AccumulateOpBounds(bounds, flags)) { - Push(0, 1, p0, p1); - CheckLayerOpacityCompatibility(); - UpdateLayerResult(result); - } + AccumulateOpBounds(bounds, flags); } void DisplayListBuilder::DrawLine(const SkPoint& p0, const SkPoint& p1, @@ -787,43 +742,29 @@ void DisplayListBuilder::DrawLine(const SkPoint& p0, drawLine(p0, p1); } void DisplayListBuilder::drawRect(const SkRect& rect) { - DisplayListAttributeFlags flags = kDrawRectFlags; - OpResult result = PaintResult(current_, flags); - if (result != OpResult::kNoEffect && AccumulateOpBounds(rect, flags)) { - Push(0, 1, rect); - CheckLayerOpacityCompatibility(); - UpdateLayerResult(result); - } + Push(0, 1, rect); + CheckLayerOpacityCompatibility(); + AccumulateOpBounds(rect, kDrawRectFlags); } void DisplayListBuilder::DrawRect(const SkRect& rect, const DlPaint& paint) { SetAttributesFromPaint(paint, DisplayListOpFlags::kDrawRectFlags); drawRect(rect); } void DisplayListBuilder::drawOval(const SkRect& bounds) { - DisplayListAttributeFlags flags = kDrawOvalFlags; - OpResult result = PaintResult(current_, flags); - if (result != OpResult::kNoEffect && AccumulateOpBounds(bounds, flags)) { - Push(0, 1, bounds); - CheckLayerOpacityCompatibility(); - UpdateLayerResult(result); - } + Push(0, 1, bounds); + CheckLayerOpacityCompatibility(); + AccumulateOpBounds(bounds, kDrawOvalFlags); } void DisplayListBuilder::DrawOval(const SkRect& bounds, const DlPaint& paint) { SetAttributesFromPaint(paint, DisplayListOpFlags::kDrawOvalFlags); drawOval(bounds); } void DisplayListBuilder::drawCircle(const SkPoint& center, SkScalar radius) { - DisplayListAttributeFlags flags = kDrawCircleFlags; - OpResult result = PaintResult(current_, flags); - if (result != OpResult::kNoEffect) { - SkRect bounds = SkRect::MakeLTRB(center.fX - radius, center.fY - radius, - center.fX + radius, center.fY + radius); - if (AccumulateOpBounds(bounds, flags)) { - Push(0, 1, center, radius); - CheckLayerOpacityCompatibility(); - UpdateLayerResult(result); - } - } + Push(0, 1, center, radius); + CheckLayerOpacityCompatibility(); + AccumulateOpBounds(SkRect::MakeLTRB(center.fX - radius, center.fY - radius, + center.fX + radius, center.fY + radius), + kDrawCircleFlags); } void DisplayListBuilder::DrawCircle(const SkPoint& center, SkScalar radius, @@ -837,14 +778,9 @@ void DisplayListBuilder::drawRRect(const SkRRect& rrect) { } else if (rrect.isOval()) { drawOval(rrect.rect()); } else { - DisplayListAttributeFlags flags = kDrawRRectFlags; - OpResult result = PaintResult(current_, flags); - if (result != OpResult::kNoEffect && - AccumulateOpBounds(rrect.getBounds(), flags)) { - Push(0, 1, rrect); - CheckLayerOpacityCompatibility(); - UpdateLayerResult(result); - } + Push(0, 1, rrect); + CheckLayerOpacityCompatibility(); + AccumulateOpBounds(rrect.getBounds(), kDrawRRectFlags); } } void DisplayListBuilder::DrawRRect(const SkRRect& rrect, const DlPaint& paint) { @@ -853,14 +789,9 @@ void DisplayListBuilder::DrawRRect(const SkRRect& rrect, const DlPaint& paint) { } void DisplayListBuilder::drawDRRect(const SkRRect& outer, const SkRRect& inner) { - DisplayListAttributeFlags flags = kDrawDRRectFlags; - OpResult result = PaintResult(current_, flags); - if (result != OpResult::kNoEffect && - AccumulateOpBounds(outer.getBounds(), flags)) { - Push(0, 1, outer, inner); - CheckLayerOpacityCompatibility(); - UpdateLayerResult(result); - } + Push(0, 1, outer, inner); + CheckLayerOpacityCompatibility(); + AccumulateOpBounds(outer.getBounds(), kDrawDRRectFlags); } void DisplayListBuilder::DrawDRRect(const SkRRect& outer, const SkRRect& inner, @@ -869,17 +800,12 @@ void DisplayListBuilder::DrawDRRect(const SkRRect& outer, drawDRRect(outer, inner); } void DisplayListBuilder::drawPath(const SkPath& path) { - DisplayListAttributeFlags flags = kDrawPathFlags; - OpResult result = PaintResult(current_, flags); - if (result != OpResult::kNoEffect) { - bool is_visible = path.isInverseFillType() - ? AccumulateUnbounded() - : AccumulateOpBounds(path.getBounds(), flags); - if (is_visible) { - Push(0, 1, path); - CheckLayerOpacityHairlineCompatibility(); - UpdateLayerResult(result); - } + Push(0, 1, path); + CheckLayerOpacityHairlineCompatibility(); + if (path.isInverseFillType()) { + AccumulateUnbounded(); + } else { + AccumulateOpBounds(path.getBounds(), kDrawPathFlags); } } void DisplayListBuilder::DrawPath(const SkPath& path, const DlPaint& paint) { @@ -891,23 +817,19 @@ void DisplayListBuilder::drawArc(const SkRect& bounds, SkScalar start, SkScalar sweep, bool useCenter) { - DisplayListAttributeFlags flags = // - useCenter // - ? kDrawArcWithCenterFlags - : kDrawArcNoCenterFlags; - OpResult result = PaintResult(current_, flags); + Push(0, 1, bounds, start, sweep, useCenter); + if (useCenter) { + CheckLayerOpacityHairlineCompatibility(); + } else { + CheckLayerOpacityCompatibility(); + } // This could be tighter if we compute where the start and end // angles are and then also consider the quadrants swept and // the center if specified. - if (result != OpResult::kNoEffect && AccumulateOpBounds(bounds, flags)) { - Push(0, 1, bounds, start, sweep, useCenter); - if (useCenter) { - CheckLayerOpacityHairlineCompatibility(); - } else { - CheckLayerOpacityCompatibility(); - } - UpdateLayerResult(result); - } + AccumulateOpBounds(bounds, + useCenter // + ? kDrawArcWithCenterFlags + : kDrawArcNoCenterFlags); } void DisplayListBuilder::DrawArc(const SkRect& bounds, SkScalar start, @@ -918,31 +840,14 @@ void DisplayListBuilder::DrawArc(const SkRect& bounds, paint, useCenter ? kDrawArcWithCenterFlags : kDrawArcNoCenterFlags); drawArc(bounds, start, sweep, useCenter); } - -DisplayListAttributeFlags DisplayListBuilder::FlagsForPointMode( - PointMode mode) { - switch (mode) { - case DlCanvas::PointMode::kPoints: - return kDrawPointsAsPointsFlags; - case PointMode::kLines: - return kDrawPointsAsLinesFlags; - case PointMode::kPolygon: - return kDrawPointsAsPolygonFlags; - } - FML_UNREACHABLE(); -} void DisplayListBuilder::drawPoints(PointMode mode, uint32_t count, const SkPoint pts[]) { if (count == 0) { return; } - DisplayListAttributeFlags flags = FlagsForPointMode(mode); - OpResult result = PaintResult(current_, flags); - if (result == OpResult::kNoEffect) { - return; - } + void* data_ptr; FML_DCHECK(count < DlOpReceiver::kMaxDrawPointsCount); int bytes = count * sizeof(SkPoint); RectBoundsAccumulator ptBounds; @@ -950,23 +855,21 @@ void DisplayListBuilder::drawPoints(PointMode mode, ptBounds.accumulate(pts[i]); } SkRect point_bounds = ptBounds.bounds(); - if (!AccumulateOpBounds(point_bounds, flags)) { - return; - } - - void* data_ptr; switch (mode) { case PointMode::kPoints: data_ptr = Push(bytes, 1, count); + AccumulateOpBounds(point_bounds, kDrawPointsAsPointsFlags); break; case PointMode::kLines: data_ptr = Push(bytes, 1, count); + AccumulateOpBounds(point_bounds, kDrawPointsAsLinesFlags); break; case PointMode::kPolygon: data_ptr = Push(bytes, 1, count); + AccumulateOpBounds(point_bounds, kDrawPointsAsPolygonFlags); break; default: - FML_UNREACHABLE(); + FML_DCHECK(false); return; } CopyV(data_ptr, pts, count); @@ -976,30 +879,39 @@ void DisplayListBuilder::drawPoints(PointMode mode, // bounds of every sub-primitive. // See: https://fiddle.skia.org/c/228459001d2de8db117ce25ef5cedb0c UpdateLayerOpacityCompatibility(false); - UpdateLayerResult(result); } void DisplayListBuilder::DrawPoints(PointMode mode, uint32_t count, const SkPoint pts[], const DlPaint& paint) { - SetAttributesFromPaint(paint, FlagsForPointMode(mode)); + const DisplayListAttributeFlags* flags; + switch (mode) { + case PointMode::kPoints: + flags = &DisplayListOpFlags::kDrawPointsAsPointsFlags; + break; + case PointMode::kLines: + flags = &DisplayListOpFlags::kDrawPointsAsLinesFlags; + break; + case PointMode::kPolygon: + flags = &DisplayListOpFlags::kDrawPointsAsPolygonFlags; + break; + default: + FML_DCHECK(false); + return; + } + SetAttributesFromPaint(paint, *flags); drawPoints(mode, count, pts); } void DisplayListBuilder::drawVertices(const DlVertices* vertices, DlBlendMode mode) { - DisplayListAttributeFlags flags = kDrawVerticesFlags; - OpResult result = PaintResult(current_, flags); - if (result != OpResult::kNoEffect && - AccumulateOpBounds(vertices->bounds(), flags)) { - void* pod = Push(vertices->size(), 1, mode); - new (pod) DlVertices(vertices); - // DrawVertices applies its colors to the paint so we have no way - // of controlling opacity using the current paint attributes. - // Although, examination of the |mode| might find some predictable - // cases. - UpdateLayerOpacityCompatibility(false); - UpdateLayerResult(result); - } + void* pod = Push(vertices->size(), 1, mode); + new (pod) DlVertices(vertices); + // DrawVertices applies its colors to the paint so we have no way + // of controlling opacity using the current paint attributes. + // Although, examination of the |mode| might find some predictable + // cases. + UpdateLayerOpacityCompatibility(false); + AccumulateOpBounds(vertices->bounds(), kDrawVerticesFlags); } void DisplayListBuilder::DrawVertices(const DlVertices* vertices, DlBlendMode mode, @@ -1012,23 +924,17 @@ void DisplayListBuilder::drawImage(const sk_sp image, const SkPoint point, DlImageSampling sampling, bool render_with_attributes) { + render_with_attributes + ? Push(0, 1, image, point, sampling) + : Push(0, 1, image, point, sampling); + CheckLayerOpacityCompatibility(render_with_attributes); + is_ui_thread_safe_ = is_ui_thread_safe_ && image->isUIThreadSafe(); + SkRect bounds = SkRect::MakeXYWH(point.fX, point.fY, // + image->width(), image->height()); DisplayListAttributeFlags flags = render_with_attributes // ? kDrawImageWithPaintFlags : kDrawImageFlags; - OpResult result = PaintResult(current_, flags); - if (result == OpResult::kNoEffect) { - return; - } - SkRect bounds = SkRect::MakeXYWH(point.fX, point.fY, // - image->width(), image->height()); - if (AccumulateOpBounds(bounds, flags)) { - render_with_attributes - ? Push(0, 1, image, point, sampling) - : Push(0, 1, image, point, sampling); - CheckLayerOpacityCompatibility(render_with_attributes); - UpdateLayerResult(result); - is_ui_thread_safe_ = is_ui_thread_safe_ && image->isUIThreadSafe(); - } + AccumulateOpBounds(bounds, flags); } void DisplayListBuilder::DrawImage(const sk_sp& image, const SkPoint point, @@ -1048,17 +954,14 @@ void DisplayListBuilder::drawImageRect(const sk_sp image, DlImageSampling sampling, bool render_with_attributes, SrcRectConstraint constraint) { + Push(0, 1, image, src, dst, sampling, render_with_attributes, + constraint); + CheckLayerOpacityCompatibility(render_with_attributes); + is_ui_thread_safe_ = is_ui_thread_safe_ && image->isUIThreadSafe(); DisplayListAttributeFlags flags = render_with_attributes ? kDrawImageRectWithPaintFlags : kDrawImageRectFlags; - OpResult result = PaintResult(current_, flags); - if (result != OpResult::kNoEffect && AccumulateOpBounds(dst, flags)) { - Push(0, 1, image, src, dst, sampling, - render_with_attributes, constraint); - CheckLayerOpacityCompatibility(render_with_attributes); - UpdateLayerResult(result); - is_ui_thread_safe_ = is_ui_thread_safe_ && image->isUIThreadSafe(); - } + AccumulateOpBounds(dst, flags); } void DisplayListBuilder::DrawImageRect(const sk_sp& image, const SkRect& src, @@ -1079,18 +982,15 @@ void DisplayListBuilder::drawImageNine(const sk_sp image, const SkRect& dst, DlFilterMode filter, bool render_with_attributes) { + render_with_attributes + ? Push(0, 1, image, center, dst, filter) + : Push(0, 1, image, center, dst, filter); + CheckLayerOpacityCompatibility(render_with_attributes); + is_ui_thread_safe_ = is_ui_thread_safe_ && image->isUIThreadSafe(); DisplayListAttributeFlags flags = render_with_attributes ? kDrawImageNineWithPaintFlags : kDrawImageNineFlags; - OpResult result = PaintResult(current_, flags); - if (result != OpResult::kNoEffect && AccumulateOpBounds(dst, flags)) { - render_with_attributes - ? Push(0, 1, image, center, dst, filter) - : Push(0, 1, image, center, dst, filter); - CheckLayerOpacityCompatibility(render_with_attributes); - UpdateLayerResult(result); - is_ui_thread_safe_ = is_ui_thread_safe_ && image->isUIThreadSafe(); - } + AccumulateOpBounds(dst, flags); } void DisplayListBuilder::DrawImageNine(const sk_sp& image, const SkIRect& center, @@ -1114,27 +1014,6 @@ void DisplayListBuilder::drawAtlas(const sk_sp atlas, DlImageSampling sampling, const SkRect* cull_rect, bool render_with_attributes) { - DisplayListAttributeFlags flags = render_with_attributes // - ? kDrawAtlasWithPaintFlags - : kDrawAtlasFlags; - OpResult result = PaintResult(current_, flags); - if (result == OpResult::kNoEffect) { - return; - } - SkPoint quad[4]; - RectBoundsAccumulator atlasBounds; - for (int i = 0; i < count; i++) { - const SkRect& src = tex[i]; - xform[i].toQuad(src.width(), src.height(), quad); - for (int j = 0; j < 4; j++) { - atlasBounds.accumulate(quad[j]); - } - } - if (atlasBounds.is_empty() || - !AccumulateOpBounds(atlasBounds.bounds(), flags)) { - return; - } - int bytes = count * (sizeof(SkRSXform) + sizeof(SkRect)); void* data_ptr; if (colors != nullptr) { @@ -1163,8 +1042,23 @@ void DisplayListBuilder::drawAtlas(const sk_sp atlas, // on it to distribute the opacity without overlap without checking all // of the transforms and texture rectangles. UpdateLayerOpacityCompatibility(false); - UpdateLayerResult(result); is_ui_thread_safe_ = is_ui_thread_safe_ && atlas->isUIThreadSafe(); + + SkPoint quad[4]; + RectBoundsAccumulator atlasBounds; + for (int i = 0; i < count; i++) { + const SkRect& src = tex[i]; + xform[i].toQuad(src.width(), src.height(), quad); + for (int j = 0; j < 4; j++) { + atlasBounds.accumulate(quad[j]); + } + } + if (atlasBounds.is_not_empty()) { + DisplayListAttributeFlags flags = render_with_attributes // + ? kDrawAtlasWithPaintFlags + : kDrawAtlasFlags; + AccumulateOpBounds(atlasBounds.bounds(), flags); + } } void DisplayListBuilder::DrawAtlas(const sk_sp& atlas, const SkRSXform xform[], @@ -1188,48 +1082,34 @@ void DisplayListBuilder::DrawAtlas(const sk_sp& atlas, void DisplayListBuilder::DrawDisplayList(const sk_sp display_list, SkScalar opacity) { - if (!SkScalarIsFinite(opacity) || opacity <= SK_ScalarNearlyZero || - display_list->op_count() == 0 || display_list->bounds().isEmpty() || - current_layer_->is_nop_) { - return; - } + DlPaint current_paint = current_; + Push(0, 1, display_list, opacity); + is_ui_thread_safe_ = is_ui_thread_safe_ && display_list->isUIThreadSafe(); + // Not really necessary if the developer is interacting with us via + // our attribute-state-less DlCanvas methods, but this avoids surprises + // for those who may have been using the stateful Dispatcher methods. + SetAttributesFromPaint(current_paint, + DisplayListOpFlags::kSaveLayerWithPaintFlags); + const SkRect bounds = display_list->bounds(); - bool accumulated; switch (accumulator()->type()) { case BoundsAccumulatorType::kRect: - accumulated = AccumulateOpBounds(bounds, kDrawDisplayListFlags); + AccumulateOpBounds(bounds, kDrawDisplayListFlags); break; case BoundsAccumulatorType::kRTree: auto rtree = display_list->rtree(); if (rtree) { std::list rects = rtree->searchAndConsolidateRects(bounds); - accumulated = false; for (const SkRect& rect : rects) { // TODO (https://github.com/flutter/flutter/issues/114919): Attributes // are not necessarily `kDrawDisplayListFlags`. - if (AccumulateOpBounds(rect, kDrawDisplayListFlags)) { - accumulated = true; - } + AccumulateOpBounds(rect, kDrawDisplayListFlags); } } else { - accumulated = AccumulateOpBounds(bounds, kDrawDisplayListFlags); + AccumulateOpBounds(bounds, kDrawDisplayListFlags); } break; } - if (!accumulated) { - return; - } - - DlPaint current_paint = current_; - Push(0, 1, display_list, - opacity < SK_Scalar1 ? opacity : SK_Scalar1); - is_ui_thread_safe_ = is_ui_thread_safe_ && display_list->isUIThreadSafe(); - // Not really necessary if the developer is interacting with us via - // our attribute-state-less DlCanvas methods, but this avoids surprises - // for those who may have been using the stateful Dispatcher methods. - SetAttributesFromPaint(current_paint, - DisplayListOpFlags::kSaveLayerWithPaintFlags); - // The non-nested op count accumulated in the |Push| method will include // this call to |drawDisplayList| for non-nested op count metrics. // But, for nested op count metrics we want the |drawDisplayList| call itself @@ -1239,36 +1119,18 @@ void DisplayListBuilder::DrawDisplayList(const sk_sp display_list, nested_op_count_ += display_list->op_count(true) - 1; nested_bytes_ += display_list->bytes(true); UpdateLayerOpacityCompatibility(display_list->can_apply_group_opacity()); - UpdateLayerResult(display_list->affects_transparent_surface() - ? OpResult::kDrawsPixels - : OpResult::kClearsPixels); } void DisplayListBuilder::drawTextBlob(const sk_sp blob, SkScalar x, SkScalar y) { - DisplayListAttributeFlags flags = kDrawTextBlobFlags; - OpResult result = PaintResult(current_, flags); - if (result == OpResult::kNoEffect) { - return; - } - bool unclipped = AccumulateOpBounds(blob->bounds().makeOffset(x, y), flags); - // TODO(https://github.com/flutter/flutter/issues/82202): Remove once the - // unit tests can use Fuchsia's font manager instead of the empty default. - // Until then we might encounter empty bounds for otherwise valid text and - // thus we ignore the results from AccumulateOpBounds. -#if defined(OS_FUCHSIA) - unclipped = true; -#endif // OS_FUCHSIA - if (unclipped) { - Push(0, 1, blob, x, y); - // There is no way to query if the glyphs of a text blob overlap and - // there are no current guarantees from either Skia or Impeller that - // they will protect overlapping glyphs from the effects of overdraw - // so we must make the conservative assessment that this DL layer is - // not compatible with group opacity inheritance. - UpdateLayerOpacityCompatibility(false); - UpdateLayerResult(result); - } + Push(0, 1, blob, x, y); + AccumulateOpBounds(blob->bounds().makeOffset(x, y), kDrawTextBlobFlags); + // There is no way to query if the glyphs of a text blob overlap and + // there are no current guarantees from either Skia or Impeller that + // they will protect overlapping glyphs from the effects of overdraw + // so we must make the conservative assessment that this DL layer is + // not compatible with group opacity inheritance. + UpdateLayerOpacityCompatibility(false); } void DisplayListBuilder::DrawTextBlob(const sk_sp& blob, SkScalar x, @@ -1282,19 +1144,14 @@ void DisplayListBuilder::DrawShadow(const SkPath& path, const SkScalar elevation, bool transparent_occluder, SkScalar dpr) { - OpResult result = PaintResult(DlPaint(color)); - if (result != OpResult::kNoEffect) { - SkRect shadow_bounds = - DlCanvas::ComputeShadowBounds(path, elevation, dpr, GetTransform()); - if (AccumulateOpBounds(shadow_bounds, kDrawShadowFlags)) { - transparent_occluder // - ? Push(0, 1, path, color, elevation, - dpr) - : Push(0, 1, path, color, elevation, dpr); - UpdateLayerOpacityCompatibility(false); - UpdateLayerResult(result); - } - } + transparent_occluder // + ? Push(0, 1, path, color, elevation, dpr) + : Push(0, 1, path, color, elevation, dpr); + + SkRect shadow_bounds = + DlCanvas::ComputeShadowBounds(path, elevation, dpr, GetTransform()); + AccumulateOpBounds(shadow_bounds, kDrawShadowFlags); + UpdateLayerOpacityCompatibility(false); } bool DisplayListBuilder::ComputeFilteredBounds(SkRect& bounds, @@ -1364,40 +1221,31 @@ bool DisplayListBuilder::AdjustBoundsForPaint(SkRect& bounds, return true; } -bool DisplayListBuilder::AccumulateUnbounded() { - SkRect clip = tracker_.device_cull_rect(); - if (clip.isEmpty()) { - return false; - } - accumulator()->accumulate(clip, op_index_); - return true; +void DisplayListBuilder::AccumulateUnbounded() { + accumulator()->accumulate(tracker_.device_cull_rect(), op_index_ - 1); } -bool DisplayListBuilder::AccumulateOpBounds(SkRect& bounds, +void DisplayListBuilder::AccumulateOpBounds(SkRect& bounds, DisplayListAttributeFlags flags) { if (AdjustBoundsForPaint(bounds, flags)) { - return AccumulateBounds(bounds); + AccumulateBounds(bounds); } else { - return AccumulateUnbounded(); + AccumulateUnbounded(); } } -bool DisplayListBuilder::AccumulateBounds(SkRect& bounds) { - if (!bounds.isEmpty()) { - tracker_.mapRect(&bounds); - if (bounds.intersect(tracker_.device_cull_rect())) { - accumulator()->accumulate(bounds, op_index_); - return true; - } +void DisplayListBuilder::AccumulateBounds(SkRect& bounds) { + tracker_.mapRect(&bounds); + if (bounds.intersect(tracker_.device_cull_rect())) { + accumulator()->accumulate(bounds, op_index_ - 1); } - return false; } bool DisplayListBuilder::paint_nops_on_transparency() { // SkImageFilter::canComputeFastBounds tests for transparency behavior // This test assumes that the blend mode checked down below will // NOP on transparent black. - if (current_.getImageFilterPtr() && - current_.getImageFilterPtr()->modifies_transparent_black()) { + if (current_.getImageFilter() && + current_.getImageFilter()->modifies_transparent_black()) { return false; } @@ -1407,8 +1255,8 @@ bool DisplayListBuilder::paint_nops_on_transparency() { // save layer untouched out to the edge of the output surface. // This test assumes that the blend mode checked down below will // NOP on transparent black. - if (current_.getColorFilterPtr() && - current_.getColorFilterPtr()->modifies_transparent_black()) { + if (current_.getColorFilter() && + current_.getColorFilter()->modifies_transparent_black()) { return false; } @@ -1465,125 +1313,4 @@ bool DisplayListBuilder::paint_nops_on_transparency() { break; } } - -DlColor DisplayListBuilder::GetEffectiveColor(const DlPaint& paint, - DisplayListAttributeFlags flags) { - DlColor color; - if (flags.applies_color()) { - const DlColorSource* source = paint.getColorSourcePtr(); - if (source) { - if (source->asColor()) { - color = source->asColor()->color(); - } else { - color = source->is_opaque() ? DlColor::kBlack() : kAnyColor; - } - } else { - color = paint.getColor(); - } - } else if (flags.applies_alpha()) { - color = kAnyColor.withAlpha(paint.getAlpha()); - } else { - color = kAnyColor; - } - if (flags.applies_image_filter()) { - auto filter = paint.getImageFilterPtr(); - if (filter) { - if (!color.isTransparent() || filter->modifies_transparent_black()) { - color = kAnyColor; - } - } - } - if (flags.applies_color_filter()) { - auto filter = paint.getColorFilterPtr(); - if (filter) { - if (!color.isTransparent() || filter->modifies_transparent_black()) { - color = kAnyColor; - } - } - } - return color; -} - -DisplayListBuilder::OpResult DisplayListBuilder::PaintResult( - const DlPaint& paint, - DisplayListAttributeFlags flags) { - if (current_layer_->is_nop_) { - return OpResult::kNoEffect; - } - if (flags.applies_blend()) { - switch (paint.getBlendMode()) { - // Nop blend mode (singular, there is only one) - case DlBlendMode::kDst: - return OpResult::kNoEffect; - - // Always clears pixels blend mode (singular, there is only one) - case DlBlendMode::kClear: - return OpResult::kClearsPixels; - - // Always destructive blend modes - // These modes ignore source alpha entirely - case DlBlendMode::kHue: - case DlBlendMode::kSaturation: - case DlBlendMode::kColor: - case DlBlendMode::kLuminosity: - return OpResult::kDrawsPixels; - - // Always destructive blend modes - // The ops will clear the destination if the source is transparent - // (Some answers might differ if dest is opaque, but that is unknown) - case DlBlendMode::kSrc: - case DlBlendMode::kSrcIn: - case DlBlendMode::kSrcOut: - case DlBlendMode::kDstATop: - case DlBlendMode::kModulate: - return GetEffectiveColor(paint, flags).isTransparent() - ? OpResult::kClearsPixels - : OpResult::kDrawsPixels; - - // The kDstIn blend mode modifies the destination unless the - // source color is opaque. Additionally, it will deterministically - // clear the destination if the source is transparent. - case DlBlendMode::kDstIn: { - DlColor color = GetEffectiveColor(paint, flags); - if (color.isOpaque()) { - return OpResult::kNoEffect; - } else if (color.isTransparent()) { - return OpResult::kClearsPixels; - } else { - return OpResult::kDrawsPixels; - } - } - - // The next group of blend modes modifies the destination unless the - // source color is transparent. - case DlBlendMode::kSrcOver: - case DlBlendMode::kDstOver: - case DlBlendMode::kDstOut: - case DlBlendMode::kSrcATop: - case DlBlendMode::kXor: - case DlBlendMode::kPlus: - case DlBlendMode::kScreen: - case DlBlendMode::kMultiply: - case DlBlendMode::kOverlay: - case DlBlendMode::kDarken: - case DlBlendMode::kLighten: - case DlBlendMode::kColorDodge: - case DlBlendMode::kHardLight: - case DlBlendMode::kSoftLight: - case DlBlendMode::kDifference: - case DlBlendMode::kExclusion: - return GetEffectiveColor(paint, flags).isTransparent() - ? OpResult::kNoEffect - : OpResult::kDrawsPixels; - - // Color Burn only leaves the pixel alone when the source is white. - case DlBlendMode::kColorBurn: - return GetEffectiveColor(paint, flags) == DlColor::kWhite() - ? OpResult::kNoEffect - : OpResult::kDrawsPixels; - } - } - return OpResult::kDrawsPixels; -} - } // namespace flutter diff --git a/display_list/dl_builder.h b/display_list/dl_builder.h index 86fe261861288..78e7d8ade81cf 100644 --- a/display_list/dl_builder.h +++ b/display_list/dl_builder.h @@ -502,13 +502,15 @@ class DisplayListBuilder final : public virtual DlCanvas, class LayerInfo { public: - explicit LayerInfo( - size_t save_offset = 0, - bool has_layer = false, - const std::shared_ptr& filter = nullptr) + explicit LayerInfo(size_t save_offset = 0, + bool has_layer = false, + std::shared_ptr filter = nullptr) : save_offset_(save_offset), has_layer_(has_layer), - filter_(filter) {} + cannot_inherit_opacity_(false), + has_compatible_op_(false), + filter_(filter), + is_unbounded_(false) {} // The offset into the memory buffer where the saveLayer DLOp record // for this saveLayer() call is placed. This may be needed if the @@ -521,9 +523,6 @@ class DisplayListBuilder final : public virtual DlCanvas, bool has_layer() const { return has_layer_; } bool cannot_inherit_opacity() const { return cannot_inherit_opacity_; } bool has_compatible_op() const { return has_compatible_op_; } - bool affects_transparent_layer() const { - return affects_transparent_layer_; - } bool is_group_opacity_compatible() const { return !cannot_inherit_opacity_; @@ -546,12 +545,6 @@ class DisplayListBuilder final : public virtual DlCanvas, } } - // Records that the current layer contains an op that produces visible - // output on a transparent surface. - void add_visible_op() { - affects_transparent_layer_ = true; - } - // The filter to apply to the layer bounds when it is restored std::shared_ptr filter() { return filter_; } @@ -586,13 +579,11 @@ class DisplayListBuilder final : public virtual DlCanvas, private: size_t save_offset_; bool has_layer_; - bool cannot_inherit_opacity_ = false; - bool has_compatible_op_ = false; + bool cannot_inherit_opacity_; + bool has_compatible_op_; std::shared_ptr filter_; - bool is_unbounded_ = false; + bool is_unbounded_; bool has_deferred_save_op_ = false; - bool is_nop_ = false; - bool affects_transparent_layer_ = false; friend class DisplayListBuilder; }; @@ -706,40 +697,9 @@ class DisplayListBuilder final : public virtual DlCanvas, return accumulator_->rtree(); } - static DisplayListAttributeFlags FlagsForPointMode(PointMode mode); - - enum class OpResult { - kNoEffect, - kClearsPixels, - kDrawsPixels, - }; - bool paint_nops_on_transparency(); - OpResult PaintResult(const DlPaint& paint, - DisplayListAttributeFlags flags = kDrawPaintFlags); - - void UpdateLayerResult(OpResult result) { - switch (result) { - case OpResult::kNoEffect: - case OpResult::kClearsPixels: - break; - case OpResult::kDrawsPixels: - current_layer_->add_visible_op(); - break; - } - } - - // kAnyColor is a non-opaque and non-transparent color that will not - // trigger any short-circuit tests about the results of a blend. - static constexpr DlColor kAnyColor = DlColor::kMidGrey().withAlpha(0x7f); - static_assert(!kAnyColor.isOpaque()); - static_assert(!kAnyColor.isTransparent()); - static DlColor GetEffectiveColor(const DlPaint& paint, - DisplayListAttributeFlags flags); // Computes the bounds of an operation adjusted for a given ImageFilter - // and returns whether the computation was possible. If the method - // returns false then the caller should assume the worst about the bounds. static bool ComputeFilteredBounds(SkRect& bounds, const DlImageFilter* filter); @@ -749,24 +709,24 @@ class DisplayListBuilder final : public virtual DlCanvas, // Records the fact that we encountered an op that either could not // estimate its bounds or that fills all of the destination space. - bool AccumulateUnbounded(); + void AccumulateUnbounded(); // Records the bounds for an op after modifying them according to the // supplied attribute flags and transforming by the current matrix. - bool AccumulateOpBounds(const SkRect& bounds, + void AccumulateOpBounds(const SkRect& bounds, DisplayListAttributeFlags flags) { SkRect safe_bounds = bounds; - return AccumulateOpBounds(safe_bounds, flags); + AccumulateOpBounds(safe_bounds, flags); } // Records the bounds for an op after modifying them according to the // supplied attribute flags and transforming by the current matrix // and clipping against the current clip. - bool AccumulateOpBounds(SkRect& bounds, DisplayListAttributeFlags flags); + void AccumulateOpBounds(SkRect& bounds, DisplayListAttributeFlags flags); // Records the given bounds after transforming by the current matrix // and clipping against the current clip. - bool AccumulateBounds(SkRect& bounds); + void AccumulateBounds(SkRect& bounds); DlPaint current_; }; diff --git a/display_list/dl_color.h b/display_list/dl_color.h index 92a39150d2f2e..d926e58c3b818 100644 --- a/display_list/dl_color.h +++ b/display_list/dl_color.h @@ -34,20 +34,20 @@ struct DlColor { uint32_t argb; - constexpr bool isOpaque() const { return getAlpha() == 0xFF; } - constexpr bool isTransparent() const { return getAlpha() == 0; } + bool isOpaque() const { return getAlpha() == 0xFF; } + bool isTransparent() const { return getAlpha() == 0; } - constexpr int getAlpha() const { return argb >> 24; } - constexpr int getRed() const { return (argb >> 16) & 0xFF; } - constexpr int getGreen() const { return (argb >> 8) & 0xFF; } - constexpr int getBlue() const { return argb & 0xFF; } + int getAlpha() const { return argb >> 24; } + int getRed() const { return (argb >> 16) & 0xFF; } + int getGreen() const { return (argb >> 8) & 0xFF; } + int getBlue() const { return argb & 0xFF; } - constexpr float getAlphaF() const { return toF(getAlpha()); } - constexpr float getRedF() const { return toF(getRed()); } - constexpr float getGreenF() const { return toF(getGreen()); } - constexpr float getBlueF() const { return toF(getBlue()); } + float getAlphaF() const { return toF(getAlpha()); } + float getRedF() const { return toF(getRed()); } + float getGreenF() const { return toF(getGreen()); } + float getBlueF() const { return toF(getBlue()); } - constexpr uint32_t premultipliedArgb() const { + uint32_t premultipliedArgb() const { if (isOpaque()) { return argb; } @@ -58,20 +58,20 @@ struct DlColor { toC(getBlueF() * f); } - constexpr DlColor withAlpha(uint8_t alpha) const { // + DlColor withAlpha(uint8_t alpha) const { // return (argb & 0x00FFFFFF) | (alpha << 24); } - constexpr DlColor withRed(uint8_t red) const { // + DlColor withRed(uint8_t red) const { // return (argb & 0xFF00FFFF) | (red << 16); } - constexpr DlColor withGreen(uint8_t green) const { // + DlColor withGreen(uint8_t green) const { // return (argb & 0xFFFF00FF) | (green << 8); } - constexpr DlColor withBlue(uint8_t blue) const { // + DlColor withBlue(uint8_t blue) const { // return (argb & 0xFFFFFF00) | (blue << 0); } - constexpr DlColor modulateOpacity(float opacity) const { + DlColor modulateOpacity(float opacity) const { return opacity <= 0 ? withAlpha(0) : opacity >= 1 ? *this : withAlpha(round(getAlpha() * opacity)); diff --git a/display_list/dl_paint.h b/display_list/dl_paint.h index 3d9220f57e3d6..77619a2567164 100644 --- a/display_list/dl_paint.h +++ b/display_list/dl_paint.h @@ -83,7 +83,6 @@ class DlPaint { color_.argb = alpha << 24 | (color_.argb & 0x00FFFFFF); return *this; } - SkScalar getOpacity() const { return color_.getAlphaF(); } DlPaint& setOpacity(SkScalar opacity) { setAlpha(SkScalarRoundToInt(opacity * 0xff)); return *this; diff --git a/display_list/testing/dl_rendering_unittests.cc b/display_list/testing/dl_rendering_unittests.cc index 0c7f11640f878..917f62509bbb1 100644 --- a/display_list/testing/dl_rendering_unittests.cc +++ b/display_list/testing/dl_rendering_unittests.cc @@ -907,14 +907,7 @@ class CanvasCompareTester { }; DlRenderer dl_safe_restore = [=](DlCanvas* cv, const DlPaint& p) { // Draw another primitive to disable peephole optimizations - // As the rendering op rejection in the DisplayList Builder - // gets smarter and smarter, this operation has had to get - // sneakier and sneakier about specifying an operation that - // won't practically show up in the output, but technically - // can't be culled. - cv->DrawRect( - SkRect::MakeXYWH(kRenderCenterX, kRenderCenterY, 0.0001, 0.0001), - DlPaint()); + cv->DrawRect(kRenderBounds.makeOffset(500, 500), DlPaint()); cv->Restore(); }; SkRenderer sk_opt_restore = [=](SkCanvas* cv, const SkPaint& p) { diff --git a/display_list/testing/dl_test_snippets.cc b/display_list/testing/dl_test_snippets.cc index 13cc2ea4e61af..e0066cc7c1b4d 100644 --- a/display_list/testing/dl_test_snippets.cc +++ b/display_list/testing/dl_test_snippets.cc @@ -515,7 +515,7 @@ std::vector CreateAllRenderingOps() { }}, {1, 16, 1, 24, [](DlOpReceiver& r) { - r.drawColor(SK_ColorBLUE, DlBlendMode::kDstOut); + r.drawColor(SK_ColorBLUE, DlBlendMode::kDstIn); }}, {1, 16, 1, 24, [](DlOpReceiver& r) { diff --git a/display_list/testing/dl_test_snippets.h b/display_list/testing/dl_test_snippets.h index 98b40599b41cf..94f7995d81eb5 100644 --- a/display_list/testing/dl_test_snippets.h +++ b/display_list/testing/dl_test_snippets.h @@ -151,9 +151,9 @@ static const DlBlurImageFilter kTestBlurImageFilter4(5.0, static const DlDilateImageFilter kTestDilateImageFilter1(5.0, 5.0); static const DlDilateImageFilter kTestDilateImageFilter2(6.0, 5.0); static const DlDilateImageFilter kTestDilateImageFilter3(5.0, 6.0); -static const DlErodeImageFilter kTestErodeImageFilter1(4.0, 4.0); -static const DlErodeImageFilter kTestErodeImageFilter2(4.0, 3.0); -static const DlErodeImageFilter kTestErodeImageFilter3(3.0, 4.0); +static const DlErodeImageFilter kTestErodeImageFilter1(5.0, 5.0); +static const DlErodeImageFilter kTestErodeImageFilter2(6.0, 5.0); +static const DlErodeImageFilter kTestErodeImageFilter3(5.0, 6.0); static const DlMatrixImageFilter kTestMatrixImageFilter1( SkMatrix::RotateDeg(45), kNearestSampling); diff --git a/display_list/utils/dl_matrix_clip_tracker.h b/display_list/utils/dl_matrix_clip_tracker.h index e62d90c1fa221..7a15b690dc878 100644 --- a/display_list/utils/dl_matrix_clip_tracker.h +++ b/display_list/utils/dl_matrix_clip_tracker.h @@ -38,7 +38,6 @@ class DisplayListMatrixClipTracker { bool content_culled(const SkRect& content_bounds) const { return current_->content_culled(content_bounds); } - bool is_cull_rect_empty() const { return current_->is_cull_rect_empty(); } void save(); void restore(); @@ -82,10 +81,9 @@ class DisplayListMatrixClipTracker { virtual SkMatrix matrix_3x3() const = 0; virtual SkM44 matrix_4x4() const = 0; - SkRect device_cull_rect() const { return cull_rect_; } + virtual SkRect device_cull_rect() const { return cull_rect_; } virtual SkRect local_cull_rect() const = 0; virtual bool content_culled(const SkRect& content_bounds) const; - bool is_cull_rect_empty() const { return cull_rect_.isEmpty(); } virtual void translate(SkScalar tx, SkScalar ty) = 0; virtual void scale(SkScalar sx, SkScalar sy) = 0; diff --git a/flow/diff_context_unittests.cc b/flow/diff_context_unittests.cc index d8b78a94070c0..e981258ef1a03 100644 --- a/flow/diff_context_unittests.cc +++ b/flow/diff_context_unittests.cc @@ -10,7 +10,7 @@ namespace testing { TEST_F(DiffContextTest, ClipAlignment) { MockLayerTree t1; t1.root()->Add(CreateDisplayListLayer( - CreateDisplayList(SkRect::MakeLTRB(30, 30, 50, 50)))); + CreateDisplayList(SkRect::MakeLTRB(30, 30, 50, 50), 1))); auto damage = DiffLayerTree(t1, MockLayerTree(), SkIRect::MakeEmpty(), 0, 0); EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(30, 30, 50, 50)); EXPECT_EQ(damage.buffer_damage, SkIRect::MakeLTRB(30, 30, 50, 50)); diff --git a/flow/layers/container_layer_unittests.cc b/flow/layers/container_layer_unittests.cc index ff8cf9ceb5b4a..a4c671d05f39d 100644 --- a/flow/layers/container_layer_unittests.cc +++ b/flow/layers/container_layer_unittests.cc @@ -561,9 +561,9 @@ using ContainerLayerDiffTest = DiffContextTest; // Insert PictureLayer amongst container layers TEST_F(ContainerLayerDiffTest, PictureLayerInsertion) { - auto pic1 = CreateDisplayList(SkRect::MakeLTRB(0, 0, 50, 50)); - auto pic2 = CreateDisplayList(SkRect::MakeLTRB(100, 0, 150, 50)); - auto pic3 = CreateDisplayList(SkRect::MakeLTRB(200, 0, 250, 50)); + auto pic1 = CreateDisplayList(SkRect::MakeLTRB(0, 0, 50, 50), 1); + auto pic2 = CreateDisplayList(SkRect::MakeLTRB(100, 0, 150, 50), 1); + auto pic3 = CreateDisplayList(SkRect::MakeLTRB(200, 0, 250, 50), 1); MockLayerTree t1; @@ -613,9 +613,9 @@ TEST_F(ContainerLayerDiffTest, PictureLayerInsertion) { // Insert picture layer amongst other picture layers TEST_F(ContainerLayerDiffTest, PictureInsertion) { - auto pic1 = CreateDisplayList(SkRect::MakeLTRB(0, 0, 50, 50)); - auto pic2 = CreateDisplayList(SkRect::MakeLTRB(100, 0, 150, 50)); - auto pic3 = CreateDisplayList(SkRect::MakeLTRB(200, 0, 250, 50)); + auto pic1 = CreateDisplayList(SkRect::MakeLTRB(0, 0, 50, 50), 1); + auto pic2 = CreateDisplayList(SkRect::MakeLTRB(100, 0, 150, 50), 1); + auto pic3 = CreateDisplayList(SkRect::MakeLTRB(200, 0, 250, 50), 1); MockLayerTree t1; t1.root()->Add(CreateDisplayListLayer(pic1)); diff --git a/flow/layers/display_list_layer_unittests.cc b/flow/layers/display_list_layer_unittests.cc index 01468aec96c1d..137b76d2472fb 100644 --- a/flow/layers/display_list_layer_unittests.cc +++ b/flow/layers/display_list_layer_unittests.cc @@ -294,7 +294,7 @@ TEST_F(DisplayListLayerTest, CachedIncompatibleDisplayListOpacityInheritance) { using DisplayListLayerDiffTest = DiffContextTest; TEST_F(DisplayListLayerDiffTest, SimpleDisplayList) { - auto display_list = CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60)); + auto display_list = CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60), 1); MockLayerTree tree1; tree1.root()->Add(CreateDisplayListLayer(display_list)); @@ -314,7 +314,7 @@ TEST_F(DisplayListLayerDiffTest, SimpleDisplayList) { } TEST_F(DisplayListLayerDiffTest, FractionalTranslation) { - auto display_list = CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60)); + auto display_list = CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60), 1); MockLayerTree tree1; tree1.root()->Add( @@ -327,7 +327,7 @@ TEST_F(DisplayListLayerDiffTest, FractionalTranslation) { } TEST_F(DisplayListLayerDiffTest, FractionalTranslationWithRasterCache) { - auto display_list = CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60)); + auto display_list = CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60), 1); MockLayerTree tree1; tree1.root()->Add( @@ -341,25 +341,21 @@ TEST_F(DisplayListLayerDiffTest, FractionalTranslationWithRasterCache) { TEST_F(DisplayListLayerDiffTest, DisplayListCompare) { MockLayerTree tree1; - auto display_list1 = - CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60), DlColor::kGreen()); + auto display_list1 = CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60), 1); tree1.root()->Add(CreateDisplayListLayer(display_list1)); auto damage = DiffLayerTree(tree1, MockLayerTree()); EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(10, 10, 60, 60)); MockLayerTree tree2; - // same DL, same offset - auto display_list2 = - CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60), DlColor::kGreen()); + auto display_list2 = CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60), 1); tree2.root()->Add(CreateDisplayListLayer(display_list2)); damage = DiffLayerTree(tree2, tree1); EXPECT_EQ(damage.frame_damage, SkIRect::MakeEmpty()); MockLayerTree tree3; - auto display_list3 = - CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60), DlColor::kGreen()); + auto display_list3 = CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60), 1); // add offset tree3.root()->Add( CreateDisplayListLayer(display_list3, SkPoint::Make(10, 10))); @@ -369,8 +365,7 @@ TEST_F(DisplayListLayerDiffTest, DisplayListCompare) { MockLayerTree tree4; // different color - auto display_list4 = - CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60), DlColor::kRed()); + auto display_list4 = CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60), 2); tree4.root()->Add( CreateDisplayListLayer(display_list4, SkPoint::Make(10, 10))); diff --git a/flow/layers/opacity_layer_unittests.cc b/flow/layers/opacity_layer_unittests.cc index 1f1562806d163..a2a119264bf8b 100644 --- a/flow/layers/opacity_layer_unittests.cc +++ b/flow/layers/opacity_layer_unittests.cc @@ -656,7 +656,7 @@ using OpacityLayerDiffTest = DiffContextTest; TEST_F(OpacityLayerDiffTest, FractionalTranslation) { auto picture = CreateDisplayListLayer( - CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60))); + CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60), 1)); auto layer = CreateOpacityLater({picture}, 128, SkPoint::Make(0.5, 0.5)); MockLayerTree tree1; @@ -669,7 +669,7 @@ TEST_F(OpacityLayerDiffTest, FractionalTranslation) { TEST_F(OpacityLayerDiffTest, FractionalTranslationWithRasterCache) { auto picture = CreateDisplayListLayer( - CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60))); + CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60), 1)); auto layer = CreateOpacityLater({picture}, 128, SkPoint::Make(0.5, 0.5)); MockLayerTree tree1; diff --git a/flow/testing/diff_context_test.cc b/flow/testing/diff_context_test.cc index c4c68bb7ab271..20153a0140d5c 100644 --- a/flow/testing/diff_context_test.cc +++ b/flow/testing/diff_context_test.cc @@ -30,7 +30,7 @@ Damage DiffContextTest::DiffLayerTree(MockLayerTree& layer_tree, } sk_sp DiffContextTest::CreateDisplayList(const SkRect& bounds, - DlColor color) { + SkColor color) { DisplayListBuilder builder; builder.DrawRect(bounds, DlPaint().setColor(color)); return builder.Build(); diff --git a/flow/testing/diff_context_test.h b/flow/testing/diff_context_test.h index f22561552fdd0..69beb41d83470 100644 --- a/flow/testing/diff_context_test.h +++ b/flow/testing/diff_context_test.h @@ -47,8 +47,7 @@ class DiffContextTest : public LayerTest { // Create display list consisting of filled rect with given color; Being able // to specify different color is useful to test deep comparison of pictures - sk_sp CreateDisplayList(const SkRect& bounds, - DlColor color = DlColor::kBlack()); + sk_sp CreateDisplayList(const SkRect& bounds, uint32_t color); std::shared_ptr CreateDisplayListLayer( const sk_sp& display_list, diff --git a/impeller/display_list/dl_unittests.cc b/impeller/display_list/dl_unittests.cc index f08087935b8ff..9029d3ea7fcb0 100644 --- a/impeller/display_list/dl_unittests.cc +++ b/impeller/display_list/dl_unittests.cc @@ -830,12 +830,18 @@ TEST_P(DisplayListTest, CanDrawShadow) { } TEST_P(DisplayListTest, TransparentShadowProducesCorrectColor) { + flutter::DisplayListBuilder builder; + { + builder.Save(); + builder.Scale(1.618, 1.618); + builder.DrawShadow(SkPath{}.addRect(SkRect::MakeXYWH(0, 0, 200, 100)), + SK_ColorTRANSPARENT, 15, false, 1); + builder.Restore(); + } + auto dl = builder.Build(); + DlDispatcher dispatcher; - dispatcher.save(); - dispatcher.scale(1.618, 1.618); - dispatcher.drawShadow(SkPath{}.addRect(SkRect::MakeXYWH(0, 0, 200, 100)), - SK_ColorTRANSPARENT, 15, false, 1); - dispatcher.restore(); + dispatcher.drawDisplayList(dl, 1); auto picture = dispatcher.EndRecordingAsPicture(); std::shared_ptr rrect_shadow; diff --git a/shell/common/dl_op_spy_unittests.cc b/shell/common/dl_op_spy_unittests.cc index 08394afdd5ba1..dba02134238c8 100644 --- a/shell/common/dl_op_spy_unittests.cc +++ b/shell/common/dl_op_spy_unittests.cc @@ -7,40 +7,15 @@ #include "flutter/shell/common/dl_op_spy.h" #include "flutter/testing/testing.h" #include "third_party/skia/include/core/SkBitmap.h" -#include "third_party/skia/include/core/SkRSXform.h" namespace flutter { namespace testing { -// The following macros demonstrate that the DlOpSpy class is equivalent -// to DisplayList::affects_transparent_surface() now that DisplayListBuilder -// implements operation culling. -// See https://github.com/flutter/flutter/issues/125403 -#define ASSERT_DID_DRAW(spy, dl) \ - do { \ - ASSERT_TRUE(spy.did_draw()); \ - ASSERT_TRUE(dl->affects_transparent_surface()); \ - } while (0) - -#define ASSERT_NO_DRAW(spy, dl) \ - do { \ - ASSERT_FALSE(spy.did_draw()); \ - ASSERT_FALSE(dl->affects_transparent_surface()); \ - } while (0) - TEST(DlOpSpy, DidDrawIsFalseByDefault) { DlOpSpy dl_op_spy; ASSERT_FALSE(dl_op_spy.did_draw()); } -TEST(DlOpSpy, EmptyDisplayList) { - DisplayListBuilder builder; - sk_sp dl = builder.Build(); - DlOpSpy dl_op_spy; - dl->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl); -} - TEST(DlOpSpy, SetColor) { { // No Color set. DisplayListBuilder builder; @@ -49,7 +24,7 @@ TEST(DlOpSpy, SetColor) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } { // Set transparent color. DisplayListBuilder builder; @@ -58,7 +33,7 @@ TEST(DlOpSpy, SetColor) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl); + ASSERT_FALSE(dl_op_spy.did_draw()); } { // Set black color. DisplayListBuilder builder; @@ -67,7 +42,7 @@ TEST(DlOpSpy, SetColor) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } } @@ -80,7 +55,7 @@ TEST(DlOpSpy, SetColorSource) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } { // Set transparent color. DisplayListBuilder builder; @@ -92,7 +67,7 @@ TEST(DlOpSpy, SetColorSource) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl); + ASSERT_FALSE(dl_op_spy.did_draw()); } { // Set black color. DisplayListBuilder builder; @@ -104,7 +79,7 @@ TEST(DlOpSpy, SetColorSource) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } } @@ -116,25 +91,16 @@ TEST(DlOpSpy, DrawColor) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } - { // Transparent color with kSrc. + { // Transparent color source. DisplayListBuilder builder; auto color = DlColor::kTransparent(); builder.DrawColor(color, DlBlendMode::kSrc); sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl); - } - { // Transparent color with kSrcOver. - DisplayListBuilder builder; - auto color = DlColor::kTransparent(); - builder.DrawColor(color, DlBlendMode::kSrcOver); - sk_sp dl = builder.Build(); - DlOpSpy dl_op_spy; - dl->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl); + ASSERT_FALSE(dl_op_spy.did_draw()); } } @@ -146,7 +112,7 @@ TEST(DlOpSpy, DrawPaint) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl); + ASSERT_FALSE(dl_op_spy.did_draw()); } { // black color in paint. DisplayListBuilder builder; @@ -155,7 +121,7 @@ TEST(DlOpSpy, DrawPaint) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } } @@ -167,7 +133,7 @@ TEST(DlOpSpy, DrawLine) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } { // transparent DisplayListBuilder builder; @@ -176,7 +142,7 @@ TEST(DlOpSpy, DrawLine) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl); + ASSERT_FALSE(dl_op_spy.did_draw()); } } @@ -188,7 +154,7 @@ TEST(DlOpSpy, DrawRect) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } { // transparent DisplayListBuilder builder; @@ -197,11 +163,11 @@ TEST(DlOpSpy, DrawRect) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl); + ASSERT_FALSE(dl_op_spy.did_draw()); } } -TEST(DlOpSpy, DrawOval) { +TEST(DlOpSpy, drawOval) { { // black DisplayListBuilder builder; DlPaint paint(DlColor::kBlack()); @@ -209,7 +175,7 @@ TEST(DlOpSpy, DrawOval) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } { // transparent DisplayListBuilder builder; @@ -218,11 +184,11 @@ TEST(DlOpSpy, DrawOval) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl); + ASSERT_FALSE(dl_op_spy.did_draw()); } } -TEST(DlOpSpy, DrawCircle) { +TEST(DlOpSpy, drawCircle) { { // black DisplayListBuilder builder; DlPaint paint(DlColor::kBlack()); @@ -230,7 +196,7 @@ TEST(DlOpSpy, DrawCircle) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } { // transparent DisplayListBuilder builder; @@ -239,11 +205,11 @@ TEST(DlOpSpy, DrawCircle) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl); + ASSERT_FALSE(dl_op_spy.did_draw()); } } -TEST(DlOpSpy, DrawRRect) { +TEST(DlOpSpy, drawRRect) { { // black DisplayListBuilder builder; DlPaint paint(DlColor::kBlack()); @@ -251,7 +217,7 @@ TEST(DlOpSpy, DrawRRect) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } { // transparent DisplayListBuilder builder; @@ -260,49 +226,34 @@ TEST(DlOpSpy, DrawRRect) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl); + ASSERT_FALSE(dl_op_spy.did_draw()); } } -TEST(DlOpSpy, DrawPath) { - { // black line +TEST(DlOpSpy, drawPath) { + { // black DisplayListBuilder builder; DlPaint paint(DlColor::kBlack()); - paint.setDrawStyle(DlDrawStyle::kStroke); builder.DrawPath(SkPath::Line(SkPoint::Make(0, 1), SkPoint::Make(1, 1)), paint); sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } - { // triangle - DisplayListBuilder builder; - DlPaint paint(DlColor::kBlack()); - SkPath path; - path.moveTo({0, 0}); - path.lineTo({1, 0}); - path.lineTo({0, 1}); - builder.DrawPath(path, paint); - sk_sp dl = builder.Build(); - DlOpSpy dl_op_spy; - dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); - } - { // transparent line + { // transparent DisplayListBuilder builder; DlPaint paint(DlColor::kTransparent()); - paint.setDrawStyle(DlDrawStyle::kStroke); builder.DrawPath(SkPath::Line(SkPoint::Make(0, 1), SkPoint::Make(1, 1)), paint); sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl); + ASSERT_FALSE(dl_op_spy.did_draw()); } } -TEST(DlOpSpy, DrawArc) { +TEST(DlOpSpy, drawArc) { { // black DisplayListBuilder builder; DlPaint paint(DlColor::kBlack()); @@ -310,7 +261,7 @@ TEST(DlOpSpy, DrawArc) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } { // transparent DisplayListBuilder builder; @@ -319,11 +270,11 @@ TEST(DlOpSpy, DrawArc) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl); + ASSERT_FALSE(dl_op_spy.did_draw()); } } -TEST(DlOpSpy, DrawPoints) { +TEST(DlOpSpy, drawPoints) { { // black DisplayListBuilder builder; DlPaint paint(DlColor::kBlack()); @@ -332,7 +283,7 @@ TEST(DlOpSpy, DrawPoints) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } { // transparent DisplayListBuilder builder; @@ -342,62 +293,38 @@ TEST(DlOpSpy, DrawPoints) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl); + ASSERT_FALSE(dl_op_spy.did_draw()); } } -TEST(DlOpSpy, DrawVertices) { +TEST(DlOpSpy, drawVertices) { { // black DisplayListBuilder builder; DlPaint paint(DlColor::kBlack()); - const SkPoint vertices[] = { - SkPoint::Make(5, 5), - SkPoint::Make(5, 15), - SkPoint::Make(15, 5), - }; - const SkPoint texture_coordinates[] = { - SkPoint::Make(5, 5), - SkPoint::Make(15, 5), - SkPoint::Make(5, 15), - }; - const DlColor colors[] = { - DlColor::kBlack(), - DlColor::kRed(), - DlColor::kGreen(), - }; - auto dl_vertices = DlVertices::Make(DlVertexMode::kTriangles, 3, vertices, + const SkPoint vertices[] = {SkPoint::Make(5, 5)}; + const SkPoint texture_coordinates[] = {SkPoint::Make(5, 5)}; + const DlColor colors[] = {DlColor::kBlack()}; + auto dl_vertices = DlVertices::Make(DlVertexMode::kTriangles, 1, vertices, texture_coordinates, colors, 0); builder.DrawVertices(dl_vertices.get(), DlBlendMode::kSrc, paint); sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } { // transparent DisplayListBuilder builder; DlPaint paint(DlColor::kTransparent()); - const SkPoint vertices[] = { - SkPoint::Make(5, 5), - SkPoint::Make(5, 15), - SkPoint::Make(15, 5), - }; - const SkPoint texture_coordinates[] = { - SkPoint::Make(5, 5), - SkPoint::Make(15, 5), - SkPoint::Make(5, 15), - }; - const DlColor colors[] = { - DlColor::kBlack(), - DlColor::kRed(), - DlColor::kGreen(), - }; - auto dl_vertices = DlVertices::Make(DlVertexMode::kTriangles, 3, vertices, + const SkPoint vertices[] = {SkPoint::Make(5, 5)}; + const SkPoint texture_coordinates[] = {SkPoint::Make(5, 5)}; + const DlColor colors[] = {DlColor::kBlack()}; + auto dl_vertices = DlVertices::Make(DlVertexMode::kTriangles, 1, vertices, texture_coordinates, colors, 0); builder.DrawVertices(dl_vertices.get(), DlBlendMode::kSrc, paint); sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl); + ASSERT_FALSE(dl_op_spy.did_draw()); } } @@ -416,7 +343,7 @@ TEST(DlOpSpy, Images) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } { // DrawImageRect DisplayListBuilder builder; @@ -432,7 +359,7 @@ TEST(DlOpSpy, Images) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } { // DrawImageNine DisplayListBuilder builder; @@ -448,7 +375,7 @@ TEST(DlOpSpy, Images) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } { // DrawAtlas DisplayListBuilder builder; @@ -459,19 +386,20 @@ TEST(DlOpSpy, Images) { SkBitmap bitmap; bitmap.allocPixels(info, 0); auto sk_image = SkImages::RasterFromBitmap(bitmap); - const SkRSXform xform[] = {SkRSXform::Make(1, 0, 0, 0)}; - const SkRect tex[] = {SkRect::MakeXYWH(10, 10, 10, 10)}; + const SkRSXform xform[] = {}; + const SkRect tex[] = {}; + const DlColor colors[] = {}; SkRect cull_rect = SkRect::MakeWH(5, 5); - builder.DrawAtlas(DlImage::Make(sk_image), xform, tex, nullptr, 1, + builder.DrawAtlas(DlImage::Make(sk_image), xform, tex, colors, 0, DlBlendMode::kSrc, DlImageSampling::kLinear, &cull_rect); sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } } -TEST(DlOpSpy, DrawDisplayList) { +TEST(DlOpSpy, drawDisplayList) { { // Recursive Transparent DisplayList DisplayListBuilder builder; DlPaint paint(DlColor::kTransparent()); @@ -486,7 +414,7 @@ TEST(DlOpSpy, DrawDisplayList) { DlOpSpy dl_op_spy; dl2->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl2); + ASSERT_FALSE(dl_op_spy.did_draw()); } { // Sub non-transparent DisplayList, DisplayListBuilder builder; @@ -502,7 +430,7 @@ TEST(DlOpSpy, DrawDisplayList) { DlOpSpy dl_op_spy; dl2->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl2); + ASSERT_TRUE(dl_op_spy.did_draw()); } { // Sub non-transparent DisplayList, 0 opacity @@ -519,7 +447,7 @@ TEST(DlOpSpy, DrawDisplayList) { DlOpSpy dl_op_spy; dl2->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl2); + ASSERT_FALSE(dl_op_spy.did_draw()); } { // Parent non-transparent DisplayList @@ -536,11 +464,11 @@ TEST(DlOpSpy, DrawDisplayList) { DlOpSpy dl_op_spy; dl2->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl2); + ASSERT_TRUE(dl_op_spy.did_draw()); } } -TEST(DlOpSpy, DrawTextBlob) { +TEST(DlOpSpy, drawTextBlob) { { // Non-transparent color. DisplayListBuilder builder; DlPaint paint(DlColor::kBlack()); @@ -551,7 +479,7 @@ TEST(DlOpSpy, DrawTextBlob) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } { // transparent color. DisplayListBuilder builder; @@ -563,11 +491,11 @@ TEST(DlOpSpy, DrawTextBlob) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl); + ASSERT_FALSE(dl_op_spy.did_draw()); } } -TEST(DlOpSpy, DrawShadow) { +TEST(DlOpSpy, drawShadow) { { // valid shadow DisplayListBuilder builder; DlPaint paint; @@ -577,7 +505,7 @@ TEST(DlOpSpy, DrawShadow) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_DID_DRAW(dl_op_spy, dl); + ASSERT_TRUE(dl_op_spy.did_draw()); } { // transparent color DisplayListBuilder builder; @@ -588,7 +516,7 @@ TEST(DlOpSpy, DrawShadow) { sk_sp dl = builder.Build(); DlOpSpy dl_op_spy; dl->Dispatch(dl_op_spy); - ASSERT_NO_DRAW(dl_op_spy, dl); + ASSERT_FALSE(dl_op_spy.did_draw()); } }