4202 {
4203 switch (mode) {
4204#define MODE_CASE(m) \
4205 case DlBlendMode::m: \
4206 return #m;
4208#undef MODE_CASE
4209 }
4210}
4211
4212TEST_F(DisplayListRendering, BlendColorFilterModifyTransparencyCheck) {
4214 std::stringstream desc_str;
4216 desc_str <<
"blend[" << mode_string <<
", " <<
color <<
"]";
4217 std::string
desc = desc_str.str();
4218 DlBlendColorFilter filter(
color, mode);
4219 if (filter.modifies_transparent_black()) {
4220 ASSERT_NE(DlBlendColorFilter::Make(
color, mode),
nullptr) <<
desc;
4221 }
4222
4223 DlPaint
paint(DlColor(0x7f7f7f7f));
4224 DlPaint filter_save_paint = DlPaint().setColorFilter(&filter);
4225
4226 DisplayListBuilder builder1;
4228 builder1.Rotate(45);
4230 builder1.DrawRect(kRenderBounds,
paint);
4231 auto display_list1 = builder1.Build();
4232
4233 DisplayListBuilder builder2;
4235 builder2.Rotate(45);
4237 builder2.SaveLayer(&kTestBounds2, &filter_save_paint);
4238 builder2.DrawRect(kRenderBounds,
paint);
4239 builder2.Restore();
4240 auto display_list2 = builder2.Build();
4241
4242 for (auto& back_end : CanvasCompareTester::TestBackends) {
4243 auto provider = CanvasCompareTester::GetProvider(back_end);
4244 auto env = std::make_unique<RenderEnvironment>(
4245 provider.get(), PixelFormat::kN32PremulPixelFormat);
4246 auto results1 =
env->getResult(display_list1);
4247 auto results2 =
env->getResult(display_list2);
4248 int modified_transparent_pixels =
4249 CanvasCompareTester::countModifiedTransparentPixels(results1.get(),
4250 results2.get());
4251 EXPECT_EQ(filter.modifies_transparent_black(),
4252 modified_transparent_pixels != 0)
4254 }
4255 };
4256
4258 test_mode_color(mode, DlColor::kTransparent());
4259 test_mode_color(mode, DlColor::kWhite());
4260 test_mode_color(mode, DlColor::kWhite().modulateOpacity(0.5));
4261 test_mode_color(mode, DlColor::kBlack());
4262 test_mode_color(mode, DlColor::kBlack().modulateOpacity(0.5));
4263 };
4264
4265#define TEST_MODE(V) test_mode(DlBlendMode::V);
4267#undef TEST_MODE
4268}
4269
4270TEST_F(DisplayListRendering, BlendColorFilterOpacityCommuteCheck) {
4272 std::stringstream desc_str;
4274 desc_str <<
"blend[" << mode_string <<
", " <<
color <<
"]";
4275 std::string
desc = desc_str.str();
4276 DlBlendColorFilter filter(
color, mode);
4277 if (filter.can_commute_with_opacity()) {
4278
4279
4280 } else {
4281 ASSERT_NE(DlBlendColorFilter::Make(
color, mode),
nullptr) <<
desc;
4282 }
4283
4284 DlPaint
paint(DlColor(0x80808080));
4285 DlPaint opacity_save_paint = DlPaint().setOpacity(0.5);
4286 DlPaint filter_save_paint = DlPaint().setColorFilter(&filter);
4287
4288 DisplayListBuilder builder1;
4289 builder1.SaveLayer(&kTestBounds2, &opacity_save_paint);
4290 builder1.SaveLayer(&kTestBounds2, &filter_save_paint);
4291
4292 builder1.DrawRect(kRenderBounds,
paint);
4293 builder1.Restore();
4294 builder1.Restore();
4295 auto display_list1 = builder1.Build();
4296
4297 DisplayListBuilder builder2;
4298 builder2.SaveLayer(&kTestBounds2, &filter_save_paint);
4299 builder2.SaveLayer(&kTestBounds2, &opacity_save_paint);
4300
4301 builder2.DrawRect(kRenderBounds,
paint);
4302 builder2.Restore();
4303 builder2.Restore();
4304 auto display_list2 = builder2.Build();
4305
4306 for (auto& back_end : CanvasCompareTester::TestBackends) {
4307 auto provider = CanvasCompareTester::GetProvider(back_end);
4308 auto env = std::make_unique<RenderEnvironment>(
4309 provider.get(), PixelFormat::kN32PremulPixelFormat);
4310 auto results1 =
env->getResult(display_list1);
4311 auto results2 =
env->getResult(display_list2);
4312 if (filter.can_commute_with_opacity()) {
4313 CanvasCompareTester::compareToReference(
4314 results2.get(), results1.get(), desc, nullptr, nullptr,
4316 } else {
4317 CanvasCompareTester::quickCompareToReference(
4318 results1.get(), results2.get(), false, desc);
4319 }
4320 }
4321 };
4322
4324 test_mode_color(mode, DlColor::kTransparent());
4325 test_mode_color(mode, DlColor::kWhite());
4326 test_mode_color(mode, DlColor::kWhite().modulateOpacity(0.5));
4327 test_mode_color(mode, DlColor::kBlack());
4328 test_mode_color(mode, DlColor::kBlack().modulateOpacity(0.5));
4329 };
4330
4331#define TEST_MODE(V) test_mode(DlBlendMode::V);
4333#undef TEST_MODE
4334}
4335
4337
4338
4339 protected:
4341 test_src_colors = {
4342 DlColor::kBlack().withAlpha(0),
4343 DlColor::kBlack().withAlpha(0x7f),
4344 DlColor::kWhite().withAlpha(0x7f),
4345 DlColor::kBlack(),
4346 DlColor::kWhite(),
4347 DlColor::kRed(),
4348 DlColor::kGreen(),
4349 DlColor::kBlue(),
4350 DlColor::kDarkGrey(),
4351 DlColor::kLightGrey(),
4352 };
4353
4354
4355
4356 test_dst_colors.push_back(DlColor::kTransparent());
4357 const int step = 0x55;
4358 static_assert(
step * 3 == 255);
4360 for (
int r =
step; r < 256; r +=
step) {
4361 for (
int g =
step; g < 256; g +=
step) {
4363 test_dst_colors.push_back(DlColor(
a << 24 | r << 16 | g << 8 |
b));
4364 }
4365 }
4366 }
4367 }
4368
4369 static constexpr float color_filter_matrix_nomtb[] = {
4370 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
4371 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
4372 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
4373 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
4374 };
4375 static constexpr float color_filter_matrix_mtb[] = {
4376 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
4377 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
4378 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
4379 0.0001, 0.0001, 0.0001, 0.9997, 0.1,
4380 };
4381 color_filter_nomtb = DlMatrixColorFilter::Make(color_filter_matrix_nomtb);
4382 color_filter_mtb = DlMatrixColorFilter::Make(color_filter_matrix_mtb);
4383 EXPECT_FALSE(color_filter_nomtb->modifies_transparent_black());
4384 EXPECT_TRUE(color_filter_mtb->modifies_transparent_black());
4385
4386 test_data =
4387 get_output(test_dst_colors.size(), 1,
true, [
this](
SkCanvas* canvas) {
4388 int x = 0;
4389 for (DlColor color : test_dst_colors) {
4390 SkPaint paint;
4391 paint.setColor(ToSk(color));
4392 paint.setBlendMode(SkBlendMode::kSrc);
4393 canvas->drawRect(SkRect::MakeXYWH(x, 0, 1, 1), paint);
4394 x++;
4395 }
4396 });
4397
4398
4399
4400
4401
4402 int data_count = test_data->image()->width();
4403 test_image_dst_data = get_output(
4404 data_count, data_count,
true, [
this, data_count](
SkCanvas* canvas) {
4405 ASSERT_EQ(test_data->width(), data_count);
4406 ASSERT_EQ(test_data->height(), 1);
4407 for (
int y = 0;
y < data_count;
y++) {
4408 canvas->
drawImage(test_data->image().get(), 0,
y);
4409 }
4410 });
4411 test_image_src_data = get_output(
4412 data_count, data_count,
true, [
this, data_count](
SkCanvas* canvas) {
4413 ASSERT_EQ(test_data->width(), data_count);
4414 ASSERT_EQ(test_data->height(), 1);
4417 for (
int y = 0;
y < data_count;
y++) {
4418 canvas->
drawImage(test_data->image().get(), 0,
y);
4419 }
4420 });
4421
4422 for (
int y = 0;
y < data_count;
y++) {
4423 for (
int x = 0;
x < data_count;
x++) {
4424 EXPECT_EQ(*test_image_dst_data->addr32(
x,
y), *test_data->addr32(
x, 0));
4425 EXPECT_EQ(*test_image_src_data->addr32(
x,
y), *test_data->addr32(
y, 0));
4426 }
4427 }
4428 }
4429
4430
4431
4432 static constexpr int kWasNotNop = 0x1;
4433 static constexpr int kWasMTB = 0x2;
4434
4435 std::vector<DlColor> test_src_colors;
4436 std::vector<DlColor> test_dst_colors;
4437
4438 std::shared_ptr<DlColorFilter> color_filter_nomtb;
4439 std::shared_ptr<DlColorFilter> color_filter_mtb;
4440
4441
4442 std::unique_ptr<RenderResult> test_data;
4443
4444
4445 std::unique_ptr<RenderResult> test_image_dst_data;
4446
4447
4448 std::unique_ptr<RenderResult> test_image_src_data;
4449
4450 std::unique_ptr<RenderResult> get_output(
4453 bool snapshot,
4454 const std::function<
void(
SkCanvas*)>& renderer) {
4458 return std::make_unique<SkRenderResult>(
surface, snapshot);
4459 }
4460
4461 int check_color_result(DlColor dst_color,
4462 DlColor result_color,
4464 const std::string& desc) {
4465 int ret = 0;
4466 bool is_error = false;
4467 if (dst_color.isTransparent() && !result_color.isTransparent()) {
4468 ret |= kWasMTB;
4469 is_error = !dl->modifies_transparent_black();
4470 }
4471 if (result_color != dst_color) {
4472 ret |= kWasNotNop;
4473 is_error = (dl->op_count() == 0u);
4474 }
4475 if (is_error) {
4476 FML_LOG(
ERROR) << std::hex << dst_color <<
" filters to " << result_color
4478 }
4479 return ret;
4480 }
4481
4482 int check_image_result(const std::unique_ptr<RenderResult>& dst_data,
4483 const std::unique_ptr<RenderResult>& result_data,
4485 const std::string& desc) {
4486 EXPECT_EQ(dst_data->width(), result_data->width());
4487 EXPECT_EQ(dst_data->height(), result_data->height());
4489 for (
int y = 0;
y < dst_data->height();
y++) {
4490 const uint32_t* dst_pixels = dst_data->addr32(0,
y);
4491 const uint32_t* result_pixels = result_data->addr32(0,
y);
4492 for (
int x = 0;
x < dst_data->width();
x++) {
4493 all_flags |= check_color_result(DlColor(dst_pixels[
x]),
4494 DlColor(result_pixels[
x]), dl, desc);
4495 }
4496 }
4498 }
4499
4500 void report_results(int all_flags,
4502 const std::string& desc) {
4503 if (!dl->modifies_transparent_black()) {
4505 } else if ((all_flags & kWasMTB) == 0) {
4506 FML_LOG(INFO) <<
"combination does not affect transparency: " <<
desc;
4507 }
4508 if (dl->op_count() == 0u) {
4510 } else if ((all_flags & kWasNotNop) == 0) {
4511 FML_LOG(INFO) <<
"combination could be classified as a nop: " <<
desc;
4512 }
4513 };
4514
4515 void test_mode_color_via_filter(DlBlendMode mode, DlColor
color) {
4516 std::stringstream desc_stream;
4517 desc_stream << " using SkColorFilter::filterColor() with: ";
4519 desc_stream <<
"/" <<
color;
4520 std::string
desc = desc_stream.str();
4521 DisplayListBuilder
builder({0.0f, 0.0f, 100.0f, 100.0f});
4522 DlPaint
paint = DlPaint(
color).setBlendMode(mode);
4525 if (dl->modifies_transparent_black()) {
4526 ASSERT_TRUE(dl->op_count() != 0u);
4527 }
4528
4533 if (sk_color_filter) {
4534 for (DlColor dst_color : test_dst_colors) {
4536 DlColor
result = DlColor(
4537 sk_color_filter->filterColor4f(dst_color_f, srgb.get(), srgb.get())
4538 .toSkColor());
4540 }
4541 if ((all_flags & kWasMTB) != 0) {
4542 EXPECT_FALSE(sk_color_filter->isAlphaUnchanged());
4543 }
4544 }
4545 report_results(all_flags, dl, desc);
4546 };
4547
4548 void test_mode_color_via_rendering(DlBlendMode mode, DlColor
color) {
4549 std::stringstream desc_stream;
4550 desc_stream << " rendering with: ";
4552 desc_stream <<
"/" <<
color;
4553 std::string
desc = desc_stream.str();
4558 DlPaint dl_paint = DlPaint(
color).setBlendMode(mode);
4561 bool dl_is_elided = dl->op_count() == 0u;
4562 bool dl_affects_transparent_pixels = dl->modifies_transparent_black();
4563 ASSERT_TRUE(!dl_is_elided || !dl_affects_transparent_pixels);
4564
4569 for (auto& back_end : CanvasCompareTester::TestBackends) {
4570 auto provider = CanvasCompareTester::GetProvider(back_end);
4571 auto result_surface = provider->MakeOffscreenSurface(
4573 DlSurfaceProvider::kN32PremulPixelFormat);
4574 SkCanvas* result_canvas = result_surface->sk_surface()->getCanvas();
4579 result_surface->sk_surface()->recordingContext())) {
4580 direct_context->flushAndSubmit();
4581 direct_context->flushAndSubmit(result_surface->sk_surface().get(),
4583 }
4584 const std::unique_ptr<RenderResult> result_pixels =
4585 std::make_unique<SkRenderResult>(result_surface->sk_surface());
4586
4587 int all_flags = check_image_result(test_data, result_pixels, dl, desc);
4588 report_results(all_flags, dl, desc);
4589 }
4590 };
4591
4592 void test_attributes_image(DlBlendMode mode,
4595 DlImageFilter* image_filter) {
4596
4597 std::stringstream desc_stream;
4598 desc_stream << " rendering with: ";
4600 desc_stream <<
"/" <<
color;
4603 ? "modifies transparency"
4604 : "preserves transparency"
4605 : "no filter";
4606 desc_stream << ", CF: " << cf_mtb;
4607 std::string if_mtb = image_filter
4608 ? image_filter->modifies_transparent_black()
4609 ? "modifies transparency"
4610 : "preserves transparency"
4611 : "no filter";
4612 desc_stream << ", IF: " << if_mtb;
4613 std::string
desc = desc_stream.str();
4614
4615 DisplayListBuilder
builder({0.0f, 0.0f, 100.0f, 100.0f});
4617 .setBlendMode(mode)
4619 .setImageFilter(image_filter);
4620 builder.DrawImage(DlImage::Make(test_image_src_data->image()), {0, 0},
4621 DlImageSampling::kNearestNeighbor, &
paint);
4623
4624 int w = test_image_src_data->width();
4625 int h = test_image_src_data->height();
4632 for (auto& back_end : CanvasCompareTester::TestBackends) {
4633 auto provider = CanvasCompareTester::GetProvider(back_end);
4634 auto result_surface = provider->MakeOffscreenSurface(
4635 w,
h, DlSurfaceProvider::kN32PremulPixelFormat);
4636 SkCanvas* result_canvas = result_surface->sk_surface()->getCanvas();
4638 result_canvas->
drawImage(test_image_dst_data->image(), 0, 0);
4639 result_canvas->
drawImage(test_image_src_data->image(), 0, 0,
4642 result_surface->sk_surface()->recordingContext())) {
4643 direct_context->flushAndSubmit();
4644 direct_context->flushAndSubmit(result_surface->sk_surface().get(),
4646 }
4647 std::unique_ptr<RenderResult> result_pixels =
4648 std::make_unique<SkRenderResult>(result_surface->sk_surface());
4649
4651 check_image_result(test_image_dst_data, result_pixels, dl, desc);
4652 report_results(all_flags, dl, desc);
4653 }
4654 };
4655};
4656
4657TEST_F(DisplayListNopTest, BlendModeAndColorViaColorFilter) {
4659 for (DlColor
color : test_src_colors) {
4660 test_mode_color_via_filter(mode,
color);
4661 }
4662 };
4663
4664#define TEST_MODE(V) test_mode_filter(DlBlendMode::V);
4666#undef TEST_MODE
4667}
4668
4669TEST_F(DisplayListNopTest, BlendModeAndColorByRendering) {
4671
4672 for (DlColor
color : test_src_colors) {
4673 test_mode_color_via_rendering(mode,
color);
4674 }
4675 };
4676
4677#define TEST_MODE(V) test_mode_render(DlBlendMode::V);
4679#undef TEST_MODE
4680}
4681
4682TEST_F(DisplayListNopTest, BlendModeAndColorAndFiltersByRendering) {
4684 auto image_filter_nomtb = DlColorFilterImageFilter(color_filter_nomtb);
4685 auto image_filter_mtb = DlColorFilterImageFilter(color_filter_mtb);
4686 for (DlColor
color : test_src_colors) {
4687 test_attributes_image(mode,
color,
nullptr,
nullptr);
4688 test_attributes_image(mode,
color, color_filter_nomtb.get(),
nullptr);
4689 test_attributes_image(mode,
color, color_filter_mtb.get(),
nullptr);
4690 test_attributes_image(mode,
color,
nullptr, &image_filter_nomtb);
4691 test_attributes_image(mode,
color,
nullptr, &image_filter_mtb);
4692 }
4693 };
4694
4695#define TEST_MODE(V) test_mode_render(DlBlendMode::V);
4697#undef TEST_MODE
4698}
4699
4700#undef FOR_EACH_BLEND_MODE_ENUM
4701
4702}
4703}
static int step(int x, SkScalar min, SkScalar max)
static void test_bounds(skiatest::Reporter *reporter, SkClipStack::Element::DeviceSpaceType primType)
static GrDirectContext * GrAsDirectContext(GrContext_Base *base)
constexpr SkColor SK_ColorTRANSPARENT
static sk_sp< SkImage > color_filter(const SkImage *image, SkColorFilter *colorFilter)
static void test_image(const sk_sp< SkSpecialImage > &img, skiatest::Reporter *reporter, GrRecordingContext *rContext, bool isGPUBacked)
void drawRect(const SkRect &rect, const SkPaint &paint)
void translate(SkScalar dx, SkScalar dy)
void clear(SkColor color)
void rotate(SkScalar degrees)
void drawImage(const SkImage *image, SkScalar left, SkScalar top)
static sk_sp< SkColorFilter > Blend(const SkColor4f &c, sk_sp< SkColorSpace >, SkBlendMode mode)
static sk_sp< SkColorSpace > MakeSRGB()
void setColor(SkColor color)
void setImageFilter(sk_sp< SkImageFilter > imageFilter)
void setBlendMode(SkBlendMode mode)
void setColorFilter(sk_sp< SkColorFilter > colorFilter)
#define FOR_EACH_BLEND_MODE_ENUM(FUNC)
TEST_F(FlGnomeSettingsTest, ClockFormat)
#define FML_LOG(severity)
SK_API sk_sp< SkSurface > Raster(const SkImageInfo &imageInfo, size_t rowBytes, const SkSurfaceProps *surfaceProps)
static std::string BlendModeToString(DlBlendMode mode)
DisplayListRenderingTestBase<::testing::Test > DisplayListRendering
constexpr SkPoint kTestCenter
SkPaint ToSk(const DlPaint &paint)
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
static SkImageInfo MakeN32Premul(int width, int height)
static SkRGBA4f FromColor(SkColor color)
static constexpr SkRect MakeWH(float w, float h)
static constexpr int kTestHeight
static constexpr int kTestWidth
#define EXPECT_TRUE(handle)