26#ifdef IMPELLER_SUPPORTS_RENDERING
31#include "third_party/skia/include/core/SkBBHFactory.h"
32#include "third_party/skia/include/core/SkColorFilter.h"
33#include "third_party/skia/include/core/SkColorSpace.h"
34#include "third_party/skia/include/core/SkFontMgr.h"
35#include "third_party/skia/include/core/SkPictureRecorder.h"
36#include "third_party/skia/include/core/SkStream.h"
37#include "third_party/skia/include/core/SkSurface.h"
38#include "third_party/skia/include/core/SkTypeface.h"
39#include "third_party/skia/include/effects/SkDashPathEffect.h"
40#include "third_party/skia/include/effects/SkGradientShader.h"
41#include "third_party/skia/include/effects/SkImageFilters.h"
42#include "third_party/skia/include/encode/SkPngEncoder.h"
43#include "third_party/skia/include/gpu/ganesh/GrDirectContext.h"
44#include "third_party/skia/include/gpu/ganesh/GrRecordingContext.h"
45#include "third_party/skia/include/gpu/ganesh/GrTypes.h"
161constexpr uint8_t toC(
DlScalar fComp) {
162 return round(fComp * 255);
165constexpr uint32_t PremultipliedArgb(
const DlColor& color) {
170 return (color.
argb() & 0xFF000000) |
171 toC(color.
getRedF() * f) << 16 |
180 SkSamplingOptions(SkFilterMode::kNearest);
182 SkSamplingOptions(SkFilterMode::kLinear);
184 SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear);
185 static constexpr SkSamplingOptions
kCubic =
186 SkSamplingOptions(SkCubicResampler{1 / 3.0f, 1 / 3.0f});
200 for (
int y = 0;
y <
width;
y += cbdim) {
201 for (
int x = 0;
x <
height;
x += cbdim) {
202 DlPaint& cellp = ((
x +
y) & 1) == 0 ? p0 : p1;
214 const sk_sp<DlImage>&
image) {
215 return std::make_shared<DlImageColorSource>(
image,
222 return image->makeShader(SkTileMode::kRepeat,
232 : warning_(warning) {}
235 if (warnings_sent_.find(
name) == warnings_sent_.end()) {
236 warnings_sent_.insert(
name);
242 std::string warning_;
243 std::set<std::string> warnings_sent_;
270 copy.bounds_pad_ +=
DlPoint(bounds_pad_x, bounds_pad_y);
276 copy.scale_ *=
DlPoint(scale_x, scale_y);
283 copy.absolute_pad_ +=
DlPoint(absolute_pad_x, absolute_pad_y);
290 copy.clip_pad_ +=
DlPoint(absolute_pad_x, absolute_pad_y);
309 return rect.
Expand(outset_x, outset_y);
313 int worst_bounds_pad_x,
314 int worst_bounds_pad_y)
const {
316 allowed = allowed.
Expand(bounds_pad_.
x, bounds_pad_.
y);
317 allowed =
Scale(allowed, scale_);
318 allowed = allowed.
Expand(absolute_pad_.
x, absolute_pad_.
y);
320 allowed = allowed.
Expand(clip_pad_.
x, clip_pad_.
y);
322 int pad_left = std::max(0, pix_bounds.
GetLeft() - rounded.
GetLeft());
323 int pad_top = std::max(0, pix_bounds.
GetTop() - rounded.
GetTop());
326 int allowed_pad_x = std::max(pad_left, pad_right);
327 int allowed_pad_y = std::max(pad_top, pad_bottom);
328 if (worst_bounds_pad_x > allowed_pad_x ||
329 worst_bounds_pad_y > allowed_pad_y) {
330 FML_LOG(ERROR) <<
"acceptable bounds padding: "
331 << allowed_pad_x <<
", " << allowed_pad_y;
333 return (worst_bounds_pad_x > allowed_pad_x ||
334 worst_bounds_pad_y > allowed_pad_y);
340 return bounds_pad_ == other.bounds_pad_ && scale_ == other.scale_ &&
341 absolute_pad_ == other.absolute_pad_ && clip_ == other.clip_ &&
342 clip_pad_ == other.clip_pad_ &&
343 discrete_offset_ == other.discrete_offset_;
349 DlPoint absolute_pad_ = {0, 0};
356template <
typename C,
typename P,
typename I>
385 virtual sk_sp<SkImage>
image()
const = 0;
388 virtual const uint32_t*
addr32(
int x,
int y)
const = 0;
395 bool take_snapshot =
false) {
396 SkImageInfo info =
surface->imageInfo();
397 info = SkImageInfo::MakeN32Premul(info.dimensions());
398 addr_ = malloc(info.computeMinByteSize() * info.height());
399 pixmap_.reset(info, addr_, info.minRowBytes());
400 surface->readPixels(pixmap_, 0, 0);
402 image_ =
surface->makeImageSnapshot();
407 sk_sp<SkImage>
image()
const override {
return image_; }
408 int width()
const override {
return pixmap_.width(); }
409 int height()
const override {
return pixmap_.height(); }
410 const uint32_t*
addr32(
int x,
int y)
const override {
411 return pixmap_.addr32(
x,
y);
414 auto stream = SkFILEWStream(
path.c_str());
415 SkPngEncoder::Options options;
416 SkPngEncoder::Encode(&stream, pixmap_, options);
421 sk_sp<SkImage> image_;
423 void* addr_ =
nullptr;
433 sk_sp<SkImage>
image()
const override {
return nullptr; };
434 int width()
const override {
return screenshot_->width(); };
435 int height()
const override {
return screenshot_->height(); }
436 const uint32_t*
addr32(
int x,
int y)
const override {
437 return screenshot_->addr32(
x,
y);
440 screenshot_->write(
path);
445 const sk_sp<DlPixelData> screenshot_;
484 const sk_sp<SkImage>& sk_image)
485 : sk_setup_(sk_setup),
486 sk_render_(sk_render),
487 sk_restore_(sk_restore),
488 sk_image_(sk_image) {}
493 sk_setup_({canvas, paint, sk_image_});
494 setup_paint_ = paint;
498 sk_render_({canvas, paint, sk_image_});
499 sk_restore_({canvas, paint, sk_image_});
503 SkPictureRecorder recorder;
504 SkRTreeFactory rtree_factory;
508 return recorder.finishRecordingAsPicture();
520 sk_sp<SkImage> sk_image_;
521 SkPaint setup_paint_;
528 const sk_sp<DlImage>& dl_image)
529 : dl_setup_(dl_setup),
530 dl_render_(dl_render),
531 dl_restore_(dl_restore),
532 dl_image_(dl_image) {}
542 dl_setup_({canvas, paint, dl_image_});
543 setup_paint_ = paint;
548 dl_render_({canvas, paint, dl_image_});
549 dl_restore_({canvas, paint, dl_image_});
555 return builder.
Build();
564 return dl_image_->impeller_texture() !=
nullptr;
571 const sk_sp<DlImage> dl_image_;
577 : picture_(
std::move(picture)) {}
581 picture_->playback(canvas);
585 sk_sp<SkPicture> picture_;
590 : display_list_(
std::move(display_list)) {}
597 sk_sp<DisplayList> display_list_;
632 ref_sk_result_ =
getResult(info, sk_job);
634 ref_dl_result_ =
getResult(info, dl_job);
641 test_impeller_image_ = makeTestImpellerImage(provider_);
643 test_impeller_image_);
652 auto canvas =
surface->getCanvas();
655 int restore_count = canvas->save();
657 renderer.
Render(canvas, info);
658 canvas->restoreToCount(restore_count);
660 if (GrDirectContext* dContext =
661 GrAsDirectContext(
surface->recordingContext())) {
662 dContext->flushAndSubmit(
surface.get(), GrSyncCpu::kYes);
664 return std::make_unique<SkRenderResult>(
surface);
667 std::unique_ptr<RenderResult>
getResult(sk_sp<DisplayList> dl)
const {
682 auto dl = builder.
Build();
684 return std::make_unique<ImpellerRenderResult>(std::move(snap),
685 render_dl->GetBounds());
702 return ref_impeller_result_.get();
705 const sk_sp<SkImage>
sk_image()
const {
return kTestSkImage; }
706 const sk_sp<DlImage>
dl_image()
const {
return kTestDlImage; }
710 sk_sp<SkSurface> getSurface(
int width,
int height)
const {
715 return surface_1x_->sk_surface();
718 return surface_2x_->sk_surface();
721 <<
") not supported.";
726 const DlSurfaceProvider* provider_;
728 std::shared_ptr<DlSurfaceInstance> surface_1x_;
729 std::shared_ptr<DlSurfaceInstance> surface_2x_;
734 std::unique_ptr<RenderResult> ref_sk_result_;
735 std::unique_ptr<RenderResult> ref_dl_result_;
736 std::unique_ptr<ImpellerRenderResult> ref_impeller_result_;
737 sk_sp<DlImage> test_impeller_image_;
739 static const sk_sp<SkImage> kTestSkImage;
740 static const sk_sp<DlImage> kTestDlImage;
741 static const sk_sp<SkImage> makeTestSkImage() {
742 sk_sp<SkSurface>
surface = SkSurfaces::Raster(
745 return surface->makeImageSnapshot();
747 static const sk_sp<DlImage> makeTestImpellerImage(
748 const DlSurfaceProvider*
provider) {
757const sk_sp<SkImage> RenderEnvironment::kTestSkImage = makeTestSkImage();
758const sk_sp<DlImage> RenderEnvironment::kTestDlImage =
801 bg_, has_diff_clip_, mutating_layer,
806 return CaseParameters(info_, sk_setup_, dl_setup_, sk_restore_, dl_restore_,
807 bg, has_diff_clip_, has_mutating_save_layer_,
808 fuzzy_compare_components_);
812 return CaseParameters(info_, sk_setup_, dl_setup_, sk_restore_, dl_restore_,
813 bg_,
true, has_mutating_save_layer_,
814 fuzzy_compare_components_);
817 std::string
info()
const {
return info_; }
829 const std::string info_;
835 const bool has_diff_clip_;
836 const bool has_mutating_save_layer_;
837 const bool fuzzy_compare_components_;
939 getCap(ref_attr, geo_flags) !=
getCap(attr, geo_flags)) {
951 ref_miter < 1.4 || test_miter < 1.4) {
952 if (ref_miter != test_miter) {
1034 h_tolerance = v_tolerance =
adjust;
1038 return new_tolerance;
1059 is_draw_text_blob_ =
true;
1063 is_draw_display_list_ =
true;
1067 is_draw_line_ =
true;
1071 is_draw_arc_center_ =
true;
1075 is_draw_path_ =
true;
1079 ignores_dashes_ =
true;
1083 is_horizontal_line_ =
true;
1087 is_vertical_line_ =
true;
1097 bool is_draw_text_blob_ =
false;
1098 bool is_draw_display_list_ =
false;
1099 bool is_draw_line_ =
false;
1100 bool is_draw_arc_center_ =
false;
1101 bool is_draw_path_ =
false;
1102 bool ignores_dashes_ =
false;
1103 bool is_horizontal_line_ =
false;
1104 bool is_vertical_line_ =
false;
1117 if (provider ==
nullptr) {
1119 <<
" not supported (ignoring)";
1123 PixelFormat::kN32PremulPixelFormat);
1134 if (provider->supports_impeller()) {
1153 if (!
checkPixels(impeller_result, impeller_result->render_bounds(),
1154 "Impeller reference")) {
1155 std::string test_name =
1156 ::testing::UnitTest::GetInstance()->current_test_info()->name();
1157 save_to_png(impeller_result, test_name +
" (Impeller reference)",
1158 "base rendering was blank or out of bounds");
1169 if (
params.uses_paint()) {
1186 ctx.canvas->restore();
1195 ctx.canvas->DrawRect(
1198 ctx.canvas->Restore();
1202 ctx.canvas->restore();
1206 ctx.canvas->Restore();
1211 "With prior save/clip/restore",
1214 ctx.canvas->clipRect(
ToSkRect(clip), SkClipOp::kIntersect,
1217 ctx.canvas->drawRect(
ToSkRect(rect), p2);
1218 p2.setBlendMode(SkBlendMode::kClear);
1219 ctx.canvas->drawRect(
ToSkRect(rect), p2);
1220 ctx.canvas->restore();
1226 ctx.canvas->DrawRect(rect, p2);
1228 ctx.canvas->DrawRect(rect, p2);
1229 ctx.canvas->Restore();
1233 "saveLayer no paint, no bounds",
1235 ctx.canvas->saveLayer(
nullptr,
nullptr);
1238 ctx.canvas->SaveLayer(std::nullopt,
nullptr);
1240 .with_restore(sk_safe_restore, dl_safe_restore,
false));
1243 "saveLayer no paint, with bounds",
1245 ctx.canvas->saveLayer(
ToSkRect(layer_bounds),
nullptr);
1248 ctx.canvas->SaveLayer(layer_bounds,
nullptr);
1250 .with_restore(sk_safe_restore, dl_safe_restore,
true));
1253 "saveLayer with alpha, no bounds",
1257 ctx.canvas->saveLayer(
nullptr, &save_p);
1261 save_p.
setColor(alpha_layer_color);
1262 ctx.canvas->SaveLayer(std::nullopt, &save_p);
1264 .with_restore(sk_safe_restore, dl_safe_restore,
true));
1267 "saveLayer with peephole alpha, no bounds",
1271 ctx.canvas->saveLayer(
nullptr, &save_p);
1275 save_p.
setColor(alpha_layer_color);
1276 ctx.canvas->SaveLayer(std::nullopt, &save_p);
1278 .with_restore(sk_opt_restore, dl_opt_restore,
true,
true));
1281 "saveLayer with alpha and bounds",
1285 ctx.canvas->saveLayer(
ToSkRect(layer_bounds), &save_p);
1289 save_p.
setColor(alpha_layer_color);
1290 ctx.canvas->SaveLayer(layer_bounds, &save_p);
1292 .with_restore(sk_safe_restore, dl_safe_restore,
true));
1306 ctx.canvas->drawPaint(setup_p);
1311 ctx.canvas->DrawPaint(setup_p);
1314 ctx.paint.
setAlpha(ctx.paint.getAlpha() / 2);
1317 ctx.paint.
setAlpha(ctx.paint.getAlpha() / 2);
1326 SkImageFilters::Blur(5, 5, SkTileMode::kDecal,
nullptr);
1328 testP, backdrop_env, tolerance,
1330 "saveLayer with backdrop",
1332 sk_backdrop_setup(ctx);
1333 ctx.canvas->saveLayer(
1334 SkCanvas::SaveLayerRec(
nullptr,
nullptr, sk_backdrop.get(),
1335 SkTileMode::kDecal,
nullptr, 0));
1336 sk_content_setup(ctx);
1339 dl_backdrop_setup(ctx);
1340 ctx.canvas->SaveLayer(std::nullopt,
nullptr, &dl_backdrop);
1341 dl_content_setup(ctx);
1343 .with_restore(sk_safe_restore, dl_safe_restore,
true));
1346 "saveLayer with bounds and backdrop",
1348 sk_backdrop_setup(ctx);
1349 ctx.canvas->saveLayer(SkCanvas::SaveLayerRec(
1350 &
ToSkRect(layer_bounds),
nullptr, sk_backdrop.get(),
1351 SkTileMode::kDecal,
nullptr, 0));
1352 sk_content_setup(ctx);
1355 dl_backdrop_setup(ctx);
1356 ctx.canvas->SaveLayer(layer_bounds,
nullptr,
1358 dl_content_setup(ctx);
1360 .with_restore(sk_safe_restore, dl_safe_restore,
true));
1362 testP, backdrop_env, tolerance,
1364 "clipped saveLayer with backdrop",
1366 sk_backdrop_setup(ctx);
1367 ctx.canvas->clipRect(
ToSkRect(layer_bounds));
1368 ctx.canvas->saveLayer(
1369 SkCanvas::SaveLayerRec(
nullptr,
nullptr, sk_backdrop.get(),
1370 SkTileMode::kDecal,
nullptr, 0));
1371 sk_content_setup(ctx);
1374 dl_backdrop_setup(ctx);
1375 ctx.canvas->ClipRect(layer_bounds);
1376 ctx.canvas->SaveLayer(std::nullopt,
nullptr, &dl_backdrop);
1377 dl_content_setup(ctx);
1379 .with_restore(sk_safe_restore, dl_safe_restore,
true));
1384 constexpr float rotate_alpha_color_matrix[20] = {
1391 auto dl_alpha_rotate_filter =
1393 auto sk_alpha_rotate_filter =
1394 SkColorFilters::Matrix(rotate_alpha_color_matrix);
1398 "saveLayer ColorFilter, no bounds",
1401 save_p.setColorFilter(sk_alpha_rotate_filter);
1402 ctx.canvas->saveLayer(
nullptr, &save_p);
1403 ctx.paint.setStrokeWidth(5.0);
1408 ctx.canvas->SaveLayer(std::nullopt, &save_p);
1411 .with_restore(sk_safe_restore, dl_safe_restore,
true));
1416 "saveLayer ColorFilter and bounds",
1419 save_p.setColorFilter(sk_alpha_rotate_filter);
1422 ctx.paint.setStrokeWidth(5.0);
1430 .with_restore(sk_safe_restore, dl_safe_restore,
true));
1436 constexpr float color_matrix[20] = {
1445 auto sk_cf_image_filter = SkImageFilters::ColorFilter(
1446 SkColorFilters::Matrix(color_matrix),
nullptr);
1450 "saveLayer ImageFilter, no bounds",
1453 save_p.setImageFilter(sk_cf_image_filter);
1454 ctx.canvas->saveLayer(
nullptr, &save_p);
1455 ctx.paint.setStrokeWidth(5.0);
1460 ctx.canvas->SaveLayer(std::nullopt, &save_p);
1463 .with_restore(sk_safe_restore, dl_safe_restore,
true));
1468 "saveLayer ImageFilter and bounds",
1471 save_p.setImageFilter(sk_cf_image_filter);
1474 ctx.paint.setStrokeWidth(5.0);
1482 .with_restore(sk_safe_restore, dl_safe_restore,
true));
1500 ctx.canvas->translate(0.1, 0.1);
1501 ctx.paint.setAntiAlias(is_aa);
1502 ctx.paint.setStrokeWidth(5.0);
1505 ctx.canvas->Translate(0.1, 0.1);
1506 ctx.paint.setAntiAlias(is_aa);
1507 ctx.paint.setStrokeWidth(5.0);
1516 testP, aa_env, aa_tolerance,
1518 "AntiAlias == True",
1522 testP, aa_env, aa_tolerance,
1524 "AntiAlias == False",
1530 testP, env, tolerance,
1534 ctx.paint.setColor(SK_ColorBLUE);
1540 testP, env, tolerance,
1544 ctx.paint.setColor(SK_ColorGREEN);
1561 ctx.paint.setBlendMode(SkBlendMode::kSrcIn);
1562 ctx.paint.setColor(blendable_color.
argb());
1565 ctx.paint.setBlendMode(DlBlendMode::kSrcIn);
1566 ctx.paint.setColor(blendable_color);
1573 ctx.paint.setBlendMode(SkBlendMode::kDstIn);
1574 ctx.paint.setColor(blendable_color.
argb());
1577 ctx.paint.setBlendMode(DlBlendMode::kDstIn);
1578 ctx.paint.setColor(blendable_color);
1590 ctx.paint.setStrokeWidth(5.0);
1594 ctx.paint.setStrokeWidth(5.0);
1601 auto sk_filter_decal_5 =
1602 SkImageFilters::Blur(5.0, 5.0, SkTileMode::kDecal,
nullptr);
1605 RenderWith(testP, blur_env, blur_5_tolerance,
1607 "ImageFilter == Decal Blur 5",
1610 ctx.paint.setImageFilter(sk_filter_decal_5);
1614 ctx.paint.setImageFilter(&dl_filter_decal_5);
1618 auto sk_filter_clamp_5 =
1619 SkImageFilters::Blur(5.0, 5.0, SkTileMode::kClamp,
nullptr);
1621 RenderWith(testP, blur_env, blur_5_tolerance,
1623 "ImageFilter == Clamp Blur 5",
1626 ctx.paint.setImageFilter(sk_filter_clamp_5);
1630 ctx.paint.setImageFilter(&dl_filter_clamp_5);
1642 ctx.paint.setStrokeWidth(5.0);
1646 ctx.paint.setStrokeWidth(5.0);
1653 auto sk_dilate_filter_5 = SkImageFilters::Dilate(5.0, 5.0,
nullptr);
1656 "ImageFilter == Dilate 5",
1658 sk_dilate_setup(ctx);
1659 ctx.paint.setImageFilter(sk_dilate_filter_5);
1662 dl_dilate_setup(ctx);
1663 ctx.paint.setImageFilter(&dl_dilate_filter_5);
1674 ctx.paint.setStrokeWidth(6.0);
1678 ctx.paint.setStrokeWidth(6.0);
1687 auto sk_erode_filter_1 = SkImageFilters::Erode(1.0, 1.0,
nullptr);
1690 "ImageFilter == Erode 1",
1692 sk_erode_setup(ctx);
1693 ctx.paint.setImageFilter(sk_erode_filter_1);
1696 dl_erode_setup(ctx);
1697 ctx.paint.setImageFilter(&dl_erode_filter_1);
1703 constexpr float rotate_color_matrix[20] = {
1709 constexpr float invert_color_matrix[20] = {
1713 1.0, 1.0, 1.0, 1.0, 0,
1717 auto sk_color_filter = SkColorFilters::Matrix(rotate_color_matrix);
1722 "ColorFilter == RotateRGB",
1724 ctx.paint.setColor(SK_ColorYELLOW);
1725 ctx.paint.setColorFilter(sk_color_filter);
1729 ctx.paint.setColorFilter(dl_color_filter);
1737 "ColorFilter == Invert",
1739 ctx.paint.setColor(SK_ColorYELLOW);
1740 ctx.paint.setColorFilter(
1741 SkColorFilters::Matrix(invert_color_matrix));
1745 ctx.paint.setInvertColors(
true);
1753 auto sk_mask_filter = SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, 5.0);
1759 "MaskFilter == Blur 5",
1761 ctx.paint.setStrokeWidth(5.0);
1762 ctx.paint.setMaskFilter(sk_mask_filter);
1765 ctx.paint.setStrokeWidth(5.0);
1766 ctx.paint.setMaskFilter(&dl_mask_filter);
1781 SkColor sk_colors[] = {
1783 SkColorSetA(SK_ColorYELLOW, 0x7f),
1794 auto sk_gradient = SkGradientShader::MakeLinear(
1795 ToSkPoints(dl_end_points), sk_colors, stops, 3, SkTileMode::kMirror,
1800 "LinearGradient GYB",
1802 ctx.paint.setShader(sk_gradient);
1806 ctx.paint.setColorSource(dl_gradient);
1824 ctx.paint.setStyle(SkPaint::kFill_Style);
1840 "Stroke + defaults",
1843 ctx.paint.setStrokeWidth(1.0);
1845 ctx.paint.setStyle(SkPaint::kStroke_Style);
1849 ctx.paint.setStrokeWidth(1.0);
1856 "Fill + unnecessary StrokeWidth 10",
1858 ctx.paint.setStyle(SkPaint::kFill_Style);
1859 ctx.paint.setStrokeWidth(10.0);
1863 ctx.paint.setStrokeWidth(10.0);
1869 ctx.paint.setStyle(SkPaint::kStroke_Style);
1870 ctx.paint.setStrokeWidth(5.0);
1874 ctx.paint.setStrokeWidth(5.0);
1881 RenderWith(testP, stroke_base_env, tolerance,
1885 ctx.paint.setStyle(SkPaint::kStroke_Style);
1886 ctx.paint.setStrokeWidth(10.0);
1890 ctx.paint.setStrokeWidth(10.0);
1892 RenderWith(testP, stroke_base_env, tolerance,
1896 ctx.paint.setStyle(SkPaint::kStroke_Style);
1897 ctx.paint.setStrokeWidth(5.0);
1901 ctx.paint.setStrokeWidth(5.0);
1904 RenderWith(testP, stroke_base_env, tolerance,
1906 "Stroke Width 5, Square Cap",
1908 ctx.paint.setStyle(SkPaint::kStroke_Style);
1909 ctx.paint.setStrokeWidth(5.0);
1910 ctx.paint.setStrokeCap(SkPaint::kSquare_Cap);
1914 ctx.paint.setStrokeWidth(5.0);
1917 RenderWith(testP, stroke_base_env, tolerance,
1919 "Stroke Width 5, Round Cap",
1921 ctx.paint.setStyle(SkPaint::kStroke_Style);
1922 ctx.paint.setStrokeWidth(5.0);
1923 ctx.paint.setStrokeCap(SkPaint::kRound_Cap);
1927 ctx.paint.setStrokeWidth(5.0);
1931 RenderWith(testP, stroke_base_env, tolerance,
1933 "Stroke Width 5, Bevel Join",
1935 ctx.paint.setStyle(SkPaint::kStroke_Style);
1936 ctx.paint.setStrokeWidth(5.0);
1937 ctx.paint.setStrokeJoin(SkPaint::kBevel_Join);
1941 ctx.paint.setStrokeWidth(5.0);
1944 RenderWith(testP, stroke_base_env, tolerance,
1946 "Stroke Width 5, Round Join",
1948 ctx.paint.setStyle(SkPaint::kStroke_Style);
1949 ctx.paint.setStrokeWidth(5.0);
1950 ctx.paint.setStrokeJoin(SkPaint::kRound_Join);
1954 ctx.paint.setStrokeWidth(5.0);
1958 RenderWith(testP, stroke_base_env, tolerance,
1960 "Stroke Width 5, Miter 10",
1962 ctx.paint.setStyle(SkPaint::kStroke_Style);
1963 ctx.paint.setStrokeWidth(5.0);
1964 ctx.paint.setStrokeMiter(10.0);
1965 ctx.paint.setStrokeJoin(SkPaint::kMiter_Join);
1969 ctx.paint.setStrokeWidth(5.0);
1970 ctx.paint.setStrokeMiter(10.0);
1974 RenderWith(testP, stroke_base_env, tolerance,
1976 "Stroke Width 5, Miter 0",
1978 ctx.paint.setStyle(SkPaint::kStroke_Style);
1979 ctx.paint.setStrokeWidth(5.0);
1980 ctx.paint.setStrokeMiter(0.0);
1981 ctx.paint.setStrokeJoin(SkPaint::kMiter_Join);
1985 ctx.paint.setStrokeWidth(5.0);
1986 ctx.paint.setStrokeMiter(0.0);
1999 testP, env, tolerance,
2002 [=](
const SkSetupContext& ctx) { ctx.canvas->translate(5, 10); },
2003 [=](
const DlSetupContext& ctx) { ctx.canvas->Translate(5, 10); }));
2005 testP, env, tolerance,
2008 [=](
const SkSetupContext& ctx) { ctx.canvas->scale(1.05, 1.05); },
2009 [=](
const DlSetupContext& ctx) { ctx.canvas->Scale(1.05, 1.05); }));
2011 testP, env, skewed_tolerance,
2017 testP, env, skewed_tolerance,
2020 [=](
const SkSetupContext& ctx) { ctx.canvas->skew(0.05, 0.05); },
2021 [=](
const DlSetupContext& ctx) { ctx.canvas->Skew(0.05, 0.05); }));
2033 1.0 + tweak, tweak, 0, 5,
2034 tweak, 1.0 + tweak, 0, 10,
2040 testP, env, skewed_tolerance,
2042 "Transform 2D Affine Matrix",
2047 ctx.canvas->Transform(matrix);
2050 testP, env, skewed_tolerance,
2052 "Transform 2D Affine inline",
2054 ctx.canvas->concat(SkMatrix::MakeAll(1.0 + tweak, tweak, 5,
2055 tweak, 1.0 + tweak, 10,
2059 ctx.canvas->Transform2DAffine(1.0 + tweak, tweak, 5,
2060 tweak, 1.0 + tweak, 10);
2066 0.0f, 0.0f, 1.0f, 0.0f,
2067 0.0f, 0.0f, .001f, 1.0f);
2072 testP, env, skewed_tolerance,
2074 "Transform Full Perspective Matrix",
2076 ctx.canvas->concat(
ToSkM44(matrix));
2079 ctx.canvas->Transform(matrix);
2082 testP, env, skewed_tolerance,
2084 "Transform Full Perspective inline",
2086 ctx.canvas->concat(SkM44(
2089 0.997564, 0.000000, 0.069756, 0.243591,
2090 0.003651, 0.998630, -0.052208, -0.228027,
2091 -0.069661, 0.052336, 0.996197, 1.732491,
2092 -0.000070, 0.000052, 0.000996, 1.001732
2097 ctx.canvas->TransformFullPerspective(
2100 0.997564, 0.000000, 0.069756, 0.243591,
2101 0.003651, 0.998630, -0.052208, -0.228027,
2102 -0.069661, 0.052336, 0.996197, 1.732491,
2103 -0.000070, 0.000052, 0.000996, 1.001732
2126 "Hard ClipRect inset by 15.4",
2128 ctx.canvas->clipRect(
ToSkRect(r_clip),
2129 SkClipOp::kIntersect,
false);
2136 "AntiAlias ClipRect inset by 15.4",
2138 ctx.canvas->clipRect(
ToSkRect(r_clip),
2139 SkClipOp::kIntersect,
true);
2146 "Hard ClipRect Diff, inset by 15.4",
2148 ctx.canvas->clipRect(
ToSkRect(r_clip),
2149 SkClipOp::kDifference,
false);
2160 ctx.canvas->clipRRect(SkRRect::MakeOval(
ToSkRect(r_clip)),
2161 SkClipOp::kIntersect,
false);
2168 "AntiAlias ClipOval",
2171 ctx.canvas->clipRRect(SkRRect::MakeOval(
ToSkRect(r_clip)),
2172 SkClipOp::kIntersect,
true);
2179 "Hard ClipOval Diff",
2182 ctx.canvas->clipRRect(SkRRect::MakeOval(
ToSkRect(r_clip)),
2183 SkClipOp::kDifference,
false);
2197 "Hard ClipRRect with radius of 9",
2199 ctx.canvas->clipRRect(
ToSkRRect(rr_clip),
2200 SkClipOp::kIntersect,
false);
2208 "AntiAlias ClipRRect with radius of 9",
2210 ctx.canvas->clipRRect(
ToSkRRect(rr_clip),
2211 SkClipOp::kIntersect,
true);
2219 "Hard ClipRRect Diff, with radius of 9",
2221 ctx.canvas->clipRRect(
ToSkRRect(rr_clip),
2222 SkClipOp::kDifference,
false);
2233 DlPath path_clip = path_builder.TakePath();
2236 "Hard ClipPath inset by 15.4",
2238 ctx.canvas->clipPath(path_clip.
GetSkPath(),
2239 SkClipOp::kIntersect,
false);
2247 "AntiAlias ClipPath inset by 15.4",
2249 ctx.canvas->clipPath(path_clip.
GetSkPath(),
2250 SkClipOp::kIntersect,
true);
2258 "Hard ClipPath Diff, inset by 15.4",
2260 ctx.canvas->clipPath(path_clip.
GetSkPath(),
2261 SkClipOp::kDifference,
false);
2279 if (ret.is_valid()) {
2284 if (ret.is_valid()) {
2287 FML_LOG(ERROR) <<
"Could not create directory (" << dir
2288 <<
") for impeller failure images" <<
", ret = " << ret.get()
2289 <<
", errno = " << errno;
2294 std::string base_dir =
"./impeller_failure_images";
2298 for (
int i = 0;
i < 10000;
i++) {
2299 std::string sub_dir = std::to_string(
i);
2300 while (sub_dir.length() < 4) {
2301 sub_dir =
"0" + sub_dir;
2303 std::string try_dir = base_dir +
"/" + sub_dir;
2314 FML_LOG(ERROR) <<
"Too many output directories for Impeller failure images";
2318 const std::string& op_desc,
2319 const std::string& reason) {
2332 for (
const char& ch : op_desc) {
2333 filename += (ch ==
':' || ch ==
' ') ?
'_' : ch;
2335 filename = filename +
".png";
2336 result->
write(filename);
2338 FML_LOG(ERROR) << reason <<
": " << filename;
2345 std::string test_name =
2346 ::testing::UnitTest::GetInstance()->current_test_info()->name();
2347 const std::string info =
2360 auto sk_result = env.
getResult(base_info, sk_job);
2366 auto dl_result = env.
getResult(base_info, dl_job);
2372 ASSERT_EQ(sk_result->width(),
kTestWidth) << info;
2373 ASSERT_EQ(sk_result->height(),
kTestHeight) << info;
2374 ASSERT_EQ(dl_result->width(),
kTestWidth) << info;
2375 ASSERT_EQ(dl_result->height(),
kTestHeight) << info;
2379 const sk_sp<SkPicture> sk_picture = sk_job.
MakePicture(base_info);
2380 const sk_sp<DisplayList> display_list = dl_job.
MakeDisplayList(base_info);
2383 checkPixels(sk_result.get(), sk_bounds, info +
" (Skia reference)", bg);
2387 info +
" (attribute should not have effect)");
2390 info +
" (attribute should affect rendering)");
2405 std::string imp_info = info +
" (Impeller)";
2406 bool success =
checkPixels(imp_result.get(), imp_result->render_bounds(),
2409 success = success &&
2412 imp_info +
" (attribute should not have effect)");
2414 success = success &&
2417 imp_info +
" (attribute should affect rendering)");
2420 FML_LOG(ERROR) <<
"Impeller issue encountered for: "
2422 save_to_png(imp_result.get(), info +
" (Impeller Result)",
2425 "compare to reference without attributes");
2426 save_to_png(sk_result.get(), info +
" (Skia Result)",
2427 "and to Skia reference with attributes");
2429 "and to Skia reference without attributes");
2434 info +
" (DlCanvas output matches SkCanvas)");
2437 DlRect dl_bounds = display_list->GetBounds();
2439 if (!sk_padded_bounds.
Contains(dl_bounds)) {
2440 FML_LOG(ERROR) <<
"For " << info;
2441 FML_LOG(ERROR) <<
"sk ref: " << sk_bounds;
2442 FML_LOG(ERROR) <<
"dl: " << dl_bounds;
2443 if (!dl_bounds.
Contains(sk_bounds)) {
2444 FML_LOG(ERROR) <<
"DisplayList bounds are too small!";
2448 FML_LOG(ERROR) <<
"###### DisplayList bounds larger than reference!";
2464 EXPECT_EQ(
static_cast<int>(display_list->op_count()),
2465 sk_picture->approximateOpCount())
2467 EXPECT_EQ(
static_cast<int>(display_list->op_count()),
2468 sk_picture->approximateOpCount())
2473 auto dl_builder_result = env.
getResult(base_info, dl_builder_job);
2476 dl_builder_result.get(), dl_result.get(),
2477 info +
" (DlCanvas DL output close to Builder Dl output)",
2478 &dl_bounds, &tolerance, bg,
true);
2481 dl_builder_result.get(), dl_result.get(),
true,
2482 info +
" (DlCanvas DL output matches Builder Dl output)");
2486 info +
" (DisplayList built directly -> surface)",
2487 &dl_bounds, &tolerance, bg,
2490 if (display_list->can_apply_group_opacity()) {
2492 info +
" with Group Opacity", bg);
2508 .
width = test_width_2,
2509 .height = test_height_2,
2511 .scale = test_scale,
2513 auto ref_x2_result = env.
getResult(info_2x, sk_job_x2);
2514 ASSERT_EQ(ref_x2_result->width(), test_width_2) << info;
2515 ASSERT_EQ(ref_x2_result->height(), test_height_2) << info;
2518 auto test_x2_result = env.
getResult(info_2x, dl_job_x2);
2520 info +
" (Both rendered scaled 2x)",
nullptr,
nullptr,
2522 test_width_2, test_height_2,
false);
2527 for (
int i = 0;
i < 32;
i += 8) {
2528 int comp_a = (pixel_a >>
i) & 0xff;
2529 int comp_b = (pixel_b >>
i) & 0xff;
2530 if (std::abs(comp_a - comp_b) > fudge) {
2538 if (env.
format() == PixelFormat::k565PixelFormat) {
2549 const sk_sp<DisplayList>& display_list,
2551 const std::string& info,
2560 auto group_opacity_result = env.
getResult(opacity_info, opacity_job);
2562 ASSERT_EQ(group_opacity_result->width(),
kTestWidth) << info;
2563 ASSERT_EQ(group_opacity_result->height(),
kTestHeight) << info;
2568 int pixels_touched = 0;
2569 int pixels_different = 0;
2581 const uint32_t* ref_row = ref_result->
addr32(0,
y);
2582 const uint32_t* test_row = group_opacity_result->addr32(0,
y);
2584 uint32_t ref_pixel = ref_row[
x];
2585 uint32_t test_pixel = test_row[
x];
2586 if (ref_pixel != bg.
argb() || test_pixel != bg.
argb()) {
2588 for (
int i = 0;
i < 32;
i += 8) {
2589 int ref_comp = (ref_pixel >>
i) & 0xff;
2590 int bg_comp = (bg.
argb() >>
i) & 0xff;
2591 DlScalar faded_comp = bg_comp + (ref_comp - bg_comp) * opacity;
2592 int test_comp = (test_pixel >>
i) & 0xff;
2593 if (std::abs(faded_comp - test_comp) > fudge) {
2594 int diff = std::abs(faded_comp - test_comp);
2595 if (max_diff < diff) {
2605 ASSERT_GT(pixels_touched, 20) << info;
2606 if (pixels_different > 1) {
2607 FML_LOG(ERROR) <<
"max diff == " << max_diff <<
" for " << info;
2609 ASSERT_LE(pixels_different, 1) << info;
2614 const std::string& info,
2616 uint32_t untouched = PremultipliedArgb(bg);
2617 int pixels_touched = 0;
2623 const uint32_t* ref_row = ref_result->
addr32(0,
y);
2625 if (ref_row[
x] != untouched) {
2633 EXPECT_EQ(pixels_oob, 0) << info;
2634 EXPECT_GT(pixels_touched, 0) << info;
2635 return pixels_oob == 0 && pixels_touched > 0;
2642 const uint32_t* ref_row = ref_result->
addr32(0,
y);
2643 const uint32_t* test_row = test_result->
addr32(0,
y);
2645 if (ref_row[
x] != test_row[
x]) {
2646 if (ref_row[
x] == 0) {
2656 const std::string& info) {
2658 info +
" reference rendering");
2664 const std::string& info) {
2665 int w = test_result->
width();
2666 int h = test_result->
height();
2667 EXPECT_EQ(w, ref_result->
width()) << info;
2668 EXPECT_EQ(
h, ref_result->
height()) << info;
2669 int pixels_different = 0;
2670 for (
int y = 0;
y <
h;
y++) {
2671 const uint32_t* ref_row = ref_result->
addr32(0,
y);
2672 const uint32_t* test_row = test_result->
addr32(0,
y);
2673 for (
int x = 0;
x < w;
x++) {
2674 if (ref_row[
x] != test_row[
x]) {
2675 if (should_match && pixels_different < 5) {
2676 FML_LOG(ERROR) << std::hex << ref_row[
x] <<
" != " << test_row[
x];
2683 EXPECT_EQ(pixels_different, 0) << info;
2684 return pixels_different == 0;
2686 EXPECT_NE(pixels_different, 0) << info;
2687 return pixels_different != 0;
2693 const std::string& info,
2697 bool fuzzyCompares =
false,
2700 bool printMismatches =
false) {
2701 uint32_t untouched = PremultipliedArgb(bg);
2702 ASSERT_EQ(test_result->
width(),
width) << info;
2707 int pixels_different = 0;
2714 const uint32_t* ref_row = ref_result->
addr32(0,
y);
2715 const uint32_t* test_row = test_result->
addr32(0,
y);
2717 if (bounds && test_row[
x] != untouched) {
2734 bool match = fuzzyCompares ?
fuzzyCompare(test_row[
x], ref_row[
x], 1)
2735 : test_row[
x] == ref_row[
x];
2737 if (printMismatches && pixels_different < 5) {
2738 FML_LOG(ERROR) <<
"pix[" <<
x <<
", " <<
y
2739 <<
"] mismatch: " << std::hex << test_row[
x]
2740 <<
"(test) != (ref)" << ref_row[
x] << std::dec;
2746 if (pixels_oob > 0) {
2747 FML_LOG(ERROR) <<
"pix bounds["
2750 FML_LOG(ERROR) <<
"dl_bounds[" << bounds <<
"]";
2751 }
else if (bounds) {
2754 ASSERT_EQ(pixels_oob, 0) << info;
2755 ASSERT_EQ(pixels_different, 0) << info;
2765 int pad_left = std::max(0, pixLeft - bounds.
GetLeft());
2766 int pad_top = std::max(0, pixTop - bounds.
GetTop());
2767 int pad_right = std::max(0, bounds.
GetRight() - pixRight);
2768 int pad_bottom = std::max(0, bounds.
GetBottom() - pixBottom);
2772 int pix_width = pix_size.
width;
2773 int pix_height = pix_size.
height;
2774 int worst_pad_x = std::max(pad_left, pad_right);
2775 int worst_pad_y = std::max(pad_top, pad_bottom);
2776 if (tolerance->
overflows(pix_bounds, worst_pad_x, worst_pad_y)) {
2777 FML_LOG(ERROR) <<
"Computed bounds for " << info;
2778 FML_LOG(ERROR) <<
"pix bounds["
2779 << pixLeft <<
", " << pixTop <<
" => "
2780 << pixRight <<
", " << pixBottom
2782 FML_LOG(ERROR) <<
"dl_bounds[" << bounds <<
"]";
2783 FML_LOG(ERROR) <<
"Bounds overly conservative by up to "
2784 << worst_pad_x <<
", " << worst_pad_y
2785 <<
" (" << (worst_pad_x * 100.0 / pix_width)
2786 <<
"%, " << (worst_pad_y * 100.0 / pix_height) <<
"%)";
2787 int pix_area = pix_size.
Area();
2788 int dl_area = bounds.
Area();
2789 FML_LOG(ERROR) <<
"Total overflow area: " << (dl_area - pix_area)
2790 <<
" (+" << (dl_area * 100.0 / pix_area - 100.0)
2799 sk_sp<SkTypeface> face = font.refTypeface();
2801 FML_CHECK(face->countGlyphs() > 0) <<
"No glyphs in font";
2802 return SkTextBlob::MakeFromText(
string.c_str(),
string.
size(), font,
2803 SkTextEncoding::kUTF8);
2820template <
typename BaseT>
2827 if (prefix.length() > str.length()) {
2830 for (
size_t i = 0;
i < prefix.length();
i++) {
2831 if (str[
i] != prefix[
i]) {
2839 bool do_software =
true;
2840 bool do_opengl =
false;
2841 bool do_metal =
false;
2842 std::vector<std::string>
args = ::testing::internal::GetArgvs();
2843 for (
auto p_arg = std::next(
args.begin()); p_arg !=
args.end(); p_arg++) {
2844 std::string arg = *p_arg;
2846 if (arg ==
"--save-impeller-failures") {
2852 arg =
"-" + arg.substr(4);
2855 arg =
"--en" + arg.substr(5);
2857 if (arg ==
"--enable-software") {
2858 do_software = enable;
2859 }
else if (arg ==
"--enable-opengl" || arg ==
"--enable-gl") {
2861 }
else if (arg ==
"--enable-metal") {
2863 }
else if (arg ==
"--enable-impeller") {
2879 std::string providers =
"";
2883 std::string libraries =
" Skia";
2886 libraries +=
" Impeller";
2888 FML_LOG(INFO) <<
"Running tests on [" << providers
2889 <<
" ], and [" << libraries <<
" ]";
2896 <<
" images saved in "
2899 FML_LOG(INFO) <<
" " << filename;
2914 ctx.canvas->drawPaint(ctx.paint);
2917 ctx.canvas->DrawPaint(ctx.paint);
2932 SkColor color = SkColorSetA(SK_ColorMAGENTA, ctx.paint.getAlpha());
2933 ctx.canvas->drawColor(color);
2941 ctx.canvas->DrawColor(
2952 ctx.canvas->drawColor(0x7FFF00FF);
2955 ctx.canvas->DrawColor(
DlColor(0x7FFF00FF));
2980 SkPaint p = ctx.paint;
2981 p.setStyle(SkPaint::kStroke_Style);
2988 ctx.canvas->DrawLine(p1, p2, ctx.paint);
2989 ctx.canvas->DrawLine(p3, p4, ctx.paint);
2990 ctx.canvas->DrawLine(p5, p6, ctx.paint);
2991 ctx.canvas->DrawLine(p7, p8, ctx.paint);
3011 SkPaint p = ctx.paint;
3012 p.setStyle(SkPaint::kStroke_Style);
3018 ctx.canvas->DrawLine(p1, p2, ctx.paint);
3019 ctx.canvas->DrawLine(p3, p4, ctx.paint);
3020 ctx.canvas->DrawLine(p5, p6, ctx.paint);
3041 SkPaint p = ctx.paint;
3042 p.setStyle(SkPaint::kStroke_Style);
3048 ctx.canvas->DrawLine(p1, p2, ctx.paint);
3049 ctx.canvas->DrawLine(p3, p4, ctx.paint);
3050 ctx.canvas->DrawLine(p5, p6, ctx.paint);
3087 SkPaint p = ctx.paint;
3088 p.setStyle(SkPaint::kStroke_Style);
3089 DlScalar intervals[2] = {25.0f, 5.0f};
3090 p.setPathEffect(SkDashPathEffect::Make({intervals, 2}, 0.0f));
3097 ctx.canvas->DrawDashedLine(p1, p2, 25.0f, 5.0f, ctx.paint);
3098 ctx.canvas->DrawDashedLine(p3, p4, 25.0f, 5.0f, ctx.paint);
3099 ctx.canvas->DrawDashedLine(p5, p6, 25.0f, 5.0f, ctx.paint);
3100 ctx.canvas->DrawDashedLine(p7, p8, 25.0f, 5.0f, ctx.paint);
3113 ctx.canvas->drawRect(
ToSkRect(rect), ctx.paint);
3116 ctx.canvas->DrawRect(rect, ctx.paint);
3127 ctx.canvas->drawOval(
ToSkRect(rect), ctx.paint);
3130 ctx.canvas->DrawOval(rect, ctx.paint);
3157 ctx.canvas->drawRRect(
ToSkRRect(rrect), ctx.paint);
3160 ctx.canvas->DrawRoundRect(rrect, ctx.paint);
3181 ctx.canvas->DrawDiffRoundRect(outer, inner, ctx.paint);
3202 path_builder.
Close();
3207 path_builder.
Close();
3214 ctx.canvas->drawPath(
path.GetSkPath(), ctx.paint);
3217 ctx.canvas->DrawPath(
path, ctx.paint);
3231 ctx.canvas->DrawArc(
kRenderBounds, 60, 330,
false, ctx.paint);
3233 kDrawArcNoCenterFlags));
3254 ctx.canvas->DrawArc(
kRenderBounds, 60, 360 - 12,
true, ctx.paint);
3256 kDrawArcWithCenterFlags)
3257 .set_draw_arc_center());
3282 {x0, y0}, {x1, y0}, {x2, y0}, {x3, y0}, {x4, y0}, {x5, y0}, {x6, y0},
3283 {x0, y1}, {x1, y1}, {x2, y1}, {x3, y1}, {x4, y1}, {x5, y1}, {x6, y1},
3284 {x0, y2}, {x1, y2}, {x2, y2}, {x3, y2}, {x4, y2}, {x5, y2}, {x6, y2},
3285 {x0, y3}, {x1, y3}, {x2, y3}, {x3, y3}, {x4, y3}, {x5, y3}, {x6, y3},
3286 {x0, y4}, {x1, y4}, {x2, y4}, {x3, y4}, {x4, y4}, {x5, y4}, {x6, y4},
3287 {x0, y5}, {x1, y5}, {x2, y5}, {x3, y5}, {x4, y5}, {x5, y5}, {x6, y5},
3288 {x0, y6}, {x1, y6}, {x2, y6}, {x3, y6}, {x4, y6}, {x5, y6}, {x6, y6},
3299 SkPaint p = ctx.paint;
3300 p.setStyle(SkPaint::kStroke_Style);
3301 auto mode = SkCanvas::kPoints_PointMode;
3306 ctx.canvas->DrawPoints(
mode, count,
points, ctx.paint);
3308 kDrawPointsAsPointsFlags)
3333 {x0, y0}, {x3, y3}, {x3, y0}, {x0, y3},
3344 ASSERT_TRUE((count & 1) == 0);
3351 SkPaint p = ctx.paint;
3352 p.setStyle(SkPaint::kStroke_Style);
3353 auto mode = SkCanvas::kLines_PointMode;
3358 ctx.canvas->DrawPoints(
mode, count,
points, ctx.paint);
3360 kDrawPointsAsLinesFlags));
3378 const int count1 =
sizeof(points1) /
sizeof(points1[0]);
3386 SkPaint p = ctx.paint;
3387 p.setStyle(SkPaint::kStroke_Style);
3388 auto mode = SkCanvas::kPolygon_PointMode;
3393 ctx.canvas->DrawPoints(
mode, count1, points1, ctx.paint);
3395 kDrawPointsAsPolygonFlags));
3418 const DlColor dl_colors[6] = {
3422 const SkColor sk_colors[6] = {
3423 SK_ColorRED, SK_ColorBLUE, SK_ColorGREEN,
3424 SK_ColorCYAN, SK_ColorYELLOW, SK_ColorMAGENTA,
3426 const std::shared_ptr<DlVertices> dl_vertices =
3428 const auto sk_vertices =
3429 SkVertices::MakeCopy(SkVertices::VertexMode::kTriangles_VertexMode, 6,
3435 ctx.canvas->drawVertices(sk_vertices, SkBlendMode::kSrcOver,
3439 ctx.canvas->DrawVertices(dl_vertices, DlBlendMode::kSrcOver,
3442 kDrawVerticesFlags));
3473 const std::shared_ptr<DlVertices> dl_vertices =
3475 const auto sk_vertices =
3476 SkVertices::MakeCopy(SkVertices::VertexMode::kTriangles_VertexMode, 6,
3482 SkPaint v_paint = ctx.paint;
3483 if (v_paint.getShader() ==
nullptr) {
3484 v_paint.setShader(MakeColorSource(ctx.image));
3486 ctx.canvas->drawVertices(sk_vertices, SkBlendMode::kSrcOver,
3494 ctx.canvas->DrawVertices(dl_vertices, DlBlendMode::kSrcOver,
3497 kDrawVerticesFlags));
3513 kDrawImageWithPaintFlags));
3541 kDrawImageWithPaintFlags));
3553 SkCanvas::kFast_SrcRectConstraint);
3556 ctx.canvas->DrawImageRect(ctx.image, src, dst,
3560 kDrawImageRectWithPaintFlags));
3572 SkCanvas::kFast_SrcRectConstraint);
3575 ctx.canvas->DrawImageRect(ctx.image, src, dst,
3579 kDrawImageRectFlags));
3590 SkCanvas::kFast_SrcRectConstraint);
3593 ctx.canvas->DrawImageRect(ctx.image, src, dst,
3597 kDrawImageRectWithPaintFlags));
3606 ctx.canvas->drawImageNine(ctx.image.get(),
ToSkIRect(src),
3607 ToSkRect(dst), SkFilterMode::kNearest,
3611 ctx.canvas->DrawImageNine(ctx.image, src, dst,
3614 kDrawImageNineWithPaintFlags));
3623 ctx.canvas->drawImageNine(ctx.image.get(),
ToSkIRect(src),
3624 ToSkRect(dst), SkFilterMode::kNearest,
3628 ctx.canvas->DrawImageNine(ctx.image, src, dst,
3631 kDrawImageNineFlags));
3640 ctx.canvas->drawImageNine(ctx.image.get(),
ToSkIRect(src),
3641 ToSkRect(dst), SkFilterMode::kLinear,
3645 ctx.canvas->DrawImageNine(ctx.image, src, dst,
3648 kDrawImageNineWithPaintFlags));
3659 const SkRSXform sk_xform[] = {
3676 relative_rect(0.0f, 0.0f, 0.5f, 0.5f),
3677 relative_rect(0.5f, 0.0f, 1.0f, 0.5f),
3678 relative_rect(0.5f, 0.5f, 1.0f, 1.0f),
3679 relative_rect(0.0f, 0.5f, 0.5f, 1.0f),
3681 const SkColor sk_colors[] = {
3698 ctx.canvas->drawAtlas(ctx.image.get(), {sk_xform, 4},
3699 {ToSkRects(tex), 4}, {sk_colors, 4},
3700 SkBlendMode::kSrcOver, sk_sampling,
nullptr,
3704 ctx.canvas->DrawAtlas(ctx.image, dl_xform, tex, dl_colors, 4,
3705 DlBlendMode::kSrcOver, dl_sampling,
nullptr,
3708 kDrawAtlasWithPaintFlags));
3719 const SkRSXform sk_xform[] = {
3736 relative_rect(0.0f, 0.0f, 0.5f, 0.5f),
3737 relative_rect(0.5f, 0.0f, 1.0f, 0.5f),
3738 relative_rect(0.5f, 0.5f, 1.0f, 1.0f),
3739 relative_rect(0.0f, 0.5f, 0.5f, 1.0f),
3741 const SkColor sk_colors[] = {
3758 ctx.canvas->drawAtlas(ctx.image.get(), {sk_xform, 4},
3759 {ToSkRects(tex), 4}, {sk_colors, 4},
3760 SkBlendMode::kSrcOver, sk_sampling,
nullptr,
3764 ctx.canvas->DrawAtlas(ctx.image, dl_xform, tex, dl_colors, 4,
3765 DlBlendMode::kSrcOver, dl_sampling,
nullptr,
3779 const SkRSXform sk_xform[] = {
3796 relative_rect(0.0f, 0.0f, 0.5f, 0.5f),
3797 relative_rect(0.5f, 0.0f, 1.0f, 0.5f),
3798 relative_rect(0.5f, 0.5f, 1.0f, 1.0f),
3799 relative_rect(0.0f, 0.5f, 0.5f, 1.0f),
3801 const SkColor sk_colors[] = {
3818 ctx.canvas->drawAtlas(ctx.image.get(), {sk_xform, 2},
3819 {ToSkRects(tex), 2}, {sk_colors, 2},
3820 SkBlendMode::kSrcOver, sk_sampling,
nullptr,
3824 ctx.canvas->DrawAtlas(ctx.image, dl_xform, tex, dl_colors, 2,
3825 DlBlendMode::kSrcOver, dl_sampling,
nullptr,
3828 kDrawAtlasWithPaintFlags));
3851 return builder.
Build();
3862 ctx.canvas->DrawDisplayList(display_list);
3864 kDrawDisplayListFlags)
3865 .set_draw_display_list());
3872#if defined(OS_FUCHSIA)
3873 GTEST_SKIP() <<
"Rendering comparisons require a valid default font manager";
3875 sk_sp<SkTextBlob> blob =
3878#ifdef IMPELLER_SUPPORTS_RENDERING
3887 auto paint = ctx.paint;
3888 ctx.canvas->drawTextBlob(blob,
kRenderLeft, render_y_1_3, paint);
3889 ctx.canvas->drawTextBlob(blob,
kRenderLeft, render_y_2_3, paint);
3893 auto paint = ctx.paint;
3894 ctx.canvas->DrawText(skiaText,
kRenderLeft, render_y_1_3, paint);
3895 ctx.canvas->DrawText(skiaText,
kRenderLeft, render_y_2_3, paint);
3898#ifdef IMPELLER_SUPPORTS_RENDERING
3900 auto paint = ctx.paint;
3901 ctx.canvas->DrawText(impellerText,
kRenderLeft, render_y_1_3,
3903 ctx.canvas->DrawText(impellerText,
kRenderLeft, render_y_2_3,
3910 .set_draw_text_blob(),
3934 color, elevation,
false, 1.0);
3937 ctx.canvas->DrawShadow(
path, color, elevation,
false, 1.0);
3958 color, elevation,
true, 1.0);
3961 ctx.canvas->DrawShadow(
path, color, elevation,
true, 1.0);
3982 color, elevation,
false, 1.5);
3985 ctx.canvas->DrawShadow(
path, color, elevation,
false, 1.5);
4002 SkImageFilters::Blur(10.0f, 10.0f, SkTileMode::kDecal,
nullptr);
4003 SkPaint layer_paint;
4004 layer_paint.setImageFilter(layer_filter);
4009 ctx.canvas->drawRect(
ToSkRect(draw_rect), ctx.paint);
4010 ctx.canvas->restore();
4011 ctx.canvas->restore();
4021 ctx.canvas->DrawRect(draw_rect, ctx.paint);
4022 ctx.canvas->Restore();
4023 ctx.canvas->Restore();
4025 kSaveLayerWithPaintFlags);
4026 CaseParameters case_params(
"Filtered SaveLayer with clipped content");
4034 test_params.imp_renderer());
4041 float commutable_color_matrix[]{
4049 float non_commutable_color_matrix[]{
4059 contract_matrix.
Scale({0.9f, 0.9f});
4062 std::vector<DlScalar> opacities = {
4067 std::vector<std::shared_ptr<const DlColorFilter>> color_filters = {
4074 std::vector<std::shared_ptr<DlImageFilter>> image_filters = {
4096 auto test_attributes_env =
4098 const DlPaint& paint_both,
bool same,
bool rev_same,
4099 const std::string& desc1,
const std::string& desc2,
4104 render_content(nested_builder);
4105 auto nested_results = env->getResult(nested_builder.
Build());
4110 render_content(reverse_builder);
4111 auto reverse_results = env->getResult(reverse_builder.
Build());
4115 render_content(combined_builder);
4116 auto combined_results = env->getResult(combined_builder.
Build());
4125 const bool always =
false;
4130 if (always || same) {
4132 nested_results.get(), combined_results.get(),
4133 "nested " + desc1 +
" then " + desc2,
nullptr,
4135 true, combined_results->width(),
4136 combined_results->height(),
true);
4138 if (always || rev_same) {
4140 reverse_results.get(), combined_results.get(),
4141 "nested " + desc2 +
" then " + desc1,
nullptr,
4143 true, combined_results->width(),
4144 combined_results->height(),
true);
4148 auto test_attributes = [test_attributes_env](
DlPaint& paint1,
DlPaint& paint2,
4150 bool same,
bool rev_same,
4151 const std::string& desc1,
4152 const std::string& desc2) {
4155 auto env = std::make_unique<RenderEnvironment>(
4156 provider.get(), PixelFormat::kN32PremulPixelFormat);
4157 test_attributes_env(paint1, paint2, paint_both,
4158 same, rev_same, desc1, desc2, env.get());
4164 for (
size_t cfi = 0; cfi < color_filters.size(); cfi++) {
4165 const auto& color_filter = color_filters[cfi];
4166 std::string cf_desc =
"color filter #" + std::to_string(cfi + 1);
4169 for (
size_t oi = 0; oi < opacities.size(); oi++) {
4171 std::string op_desc =
"opacity " + std::to_string(opacity);
4174 DlPaint combined_paint = nested_paint1;
4177 bool op_then_cf_works = opacity <= 0.0 || opacity >= 1.0 ||
4178 color_filter->can_commute_with_opacity();
4180 test_attributes(nested_paint1, nested_paint2, combined_paint,
true,
4181 op_then_cf_works, cf_desc, op_desc);
4189 for (
size_t oi = 0; oi < opacities.size(); oi++) {
4191 std::string op_desc =
"opacity " + std::to_string(opacity);
4194 for (
size_t ifi = 0; ifi < image_filters.size(); ifi++) {
4195 const auto& image_filter = image_filters[ifi];
4196 std::string if_desc =
"image filter #" + std::to_string(ifi + 1);
4199 DlPaint combined_paint = nested_paint1;
4202 bool if_then_op_works = opacity <= 0.0 || opacity >= 1.0;
4203 test_attributes(nested_paint1, nested_paint2, combined_paint,
true,
4204 if_then_op_works, op_desc, if_desc);
4210 for (
size_t cfi = 0; cfi < color_filters.size(); cfi++) {
4211 const auto& color_filter = color_filters[cfi];
4212 std::string cf_desc =
"color filter #" + std::to_string(cfi + 1);
4215 for (
size_t ifi = 0; ifi < image_filters.size(); ifi++) {
4216 const auto& image_filter = image_filters[ifi];
4217 std::string if_desc =
"image filter #" + std::to_string(ifi + 1);
4220 DlPaint combined_paint = nested_paint1;
4223 test_attributes(nested_paint1, nested_paint2, combined_paint,
true,
false,
4240 "matrix[" + std::to_string(element) +
"] = " + std::to_string(
value);
4241 float original_value = matrix[element];
4242 matrix[element] =
value;
4250 bool is_identity = (dl_filter ==
nullptr || original_value ==
value);
4260 auto display_list1 = builder1.
Build();
4269 auto display_list2 = builder2.
Build();
4273 auto env = std::make_unique<RenderEnvironment>(
4274 provider.get(), PixelFormat::kN32PremulPixelFormat);
4275 auto results1 = env->getResult(display_list1);
4276 auto results2 = env->getResult(display_list2);
4278 results1.get(), results2.get(), is_identity,
4279 desc +
" filter affects rendering");
4280 int modified_transparent_pixels =
4284 modified_transparent_pixels != 0)
4292 for (
int i = 0;
i < 20;
i++) {
4293 test_matrix(
i, -0.25);
4295 test_matrix(
i, 0.25);
4297 test_matrix(
i, 1.25);
4298 test_matrix(
i, SK_ScalarNaN);
4299 test_matrix(
i, SK_ScalarInfinity);
4300 test_matrix(
i, -SK_ScalarInfinity);
4315 "matrix[" + std::to_string(element) +
"] = " + std::to_string(
value);
4316 matrix[element] =
value;
4318 EXPECT_EQ(std::isfinite(
value), filter !=
nullptr);
4331 auto display_list1 = builder1.
Build();
4340 auto display_list2 = builder2.
Build();
4344 auto env = std::make_unique<RenderEnvironment>(
4345 provider.get(), PixelFormat::kN32PremulPixelFormat);
4346 auto results1 = env->getResult(display_list1);
4347 auto results2 = env->getResult(display_list2);
4348 if (!filter || filter->can_commute_with_opacity()) {
4350 results2.get(), results1.get(), desc,
nullptr,
nullptr,
4354 results1.get(), results2.get(),
false, desc);
4362 for (
int i = 0;
i < 20;
i++) {
4363 test_matrix(
i, -0.25);
4365 test_matrix(
i, 0.25);
4367 test_matrix(
i, 1.1);
4368 test_matrix(
i, SK_ScalarNaN);
4369 test_matrix(
i, SK_ScalarInfinity);
4370 test_matrix(
i, -SK_ScalarInfinity);
4374#define FOR_EACH_BLEND_MODE_ENUM(FUNC) \
4407 std::stringstream desc_str;
4409 desc_str <<
"blend[" << mode_string <<
", " << color <<
"]";
4410 std::string desc = desc_str.str();
4424 auto display_list1 = builder1.
Build();
4433 auto display_list2 = builder2.
Build();
4437 auto env = std::make_unique<RenderEnvironment>(
4438 provider.get(), PixelFormat::kN32PremulPixelFormat);
4439 auto results1 = env->getResult(display_list1);
4440 auto results2 = env->getResult(display_list2);
4441 int modified_transparent_pixels =
4445 modified_transparent_pixels != 0)
4458#define TEST_MODE(V) test_mode(DlBlendMode::V);
4465 std::stringstream desc_str;
4467 desc_str <<
"blend[" << mode_string <<
", " << color <<
"]";
4468 std::string desc = desc_str.str();
4488 auto display_list1 = builder1.
Build();
4497 auto display_list2 = builder2.
Build();
4501 auto env = std::make_unique<RenderEnvironment>(
4502 provider.get(), PixelFormat::kN32PremulPixelFormat);
4503 auto results1 = env->getResult(display_list1);
4504 auto results2 = env->getResult(display_list2);
4507 results2.get(), results1.get(), desc,
nullptr,
nullptr,
4511 results1.get(), results2.get(),
false, desc);
4524#define TEST_MODE(V) test_mode(DlBlendMode::V);
4550 const int step = 0x55;
4551 static_assert(step * 3 == 255);
4552 for (
int a = step; a < 256; a += step) {
4553 for (
int r = step; r < 256; r += step) {
4554 for (
int g = step; g < 256; g += step) {
4555 for (
int b = step; b < 256; b += step) {
4562 static constexpr float color_filter_matrix_nomtb[] = {
4563 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
4564 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
4565 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
4566 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
4568 static constexpr float color_filter_matrix_mtb[] = {
4569 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
4570 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
4571 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
4572 0.0001, 0.0001, 0.0001, 0.9997, 0.1,
4582 for (DlColor color : test_dst_colors) {
4584 paint.setColor(ToSkColor4f(color));
4585 paint.setBlendMode(SkBlendMode::kSrc);
4586 canvas->drawRect(SkRect::MakeXYWH(x, 0, 1, 1), paint);
4595 int data_count =
test_data->image()->width();
4597 data_count, data_count,
true, [
this, data_count](SkCanvas* canvas) {
4598 ASSERT_EQ(
test_data->width(), data_count);
4600 for (
int y = 0;
y < data_count;
y++) {
4601 canvas->drawImage(
test_data->image().get(), 0,
y);
4605 data_count, data_count,
true, [
this, data_count](SkCanvas* canvas) {
4606 ASSERT_EQ(
test_data->width(), data_count);
4608 canvas->translate(data_count, 0);
4610 for (
int y = 0;
y < data_count;
y++) {
4611 canvas->drawImage(
test_data->image().get(), 0,
y);
4615 for (
int y = 0;
y < data_count;
y++) {
4616 for (
int x = 0;
x < data_count;
x++) {
4625 static constexpr int kWasNotNop = 0x1;
4626 static constexpr int kWasMTB = 0x2;
4647 const std::function<
void(SkCanvas*)>& renderer) {
4648 auto surface = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(w,
h));
4649 SkCanvas* canvas =
surface->getCanvas();
4651 return std::make_unique<SkRenderResult>(
surface, snapshot);
4656 const sk_sp<DisplayList>& dl,
4657 const std::string& desc) {
4659 bool is_error =
false;
4662 is_error = !dl->modifies_transparent_black();
4664 if (result_color != dst_color) {
4666 is_error = (dl->op_count() == 0u);
4669 FML_LOG(ERROR) << std::hex << dst_color <<
" filters to " << result_color
4676 const std::unique_ptr<RenderResult>& result_data,
4677 const sk_sp<DisplayList>& dl,
4678 const std::string& desc) {
4679 EXPECT_EQ(dst_data->width(), result_data->width());
4680 EXPECT_EQ(dst_data->height(), result_data->height());
4682 for (
int y = 0;
y < dst_data->height();
y++) {
4683 const uint32_t* dst_pixels = dst_data->addr32(0,
y);
4684 const uint32_t* result_pixels = result_data->addr32(0,
y);
4685 for (
int x = 0;
x < dst_data->width();
x++) {
4686 all_flags |= check_color_result(
DlColor(dst_pixels[
x]),
4687 DlColor(result_pixels[
x]), dl, desc);
4694 const sk_sp<DisplayList>& dl,
4695 const std::string& desc) {
4696 if (!dl->modifies_transparent_black()) {
4697 EXPECT_TRUE((all_flags & kWasMTB) == 0);
4698 }
else if ((all_flags & kWasMTB) == 0) {
4699 FML_LOG(INFO) <<
"combination does not affect transparency: " << desc;
4701 if (dl->op_count() == 0u) {
4702 EXPECT_TRUE((all_flags & kWasNotNop) == 0);
4703 }
else if ((all_flags & kWasNotNop) == 0) {
4704 FML_LOG(INFO) <<
"combination could be classified as a nop: " << desc;
4709 std::stringstream desc_stream;
4710 desc_stream <<
" using SkColorFilter::filterColor() with: ";
4712 desc_stream <<
"/" << color;
4713 std::string desc = desc_stream.str();
4717 auto dl = builder.
Build();
4718 if (dl->modifies_transparent_black()) {
4719 ASSERT_TRUE(dl->op_count() != 0u);
4722 auto sk_mode =
static_cast<SkBlendMode
>(
mode);
4723 auto sk_color_filter =
4724 SkColorFilters::Blend(
ToSkColor4f(color),
nullptr, sk_mode);
4725 auto srgb = SkColorSpace::MakeSRGB();
4727 if (sk_color_filter) {
4728 for (
DlColor dst_color : test_dst_colors) {
4731 sk_color_filter->filterColor4f(dst_color_f, srgb.get(), srgb.get())
4733 all_flags |= check_color_result(dst_color, result, dl, desc);
4735 if ((all_flags & kWasMTB) != 0) {
4736 EXPECT_FALSE(sk_color_filter->isAlphaUnchanged());
4739 report_results(all_flags, dl, desc);
4743 std::stringstream desc_stream;
4744 desc_stream <<
" rendering with: ";
4746 desc_stream <<
"/" << color;
4747 std::string desc = desc_stream.str();
4748 auto test_image = test_data->image();
4753 builder.
DrawRect(test_bounds, dl_paint);
4754 auto dl = builder.
Build();
4755 bool dl_is_elided = dl->op_count() == 0u;
4756 bool dl_affects_transparent_pixels = dl->modifies_transparent_black();
4757 ASSERT_TRUE(!dl_is_elided || !dl_affects_transparent_pixels);
4759 auto sk_mode =
static_cast<SkBlendMode
>(
mode);
4761 sk_paint.setBlendMode(sk_mode);
4765 auto result_surface = provider->MakeOffscreenSurface(
4766 test_image->width(), test_image->height(),
4768 SkCanvas* result_canvas = result_surface->sk_surface()->getCanvas();
4769 result_canvas->clear(SK_ColorTRANSPARENT);
4770 result_canvas->drawImage(test_image.get(), 0, 0);
4771 result_canvas->drawRect(
ToSkRect(test_bounds), sk_paint);
4772 if (GrDirectContext* direct_context = GrAsDirectContext(
4773 result_surface->sk_surface()->recordingContext())) {
4774 direct_context->flushAndSubmit();
4775 direct_context->flushAndSubmit(result_surface->sk_surface().get(),
4778 const std::unique_ptr<RenderResult> result_pixels =
4779 std::make_unique<SkRenderResult>(result_surface->sk_surface());
4781 int all_flags = check_image_result(test_data, result_pixels, dl, desc);
4782 report_results(all_flags, dl, desc);
4791 std::stringstream desc_stream;
4792 desc_stream <<
" rendering with: ";
4794 desc_stream <<
"/" << color;
4795 std::string cf_mtb = color_filter
4797 ?
"modifies transparency"
4798 :
"preserves transparency"
4800 desc_stream <<
", CF: " << cf_mtb;
4801 std::string if_mtb = image_filter
4803 ?
"modifies transparency"
4804 :
"preserves transparency"
4806 desc_stream <<
", IF: " << if_mtb;
4807 std::string desc = desc_stream.str();
4816 auto dl = builder.
Build();
4818 int w = test_image_src_data->width();
4819 int h = test_image_src_data->height();
4820 auto sk_mode =
static_cast<SkBlendMode
>(
mode);
4822 sk_paint.setBlendMode(sk_mode);
4824 sk_paint.setColorFilter(
ToSk(color_filter));
4825 sk_paint.setImageFilter(
ToSk(image_filter));
4828 auto result_surface = provider->MakeOffscreenSurface(
4830 SkCanvas* result_canvas = result_surface->sk_surface()->getCanvas();
4831 result_canvas->clear(SK_ColorTRANSPARENT);
4832 result_canvas->drawImage(test_image_dst_data->image(), 0, 0);
4833 result_canvas->drawImage(test_image_src_data->image(), 0, 0,
4834 SkSamplingOptions(), &sk_paint);
4835 if (GrDirectContext* direct_context = GrAsDirectContext(
4836 result_surface->sk_surface()->recordingContext())) {
4837 direct_context->flushAndSubmit();
4838 direct_context->flushAndSubmit(result_surface->sk_surface().get(),
4841 std::unique_ptr<RenderResult> result_pixels =
4842 std::make_unique<SkRenderResult>(result_surface->sk_surface());
4845 check_image_result(test_image_dst_data, result_pixels, dl, desc);
4846 report_results(all_flags, dl, desc);
4853 for (
DlColor color : test_src_colors) {
4854 test_mode_color_via_filter(
mode, color);
4858#define TEST_MODE(V) test_mode_filter(DlBlendMode::V);
4866 for (
DlColor color : test_src_colors) {
4867 test_mode_color_via_rendering(
mode, color);
4871#define TEST_MODE(V) test_mode_render(DlBlendMode::V);
4880 for (
DlColor color : test_src_colors) {
4881 test_attributes_image(
mode, color,
nullptr,
nullptr);
4882 test_attributes_image(
mode, color, color_filter_nomtb.get(),
nullptr);
4883 test_attributes_image(
mode, color, color_filter_mtb.get(),
nullptr);
4884 test_attributes_image(
mode, color,
nullptr, &image_filter_nomtb);
4885 test_attributes_image(
mode, color,
nullptr, &image_filter_mtb);
4889#define TEST_MODE(V) test_mode_render(DlBlendMode::V);
4894#undef FOR_EACH_BLEND_MODE_ENUM
constexpr bool applies_color() const
constexpr bool is_stroked(DlDrawStyle style=DlDrawStyle::kStroke) const
constexpr bool applies_color_filter() const
constexpr bool ignores_paint() const
constexpr bool applies_image_filter() const
constexpr bool applies_shader() const
const DisplayListSpecialGeometryFlags GeometryFlags(bool is_stroked) const
constexpr bool applies_anti_alias() const
constexpr bool applies_mask_filter() const
constexpr bool applies_blend() const
The primitive honors the DlBlendMode.
constexpr bool is_flood() const
void DrawImage(const sk_sp< DlImage > &image, const DlPoint &point, DlImageSampling sampling, const DlPaint *paint=nullptr) override
void SaveLayer(const std::optional< DlRect > &bounds, const DlPaint *paint=nullptr, const DlImageFilter *backdrop=nullptr, std::optional< int64_t > backdrop_id=std::nullopt) override
void Rotate(DlScalar degrees) override
void DrawDisplayList(const sk_sp< DisplayList > display_list, DlScalar opacity=SK_Scalar1) override
void Translate(DlScalar tx, DlScalar ty) override
sk_sp< DisplayList > Build()
void DrawRect(const DlRect &rect, const DlPaint &paint) override
constexpr bool may_have_joins() const
The geometry may have segments connect non-continuously.
constexpr bool may_have_end_caps() const
The geometry may have segments that end without closing the path.
constexpr bool may_have_acute_joins() const
constexpr bool butt_cap_becomes_square() const
Mainly for drawPoints(PointMode) where Butt caps are rendered as squares.
bool can_commute_with_opacity() const override
bool modifies_transparent_black() const override
Developer-facing API for rendering anything within the engine.
virtual DlRect GetDestinationClipCoverage() const =0
virtual DlISize GetBaseLayerDimensions() const =0
virtual void DrawRect(const DlRect &rect, const DlPaint &paint)=0
virtual DlMatrix GetMatrix() const =0
void Clear(DlColor color)
static std::shared_ptr< const DlColorFilter > MakeBlend(DlColor color, DlBlendMode mode)
static std::shared_ptr< const DlColorFilter > MakeLinearToSrgbGamma()
virtual bool modifies_transparent_black() const =0
static std::shared_ptr< const DlColorFilter > MakeMatrix(const float matrix[20])
static std::shared_ptr< const DlColorFilter > MakeSrgbToLinearGamma()
static std::shared_ptr< DlColorSource > MakeLinear(const DlPoint start_point, const DlPoint end_point, uint32_t stop_count, const DlColor *colors, const float *stops, DlTileMode tile_mode, const DlMatrix *matrix=nullptr)
static std::shared_ptr< DlImageFilter > MakeDilate(DlScalar radius_x, DlScalar radius_y)
static std::shared_ptr< DlImageFilter > MakeBlur(DlScalar sigma_x, DlScalar sigma_y, DlTileMode tile_mode)
static std::shared_ptr< DlImageFilter > MakeColorFilter(const std::shared_ptr< const DlColorFilter > &filter)
virtual bool modifies_transparent_black() const =0
static std::shared_ptr< DlImageFilter > MakeMatrix(const DlMatrix &matrix, DlImageSampling sampling)
static std::shared_ptr< DlImageFilter > MakeErode(DlScalar radius_x, DlScalar radius_y)
static sk_sp< DlImage > Make(const SkImage *image)
bool modifies_transparent_black() const override
DlStrokeCap getStrokeCap() const
DlPaint & setColor(DlColor color)
DlBlendMode getBlendMode() const
float getStrokeMiter() const
DlStrokeJoin getStrokeJoin() const
const DlColorSource * getColorSourcePtr() const
DlPaint & setStrokeWidth(float width)
DlPaint & setAlpha(uint8_t alpha)
DlPaint & setBlendMode(DlBlendMode mode)
const std::shared_ptr< const DlMaskFilter > & getMaskFilter() const
DlDrawStyle getDrawStyle() const
DlPaint & setImageFilter(std::nullptr_t filter)
const std::shared_ptr< const DlColorSource > & getColorSource() const
const std::shared_ptr< DlImageFilter > & getImageFilter() const
float getStrokeWidth() const
const std::shared_ptr< const DlColorFilter > & getColorFilter() const
DlPaint & setDrawStyle(DlDrawStyle style)
DlPaint & setOpacity(DlScalar opacity)
DlPaint & setColorFilter(std::nullptr_t filter)
DlPaint & setColorSource(std::nullptr_t source)
bool isInvertColors() const
DlPathBuilder & LineTo(DlPoint p2)
Draw a line from the current point to the indicated point p2.
DlPathBuilder & MoveTo(DlPoint p2)
Start a new contour that will originate at the indicated point p2.
DlPathBuilder & SetFillType(DlPathFillType fill_type)
Set the fill type that should be used to determine the interior of this path to the indicated |fill_t...
const DlPath TakePath()
Returns the path constructed by this path builder and resets its internal state to the default state ...
DlPathBuilder & AddCircle(DlPoint center, DlScalar radius)
Append a closed circular contour to the path centered on the provided point at the provided radius.
DlPathBuilder & AddRect(const DlRect &rect)
Append a closed rectangular contour to the path.
DlPathBuilder & AddRoundRect(const DlRoundRect &round_rect)
Append a closed rounded rect contour to the path.
DlPathBuilder & Close()
The path is closed back to the location of the most recent MoveTo call. Contours that are filled are ...
const SkPath & GetSkPath() const
Backend implementation of |DlCanvas| for |SkCanvas|.
void DrawDisplayList(const sk_sp< DisplayList > display_list, DlScalar opacity=SK_Scalar1) override
static void DrawShadow(SkCanvas *canvas, const SkPath &path, DlColor color, float elevation, bool transparentOccluder, DlScalar dpr)
static std::shared_ptr< DlTextImpeller > Make(const std::shared_ptr< impeller::TextFrame > &frame)
static std::shared_ptr< DlTextSkia > Make(const sk_sp< SkTextBlob > &blob)
static std::shared_ptr< DlVertices > Make(DlVertexMode mode, int vertex_count, const DlPoint vertices[], const DlPoint texture_coordinates[], const DlColor colors[], int index_count=0, const uint16_t indices[]=nullptr, const DlRect *bounds=nullptr)
Constructs a DlVector with compact inline storage for all of its required and optional lists of data.
BoundsTolerance()=default
bool overflows(DlIRect pix_bounds, int worst_bounds_pad_x, int worst_bounds_pad_y) const
BoundsTolerance addBoundsPadding(DlScalar bounds_pad_x, DlScalar bounds_pad_y) const
static DlRect Scale(const DlRect &rect, const DlPoint &scales)
BoundsTolerance addPostClipPadding(DlScalar absolute_pad_x, DlScalar absolute_pad_y) const
BoundsTolerance mulScale(DlScalar scale_x, DlScalar scale_y) const
BoundsTolerance(const BoundsTolerance &)=default
BoundsTolerance clip(DlRect clip) const
BoundsTolerance addAbsolutePadding(DlScalar absolute_pad_x, DlScalar absolute_pad_y) const
bool operator==(BoundsTolerance const &other) const
BoundsTolerance addDiscreteOffset(DlScalar discrete_offset) const
DlScalar discrete_offset() const
static std::vector< BackendType > TestBackends
static bool checkPixels(const RenderResult *ref_result, const DlRect ref_bounds, const std::string &info, const DlColor bg=DlColor::kTransparent())
static void RenderWithAttributes(const TestParameters &testP, const RenderEnvironment &env, const BoundsTolerance &tolerance)
static int countModifiedTransparentPixels(const RenderResult *ref_result, const RenderResult *test_result)
static void RenderWithStrokes(const TestParameters &testP, const RenderEnvironment &env, const BoundsTolerance &tolerance_in)
static void SetupImpellerFailureImageDirectory()
static void RenderWithSaveRestore(const TestParameters &testP, const RenderEnvironment &env, const BoundsTolerance &tolerance)
static bool SaveImpellerFailureImages
static DirectoryStatus CheckDir(const std::string &dir)
static std::unique_ptr< DlSurfaceProvider > GetProvider(BackendType type)
static void compareToReference(const RenderResult *test_result, const RenderResult *ref_result, const std::string &info, const DlRect *bounds, const BoundsTolerance *tolerance, const DlColor bg, bool fuzzyCompares=false, int width=kTestWidth, int height=kTestHeight, bool printMismatches=false)
static void RenderWithClips(const TestParameters &testP, const RenderEnvironment &env, const BoundsTolerance &diff_tolerance)
static void RenderWith(const TestParameters &testP, const RenderEnvironment &env, const BoundsTolerance &tolerance_in, const CaseParameters &caseP)
static bool quickCompareToReference(const RenderResult *ref_result, const RenderResult *test_result, bool should_match, const std::string &info)
static void checkGroupOpacity(const RenderEnvironment &env, const sk_sp< DisplayList > &display_list, const RenderResult *ref_result, const std::string &info, DlColor bg)
static void save_to_png(const RenderResult *result, const std::string &op_desc, const std::string &reason)
static bool ImpellerSupported
static void showBoundsOverflow(const std::string &info, DlIRect &bounds, const BoundsTolerance *tolerance, int pixLeft, int pixTop, int pixRight, int pixBottom)
static void RenderAll(const TestParameters ¶ms, const BoundsTolerance &tolerance=DefaultTolerance)
static bool AddProvider(BackendType type)
static std::vector< std::string > ImpellerFailureImages
static void ClearProviders()
static bool fuzzyCompare(uint32_t pixel_a, uint32_t pixel_b, int fudge)
static void quickCompareToReference(const RenderEnvironment &env, const std::string &info)
static void RenderWithTransforms(const TestParameters &testP, const RenderEnvironment &env, const BoundsTolerance &tolerance)
static sk_sp< SkTextBlob > MakeTextBlob(const std::string &string, DlScalar font_height)
static BoundsTolerance DefaultTolerance
static std::string ImpellerFailureImageDirectory
static int groupOpacityFudgeFactor(const RenderEnvironment &env)
CaseParameters with_diff_clip()
bool fuzzy_compare_components() const
bool has_mutating_save_layer() const
bool has_diff_clip() const
CaseParameters(std::string info)
SkRenderer sk_restore() const
CaseParameters with_restore(SkRenderer &sk_restore, DlRenderer &dl_restore, bool mutating_layer, bool fuzzy_compare_components=false)
CaseParameters(std::string info, SkSetup &sk_setup, DlSetup &dl_setup, SkRenderer &sk_restore, DlRenderer &dl_restore, DlColor bg, bool has_diff_clip, bool has_mutating_save_layer, bool fuzzy_compare_components)
CaseParameters with_bg(DlColor bg)
CaseParameters(std::string info, SkSetup &sk_setup, DlSetup &dl_setup)
DlRenderer dl_restore() const
void report_results(int all_flags, const sk_sp< DisplayList > &dl, const std::string &desc)
std::unique_ptr< RenderResult > test_data
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)
std::shared_ptr< const DlColorFilter > color_filter_nomtb
std::unique_ptr< RenderResult > test_image_dst_data
std::vector< DlColor > test_dst_colors
void test_mode_color_via_rendering(DlBlendMode mode, DlColor color)
std::unique_ptr< RenderResult > test_image_src_data
int check_color_result(DlColor dst_color, DlColor result_color, const sk_sp< DisplayList > &dl, const std::string &desc)
std::vector< DlColor > test_src_colors
std::shared_ptr< const DlColorFilter > color_filter_mtb
void test_mode_color_via_filter(DlBlendMode mode, DlColor color)
void test_attributes_image(DlBlendMode mode, DlColor color, const DlColorFilter *color_filter, DlImageFilter *image_filter)
std::unique_ptr< RenderResult > get_output(int w, int h, bool snapshot, const std::function< void(SkCanvas *)> &renderer)
DisplayListRenderingTestBase()=default
static void SetUpTestSuite()
static bool StartsWith(std::string str, std::string prefix)
static void TearDownTestSuite()
virtual bool supports(PixelFormat format) const =0
virtual sk_sp< DlImage > MakeImpellerImage(const sk_sp< DisplayList > &list, int width, int height) const
virtual bool supports_impeller() const
static std::string BackendName(BackendType type)
static std::unique_ptr< DlSurfaceProvider > Create(BackendType backend_type)
virtual sk_sp< DlPixelData > ImpellerSnapshot(const sk_sp< DisplayList > &list, int width, int height) const
virtual std::shared_ptr< DlSurfaceInstance > MakeOffscreenSurface(size_t width, size_t height, PixelFormat format=kN32PremulPixelFormat) const =0
virtual BackendType backend_type() const =0
virtual const std::string backend_name() const =0
void write(const std::string &path) const override
int width() const override
~ImpellerRenderResult() override=default
int height() const override
const uint32_t * addr32(int x, int y) const override
sk_sp< SkImage > image() const override
const DlRect & render_bounds() const
ImpellerRenderResult(sk_sp< DlPixelData > screenshot, DlRect render_bounds)
void warn(const std::string &name)
OncePerBackendWarning(const std::string &warning)
std::unique_ptr< RenderResult > getResult(const RenderJobInfo &info, JobRenderer &renderer) const
void init_ref(SkSetup &sk_setup, SkRenderer &sk_renderer, DlSetup &dl_setup, DlRenderer &dl_renderer, DlRenderer &imp_renderer, DlColor bg=DlColor::kTransparent())
std::unique_ptr< ImpellerRenderResult > getImpellerResult(const RenderJobInfo &info, DlJobRenderer &renderer) const
const DlPaint & ref_dl_paint() const
PixelFormat format() const
static RenderEnvironment MakeN32(const DlSurfaceProvider *provider)
const DlMatrix & ref_matrix() const
const DlSurfaceProvider * provider() const
const sk_sp< SkImage > sk_image() const
const sk_sp< DlImage > dl_image() const
RenderEnvironment(const DlSurfaceProvider *provider, PixelFormat format)
static RenderEnvironment Make565(const DlSurfaceProvider *provider)
bool supports_impeller() const
std::unique_ptr< RenderResult > getResult(sk_sp< DisplayList > dl) const
const std::string backend_name() const
const sk_sp< DlImage > impeller_image() const
const RenderResult * ref_dl_result() const
const DlIRect & ref_clip_bounds() const
const ImpellerRenderResult * ref_impeller_result() const
static bool EnableImpeller
const RenderResult * ref_sk_result() const
virtual int width() const =0
virtual const uint32_t * addr32(int x, int y) const =0
virtual int height() const =0
virtual ~RenderResult()=default
virtual sk_sp< SkImage > image() const =0
virtual void write(const std::string &path) const =0
static constexpr SkSamplingOptions kCubic
static constexpr SkSamplingOptions kMipmapLinear
static constexpr SkSamplingOptions kLinear
static constexpr SkSamplingOptions kNearestNeighbor
const uint32_t * addr32(int x, int y) const override
~SkRenderResult() override
SkRenderResult(const sk_sp< SkSurface > &surface, bool take_snapshot=false)
sk_sp< SkImage > image() const override
int width() const override
int height() const override
void write(const std::string &path) const
TestParameters & set_draw_display_list()
TestParameters(const SkRenderer &sk_renderer, const DlRenderer &dl_renderer, const DisplayListAttributeFlags &flags)
const DlRenderer & imp_renderer() const
TestParameters & set_draw_text_blob()
TestParameters & set_vertical_line()
bool ignores_dashes() const
bool is_draw_display_list() const
bool is_draw_arc_center() const
TestParameters(const SkRenderer &sk_renderer, const DlRenderer &dl_renderer, const DlRenderer &imp_renderer, const DisplayListAttributeFlags &flags)
const BoundsTolerance lineAdjust(const BoundsTolerance &tolerance, const DlPaint &paint, const DlMatrix &matrix) const
TestParameters & set_draw_path()
bool uses_gradient() const
TestParameters & set_ignores_dashes()
bool is_draw_path() const
bool is_horizontal_line() const
TestParameters & set_draw_line()
bool is_draw_line() const
TestParameters & set_draw_arc_center()
TestParameters & set_horizontal_line()
bool is_draw_text_blob() const
const BoundsTolerance adjust(const BoundsTolerance &tolerance, const DlPaint &paint, const DlMatrix &matrix) const
bool is_vertical_line() const
const DlRenderer & dl_renderer() const
bool impeller_compatible(const DlPaint &paint) const
bool should_match(const RenderEnvironment &env, const CaseParameters &caseP, const DlPaint &attr, const MatrixClipJobRenderer &renderer) const
DlStrokeCap getCap(const DlPaint &attr, DisplayListSpecialGeometryFlags geo_flags) const
const SkRenderer & sk_renderer() const
#define FOR_EACH_BLEND_MODE_ENUM(FUNC)
const EmbeddedViewParams * params
FlutterVulkanImage * image
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
#define FML_LOG(severity)
#define FML_CHECK(condition)
#define FML_DCHECK(condition)
#define FML_DISALLOW_COPY_AND_ASSIGN(TypeName)
const std::function< void(const SkRenderContext &)> SkRenderer
constexpr int kTestHeight
TEST_F(DisplayListTest, Defaults)
constexpr DlScalar kYOffsetU3
constexpr DlRect kRenderBounds
const std::function< void(const DlSetupContext &)> DlSetup
static void DrawCheckerboard(DlCanvas *canvas)
RenderContext< DlCanvas *, DlPaint &, sk_sp< DlImage > > DlSetupContext
constexpr int kRenderCenterY
constexpr DlScalar kMiter4DiamondOffsetX
const DlPoint kHorizontalMiterDiamondPoints[]
constexpr int kRenderCenterX
constexpr int kRenderRight
RenderContext< SkCanvas *, SkPaint &, sk_sp< SkImage > > SkSetupContext
constexpr DlRect kTestBounds2
constexpr DlScalar kYOffsetD3
static const DlSetup kEmptyDlSetup
static const SkRenderer kEmptySkRenderer
SkFont CreateTestFontOfSize(DlScalar scalar)
constexpr DlScalar kYOffsetU2
sk_sp< DisplayList > makeTestDisplayList()
const int kHorizontalMiterDiamondPointCount
static std::shared_ptr< DlImageColorSource > MakeColorSource(const sk_sp< DlImage > &image)
constexpr DlScalar kYOffsetU1
constexpr DlScalar kMiter4DiamondOffsetY
constexpr int kRenderBottom
constexpr DlScalar kXOffsetR2
constexpr DlScalar kYOffset0
DlSurfaceProvider::PixelFormat PixelFormat
constexpr DlScalar kXOffset0
constexpr int kRenderHeight
const std::function< void(const SkSetupContext &)> SkSetup
constexpr DlScalar kMiterExtremeDiamondOffsetY
constexpr DlScalar kXOffsetL1
constexpr DlScalar kYOffsetD1
constexpr int kRenderWidth
constexpr DlScalar kMiter10DiamondOffsetY
constexpr DlScalar kXOffsetL2
constexpr DlScalar kXOffsetL3
constexpr DlScalar kRenderCornerRadius
constexpr DlScalar kXOffsetR3
const int kVerticalMiterDiamondPointCount
const DlPoint kTestCenter2
constexpr int kRenderLeft
RenderContext< DlCanvas *, const DlPaint &, sk_sp< DlImage > > DlRenderContext
constexpr DlScalar kMiterExtremeDiamondOffsetX
static const DlRenderer kEmptyDlRenderer
static const SkSetup kEmptySkSetup
constexpr DlScalar kMiter10DiamondOffsetX
RenderContext< SkCanvas *, const SkPaint &, sk_sp< SkImage > > SkRenderContext
constexpr DlPoint kVerticalMiterDiamondPoints[]
const std::function< void(const DlRenderContext &)> DlRenderer
constexpr DlScalar kXOffsetR1
constexpr DlScalar kYOffsetD2
constexpr DlScalar kRenderRadius
impeller::Scalar DlScalar
SkPaint ToSk(const DlPaint &paint)
@ kMiter
extends to miter limit
@ kBevel
connects outside edges
const SkPoint & ToSkPoint(const DlPoint &point)
@ kButt
no stroke extension
impeller::Matrix DlMatrix
impeller::Degrees DlDegrees
const SkIRect & ToSkIRect(const DlIRect &rect)
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all 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 keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
@ kLines
draw each separate pair of points as a line segment
@ kPolygon
draw each pair of overlapping points as a line segment
@ kPoints
draw each point separately
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
SkColor4f ToSkColor4f(DlColor color)
DEF_SWITCHES_START aot vmservice shared library name
@ kTriangles
The vertices are taken 3 at a time to form a triangle.
@ kStroke
strokes boundary of shapes
@ kFill
fills interior of shapes
SkMatrix ToSkMatrix(const DlMatrix &matrix)
impeller::IRect32 DlIRect
const DlIRect & ToDlIRect(const SkIRect &rect)
const SkPoint * ToSkPoints(const DlPoint *points)
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all 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
@ kNormal
fuzzy inside and outside
bool NotEquals(const T *a, const U *b)
const SkRRect ToSkRRect(const DlRoundRect &round_rect)
TEST_F(EngineAnimatorTest, AnimatorAcceptsMultipleRenders)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder h
DlMatrix ToDlMatrix(const SkMatrix &matrix)
SkM44 ToSkM44(const DlMatrix &matrix)
const DlRect & ToDlRect(const SkRect &rect)
const SkRect & ToSkRect(const DlRect &rect)
fml::UniqueFD OpenDirectory(const char *path, bool create_if_necessary, FilePermission permission)
const char * BlendModeToString(BlendMode blend_mode)
std::shared_ptr< TextFrame > MakeTextFrameFromTextBlobSkia(const sk_sp< SkTextBlob > &blob)
static constexpr DlColor kMagenta()
static constexpr DlColor kWhite()
static constexpr DlColor kBlue()
static constexpr DlColor kBlack()
static constexpr DlColor kYellow()
static constexpr DlColor kLightGrey()
constexpr DlScalar getRedF() const
constexpr DlScalar getAlphaF() const
constexpr DlScalar getBlueF() const
constexpr DlScalar getGreenF() const
static constexpr DlColor kTransparent()
static constexpr DlColor kRed()
static constexpr DlColor kGreen()
constexpr bool isTransparent() const
static constexpr DlColor kDarkGrey()
static constexpr DlColor kCyan()
constexpr bool isOpaque() const
DlColor withAlpha(uint8_t alpha) const
void Render(SkCanvas *canvas, const RenderJobInfo &info)
DisplayListJobRenderer(sk_sp< DisplayList > display_list)
void Render(DlCanvas *canvas, const RenderJobInfo &info)
sk_sp< DisplayList > MakeDisplayList(const RenderJobInfo &info)
bool targets_impeller() const override
const DlPaint & setup_paint() const
void Render(SkCanvas *sk_canvas, const RenderJobInfo &info) override
DlJobRenderer(const DlSetup &dl_setup, const DlRenderer &dl_render, const DlRenderer &dl_restore, const sk_sp< DlImage > &dl_image)
virtual void Render(SkCanvas *canvas, const RenderJobInfo &info)=0
virtual bool targets_impeller() const
DlIRect setup_clip_bounds_
const DlMatrix & setup_matrix() const
const DlIRect & setup_clip_bounds() const
SkJobRenderer(const SkSetup &sk_setup, const SkRenderer &sk_render, const SkRenderer &sk_restore, const sk_sp< SkImage > &sk_image)
void Render(SkCanvas *canvas, const RenderJobInfo &info) override
const SkPaint & setup_paint() const
sk_sp< SkPicture > MakePicture(const RenderJobInfo &info)
void Render(SkCanvas *canvas, const RenderJobInfo &info)
SkPictureJobRenderer(sk_sp< SkPicture > picture)
A 4x4 matrix using column-major storage.
constexpr Matrix Translate(const Vector3 &t) const
static Matrix MakeRotationY(Radians r)
static constexpr Matrix MakeRow(Scalar m0, Scalar m1, Scalar m2, Scalar m3, Scalar m4, Scalar m5, Scalar m6, Scalar m7, Scalar m8, Scalar m9, Scalar m10, Scalar m11, Scalar m12, Scalar m13, Scalar m14, Scalar m15)
constexpr Matrix Scale(const Vector3 &s) const
static Matrix MakeRotationX(Radians r)
static RoundRect MakeRectXY(const Rect &rect, Scalar x_radius, Scalar y_radius)
constexpr auto GetBottom() const
static constexpr TRect MakeWH(Type width, Type height)
constexpr auto GetTop() const
constexpr TSize< Type > GetSize() const
Returns the size of the rectangle which may be negative in either width or height and may have been c...
constexpr Type GetHeight() const
Returns the height of the rectangle, equivalent to |GetSize().height|.
constexpr bool IsEmpty() const
Returns true if either of the width or height are 0, negative, or NaN.
constexpr T Area() const
Get the area of the rectangle, equivalent to |GetSize().Area()|.
constexpr bool Contains(const TPoint< Type > &p) const
Returns true iff the provided point |p| is inside the half-open interior of this rectangle.
static constexpr std::enable_if_t< std::is_floating_point_v< FT >, TRect > Make(const TRect< U > &rect)
constexpr auto GetLeft() const
constexpr TPoint< T > GetLeftTop() const
RoundOut(const TRect< U > &r)
constexpr auto GetRight() const
static constexpr TRect MakeXYWH(Type x, Type y, Type width, Type height)
constexpr TPoint< T > GetRightBottom() const
constexpr Type GetWidth() const
Returns the width of the rectangle, equivalent to |GetSize().width|.
constexpr TRect< T > Expand(T left, T top, T right, T bottom) const
Returns a rectangle with expanded edges. Negative expansion results in shrinking.
constexpr Point GetCenter() const
Get the center point as a |Point|.
constexpr TRect IntersectionOrEmpty(const TRect &o) const
constexpr TRect< T > Shift(T dx, T dy) const
Returns a new rectangle translated by the given offset.
static constexpr TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
constexpr Type Area() const
std::vector< Point > points