in display_list/display_list_canvas_unittests.cc [897:1278]
static void RenderWithAttributes(const TestParameters& testP,
const RenderEnvironment& env,
const BoundsTolerance& tolerance) {
RenderWith(testP, env, tolerance, CaseParameters("Defaults Test"));
{
// CPU renderer with default line width of 0 does not show antialiasing
// for stroked primitives, so we make a new reference with a non-trivial
// stroke width to demonstrate the differences
RenderEnvironment aa_env = RenderEnvironment::MakeN32();
// Tweak the bounds tolerance for the displacement of 1/10 of a pixel
const BoundsTolerance aa_tolerance = tolerance.addBoundsPadding(1, 1);
CvSetup cv_aa_setup = [=](SkCanvas* cv, SkPaint& p) {
cv->translate(0.1, 0.1);
p.setStrokeWidth(5.0);
};
DlRenderer dl_aa_setup = [=](DisplayListBuilder& b) {
b.translate(0.1, 0.1);
b.setStrokeWidth(5.0);
};
aa_env.init_ref(cv_aa_setup, testP.cv_renderer());
RenderWith(testP, aa_env, aa_tolerance,
CaseParameters(
"AntiAlias == True",
[=](SkCanvas* cv, SkPaint& p) {
cv_aa_setup(cv, p);
p.setAntiAlias(true);
},
[=](DisplayListBuilder& b) {
dl_aa_setup(b);
b.setAntiAlias(true);
}));
RenderWith(testP, aa_env, aa_tolerance,
CaseParameters(
"AntiAlias == False",
[=](SkCanvas* cv, SkPaint& p) {
cv_aa_setup(cv, p);
p.setAntiAlias(false);
},
[=](DisplayListBuilder& b) {
dl_aa_setup(b);
b.setAntiAlias(false);
}));
}
{
// The CPU renderer does not always dither for solid colors and we
// need to use a non-default color (default is black) on an opaque
// surface, so we use a shader instead of a color. Also, thin stroked
// primitives (mainly drawLine and drawPoints) do not show much
// dithering so we use a non-trivial stroke width as well.
RenderEnvironment dither_env = RenderEnvironment::Make565();
SkColor dither_bg = SK_ColorBLACK;
CvSetup cv_dither_setup = [=](SkCanvas*, SkPaint& p) {
p.setShader(testImageShader);
p.setAlpha(0xf0);
p.setStrokeWidth(5.0);
};
DlRenderer dl_dither_setup = [=](DisplayListBuilder& b) {
b.setShader(testImageShader);
b.setColor(SkColor(0xf0000000));
b.setStrokeWidth(5.0);
};
dither_env.init_ref(cv_dither_setup, testP.cv_renderer(), dither_bg);
RenderWith(testP, dither_env, tolerance,
CaseParameters(
"Dither == True",
[=](SkCanvas* cv, SkPaint& p) {
cv_dither_setup(cv, p);
p.setDither(true);
},
[=](DisplayListBuilder& b) {
dl_dither_setup(b);
b.setDither(true);
})
.with_bg(dither_bg));
RenderWith(testP, dither_env, tolerance,
CaseParameters(
"Dither = False",
[=](SkCanvas* cv, SkPaint& p) {
cv_dither_setup(cv, p);
p.setDither(false);
},
[=](DisplayListBuilder& b) {
dl_dither_setup(b);
b.setDither(false);
})
.with_bg(dither_bg));
}
EXPECT_TRUE(testImageShader->unique()) << "Dither Cleanup";
RenderWith(testP, env, tolerance,
CaseParameters(
"Color == Blue",
[=](SkCanvas*, SkPaint& p) { p.setColor(SK_ColorBLUE); },
[=](DisplayListBuilder& b) { b.setColor(SK_ColorBLUE); }));
RenderWith(testP, env, tolerance,
CaseParameters(
"Color == Green",
[=](SkCanvas*, SkPaint& p) { p.setColor(SK_ColorGREEN); },
[=](DisplayListBuilder& b) { b.setColor(SK_ColorGREEN); }));
RenderWithStrokes(testP, env, tolerance);
{
// half opaque cyan
SkColor blendableColor = SkColorSetARGB(0x7f, 0x00, 0xff, 0xff);
SkColor bg = SK_ColorWHITE;
RenderWith(testP, env, tolerance,
CaseParameters(
"Blend == SrcIn",
[=](SkCanvas*, SkPaint& p) {
p.setBlendMode(SkBlendMode::kSrcIn);
p.setColor(blendableColor);
},
[=](DisplayListBuilder& b) {
b.setBlendMode(SkBlendMode::kSrcIn);
b.setColor(blendableColor);
})
.with_bg(bg));
RenderWith(testP, env, tolerance,
CaseParameters(
"Blend == DstIn",
[=](SkCanvas*, SkPaint& p) {
p.setBlendMode(SkBlendMode::kDstIn);
p.setColor(blendableColor);
},
[=](DisplayListBuilder& b) {
b.setBlendMode(SkBlendMode::kDstIn);
b.setColor(blendableColor);
})
.with_bg(bg));
}
if (!(testP.is_draw_atlas() || testP.is_draw_vertices())) {
sk_sp<SkBlender> blender =
SkBlenders::Arithmetic(0.25, 0.25, 0.25, 0.25, false);
{
RenderWith(testP, env, tolerance,
CaseParameters(
"Blender == Arithmetic 0.25-false",
[=](SkCanvas*, SkPaint& p) { p.setBlender(blender); },
[=](DisplayListBuilder& b) { b.setBlender(blender); }));
}
EXPECT_TRUE(blender->unique()) << "Blender Cleanup";
blender = SkBlenders::Arithmetic(0.25, 0.25, 0.25, 0.25, true);
{
RenderWith(testP, env, tolerance,
CaseParameters(
"Blender == Arithmetic 0.25-true",
[=](SkCanvas*, SkPaint& p) { p.setBlender(blender); },
[=](DisplayListBuilder& b) { b.setBlender(blender); }));
}
EXPECT_TRUE(blender->unique()) << "Blender Cleanup";
}
{
// Being able to see a blur requires some non-default attributes,
// like a non-trivial stroke width and a shader rather than a color
// (for drawPaint) so we create a new environment for these tests.
RenderEnvironment blur_env = RenderEnvironment::MakeN32();
CvSetup cv_blur_setup = [=](SkCanvas*, SkPaint& p) {
p.setShader(testImageShader);
p.setStrokeWidth(5.0);
};
DlRenderer dl_blur_setup = [=](DisplayListBuilder& b) {
b.setShader(testImageShader);
b.setStrokeWidth(5.0);
};
blur_env.init_ref(cv_blur_setup, testP.cv_renderer());
sk_sp<SkImageFilter> filter =
SkImageFilters::Blur(5.0, 5.0, SkTileMode::kDecal, nullptr, nullptr);
BoundsTolerance blur5Tolerance = tolerance.addBoundsPadding(4, 4);
{
RenderWith(testP, blur_env, blur5Tolerance,
CaseParameters(
"ImageFilter == Decal Blur 5",
[=](SkCanvas* cv, SkPaint& p) {
cv_blur_setup(cv, p);
p.setImageFilter(filter);
},
[=](DisplayListBuilder& b) {
dl_blur_setup(b);
b.setImageFilter(filter);
}));
}
EXPECT_TRUE(filter->unique()) << "ImageFilter Cleanup";
filter =
SkImageFilters::Blur(5.0, 5.0, SkTileMode::kClamp, nullptr, nullptr);
{
RenderWith(testP, blur_env, blur5Tolerance,
CaseParameters(
"ImageFilter == Clamp Blur 5",
[=](SkCanvas* cv, SkPaint& p) {
cv_blur_setup(cv, p);
p.setImageFilter(filter);
},
[=](DisplayListBuilder& b) {
dl_blur_setup(b);
b.setImageFilter(filter);
}));
}
EXPECT_TRUE(filter->unique()) << "ImageFilter Cleanup";
}
{
// clang-format off
constexpr float rotate_color_matrix[20] = {
0, 1, 0, 0, 0,
0, 0, 1, 0, 0,
1, 0, 0, 0, 0,
0, 0, 0, 1, 0,
};
constexpr float invert_color_matrix[20] = {
-1.0, 0, 0, 1.0, 0,
0, -1.0, 0, 1.0, 0,
0, 0, -1.0, 1.0, 0,
1.0, 1.0, 1.0, 1.0, 0,
};
// clang-format on
sk_sp<SkColorFilter> filter = SkColorFilters::Matrix(rotate_color_matrix);
{
SkColor bg = SK_ColorWHITE;
RenderWith(testP, env, tolerance,
CaseParameters(
"ColorFilter == RotateRGB",
[=](SkCanvas*, SkPaint& p) {
p.setColor(SK_ColorYELLOW);
p.setColorFilter(filter);
},
[=](DisplayListBuilder& b) {
b.setColor(SK_ColorYELLOW);
b.setColorFilter(filter);
})
.with_bg(bg));
}
EXPECT_TRUE(filter->unique()) << "ColorFilter == RotateRGB Cleanup";
filter = SkColorFilters::Matrix(invert_color_matrix);
{
SkColor bg = SK_ColorWHITE;
RenderWith(testP, env, tolerance,
CaseParameters(
"ColorFilter == Invert",
[=](SkCanvas*, SkPaint& p) {
p.setColor(SK_ColorYELLOW);
p.setColorFilter(filter);
},
[=](DisplayListBuilder& b) {
b.setColor(SK_ColorYELLOW);
b.setInvertColors(true);
})
.with_bg(bg));
}
EXPECT_TRUE(filter->unique()) << "ColorFilter == Invert Cleanup";
}
{
sk_sp<SkPathEffect> effect = SkDiscretePathEffect::Make(3, 5);
{
// Discrete path effects need a stroke width for drawPointsAsPoints
// to do something realistic
// And a Discrete(3, 5) effect produces miters that are near
// maximal for a miter limit of 3.0.
BoundsTolerance discrete_tolerance =
tolerance
// register the discrete offset so adjusters can compensate
.addDiscreteOffset(5)
// the miters in the 3-5 discrete effect don't always fill
// their conservative bounds, so tolerate a couple of pixels
.addBoundsPadding(2, 2);
RenderWith(testP, env, discrete_tolerance,
CaseParameters(
"PathEffect == Discrete-3-5",
[=](SkCanvas*, SkPaint& p) {
p.setStrokeWidth(5.0);
p.setStrokeMiter(3.0);
p.setPathEffect(effect);
},
[=](DisplayListBuilder& b) {
b.setStrokeWidth(5.0);
b.setStrokeMiter(3.0);
b.setPathEffect(effect);
}));
}
EXPECT_TRUE(testP.is_draw_text_blob() || effect->unique())
<< "PathEffect == Discrete-3-5 Cleanup";
effect = SkDiscretePathEffect::Make(2, 3);
{
// Discrete path effects need a stroke width for drawPointsAsPoints
// to do something realistic
// And a Discrete(2, 3) effect produces miters that are near
// maximal for a miter limit of 2.5.
BoundsTolerance discrete_tolerance =
tolerance
// register the discrete offset so adjusters can compensate
.addDiscreteOffset(3)
// the miters in the 3-5 discrete effect don't always fill
// their conservative bounds, so tolerate a couple of pixels
.addBoundsPadding(2, 2);
RenderWith(testP, env, discrete_tolerance,
CaseParameters(
"PathEffect == Discrete-2-3",
[=](SkCanvas*, SkPaint& p) {
p.setStrokeWidth(5.0);
p.setStrokeMiter(2.5);
p.setPathEffect(effect);
},
[=](DisplayListBuilder& b) {
b.setStrokeWidth(5.0);
b.setStrokeMiter(2.5);
b.setPathEffect(effect);
}));
}
EXPECT_TRUE(testP.is_draw_text_blob() || effect->unique())
<< "PathEffect == Discrete-2-3 Cleanup";
}
{
sk_sp<SkMaskFilter> filter =
SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, 5.0);
BoundsTolerance blur5Tolerance = tolerance.addBoundsPadding(4, 4);
{
// Stroked primitives need some non-trivial stroke size to be blurred
RenderWith(testP, env, blur5Tolerance,
CaseParameters(
"MaskFilter == Blur 5",
[=](SkCanvas*, SkPaint& p) {
p.setStrokeWidth(5.0);
p.setMaskFilter(filter);
},
[=](DisplayListBuilder& b) {
b.setStrokeWidth(5.0);
b.setMaskFilter(filter);
}));
}
EXPECT_TRUE(testP.is_draw_text_blob() || filter->unique())
<< "MaskFilter == Blur 5 Cleanup";
{
RenderWith(testP, env, blur5Tolerance,
CaseParameters(
"MaskFilter == Blur(Normal, 5.0)",
[=](SkCanvas*, SkPaint& p) {
p.setStrokeWidth(5.0);
p.setMaskFilter(filter);
},
[=](DisplayListBuilder& b) {
b.setStrokeWidth(5.0);
b.setMaskBlurFilter(kNormal_SkBlurStyle, 5.0);
}));
}
EXPECT_TRUE(testP.is_draw_text_blob() || filter->unique())
<< "MaskFilter == Blur(Normal, 5.0) Cleanup";
}
{
SkPoint end_points[] = {
SkPoint::Make(RenderBounds.fLeft, RenderBounds.fTop),
SkPoint::Make(RenderBounds.fRight, RenderBounds.fBottom),
};
SkColor colors[] = {
SK_ColorGREEN,
SkColorSetA(SK_ColorYELLOW, 0x7f),
SK_ColorBLUE,
};
float stops[] = {
0.0,
0.5,
1.0,
};
sk_sp<SkShader> shader = SkGradientShader::MakeLinear(
end_points, colors, stops, 3, SkTileMode::kMirror, 0, nullptr);
{
RenderWith(testP, env, tolerance,
CaseParameters(
"LinearGradient GYB",
[=](SkCanvas*, SkPaint& p) { p.setShader(shader); },
[=](DisplayListBuilder& b) { b.setShader(shader); }));
}
EXPECT_TRUE(shader->unique()) << "LinearGradient GYB Cleanup";
}
}