Revert "Reland "add non-rendering operation culling to DisplayListBuilder" (#41463)" (flutter/engine#43721)
Reverts flutter/engine#43698 A framework tree test started failing on the engine roll with this PR: https://github.com/flutter/flutter/pull/130643 The test failure is in https://ci.chromium.org/ui/p/flutter/builders/prod/Linux_android%20hybrid_android_views_integration_test/8517/overview ``` [2023-07-14 19:33:21.980926] [STDOUT] stdout: [ +6 ms] I/PlatformViewsController( 9988): Using hybrid composition for platform view: 5 [2023-07-14 19:33:22.767236] [STDOUT] stdout: [ +786 ms] 00:19 [32m+4[0m[31m -1[0m: Flutter surface with hybrid composition Uses FlutterImageView when Android view is on the screen [1m[31m[E][0m[0m [2023-07-14 19:33:22.767765] [STDOUT] stdout: [ ] Expected: '|-FlutterView\n' [2023-07-14 19:33:22.767815] [STDOUT] stdout: [ ] ' |-FlutterSurfaceView\n' [2023-07-14 19:33:22.767924] [STDOUT] stdout: [ ] ' |-FlutterImageView\n' [2023-07-14 19:33:22.768084] [STDOUT] stdout: [ ] ' |-ViewGroup\n' [2023-07-14 19:33:22.768162] [STDOUT] stdout: [ ] ' |-ViewGroup\n' [2023-07-14 19:33:22.768800] [STDOUT] stdout: [ ] ' |-FlutterImageView\n' [2023-07-14 19:33:22.768835] [STDOUT] stdout: [ ] '' [2023-07-14 19:33:22.768853] [STDOUT] stdout: [ ] Actual: '|-FlutterView\n' [2023-07-14 19:33:22.768882] [STDOUT] stdout: [ ] ' |-FlutterSurfaceView\n' [2023-07-14 19:33:22.768900] [STDOUT] stdout: [ ] ' |-FlutterImageView\n' [2023-07-14 19:33:22.768917] [STDOUT] stdout: [ ] ' |-ViewGroup\n' [2023-07-14 19:33:22.768956] [STDOUT] stdout: [ ] ' |-ViewGroup\n' [2023-07-14 19:33:22.769119] [STDOUT] stdout: [ ] '' [2023-07-14 19:33:22.769156] [STDOUT] stdout: [ ] Which: is different. Both strings start the same, but the actual value is missing the following trailing characters: |-Flutte ... [2023-07-14 19:33:22.779280] [STDOUT] stdout: [ +10 ms] package:matcher/src/expect/expect.dart 149:31 fail [2023-07-14 19:33:22.779326] [STDOUT] stdout: [ ] package:matcher/src/expect/expect.dart 144:3 _expect [2023-07-14 19:33:22.780315] [STDOUT] stdout: [ ] package:matcher/src/expect/expect.dart 56:3 expect [2023-07-14 19:33:22.780345] [STDOUT] stdout: [ ] test_driver/main_test.dart 124:7 main.<fn>.<fn> [2023-07-14 19:33:22.780356] [STDOUT] stdout: [ ] ===== asynchronous gap =========================== [2023-07-14 19:33:22.780365] [STDOUT] stdout: [ ] package:test_api/src/backend/declarer.dart 215:9 Declarer.test.<fn>.<fn> [2023-07-14 19:33:22.780376] [STDOUT] stdout: [ ] ===== asynchronous gap =========================== [2023-07-14 19:33:22.780385] [STDOUT] stdout: [ ] package:test_api/src/backend/declarer.dart 213:7 Declarer.test.<fn> [2023-07-14 19:33:22.780395] [STDOUT] stdout: [ ] ===== asynchronous gap =========================== [2023-07-14 19:33:22.780405] [STDOUT] stdout: [ ] package:test_api/src/backend/invoker.dart 258:9 Invoker._waitForOutstandingCallbacks.<fn> [2023-07-14 19:33:22.780415] [STDOUT] stdout: [ ] 00:19 [32m+4[0m[31m -1[0m: Flutter surface with hybrid composition (tearDownAll)[0m [2023-07-14 19:33:22.907295] [STDOUT] stdout: [ +126 ms] 00:19 [32m+4[0m[31m -1[0m: (tearDownAll)[0m [2023-07-14 19:33:22.947855] [STDOUT] stdout: [ +41 ms] 00:19 [32m+4[0m[31m -1[0m: [31mSome tests failed.[0m ``` This change in that roll looks like it may be related.
This commit is contained in:
@@ -423,7 +423,7 @@ TEST(DisplayListComplexity, DrawAtlas) {
|
||||
std::vector<SkRSXform> 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;
|
||||
|
||||
@@ -22,8 +22,7 @@ DisplayList::DisplayList()
|
||||
unique_id_(0),
|
||||
bounds_({0, 0, 0, 0}),
|
||||
can_apply_group_opacity_(true),
|
||||
is_ui_thread_safe_(true),
|
||||
modifies_transparent_black_(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 modifies_transparent_black,
|
||||
sk_sp<const DlRTree> 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),
|
||||
modifies_transparent_black_(modifies_transparent_black),
|
||||
rtree_(std::move(rtree)) {}
|
||||
|
||||
DisplayList::~DisplayList() {
|
||||
|
||||
@@ -265,19 +265,6 @@ class DisplayList : public SkRefCnt {
|
||||
bool can_apply_group_opacity() const { return can_apply_group_opacity_; }
|
||||
bool isUIThreadSafe() const { return is_ui_thread_safe_; }
|
||||
|
||||
/// @brief Indicates if there are any rendering operations in this
|
||||
/// DisplayList that will modify a surface of transparent black
|
||||
/// pixels.
|
||||
///
|
||||
/// This condition can be used to determine whether to create a cleared
|
||||
/// surface, render a DisplayList into it, and then composite the
|
||||
/// result into a scene. It is not uncommon for code in the engine to
|
||||
/// come across such degenerate DisplayList objects when slicing up a
|
||||
/// frame between platform views.
|
||||
bool modifies_transparent_black() const {
|
||||
return modifies_transparent_black_;
|
||||
}
|
||||
|
||||
private:
|
||||
DisplayList(DisplayListStorage&& ptr,
|
||||
size_t byte_count,
|
||||
@@ -287,7 +274,6 @@ class DisplayList : public SkRefCnt {
|
||||
const SkRect& bounds,
|
||||
bool can_apply_group_opacity,
|
||||
bool is_ui_thread_safe,
|
||||
bool modifies_transparent_black,
|
||||
sk_sp<const DlRTree> rtree);
|
||||
|
||||
static uint32_t next_unique_id();
|
||||
@@ -306,8 +292,6 @@ class DisplayList : public SkRefCnt {
|
||||
|
||||
const bool can_apply_group_opacity_;
|
||||
const bool is_ui_thread_safe_;
|
||||
const bool modifies_transparent_black_;
|
||||
|
||||
const sk_sp<const DlRTree> rtree_;
|
||||
|
||||
void Dispatch(DlOpReceiver& ctx,
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "third_party/skia/include/core/SkBBHFactory.h"
|
||||
#include "third_party/skia/include/core/SkColorFilter.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 {
|
||||
@@ -3019,164 +3018,5 @@ TEST_F(DisplayListTest, DrawUnorderedRoundRectPathCCW) {
|
||||
check_inverted_bounds(renderer, "DrawRoundRectPath Counter-Clockwise");
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -72,22 +70,20 @@ sk_sp<DisplayList> DisplayListBuilder::Build() {
|
||||
int count = render_op_count_;
|
||||
size_t nested_bytes = nested_bytes_;
|
||||
int nested_count = nested_op_count_;
|
||||
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();
|
||||
|
||||
used_ = allocated_ = render_op_count_ = op_index_ = 0;
|
||||
nested_bytes_ = nested_op_count_ = 0;
|
||||
is_ui_thread_safe_ = true;
|
||||
storage_.realloc(bytes);
|
||||
layer_stack_.pop_back();
|
||||
layer_stack_.emplace_back();
|
||||
tracker_.reset();
|
||||
current_ = DlPaint();
|
||||
|
||||
return sk_sp<DisplayList>(new DisplayList(
|
||||
std::move(storage_), bytes, count, nested_bytes, nested_count, bounds(),
|
||||
compatible, is_safe, affects_transparency, rtree()));
|
||||
return sk_sp<DisplayList>(
|
||||
new DisplayList(std::move(storage_), bytes, count, nested_bytes,
|
||||
nested_count, bounds(), compatible, is_safe, rtree()));
|
||||
}
|
||||
|
||||
DisplayListBuilder::DisplayListBuilder(const SkRect& cull_rect,
|
||||
@@ -393,11 +389,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();
|
||||
}
|
||||
@@ -484,16 +478,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<SaveLayerBackdropBoundsOp>(0, 1, options, *bounds, backdrop)
|
||||
: Push<SaveLayerBackdropOp>(0, 1, options, backdrop);
|
||||
} else {
|
||||
bounds //
|
||||
? Push<SaveLayerBoundsOp>(0, 1, options, *bounds)
|
||||
: Push<SaveLayerOp>(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
|
||||
@@ -504,41 +500,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<SaveLayerBackdropBoundsOp>(0, 1, options, *bounds, backdrop)
|
||||
: Push<SaveLayerBackdropOp>(0, 1, options, backdrop);
|
||||
} else {
|
||||
bounds //
|
||||
? Push<SaveLayerBoundsOp>(0, 1, options, *bounds)
|
||||
: Push<SaveLayerOp>(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
|
||||
@@ -549,7 +521,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
|
||||
@@ -557,6 +528,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,
|
||||
@@ -679,11 +654,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:
|
||||
@@ -693,6 +663,7 @@ void DisplayListBuilder::ClipRect(const SkRect& rect,
|
||||
Push<ClipDifferenceRectOp>(0, 1, rect, is_aa);
|
||||
break;
|
||||
}
|
||||
tracker_.clipRect(rect, clip_op, is_aa);
|
||||
}
|
||||
void DisplayListBuilder::ClipRRect(const SkRRect& rrect,
|
||||
ClipOp clip_op,
|
||||
@@ -700,11 +671,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:
|
||||
@@ -714,6 +680,7 @@ void DisplayListBuilder::ClipRRect(const SkRRect& rrect,
|
||||
Push<ClipDifferenceRRectOp>(0, 1, rrect, is_aa);
|
||||
break;
|
||||
}
|
||||
tracker_.clipRRect(rrect, clip_op, is_aa);
|
||||
}
|
||||
}
|
||||
void DisplayListBuilder::ClipPath(const SkPath& path,
|
||||
@@ -736,11 +703,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:
|
||||
@@ -750,6 +712,7 @@ void DisplayListBuilder::ClipPath(const SkPath& path,
|
||||
Push<ClipDifferencePathOp>(0, 1, path, is_aa);
|
||||
break;
|
||||
}
|
||||
tracker_.clipPath(path, clip_op, is_aa);
|
||||
}
|
||||
|
||||
bool DisplayListBuilder::QuickReject(const SkRect& bounds) const {
|
||||
@@ -757,36 +720,27 @@ bool DisplayListBuilder::QuickReject(const SkRect& bounds) const {
|
||||
}
|
||||
|
||||
void DisplayListBuilder::drawPaint() {
|
||||
OpResult result = PaintResult(current_, kDrawPaintFlags);
|
||||
if (result != OpResult::kNoEffect && AccumulateUnbounded()) {
|
||||
Push<DrawPaintOp>(0, 1);
|
||||
CheckLayerOpacityCompatibility();
|
||||
UpdateLayerResult(result);
|
||||
}
|
||||
Push<DrawPaintOp>(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<DrawColorOp>(0, 1, color, mode);
|
||||
CheckLayerOpacityCompatibility(mode);
|
||||
UpdateLayerResult(result);
|
||||
}
|
||||
Push<DrawColorOp>(0, 1, color, mode);
|
||||
CheckLayerOpacityCompatibility(mode);
|
||||
AccumulateUnbounded();
|
||||
}
|
||||
void DisplayListBuilder::drawLine(const SkPoint& p0, const SkPoint& p1) {
|
||||
Push<DrawLineOp>(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<DrawLineOp>(0, 1, p0, p1);
|
||||
CheckLayerOpacityCompatibility();
|
||||
UpdateLayerResult(result);
|
||||
}
|
||||
AccumulateOpBounds(bounds, flags);
|
||||
}
|
||||
void DisplayListBuilder::DrawLine(const SkPoint& p0,
|
||||
const SkPoint& p1,
|
||||
@@ -795,45 +749,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.makeSorted(), flags)) {
|
||||
Push<DrawRectOp>(0, 1, rect);
|
||||
CheckLayerOpacityCompatibility();
|
||||
UpdateLayerResult(result);
|
||||
}
|
||||
Push<DrawRectOp>(0, 1, rect);
|
||||
CheckLayerOpacityCompatibility();
|
||||
AccumulateOpBounds(rect.makeSorted(), 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.makeSorted(), flags)) {
|
||||
Push<DrawOvalOp>(0, 1, bounds);
|
||||
CheckLayerOpacityCompatibility();
|
||||
UpdateLayerResult(result);
|
||||
}
|
||||
Push<DrawOvalOp>(0, 1, bounds);
|
||||
CheckLayerOpacityCompatibility();
|
||||
AccumulateOpBounds(bounds.makeSorted(), 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<DrawCircleOp>(0, 1, center, radius);
|
||||
CheckLayerOpacityCompatibility();
|
||||
UpdateLayerResult(result);
|
||||
}
|
||||
}
|
||||
Push<DrawCircleOp>(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,
|
||||
@@ -847,14 +785,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<DrawRRectOp>(0, 1, rrect);
|
||||
CheckLayerOpacityCompatibility();
|
||||
UpdateLayerResult(result);
|
||||
}
|
||||
Push<DrawRRectOp>(0, 1, rrect);
|
||||
CheckLayerOpacityCompatibility();
|
||||
AccumulateOpBounds(rrect.getBounds(), kDrawRRectFlags);
|
||||
}
|
||||
}
|
||||
void DisplayListBuilder::DrawRRect(const SkRRect& rrect, const DlPaint& paint) {
|
||||
@@ -863,14 +796,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<DrawDRRectOp>(0, 1, outer, inner);
|
||||
CheckLayerOpacityCompatibility();
|
||||
UpdateLayerResult(result);
|
||||
}
|
||||
Push<DrawDRRectOp>(0, 1, outer, inner);
|
||||
CheckLayerOpacityCompatibility();
|
||||
AccumulateOpBounds(outer.getBounds(), kDrawDRRectFlags);
|
||||
}
|
||||
void DisplayListBuilder::DrawDRRect(const SkRRect& outer,
|
||||
const SkRRect& inner,
|
||||
@@ -879,17 +807,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<DrawPathOp>(0, 1, path);
|
||||
CheckLayerOpacityHairlineCompatibility();
|
||||
UpdateLayerResult(result);
|
||||
}
|
||||
Push<DrawPathOp>(0, 1, path);
|
||||
CheckLayerOpacityHairlineCompatibility();
|
||||
if (path.isInverseFillType()) {
|
||||
AccumulateUnbounded();
|
||||
} else {
|
||||
AccumulateOpBounds(path.getBounds(), kDrawPathFlags);
|
||||
}
|
||||
}
|
||||
void DisplayListBuilder::DrawPath(const SkPath& path, const DlPaint& paint) {
|
||||
@@ -901,23 +824,19 @@ void DisplayListBuilder::drawArc(const SkRect& bounds,
|
||||
SkScalar start,
|
||||
SkScalar sweep,
|
||||
bool useCenter) {
|
||||
DisplayListAttributeFlags flags = //
|
||||
useCenter //
|
||||
? kDrawArcWithCenterFlags
|
||||
: kDrawArcNoCenterFlags;
|
||||
OpResult result = PaintResult(current_, flags);
|
||||
Push<DrawArcOp>(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<DrawArcOp>(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,
|
||||
@@ -928,31 +847,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;
|
||||
@@ -960,23 +862,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<DrawPointsOp>(bytes, 1, count);
|
||||
AccumulateOpBounds(point_bounds, kDrawPointsAsPointsFlags);
|
||||
break;
|
||||
case PointMode::kLines:
|
||||
data_ptr = Push<DrawLinesOp>(bytes, 1, count);
|
||||
AccumulateOpBounds(point_bounds, kDrawPointsAsLinesFlags);
|
||||
break;
|
||||
case PointMode::kPolygon:
|
||||
data_ptr = Push<DrawPolygonOp>(bytes, 1, count);
|
||||
AccumulateOpBounds(point_bounds, kDrawPointsAsPolygonFlags);
|
||||
break;
|
||||
default:
|
||||
FML_UNREACHABLE();
|
||||
FML_DCHECK(false);
|
||||
return;
|
||||
}
|
||||
CopyV(data_ptr, pts, count);
|
||||
@@ -986,30 +886,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<DrawVerticesOp>(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<DrawVerticesOp>(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,
|
||||
@@ -1022,23 +931,17 @@ void DisplayListBuilder::drawImage(const sk_sp<DlImage> image,
|
||||
const SkPoint point,
|
||||
DlImageSampling sampling,
|
||||
bool render_with_attributes) {
|
||||
render_with_attributes
|
||||
? Push<DrawImageWithAttrOp>(0, 1, image, point, sampling)
|
||||
: Push<DrawImageOp>(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<DrawImageWithAttrOp>(0, 1, image, point, sampling)
|
||||
: Push<DrawImageOp>(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<DlImage>& image,
|
||||
const SkPoint point,
|
||||
@@ -1058,17 +961,14 @@ void DisplayListBuilder::drawImageRect(const sk_sp<DlImage> image,
|
||||
DlImageSampling sampling,
|
||||
bool render_with_attributes,
|
||||
SrcRectConstraint constraint) {
|
||||
Push<DrawImageRectOp>(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<DrawImageRectOp>(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<DlImage>& image,
|
||||
const SkRect& src,
|
||||
@@ -1089,18 +989,15 @@ void DisplayListBuilder::drawImageNine(const sk_sp<DlImage> image,
|
||||
const SkRect& dst,
|
||||
DlFilterMode filter,
|
||||
bool render_with_attributes) {
|
||||
render_with_attributes
|
||||
? Push<DrawImageNineWithAttrOp>(0, 1, image, center, dst, filter)
|
||||
: Push<DrawImageNineOp>(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<DrawImageNineWithAttrOp>(0, 1, image, center, dst, filter)
|
||||
: Push<DrawImageNineOp>(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<DlImage>& image,
|
||||
const SkIRect& center,
|
||||
@@ -1124,27 +1021,6 @@ void DisplayListBuilder::drawAtlas(const sk_sp<DlImage> 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) {
|
||||
@@ -1173,8 +1049,23 @@ void DisplayListBuilder::drawAtlas(const sk_sp<DlImage> 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<DlImage>& atlas,
|
||||
const SkRSXform xform[],
|
||||
@@ -1198,42 +1089,8 @@ void DisplayListBuilder::DrawAtlas(const sk_sp<DlImage>& atlas,
|
||||
|
||||
void DisplayListBuilder::DrawDisplayList(const sk_sp<DisplayList> display_list,
|
||||
SkScalar opacity) {
|
||||
if (!SkScalarIsFinite(opacity) || opacity <= SK_ScalarNearlyZero ||
|
||||
display_list->op_count() == 0 || display_list->bounds().isEmpty() ||
|
||||
current_layer_->is_nop_) {
|
||||
return;
|
||||
}
|
||||
const SkRect bounds = display_list->bounds();
|
||||
bool accumulated;
|
||||
switch (accumulator()->type()) {
|
||||
case BoundsAccumulatorType::kRect:
|
||||
accumulated = AccumulateOpBounds(bounds, kDrawDisplayListFlags);
|
||||
break;
|
||||
case BoundsAccumulatorType::kRTree:
|
||||
auto rtree = display_list->rtree();
|
||||
if (rtree) {
|
||||
std::list<SkRect> rects =
|
||||
rtree->searchAndConsolidateRects(bounds, false);
|
||||
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;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
accumulated = AccumulateOpBounds(bounds, kDrawDisplayListFlags);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!accumulated) {
|
||||
return;
|
||||
}
|
||||
|
||||
DlPaint current_paint = current_;
|
||||
Push<DrawDisplayListOp>(0, 1, display_list,
|
||||
opacity < SK_Scalar1 ? opacity : SK_Scalar1);
|
||||
Push<DrawDisplayListOp>(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
|
||||
@@ -1241,6 +1098,26 @@ void DisplayListBuilder::DrawDisplayList(const sk_sp<DisplayList> display_list,
|
||||
SetAttributesFromPaint(current_paint,
|
||||
DisplayListOpFlags::kSaveLayerWithPaintFlags);
|
||||
|
||||
const SkRect bounds = display_list->bounds();
|
||||
switch (accumulator()->type()) {
|
||||
case BoundsAccumulatorType::kRect:
|
||||
AccumulateOpBounds(bounds, kDrawDisplayListFlags);
|
||||
break;
|
||||
case BoundsAccumulatorType::kRTree:
|
||||
auto rtree = display_list->rtree();
|
||||
if (rtree) {
|
||||
std::list<SkRect> rects =
|
||||
rtree->searchAndConsolidateRects(bounds, false);
|
||||
for (const SkRect& rect : rects) {
|
||||
// TODO (https://github.com/flutter/flutter/issues/114919): Attributes
|
||||
// are not necessarily `kDrawDisplayListFlags`.
|
||||
AccumulateOpBounds(rect, kDrawDisplayListFlags);
|
||||
}
|
||||
} else {
|
||||
AccumulateOpBounds(bounds, kDrawDisplayListFlags);
|
||||
}
|
||||
break;
|
||||
}
|
||||
// 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
|
||||
@@ -1250,38 +1127,18 @@ void DisplayListBuilder::DrawDisplayList(const sk_sp<DisplayList> display_list,
|
||||
nested_op_count_ += display_list->op_count(true) - 1;
|
||||
nested_bytes_ += display_list->bytes(true);
|
||||
UpdateLayerOpacityCompatibility(display_list->can_apply_group_opacity());
|
||||
// Nop DisplayLists are eliminated above so we either affect transparent
|
||||
// pixels or we do not. We should not have [kNoEffect].
|
||||
UpdateLayerResult(display_list->modifies_transparent_black()
|
||||
? OpResult::kAffectsAll
|
||||
: OpResult::kPreservesTransparency);
|
||||
}
|
||||
void DisplayListBuilder::drawTextBlob(const sk_sp<SkTextBlob> 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<DrawTextBlobOp>(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<DrawTextBlobOp>(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<SkTextBlob>& blob,
|
||||
SkScalar x,
|
||||
@@ -1295,19 +1152,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<DrawShadowTransparentOccluderOp>(0, 1, path, color, elevation,
|
||||
dpr)
|
||||
: Push<DrawShadowOp>(0, 1, path, color, elevation, dpr);
|
||||
UpdateLayerOpacityCompatibility(false);
|
||||
UpdateLayerResult(result);
|
||||
}
|
||||
}
|
||||
transparent_occluder //
|
||||
? Push<DrawShadowTransparentOccluderOp>(0, 1, path, color, elevation, dpr)
|
||||
: Push<DrawShadowOp>(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,
|
||||
@@ -1377,40 +1229,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;
|
||||
}
|
||||
|
||||
@@ -1420,8 +1263,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;
|
||||
}
|
||||
|
||||
@@ -1478,130 +1321,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()) {
|
||||
// If the operation applies alpha, but not color, then the only impact
|
||||
// of the alpha is to modulate the output towards transparency.
|
||||
// We can not guarantee an opaque source even if the alpha is opaque
|
||||
// since that would require knowing something about the colors that
|
||||
// the alpha is modulating, but we can guarantee a transparent source
|
||||
// if the alpha is 0.
|
||||
color = (paint.getAlpha() == 0) ? DlColor::kTransparent() : kAnyColor;
|
||||
} 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::kPreservesTransparency;
|
||||
|
||||
case DlBlendMode::kHue:
|
||||
case DlBlendMode::kSaturation:
|
||||
case DlBlendMode::kColor:
|
||||
case DlBlendMode::kLuminosity:
|
||||
case DlBlendMode::kColorBurn:
|
||||
return GetEffectiveColor(paint, flags).isTransparent()
|
||||
? OpResult::kNoEffect
|
||||
: OpResult::kAffectsAll;
|
||||
|
||||
// kSrcIn modifies pixels towards transparency
|
||||
case DlBlendMode::kSrcIn:
|
||||
return OpResult::kPreservesTransparency;
|
||||
|
||||
// These blend modes preserve destination alpha
|
||||
case DlBlendMode::kSrcATop:
|
||||
case DlBlendMode::kDstOut:
|
||||
return GetEffectiveColor(paint, flags).isTransparent()
|
||||
? OpResult::kNoEffect
|
||||
: OpResult::kPreservesTransparency;
|
||||
|
||||
// Always destructive blend modes, potentially not affecting transparency
|
||||
case DlBlendMode::kSrc:
|
||||
case DlBlendMode::kSrcOut:
|
||||
case DlBlendMode::kDstATop:
|
||||
return GetEffectiveColor(paint, flags).isTransparent()
|
||||
? OpResult::kPreservesTransparency
|
||||
: OpResult::kAffectsAll;
|
||||
|
||||
// The kDstIn blend mode modifies the destination unless the
|
||||
// source color is opaque.
|
||||
case DlBlendMode::kDstIn:
|
||||
return GetEffectiveColor(paint, flags).isOpaque()
|
||||
? OpResult::kNoEffect
|
||||
: OpResult::kPreservesTransparency;
|
||||
|
||||
// The next group of blend modes modifies the destination unless the
|
||||
// source color is transparent.
|
||||
case DlBlendMode::kSrcOver:
|
||||
case DlBlendMode::kDstOver:
|
||||
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::kAffectsAll;
|
||||
|
||||
// Modulate only leaves the pixel alone when the source is white.
|
||||
case DlBlendMode::kModulate:
|
||||
return GetEffectiveColor(paint, flags) == DlColor::kWhite()
|
||||
? OpResult::kNoEffect
|
||||
: OpResult::kPreservesTransparency;
|
||||
}
|
||||
}
|
||||
return OpResult::kAffectsAll;
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
@@ -506,13 +506,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<const DlImageFilter>& filter = nullptr)
|
||||
explicit LayerInfo(size_t save_offset = 0,
|
||||
bool has_layer = false,
|
||||
std::shared_ptr<const DlImageFilter> 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
|
||||
@@ -525,9 +527,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_;
|
||||
@@ -550,12 +549,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<const DlImageFilter> filter() { return filter_; }
|
||||
|
||||
@@ -590,13 +583,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<const DlImageFilter> 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;
|
||||
};
|
||||
@@ -710,40 +701,9 @@ class DisplayListBuilder final : public virtual DlCanvas,
|
||||
return accumulator_->rtree();
|
||||
}
|
||||
|
||||
static DisplayListAttributeFlags FlagsForPointMode(PointMode mode);
|
||||
|
||||
enum class OpResult {
|
||||
kNoEffect,
|
||||
kPreservesTransparency,
|
||||
kAffectsAll,
|
||||
};
|
||||
|
||||
bool paint_nops_on_transparency();
|
||||
OpResult PaintResult(const DlPaint& paint,
|
||||
DisplayListAttributeFlags flags = kDrawPaintFlags);
|
||||
|
||||
void UpdateLayerResult(OpResult result) {
|
||||
switch (result) {
|
||||
case OpResult::kNoEffect:
|
||||
case OpResult::kPreservesTransparency:
|
||||
break;
|
||||
case OpResult::kAffectsAll:
|
||||
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(0x80);
|
||||
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);
|
||||
|
||||
@@ -753,24 +713,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_;
|
||||
};
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include "flutter/display_list/dl_op_flags.h"
|
||||
#include "flutter/display_list/dl_sampling_options.h"
|
||||
#include "flutter/display_list/skia/dl_sk_canvas.h"
|
||||
#include "flutter/display_list/skia/dl_sk_conversions.h"
|
||||
#include "flutter/display_list/skia/dl_sk_dispatcher.h"
|
||||
#include "flutter/display_list/testing/dl_test_surface_provider.h"
|
||||
#include "flutter/display_list/utils/dl_comparable.h"
|
||||
@@ -284,26 +283,20 @@ using BackendType = DlSurfaceProvider::BackendType;
|
||||
|
||||
class RenderResult {
|
||||
public:
|
||||
explicit RenderResult(const sk_sp<SkSurface>& surface,
|
||||
bool take_snapshot = false) {
|
||||
explicit RenderResult(const sk_sp<SkSurface>& surface) {
|
||||
SkImageInfo info = surface->imageInfo();
|
||||
info = SkImageInfo::MakeN32Premul(info.dimensions());
|
||||
addr_ = malloc(info.computeMinByteSize() * info.height());
|
||||
pixmap_.reset(info, addr_, info.minRowBytes());
|
||||
surface->readPixels(pixmap_, 0, 0);
|
||||
if (take_snapshot) {
|
||||
image_ = surface->makeImageSnapshot();
|
||||
}
|
||||
EXPECT_TRUE(surface->readPixels(pixmap_, 0, 0));
|
||||
}
|
||||
~RenderResult() { free(addr_); }
|
||||
|
||||
sk_sp<SkImage> image() const { return image_; }
|
||||
int width() const { return pixmap_.width(); }
|
||||
int height() const { return pixmap_.height(); }
|
||||
const uint32_t* addr32(int x, int y) const { return pixmap_.addr32(x, y); }
|
||||
|
||||
private:
|
||||
sk_sp<SkImage> image_;
|
||||
SkPixmap pixmap_;
|
||||
void* addr_ = nullptr;
|
||||
};
|
||||
@@ -919,14 +912,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) {
|
||||
@@ -3799,6 +3785,7 @@ TEST_F(DisplayListCanvas, MatrixColorFilterOpacityCommuteCheck) {
|
||||
}
|
||||
|
||||
#define FOR_EACH_BLEND_MODE_ENUM(FUNC) \
|
||||
FUNC(kSrc) \
|
||||
FUNC(kClear) \
|
||||
FUNC(kSrc) \
|
||||
FUNC(kDst) \
|
||||
@@ -3829,18 +3816,6 @@ TEST_F(DisplayListCanvas, MatrixColorFilterOpacityCommuteCheck) {
|
||||
FUNC(kColor) \
|
||||
FUNC(kLuminosity)
|
||||
|
||||
// This function serves both to enhance error output below and to double
|
||||
// check that the macro supplies all modes (otherwise it won't compile)
|
||||
static std::string BlendModeToString(DlBlendMode mode) {
|
||||
switch (mode) {
|
||||
#define MODE_CASE(m) \
|
||||
case DlBlendMode::m: \
|
||||
return #m;
|
||||
FOR_EACH_BLEND_MODE_ENUM(MODE_CASE)
|
||||
#undef MODE_CASE
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(DisplayListCanvas, BlendColorFilterModifyTransparencyCheck) {
|
||||
std::vector<std::unique_ptr<RenderEnvironment>> environments;
|
||||
for (auto& provider : CanvasCompareTester::kTestProviders) {
|
||||
@@ -3851,8 +3826,7 @@ TEST_F(DisplayListCanvas, BlendColorFilterModifyTransparencyCheck) {
|
||||
|
||||
auto test_mode_color = [&environments](DlBlendMode mode, DlColor color) {
|
||||
std::stringstream desc_str;
|
||||
std::string mode_string = BlendModeToString(mode);
|
||||
desc_str << "blend[" << mode_string << ", " << color << "]";
|
||||
desc_str << "blend[" << mode << ", " << color << "]";
|
||||
std::string desc = desc_str.str();
|
||||
DlBlendColorFilter filter(color, mode);
|
||||
if (filter.modifies_transparent_black()) {
|
||||
@@ -3913,8 +3887,7 @@ TEST_F(DisplayListCanvas, BlendColorFilterOpacityCommuteCheck) {
|
||||
|
||||
auto test_mode_color = [&environments](DlBlendMode mode, DlColor color) {
|
||||
std::stringstream desc_str;
|
||||
std::string mode_string = BlendModeToString(mode);
|
||||
desc_str << "blend[" << mode_string << ", " << color << "]";
|
||||
desc_str << "blend[" << mode << ", " << color << "]";
|
||||
std::string desc = desc_str.str();
|
||||
DlBlendColorFilter filter(color, mode);
|
||||
if (filter.can_commute_with_opacity()) {
|
||||
@@ -3973,359 +3946,7 @@ TEST_F(DisplayListCanvas, BlendColorFilterOpacityCommuteCheck) {
|
||||
#undef TEST_MODE
|
||||
}
|
||||
|
||||
class DisplayListNopTest : public DisplayListCanvas {
|
||||
// The following code uses the acronym MTB for "modifies_transparent_black"
|
||||
|
||||
protected:
|
||||
DisplayListNopTest() : DisplayListCanvas() {
|
||||
test_src_colors = {
|
||||
DlColor::kBlack().withAlpha(0), // transparent black
|
||||
DlColor::kBlack().withAlpha(0x7f), // half transparent black
|
||||
DlColor::kWhite().withAlpha(0x7f), // half transparent white
|
||||
DlColor::kBlack(), // opaque black
|
||||
DlColor::kWhite(), // opaque white
|
||||
DlColor::kRed(), // opaque red
|
||||
DlColor::kGreen(), // opaque green
|
||||
DlColor::kBlue(), // opaque blue
|
||||
DlColor::kDarkGrey(), // dark grey
|
||||
DlColor::kLightGrey(), // light grey
|
||||
};
|
||||
|
||||
// We test against a color cube of 3x3x3 colors [55,aa,ff]
|
||||
// plus transparency as the first color/pixel
|
||||
test_dst_colors.push_back(DlColor::kTransparent());
|
||||
const int step = 0x55;
|
||||
static_assert(step * 3 == 255);
|
||||
for (int a = step; a < 256; a += step) {
|
||||
for (int r = step; r < 256; r += step) {
|
||||
for (int g = step; g < 256; g += step) {
|
||||
for (int b = step; b < 256; b += step) {
|
||||
test_dst_colors.push_back(DlColor(a << 24 | r << 16 | g << 8 | b));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr float color_filter_matrix_nomtb[] = {
|
||||
0.0001, 0.0001, 0.0001, 0.9997, 0.0, //
|
||||
0.0001, 0.0001, 0.0001, 0.9997, 0.0, //
|
||||
0.0001, 0.0001, 0.0001, 0.9997, 0.0, //
|
||||
0.0001, 0.0001, 0.0001, 0.9997, 0.0, //
|
||||
};
|
||||
static constexpr float color_filter_matrix_mtb[] = {
|
||||
0.0001, 0.0001, 0.0001, 0.9997, 0.0, //
|
||||
0.0001, 0.0001, 0.0001, 0.9997, 0.0, //
|
||||
0.0001, 0.0001, 0.0001, 0.9997, 0.0, //
|
||||
0.0001, 0.0001, 0.0001, 0.9997, 0.1, //
|
||||
};
|
||||
color_filter_nomtb = DlMatrixColorFilter::Make(color_filter_matrix_nomtb);
|
||||
color_filter_mtb = DlMatrixColorFilter::Make(color_filter_matrix_mtb);
|
||||
EXPECT_FALSE(color_filter_nomtb->modifies_transparent_black());
|
||||
EXPECT_TRUE(color_filter_mtb->modifies_transparent_black());
|
||||
|
||||
test_data =
|
||||
get_output(test_dst_colors.size(), 1, true, [this](SkCanvas* canvas) {
|
||||
int x = 0;
|
||||
for (DlColor color : test_dst_colors) {
|
||||
SkPaint paint;
|
||||
paint.setColor(color);
|
||||
paint.setBlendMode(SkBlendMode::kSrc);
|
||||
canvas->drawRect(SkRect::MakeXYWH(x, 0, 1, 1), paint);
|
||||
x++;
|
||||
}
|
||||
});
|
||||
|
||||
// For image-on-image tests, the src and dest images will have repeated
|
||||
// rows/columns that have every color, but laid out at right angles to
|
||||
// each other so we see an interaction with every test color against
|
||||
// every other test color.
|
||||
int data_count = test_data->image()->width();
|
||||
test_image_dst_data = get_output(
|
||||
data_count, data_count, true, [this, data_count](SkCanvas* canvas) {
|
||||
ASSERT_EQ(test_data->width(), data_count);
|
||||
ASSERT_EQ(test_data->height(), 1);
|
||||
for (int y = 0; y < data_count; y++) {
|
||||
canvas->drawImage(test_data->image().get(), 0, y);
|
||||
}
|
||||
});
|
||||
test_image_src_data = get_output(
|
||||
data_count, data_count, true, [this, data_count](SkCanvas* canvas) {
|
||||
ASSERT_EQ(test_data->width(), data_count);
|
||||
ASSERT_EQ(test_data->height(), 1);
|
||||
canvas->translate(data_count, 0);
|
||||
canvas->rotate(90);
|
||||
for (int y = 0; y < data_count; y++) {
|
||||
canvas->drawImage(test_data->image().get(), 0, y);
|
||||
}
|
||||
});
|
||||
// Double check that the pixel data is laid out in orthogonal stripes
|
||||
for (int y = 0; y < data_count; y++) {
|
||||
for (int x = 0; x < data_count; x++) {
|
||||
EXPECT_EQ(*test_image_dst_data->addr32(x, y), *test_data->addr32(x, 0));
|
||||
EXPECT_EQ(*test_image_src_data->addr32(x, y), *test_data->addr32(y, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// These flags are 0 by default until they encounter a counter-example
|
||||
// result and get set.
|
||||
static constexpr int kWasNotNop = 0x1; // Some tested pixel was modified
|
||||
static constexpr int kWasMTB = 0x2; // A transparent pixel was modified
|
||||
|
||||
std::vector<DlColor> test_src_colors;
|
||||
std::vector<DlColor> test_dst_colors;
|
||||
|
||||
std::shared_ptr<DlColorFilter> color_filter_nomtb;
|
||||
std::shared_ptr<DlColorFilter> color_filter_mtb;
|
||||
|
||||
// A 1-row image containing every color in test_dst_colors
|
||||
std::unique_ptr<RenderResult> test_data;
|
||||
|
||||
// A square image containing test_data duplicated in each row
|
||||
std::unique_ptr<RenderResult> test_image_dst_data;
|
||||
|
||||
// A square image containing test_data duplicated in each column
|
||||
std::unique_ptr<RenderResult> test_image_src_data;
|
||||
|
||||
std::unique_ptr<RenderResult> get_output(
|
||||
int w,
|
||||
int h,
|
||||
bool snapshot,
|
||||
const std::function<void(SkCanvas*)>& renderer) {
|
||||
auto surface = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(w, h));
|
||||
SkCanvas* canvas = surface->getCanvas();
|
||||
renderer(canvas);
|
||||
canvas->flush();
|
||||
surface->flushAndSubmit(true);
|
||||
return std::make_unique<RenderResult>(surface, snapshot);
|
||||
}
|
||||
|
||||
int check_color_result(DlColor dst_color,
|
||||
DlColor result_color,
|
||||
const sk_sp<DisplayList>& dl,
|
||||
const std::string& desc) {
|
||||
int ret = 0;
|
||||
bool is_error = false;
|
||||
if (dst_color.isTransparent() && !result_color.isTransparent()) {
|
||||
ret |= kWasMTB;
|
||||
is_error = !dl->modifies_transparent_black();
|
||||
}
|
||||
if (result_color != dst_color) {
|
||||
ret |= kWasNotNop;
|
||||
is_error = (dl->op_count() == 0u);
|
||||
}
|
||||
if (is_error) {
|
||||
FML_LOG(ERROR) << std::hex << dst_color << " filters to " << result_color
|
||||
<< desc;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int check_image_result(const std::unique_ptr<RenderResult>& dst_data,
|
||||
const std::unique_ptr<RenderResult>& result_data,
|
||||
const sk_sp<DisplayList>& dl,
|
||||
const std::string& desc) {
|
||||
EXPECT_EQ(dst_data->width(), result_data->width());
|
||||
EXPECT_EQ(dst_data->height(), result_data->height());
|
||||
int all_flags = 0;
|
||||
for (int y = 0; y < dst_data->height(); y++) {
|
||||
const uint32_t* dst_pixels = dst_data->addr32(0, y);
|
||||
const uint32_t* result_pixels = result_data->addr32(0, y);
|
||||
for (int x = 0; x < dst_data->width(); x++) {
|
||||
all_flags |=
|
||||
check_color_result(dst_pixels[x], result_pixels[x], dl, desc);
|
||||
}
|
||||
}
|
||||
return all_flags;
|
||||
}
|
||||
|
||||
void report_results(int all_flags,
|
||||
const sk_sp<DisplayList>& dl,
|
||||
const std::string& desc) {
|
||||
if (!dl->modifies_transparent_black()) {
|
||||
EXPECT_TRUE((all_flags & kWasMTB) == 0);
|
||||
} else if ((all_flags & kWasMTB) == 0) {
|
||||
FML_LOG(INFO) << "combination does not affect transparency: " << desc;
|
||||
}
|
||||
if (dl->op_count() == 0u) {
|
||||
EXPECT_TRUE((all_flags & kWasNotNop) == 0);
|
||||
} else if ((all_flags & kWasNotNop) == 0) {
|
||||
FML_LOG(INFO) << "combination could be classified as a nop: " << desc;
|
||||
}
|
||||
};
|
||||
|
||||
void test_mode_color_via_filter(DlBlendMode mode, DlColor color) {
|
||||
std::stringstream desc_stream;
|
||||
desc_stream << " using SkColorFilter::filterColor() with: ";
|
||||
desc_stream << BlendModeToString(mode);
|
||||
desc_stream << "/" << color;
|
||||
std::string desc = desc_stream.str();
|
||||
DisplayListBuilder builder({0.0f, 0.0f, 100.0f, 100.0f});
|
||||
DlPaint paint = DlPaint(color).setBlendMode(mode);
|
||||
builder.DrawRect({0.0f, 0.0f, 10.0f, 10.0f}, paint);
|
||||
auto dl = builder.Build();
|
||||
if (dl->modifies_transparent_black()) {
|
||||
ASSERT_TRUE(dl->op_count() != 0u);
|
||||
}
|
||||
|
||||
auto sk_mode = static_cast<SkBlendMode>(mode);
|
||||
auto sk_color_filter = SkColorFilters::Blend(color, sk_mode);
|
||||
int all_flags = 0;
|
||||
if (sk_color_filter) {
|
||||
for (DlColor dst_color : test_dst_colors) {
|
||||
DlColor result = sk_color_filter->filterColor(dst_color);
|
||||
all_flags |= check_color_result(dst_color, result, dl, desc);
|
||||
}
|
||||
if ((all_flags & kWasMTB) != 0) {
|
||||
EXPECT_FALSE(sk_color_filter->isAlphaUnchanged());
|
||||
}
|
||||
}
|
||||
report_results(all_flags, dl, desc);
|
||||
};
|
||||
|
||||
void test_mode_color_via_rendering(DlBlendMode mode, DlColor color) {
|
||||
std::stringstream desc_stream;
|
||||
desc_stream << " rendering with: ";
|
||||
desc_stream << BlendModeToString(mode);
|
||||
desc_stream << "/" << color;
|
||||
std::string desc = desc_stream.str();
|
||||
auto test_image = test_data->image();
|
||||
SkRect test_bounds =
|
||||
SkRect::MakeWH(test_image->width(), test_image->height());
|
||||
DisplayListBuilder builder(test_bounds);
|
||||
DlPaint dl_paint = DlPaint(color).setBlendMode(mode);
|
||||
builder.DrawRect(test_bounds, dl_paint);
|
||||
auto dl = builder.Build();
|
||||
bool dl_is_elided = dl->op_count() == 0u;
|
||||
bool dl_affects_transparent_pixels = dl->modifies_transparent_black();
|
||||
ASSERT_TRUE(!dl_is_elided || !dl_affects_transparent_pixels);
|
||||
|
||||
auto sk_mode = static_cast<SkBlendMode>(mode);
|
||||
SkPaint sk_paint;
|
||||
sk_paint.setBlendMode(sk_mode);
|
||||
sk_paint.setColor(color);
|
||||
for (auto& provider : CanvasCompareTester::kTestProviders) {
|
||||
auto result_surface = provider->MakeOffscreenSurface(
|
||||
test_image->width(), test_image->height(),
|
||||
DlSurfaceProvider::kN32Premul_PixelFormat);
|
||||
SkCanvas* result_canvas = result_surface->sk_surface()->getCanvas();
|
||||
result_canvas->clear(SK_ColorTRANSPARENT);
|
||||
result_canvas->drawImage(test_image.get(), 0, 0);
|
||||
result_canvas->drawRect(test_bounds, sk_paint);
|
||||
result_canvas->flush();
|
||||
result_surface->sk_surface()->flushAndSubmit(true);
|
||||
auto result_pixels =
|
||||
std::make_unique<RenderResult>(result_surface->sk_surface());
|
||||
|
||||
int all_flags = check_image_result(test_data, result_pixels, dl, desc);
|
||||
report_results(all_flags, dl, desc);
|
||||
}
|
||||
};
|
||||
|
||||
void test_attributes_image(DlBlendMode mode,
|
||||
DlColor color,
|
||||
DlColorFilter* color_filter,
|
||||
DlImageFilter* image_filter) {
|
||||
// if (true) { return; }
|
||||
std::stringstream desc_stream;
|
||||
desc_stream << " rendering with: ";
|
||||
desc_stream << BlendModeToString(mode);
|
||||
desc_stream << "/" << color;
|
||||
std::string cf_mtb = color_filter
|
||||
? color_filter->modifies_transparent_black()
|
||||
? "modifies transparency"
|
||||
: "preserves transparency"
|
||||
: "no filter";
|
||||
desc_stream << ", CF: " << cf_mtb;
|
||||
std::string if_mtb = image_filter
|
||||
? image_filter->modifies_transparent_black()
|
||||
? "modifies transparency"
|
||||
: "preserves transparency"
|
||||
: "no filter";
|
||||
desc_stream << ", IF: " << if_mtb;
|
||||
std::string desc = desc_stream.str();
|
||||
|
||||
DisplayListBuilder builder({0.0f, 0.0f, 100.0f, 100.0f});
|
||||
DlPaint paint = DlPaint(color) //
|
||||
.setBlendMode(mode) //
|
||||
.setColorFilter(color_filter) //
|
||||
.setImageFilter(image_filter);
|
||||
builder.DrawImage(DlImage::Make(test_image_src_data->image()), {0, 0},
|
||||
DlImageSampling::kNearestNeighbor, &paint);
|
||||
auto dl = builder.Build();
|
||||
|
||||
int w = test_image_src_data->width();
|
||||
int h = test_image_src_data->height();
|
||||
auto sk_mode = static_cast<SkBlendMode>(mode);
|
||||
SkPaint sk_paint;
|
||||
sk_paint.setBlendMode(sk_mode);
|
||||
sk_paint.setColor(color);
|
||||
sk_paint.setColorFilter(ToSk(color_filter));
|
||||
sk_paint.setImageFilter(ToSk(image_filter));
|
||||
for (auto& provider : CanvasCompareTester::kTestProviders) {
|
||||
auto result_surface = provider->MakeOffscreenSurface(
|
||||
w, h, DlSurfaceProvider::kN32Premul_PixelFormat);
|
||||
SkCanvas* result_canvas = result_surface->sk_surface()->getCanvas();
|
||||
result_canvas->clear(SK_ColorTRANSPARENT);
|
||||
result_canvas->drawImage(test_image_dst_data->image(), 0, 0);
|
||||
result_canvas->drawImage(test_image_src_data->image(), 0, 0,
|
||||
SkSamplingOptions(), &sk_paint);
|
||||
result_canvas->flush();
|
||||
result_surface->sk_surface()->flushAndSubmit(true);
|
||||
auto result_pixels =
|
||||
std::make_unique<RenderResult>(result_surface->sk_surface());
|
||||
|
||||
int all_flags =
|
||||
check_image_result(test_image_dst_data, result_pixels, dl, desc);
|
||||
report_results(all_flags, dl, desc);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
TEST_F(DisplayListNopTest, BlendModeAndColorViaColorFilter) {
|
||||
auto test_mode_filter = [this](DlBlendMode mode) {
|
||||
for (DlColor color : test_src_colors) {
|
||||
test_mode_color_via_filter(mode, color);
|
||||
}
|
||||
};
|
||||
|
||||
#define TEST_MODE(V) test_mode_filter(DlBlendMode::V);
|
||||
FOR_EACH_BLEND_MODE_ENUM(TEST_MODE)
|
||||
#undef TEST_MODE
|
||||
}
|
||||
|
||||
TEST_F(DisplayListNopTest, BlendModeAndColorByRendering) {
|
||||
auto test_mode_render = [this](DlBlendMode mode) {
|
||||
// First check rendering a variety of colors onto image
|
||||
for (DlColor color : test_src_colors) {
|
||||
test_mode_color_via_rendering(mode, color);
|
||||
}
|
||||
};
|
||||
|
||||
#define TEST_MODE(V) test_mode_render(DlBlendMode::V);
|
||||
FOR_EACH_BLEND_MODE_ENUM(TEST_MODE)
|
||||
#undef TEST_MODE
|
||||
}
|
||||
|
||||
TEST_F(DisplayListNopTest, BlendModeAndColorAndFiltersByRendering) {
|
||||
auto test_mode_render = [this](DlBlendMode mode) {
|
||||
auto image_filter_nomtb = DlColorFilterImageFilter(color_filter_nomtb);
|
||||
auto image_filter_mtb = DlColorFilterImageFilter(color_filter_mtb);
|
||||
for (DlColor color : test_src_colors) {
|
||||
test_attributes_image(mode, color, nullptr, nullptr);
|
||||
test_attributes_image(mode, color, color_filter_nomtb.get(), nullptr);
|
||||
test_attributes_image(mode, color, color_filter_mtb.get(), nullptr);
|
||||
test_attributes_image(mode, color, nullptr, &image_filter_nomtb);
|
||||
test_attributes_image(mode, color, nullptr, &image_filter_mtb);
|
||||
}
|
||||
};
|
||||
|
||||
#define TEST_MODE(V) test_mode_render(DlBlendMode::V);
|
||||
FOR_EACH_BLEND_MODE_ENUM(TEST_MODE)
|
||||
#undef TEST_MODE
|
||||
}
|
||||
|
||||
#undef FOR_EACH_BLEND_MODE_ENUM
|
||||
#undef FOR_EACH_ENUM
|
||||
|
||||
} // namespace testing
|
||||
} // namespace flutter
|
||||
|
||||
@@ -517,7 +517,7 @@ std::vector<DisplayListInvocationGroup> 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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -40,7 +40,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();
|
||||
@@ -89,10 +88,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;
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -564,9 +564,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;
|
||||
|
||||
@@ -616,9 +616,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));
|
||||
|
||||
@@ -355,7 +355,7 @@ TEST_F(DisplayListLayerTest, RasterCachePreservesRTree) {
|
||||
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));
|
||||
@@ -375,7 +375,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(
|
||||
@@ -388,7 +388,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(
|
||||
@@ -402,25 +402,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)));
|
||||
@@ -430,8 +426,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)));
|
||||
|
||||
|
||||
@@ -659,7 +659,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;
|
||||
@@ -672,7 +672,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;
|
||||
|
||||
@@ -30,7 +30,7 @@ Damage DiffContextTest::DiffLayerTree(MockLayerTree& layer_tree,
|
||||
}
|
||||
|
||||
sk_sp<DisplayList> DiffContextTest::CreateDisplayList(const SkRect& bounds,
|
||||
DlColor color) {
|
||||
SkColor color) {
|
||||
DisplayListBuilder builder;
|
||||
builder.DrawRect(bounds, DlPaint().setColor(color));
|
||||
return builder.Build();
|
||||
|
||||
@@ -45,8 +45,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<DisplayList> CreateDisplayList(const SkRect& bounds,
|
||||
DlColor color = DlColor::kBlack());
|
||||
sk_sp<DisplayList> CreateDisplayList(const SkRect& bounds, uint32_t color);
|
||||
|
||||
std::shared_ptr<DisplayListLayer> CreateDisplayListLayer(
|
||||
const sk_sp<DisplayList>& display_list,
|
||||
|
||||
@@ -856,12 +856,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<SolidRRectBlurContents> rrect_blur;
|
||||
|
||||
@@ -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->modifies_transparent_black()); \
|
||||
} while (0)
|
||||
|
||||
#define ASSERT_NO_DRAW(spy, dl) \
|
||||
do { \
|
||||
ASSERT_FALSE(spy.did_draw()); \
|
||||
ASSERT_FALSE(dl->modifies_transparent_black()); \
|
||||
} while (0)
|
||||
|
||||
TEST(DlOpSpy, DidDrawIsFalseByDefault) {
|
||||
DlOpSpy dl_op_spy;
|
||||
ASSERT_FALSE(dl_op_spy.did_draw());
|
||||
}
|
||||
|
||||
TEST(DlOpSpy, EmptyDisplayList) {
|
||||
DisplayListBuilder builder;
|
||||
sk_sp<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user