26#include "include/core/SkColor.h"
27#ifdef IMPELLER_SUPPORTS_RENDERING
32#include "third_party/skia/include/core/SkBBHFactory.h"
33#include "third_party/skia/include/core/SkColorFilter.h"
34#include "third_party/skia/include/core/SkColorSpace.h"
35#include "third_party/skia/include/core/SkFontMgr.h"
36#include "third_party/skia/include/core/SkPictureRecorder.h"
37#include "third_party/skia/include/core/SkStream.h"
38#include "third_party/skia/include/core/SkSurface.h"
39#include "third_party/skia/include/core/SkTypeface.h"
40#include "third_party/skia/include/effects/SkDashPathEffect.h"
41#include "third_party/skia/include/effects/SkGradient.h"
42#include "third_party/skia/include/effects/SkImageFilters.h"
43#include "third_party/skia/include/encode/SkPngEncoder.h"
44#include "third_party/skia/include/gpu/ganesh/GrDirectContext.h"
45#include "third_party/skia/include/gpu/ganesh/GrRecordingContext.h"
46#include "third_party/skia/include/gpu/ganesh/GrTypes.h"
162constexpr uint8_t toC(
DlScalar fComp) {
163 return round(fComp * 255);
166constexpr uint32_t PremultipliedArgb(
const DlColor& color) {
171 return (color.
argb() & 0xFF000000) |
172 toC(color.
getRedF() * f) << 16 |
181 SkSamplingOptions(SkFilterMode::kNearest);
183 SkSamplingOptions(SkFilterMode::kLinear);
185 SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear);
186 static constexpr SkSamplingOptions
kCubic =
187 SkSamplingOptions(SkCubicResampler{1 / 3.0f, 1 / 3.0f});
201 for (
int y = 0;
y <
width;
y += cbdim) {
202 for (
int x = 0;
x <
height;
x += cbdim) {
203 DlPaint& cellp = ((
x +
y) & 1) == 0 ? p0 : p1;
215 const sk_sp<DlImage>&
image) {
216 return std::make_shared<DlImageColorSource>(
image,
223 return image->makeShader(SkTileMode::kRepeat,
233 : warning_(warning) {}
236 if (warnings_sent_.find(
name) == warnings_sent_.end()) {
237 warnings_sent_.insert(
name);
243 std::string warning_;
244 std::set<std::string> warnings_sent_;
271 copy.bounds_pad_ +=
DlPoint(bounds_pad_x, bounds_pad_y);
277 copy.scale_ *=
DlPoint(scale_x, scale_y);
284 copy.absolute_pad_ +=
DlPoint(absolute_pad_x, absolute_pad_y);
291 copy.clip_pad_ +=
DlPoint(absolute_pad_x, absolute_pad_y);
310 return rect.
Expand(outset_x, outset_y);
314 int worst_bounds_pad_x,
315 int worst_bounds_pad_y)
const {
317 allowed = allowed.
Expand(bounds_pad_.
x, bounds_pad_.
y);
318 allowed =
Scale(allowed, scale_);
319 allowed = allowed.
Expand(absolute_pad_.
x, absolute_pad_.
y);
321 allowed = allowed.
Expand(clip_pad_.
x, clip_pad_.
y);
323 int pad_left = std::max(0, pix_bounds.
GetLeft() - rounded.
GetLeft());
324 int pad_top = std::max(0, pix_bounds.
GetTop() - rounded.
GetTop());
327 int allowed_pad_x = std::max(pad_left, pad_right);
328 int allowed_pad_y = std::max(pad_top, pad_bottom);
329 if (worst_bounds_pad_x > allowed_pad_x ||
330 worst_bounds_pad_y > allowed_pad_y) {
331 FML_LOG(ERROR) <<
"acceptable bounds padding: "
332 << allowed_pad_x <<
", " << allowed_pad_y;
334 return (worst_bounds_pad_x > allowed_pad_x ||
335 worst_bounds_pad_y > allowed_pad_y);
341 return bounds_pad_ == other.bounds_pad_ && scale_ == other.scale_ &&
342 absolute_pad_ == other.absolute_pad_ && clip_ == other.clip_ &&
343 clip_pad_ == other.clip_pad_ &&
344 discrete_offset_ == other.discrete_offset_;
350 DlPoint absolute_pad_ = {0, 0};
357template <
typename C,
typename P,
typename I>
386 virtual sk_sp<SkImage>
image()
const = 0;
389 virtual const uint32_t*
addr32(
int x,
int y)
const = 0;
396 bool take_snapshot =
false) {
397 SkImageInfo info =
surface->imageInfo();
398 info = SkImageInfo::MakeN32Premul(info.dimensions());
399 addr_ = malloc(info.computeMinByteSize() * info.height());
400 pixmap_.reset(info, addr_, info.minRowBytes());
401 surface->readPixels(pixmap_, 0, 0);
403 image_ =
surface->makeImageSnapshot();
408 sk_sp<SkImage>
image()
const override {
return image_; }
409 int width()
const override {
return pixmap_.width(); }
410 int height()
const override {
return pixmap_.height(); }
411 const uint32_t*
addr32(
int x,
int y)
const override {
412 return pixmap_.addr32(
x,
y);
415 auto stream = SkFILEWStream(
path.c_str());
416 SkPngEncoder::Options options;
417 SkPngEncoder::Encode(&stream, pixmap_, options);
422 sk_sp<SkImage> image_;
424 void* addr_ =
nullptr;
434 sk_sp<SkImage>
image()
const override {
return nullptr; };
435 int width()
const override {
return screenshot_->width(); };
436 int height()
const override {
return screenshot_->height(); }
437 const uint32_t*
addr32(
int x,
int y)
const override {
438 return screenshot_->addr32(
x,
y);
441 screenshot_->write(
path);
446 const sk_sp<DlPixelData> screenshot_;
485 const sk_sp<SkImage>& sk_image)
486 : sk_setup_(sk_setup),
487 sk_render_(sk_render),
488 sk_restore_(sk_restore),
489 sk_image_(sk_image) {}
494 sk_setup_({canvas, paint, sk_image_});
495 setup_paint_ = paint;
499 sk_render_({canvas, paint, sk_image_});
500 sk_restore_({canvas, paint, sk_image_});
504 SkPictureRecorder recorder;
505 SkRTreeFactory rtree_factory;
509 return recorder.finishRecordingAsPicture();
521 sk_sp<SkImage> sk_image_;
522 SkPaint setup_paint_;
529 const sk_sp<DlImage>& dl_image)
530 : dl_setup_(dl_setup),
531 dl_render_(dl_render),
532 dl_restore_(dl_restore),
533 dl_image_(dl_image) {}
543 dl_setup_({canvas, paint, dl_image_});
544 setup_paint_ = paint;
549 dl_render_({canvas, paint, dl_image_});
550 dl_restore_({canvas, paint, dl_image_});
556 return builder.
Build();
565 return dl_image_->impeller_texture() !=
nullptr;
572 const sk_sp<DlImage> dl_image_;
578 : picture_(
std::move(picture)) {}
582 picture_->playback(canvas);
586 sk_sp<SkPicture> picture_;
591 : display_list_(
std::move(display_list)) {}
598 sk_sp<DisplayList> display_list_;
633 ref_sk_result_ =
getResult(info, sk_job);
635 ref_dl_result_ =
getResult(info, dl_job);
642 test_impeller_image_ = makeTestImpellerImage(provider_);
644 test_impeller_image_);
653 auto canvas =
surface->getCanvas();
656 int restore_count = canvas->save();
658 renderer.
Render(canvas, info);
659 canvas->restoreToCount(restore_count);
661 if (GrDirectContext* dContext =
662 GrAsDirectContext(
surface->recordingContext())) {
663 dContext->flushAndSubmit(
surface.get(), GrSyncCpu::kYes);
665 return std::make_unique<SkRenderResult>(
surface);
668 std::unique_ptr<RenderResult>
getResult(sk_sp<DisplayList> dl)
const {
683 auto dl = builder.
Build();
685 return std::make_unique<ImpellerRenderResult>(std::move(snap),
686 render_dl->GetBounds());
703 return ref_impeller_result_.get();
706 const sk_sp<SkImage>
sk_image()
const {
return kTestSkImage; }
707 const sk_sp<DlImage>
dl_image()
const {
return kTestDlImage; }
711 sk_sp<SkSurface> getSurface(
int width,
int height)
const {
716 return surface_1x_->sk_surface();
719 return surface_2x_->sk_surface();
722 <<
") not supported.";
727 const DlSurfaceProvider* provider_;
729 std::shared_ptr<DlSurfaceInstance> surface_1x_;
730 std::shared_ptr<DlSurfaceInstance> surface_2x_;
735 std::unique_ptr<RenderResult> ref_sk_result_;
736 std::unique_ptr<RenderResult> ref_dl_result_;
737 std::unique_ptr<ImpellerRenderResult> ref_impeller_result_;
738 sk_sp<DlImage> test_impeller_image_;
740 static const sk_sp<SkImage> kTestSkImage;
741 static const sk_sp<DlImage> kTestDlImage;
742 static const sk_sp<SkImage> makeTestSkImage() {
743 sk_sp<SkSurface>
surface = SkSurfaces::Raster(
746 return surface->makeImageSnapshot();
748 static const sk_sp<DlImage> makeTestImpellerImage(
749 const DlSurfaceProvider*
provider) {
758const sk_sp<SkImage> RenderEnvironment::kTestSkImage = makeTestSkImage();
759const sk_sp<DlImage> RenderEnvironment::kTestDlImage =
802 bg_, has_diff_clip_, mutating_layer,
807 return CaseParameters(info_, sk_setup_, dl_setup_, sk_restore_, dl_restore_,
808 bg, has_diff_clip_, has_mutating_save_layer_,
809 fuzzy_compare_components_);
813 return CaseParameters(info_, sk_setup_, dl_setup_, sk_restore_, dl_restore_,
814 bg_,
true, has_mutating_save_layer_,
815 fuzzy_compare_components_);
818 std::string
info()
const {
return info_; }
830 const std::string info_;
836 const bool has_diff_clip_;
837 const bool has_mutating_save_layer_;
838 const bool fuzzy_compare_components_;
940 getCap(ref_attr, geo_flags) !=
getCap(attr, geo_flags)) {
952 ref_miter < 1.4 || test_miter < 1.4) {
953 if (ref_miter != test_miter) {
1035 h_tolerance = v_tolerance =
adjust;
1039 return new_tolerance;
1060 is_draw_text_blob_ =
true;
1064 is_draw_display_list_ =
true;
1068 is_draw_line_ =
true;
1072 is_draw_arc_center_ =
true;
1076 is_draw_path_ =
true;
1080 ignores_dashes_ =
true;
1084 is_horizontal_line_ =
true;
1088 is_vertical_line_ =
true;
1098 bool is_draw_text_blob_ =
false;
1099 bool is_draw_display_list_ =
false;
1100 bool is_draw_line_ =
false;
1101 bool is_draw_arc_center_ =
false;
1102 bool is_draw_path_ =
false;
1103 bool ignores_dashes_ =
false;
1104 bool is_horizontal_line_ =
false;
1105 bool is_vertical_line_ =
false;
1118 if (provider ==
nullptr) {
1120 <<
" not supported (ignoring)";
1124 PixelFormat::kN32PremulPixelFormat);
1135 if (provider->supports_impeller()) {
1154 if (!
checkPixels(impeller_result, impeller_result->render_bounds(),
1155 "Impeller reference")) {
1156 std::string test_name =
1157 ::testing::UnitTest::GetInstance()->current_test_info()->name();
1158 save_to_png(impeller_result, test_name +
" (Impeller reference)",
1159 "base rendering was blank or out of bounds");
1170 if (
params.uses_paint()) {
1187 ctx.canvas->restore();
1196 ctx.canvas->DrawRect(
1199 ctx.canvas->Restore();
1203 ctx.canvas->restore();
1207 ctx.canvas->Restore();
1212 "With prior save/clip/restore",
1215 ctx.canvas->clipRect(
ToSkRect(clip), SkClipOp::kIntersect,
1218 ctx.canvas->drawRect(
ToSkRect(rect), p2);
1219 p2.setBlendMode(SkBlendMode::kClear);
1220 ctx.canvas->drawRect(
ToSkRect(rect), p2);
1221 ctx.canvas->restore();
1227 ctx.canvas->DrawRect(rect, p2);
1229 ctx.canvas->DrawRect(rect, p2);
1230 ctx.canvas->Restore();
1234 "saveLayer no paint, no bounds",
1236 ctx.canvas->saveLayer(
nullptr,
nullptr);
1239 ctx.canvas->SaveLayer(std::nullopt,
nullptr);
1241 .with_restore(sk_safe_restore, dl_safe_restore,
false));
1244 "saveLayer no paint, with bounds",
1246 ctx.canvas->saveLayer(
ToSkRect(layer_bounds),
nullptr);
1249 ctx.canvas->SaveLayer(layer_bounds,
nullptr);
1251 .with_restore(sk_safe_restore, dl_safe_restore,
true));
1254 "saveLayer with alpha, no bounds",
1258 ctx.canvas->saveLayer(
nullptr, &save_p);
1262 save_p.
setColor(alpha_layer_color);
1263 ctx.canvas->SaveLayer(std::nullopt, &save_p);
1265 .with_restore(sk_safe_restore, dl_safe_restore,
true));
1268 "saveLayer with peephole alpha, no bounds",
1272 ctx.canvas->saveLayer(
nullptr, &save_p);
1276 save_p.
setColor(alpha_layer_color);
1277 ctx.canvas->SaveLayer(std::nullopt, &save_p);
1279 .with_restore(sk_opt_restore, dl_opt_restore,
true,
true));
1282 "saveLayer with alpha and bounds",
1286 ctx.canvas->saveLayer(
ToSkRect(layer_bounds), &save_p);
1290 save_p.
setColor(alpha_layer_color);
1291 ctx.canvas->SaveLayer(layer_bounds, &save_p);
1293 .with_restore(sk_safe_restore, dl_safe_restore,
true));
1307 ctx.canvas->drawPaint(setup_p);
1312 ctx.canvas->DrawPaint(setup_p);
1315 ctx.paint.
setAlpha(ctx.paint.getAlpha() / 2);
1318 ctx.paint.
setAlpha(ctx.paint.getAlpha() / 2);
1327 SkImageFilters::Blur(5, 5, SkTileMode::kDecal,
nullptr);
1329 testP, backdrop_env, tolerance,
1331 "saveLayer with backdrop",
1333 sk_backdrop_setup(ctx);
1334 ctx.canvas->saveLayer(
1335 SkCanvas::SaveLayerRec(
nullptr,
nullptr, sk_backdrop.get(),
1336 SkTileMode::kDecal,
nullptr, 0));
1337 sk_content_setup(ctx);
1340 dl_backdrop_setup(ctx);
1341 ctx.canvas->SaveLayer(std::nullopt,
nullptr, &dl_backdrop);
1342 dl_content_setup(ctx);
1344 .with_restore(sk_safe_restore, dl_safe_restore,
true));
1347 "saveLayer with bounds and backdrop",
1349 sk_backdrop_setup(ctx);
1350 ctx.canvas->saveLayer(SkCanvas::SaveLayerRec(
1351 &
ToSkRect(layer_bounds),
nullptr, sk_backdrop.get(),
1352 SkTileMode::kDecal,
nullptr, 0));
1353 sk_content_setup(ctx);
1356 dl_backdrop_setup(ctx);
1357 ctx.canvas->SaveLayer(layer_bounds,
nullptr,
1359 dl_content_setup(ctx);
1361 .with_restore(sk_safe_restore, dl_safe_restore,
true));
1363 testP, backdrop_env, tolerance,
1365 "clipped saveLayer with backdrop",
1367 sk_backdrop_setup(ctx);
1368 ctx.canvas->clipRect(
ToSkRect(layer_bounds));
1369 ctx.canvas->saveLayer(
1370 SkCanvas::SaveLayerRec(
nullptr,
nullptr, sk_backdrop.get(),
1371 SkTileMode::kDecal,
nullptr, 0));
1372 sk_content_setup(ctx);
1375 dl_backdrop_setup(ctx);
1376 ctx.canvas->ClipRect(layer_bounds);
1377 ctx.canvas->SaveLayer(std::nullopt,
nullptr, &dl_backdrop);
1378 dl_content_setup(ctx);
1380 .with_restore(sk_safe_restore, dl_safe_restore,
true));
1385 constexpr float rotate_alpha_color_matrix[20] = {
1392 auto dl_alpha_rotate_filter =
1394 auto sk_alpha_rotate_filter =
1395 SkColorFilters::Matrix(rotate_alpha_color_matrix);
1399 "saveLayer ColorFilter, no bounds",
1402 save_p.setColorFilter(sk_alpha_rotate_filter);
1403 ctx.canvas->saveLayer(
nullptr, &save_p);
1404 ctx.paint.setStrokeWidth(5.0);
1409 ctx.canvas->SaveLayer(std::nullopt, &save_p);
1412 .with_restore(sk_safe_restore, dl_safe_restore,
true));
1417 "saveLayer ColorFilter and bounds",
1420 save_p.setColorFilter(sk_alpha_rotate_filter);
1423 ctx.paint.setStrokeWidth(5.0);
1431 .with_restore(sk_safe_restore, dl_safe_restore,
true));
1437 constexpr float color_matrix[20] = {
1446 auto sk_cf_image_filter = SkImageFilters::ColorFilter(
1447 SkColorFilters::Matrix(color_matrix),
nullptr);
1451 "saveLayer ImageFilter, no bounds",
1454 save_p.setImageFilter(sk_cf_image_filter);
1455 ctx.canvas->saveLayer(
nullptr, &save_p);
1456 ctx.paint.setStrokeWidth(5.0);
1461 ctx.canvas->SaveLayer(std::nullopt, &save_p);
1464 .with_restore(sk_safe_restore, dl_safe_restore,
true));
1469 "saveLayer ImageFilter and bounds",
1472 save_p.setImageFilter(sk_cf_image_filter);
1475 ctx.paint.setStrokeWidth(5.0);
1483 .with_restore(sk_safe_restore, dl_safe_restore,
true));
1501 ctx.canvas->translate(0.1, 0.1);
1502 ctx.paint.setAntiAlias(is_aa);
1503 ctx.paint.setStrokeWidth(5.0);
1506 ctx.canvas->Translate(0.1, 0.1);
1507 ctx.paint.setAntiAlias(is_aa);
1508 ctx.paint.setStrokeWidth(5.0);
1517 testP, aa_env, aa_tolerance,
1519 "AntiAlias == True",
1523 testP, aa_env, aa_tolerance,
1525 "AntiAlias == False",
1531 testP, env, tolerance,
1535 ctx.paint.setColor(SK_ColorBLUE);
1541 testP, env, tolerance,
1545 ctx.paint.setColor(SK_ColorGREEN);
1562 ctx.paint.setBlendMode(SkBlendMode::kSrcIn);
1563 ctx.paint.setColor(blendable_color.
argb());
1566 ctx.paint.setBlendMode(DlBlendMode::kSrcIn);
1567 ctx.paint.setColor(blendable_color);
1574 ctx.paint.setBlendMode(SkBlendMode::kDstIn);
1575 ctx.paint.setColor(blendable_color.
argb());
1578 ctx.paint.setBlendMode(DlBlendMode::kDstIn);
1579 ctx.paint.setColor(blendable_color);
1591 ctx.paint.setStrokeWidth(5.0);
1595 ctx.paint.setStrokeWidth(5.0);
1602 auto sk_filter_decal_5 =
1603 SkImageFilters::Blur(5.0, 5.0, SkTileMode::kDecal,
nullptr);
1606 RenderWith(testP, blur_env, blur_5_tolerance,
1608 "ImageFilter == Decal Blur 5",
1611 ctx.paint.setImageFilter(sk_filter_decal_5);
1615 ctx.paint.setImageFilter(&dl_filter_decal_5);
1619 auto sk_filter_clamp_5 =
1620 SkImageFilters::Blur(5.0, 5.0, SkTileMode::kClamp,
nullptr);
1622 RenderWith(testP, blur_env, blur_5_tolerance,
1624 "ImageFilter == Clamp Blur 5",
1627 ctx.paint.setImageFilter(sk_filter_clamp_5);
1631 ctx.paint.setImageFilter(&dl_filter_clamp_5);
1643 ctx.paint.setStrokeWidth(5.0);
1647 ctx.paint.setStrokeWidth(5.0);
1654 auto sk_dilate_filter_5 = SkImageFilters::Dilate(5.0, 5.0,
nullptr);
1657 "ImageFilter == Dilate 5",
1659 sk_dilate_setup(ctx);
1660 ctx.paint.setImageFilter(sk_dilate_filter_5);
1663 dl_dilate_setup(ctx);
1664 ctx.paint.setImageFilter(&dl_dilate_filter_5);
1675 ctx.paint.setStrokeWidth(6.0);
1679 ctx.paint.setStrokeWidth(6.0);
1688 auto sk_erode_filter_1 = SkImageFilters::Erode(1.0, 1.0,
nullptr);
1691 "ImageFilter == Erode 1",
1693 sk_erode_setup(ctx);
1694 ctx.paint.setImageFilter(sk_erode_filter_1);
1697 dl_erode_setup(ctx);
1698 ctx.paint.setImageFilter(&dl_erode_filter_1);
1704 constexpr float rotate_color_matrix[20] = {
1710 constexpr float invert_color_matrix[20] = {
1714 1.0, 1.0, 1.0, 1.0, 0,
1718 auto sk_color_filter = SkColorFilters::Matrix(rotate_color_matrix);
1723 "ColorFilter == RotateRGB",
1725 ctx.paint.setColor(SK_ColorYELLOW);
1726 ctx.paint.setColorFilter(sk_color_filter);
1730 ctx.paint.setColorFilter(dl_color_filter);
1738 "ColorFilter == Invert",
1740 ctx.paint.setColor(SK_ColorYELLOW);
1741 ctx.paint.setColorFilter(
1742 SkColorFilters::Matrix(invert_color_matrix));
1746 ctx.paint.setInvertColors(
true);
1754 auto sk_mask_filter = SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, 5.0);
1760 "MaskFilter == Blur 5",
1762 ctx.paint.setStrokeWidth(5.0);
1763 ctx.paint.setMaskFilter(sk_mask_filter);
1766 ctx.paint.setStrokeWidth(5.0);
1767 ctx.paint.setMaskFilter(&dl_mask_filter);
1782 SkColor4f sk_colors[] = {
1784 SkColors::kYellow.
withAlpha(127.0f / 255.0f),
1795 auto sk_gradient = SkShaders::LinearGradient(
1797 SkGradient(SkGradient::Colors(sk_colors, stops, SkTileMode::kMirror),
1798 SkGradient::Interpolation()),
1803 "LinearGradient GYB",
1805 ctx.paint.setShader(sk_gradient);
1809 ctx.paint.setColorSource(dl_gradient);
1827 ctx.paint.setStyle(SkPaint::kFill_Style);
1843 "Stroke + defaults",
1846 ctx.paint.setStrokeWidth(1.0);
1848 ctx.paint.setStyle(SkPaint::kStroke_Style);
1852 ctx.paint.setStrokeWidth(1.0);
1859 "Fill + unnecessary StrokeWidth 10",
1861 ctx.paint.setStyle(SkPaint::kFill_Style);
1862 ctx.paint.setStrokeWidth(10.0);
1866 ctx.paint.setStrokeWidth(10.0);
1872 ctx.paint.setStyle(SkPaint::kStroke_Style);
1873 ctx.paint.setStrokeWidth(5.0);
1877 ctx.paint.setStrokeWidth(5.0);
1884 RenderWith(testP, stroke_base_env, tolerance,
1888 ctx.paint.setStyle(SkPaint::kStroke_Style);
1889 ctx.paint.setStrokeWidth(10.0);
1893 ctx.paint.setStrokeWidth(10.0);
1895 RenderWith(testP, stroke_base_env, tolerance,
1899 ctx.paint.setStyle(SkPaint::kStroke_Style);
1900 ctx.paint.setStrokeWidth(5.0);
1904 ctx.paint.setStrokeWidth(5.0);
1907 RenderWith(testP, stroke_base_env, tolerance,
1909 "Stroke Width 5, Square Cap",
1911 ctx.paint.setStyle(SkPaint::kStroke_Style);
1912 ctx.paint.setStrokeWidth(5.0);
1913 ctx.paint.setStrokeCap(SkPaint::kSquare_Cap);
1917 ctx.paint.setStrokeWidth(5.0);
1920 RenderWith(testP, stroke_base_env, tolerance,
1922 "Stroke Width 5, Round Cap",
1924 ctx.paint.setStyle(SkPaint::kStroke_Style);
1925 ctx.paint.setStrokeWidth(5.0);
1926 ctx.paint.setStrokeCap(SkPaint::kRound_Cap);
1930 ctx.paint.setStrokeWidth(5.0);
1934 RenderWith(testP, stroke_base_env, tolerance,
1936 "Stroke Width 5, Bevel Join",
1938 ctx.paint.setStyle(SkPaint::kStroke_Style);
1939 ctx.paint.setStrokeWidth(5.0);
1940 ctx.paint.setStrokeJoin(SkPaint::kBevel_Join);
1944 ctx.paint.setStrokeWidth(5.0);
1947 RenderWith(testP, stroke_base_env, tolerance,
1949 "Stroke Width 5, Round Join",
1951 ctx.paint.setStyle(SkPaint::kStroke_Style);
1952 ctx.paint.setStrokeWidth(5.0);
1953 ctx.paint.setStrokeJoin(SkPaint::kRound_Join);
1957 ctx.paint.setStrokeWidth(5.0);
1961 RenderWith(testP, stroke_base_env, tolerance,
1963 "Stroke Width 5, Miter 10",
1965 ctx.paint.setStyle(SkPaint::kStroke_Style);
1966 ctx.paint.setStrokeWidth(5.0);
1967 ctx.paint.setStrokeMiter(10.0);
1968 ctx.paint.setStrokeJoin(SkPaint::kMiter_Join);
1972 ctx.paint.setStrokeWidth(5.0);
1973 ctx.paint.setStrokeMiter(10.0);
1977 RenderWith(testP, stroke_base_env, tolerance,
1979 "Stroke Width 5, Miter 0",
1981 ctx.paint.setStyle(SkPaint::kStroke_Style);
1982 ctx.paint.setStrokeWidth(5.0);
1983 ctx.paint.setStrokeMiter(0.0);
1984 ctx.paint.setStrokeJoin(SkPaint::kMiter_Join);
1988 ctx.paint.setStrokeWidth(5.0);
1989 ctx.paint.setStrokeMiter(0.0);
2002 testP, env, tolerance,
2005 [=](
const SkSetupContext& ctx) { ctx.canvas->translate(5, 10); },
2006 [=](
const DlSetupContext& ctx) { ctx.canvas->Translate(5, 10); }));
2008 testP, env, tolerance,
2011 [=](
const SkSetupContext& ctx) { ctx.canvas->scale(1.05, 1.05); },
2012 [=](
const DlSetupContext& ctx) { ctx.canvas->Scale(1.05, 1.05); }));
2014 testP, env, skewed_tolerance,
2020 testP, env, skewed_tolerance,
2023 [=](
const SkSetupContext& ctx) { ctx.canvas->skew(0.05, 0.05); },
2024 [=](
const DlSetupContext& ctx) { ctx.canvas->Skew(0.05, 0.05); }));
2036 1.0 + tweak, tweak, 0, 5,
2037 tweak, 1.0 + tweak, 0, 10,
2043 testP, env, skewed_tolerance,
2045 "Transform 2D Affine Matrix",
2050 ctx.canvas->Transform(matrix);
2053 testP, env, skewed_tolerance,
2055 "Transform 2D Affine inline",
2057 ctx.canvas->concat(SkMatrix::MakeAll(1.0 + tweak, tweak, 5,
2058 tweak, 1.0 + tweak, 10,
2062 ctx.canvas->Transform2DAffine(1.0 + tweak, tweak, 5,
2063 tweak, 1.0 + tweak, 10);
2069 0.0f, 0.0f, 1.0f, 0.0f,
2070 0.0f, 0.0f, .001f, 1.0f);
2075 testP, env, skewed_tolerance,
2077 "Transform Full Perspective Matrix",
2079 ctx.canvas->concat(
ToSkM44(matrix));
2082 ctx.canvas->Transform(matrix);
2085 testP, env, skewed_tolerance,
2087 "Transform Full Perspective inline",
2089 ctx.canvas->concat(SkM44(
2092 0.997564, 0.000000, 0.069756, 0.243591,
2093 0.003651, 0.998630, -0.052208, -0.228027,
2094 -0.069661, 0.052336, 0.996197, 1.732491,
2095 -0.000070, 0.000052, 0.000996, 1.001732
2100 ctx.canvas->TransformFullPerspective(
2103 0.997564, 0.000000, 0.069756, 0.243591,
2104 0.003651, 0.998630, -0.052208, -0.228027,
2105 -0.069661, 0.052336, 0.996197, 1.732491,
2106 -0.000070, 0.000052, 0.000996, 1.001732
2129 "Hard ClipRect inset by 15.4",
2131 ctx.canvas->clipRect(
ToSkRect(r_clip),
2132 SkClipOp::kIntersect,
false);
2139 "AntiAlias ClipRect inset by 15.4",
2141 ctx.canvas->clipRect(
ToSkRect(r_clip),
2142 SkClipOp::kIntersect,
true);
2149 "Hard ClipRect Diff, inset by 15.4",
2151 ctx.canvas->clipRect(
ToSkRect(r_clip),
2152 SkClipOp::kDifference,
false);
2163 ctx.canvas->clipRRect(SkRRect::MakeOval(
ToSkRect(r_clip)),
2164 SkClipOp::kIntersect,
false);
2171 "AntiAlias ClipOval",
2174 ctx.canvas->clipRRect(SkRRect::MakeOval(
ToSkRect(r_clip)),
2175 SkClipOp::kIntersect,
true);
2182 "Hard ClipOval Diff",
2185 ctx.canvas->clipRRect(SkRRect::MakeOval(
ToSkRect(r_clip)),
2186 SkClipOp::kDifference,
false);
2200 "Hard ClipRRect with radius of 9",
2202 ctx.canvas->clipRRect(
ToSkRRect(rr_clip),
2203 SkClipOp::kIntersect,
false);
2211 "AntiAlias ClipRRect with radius of 9",
2213 ctx.canvas->clipRRect(
ToSkRRect(rr_clip),
2214 SkClipOp::kIntersect,
true);
2222 "Hard ClipRRect Diff, with radius of 9",
2224 ctx.canvas->clipRRect(
ToSkRRect(rr_clip),
2225 SkClipOp::kDifference,
false);
2236 DlPath path_clip = path_builder.TakePath();
2239 "Hard ClipPath inset by 15.4",
2241 ctx.canvas->clipPath(path_clip.
GetSkPath(),
2242 SkClipOp::kIntersect,
false);
2250 "AntiAlias ClipPath inset by 15.4",
2252 ctx.canvas->clipPath(path_clip.
GetSkPath(),
2253 SkClipOp::kIntersect,
true);
2261 "Hard ClipPath Diff, inset by 15.4",
2263 ctx.canvas->clipPath(path_clip.
GetSkPath(),
2264 SkClipOp::kDifference,
false);
2282 if (ret.is_valid()) {
2287 if (ret.is_valid()) {
2290 FML_LOG(ERROR) <<
"Could not create directory (" << dir
2291 <<
") for impeller failure images" <<
", ret = " << ret.get()
2292 <<
", errno = " << errno;
2297 std::string base_dir =
"./impeller_failure_images";
2301 for (
int i = 0;
i < 10000;
i++) {
2302 std::string sub_dir = std::to_string(
i);
2303 while (sub_dir.length() < 4) {
2304 sub_dir =
"0" + sub_dir;
2306 std::string try_dir = base_dir +
"/" + sub_dir;
2317 FML_LOG(ERROR) <<
"Too many output directories for Impeller failure images";
2321 const std::string& op_desc,
2322 const std::string& reason) {
2335 for (
const char& ch : op_desc) {
2336 filename += (ch ==
':' || ch ==
' ') ?
'_' : ch;
2338 filename = filename +
".png";
2339 result->
write(filename);
2341 FML_LOG(ERROR) << reason <<
": " << filename;
2348 std::string test_name =
2349 ::testing::UnitTest::GetInstance()->current_test_info()->name();
2350 const std::string info =
2363 auto sk_result = env.
getResult(base_info, sk_job);
2369 auto dl_result = env.
getResult(base_info, dl_job);
2375 ASSERT_EQ(sk_result->width(),
kTestWidth) << info;
2376 ASSERT_EQ(sk_result->height(),
kTestHeight) << info;
2377 ASSERT_EQ(dl_result->width(),
kTestWidth) << info;
2378 ASSERT_EQ(dl_result->height(),
kTestHeight) << info;
2382 const sk_sp<SkPicture> sk_picture = sk_job.
MakePicture(base_info);
2383 const sk_sp<DisplayList> display_list = dl_job.
MakeDisplayList(base_info);
2386 checkPixels(sk_result.get(), sk_bounds, info +
" (Skia reference)", bg);
2390 info +
" (attribute should not have effect)");
2393 info +
" (attribute should affect rendering)");
2408 std::string imp_info = info +
" (Impeller)";
2409 bool success =
checkPixels(imp_result.get(), imp_result->render_bounds(),
2412 success = success &&
2415 imp_info +
" (attribute should not have effect)");
2417 success = success &&
2420 imp_info +
" (attribute should affect rendering)");
2423 FML_LOG(ERROR) <<
"Impeller issue encountered for: "
2425 save_to_png(imp_result.get(), info +
" (Impeller Result)",
2428 "compare to reference without attributes");
2429 save_to_png(sk_result.get(), info +
" (Skia Result)",
2430 "and to Skia reference with attributes");
2432 "and to Skia reference without attributes");
2437 info +
" (DlCanvas output matches SkCanvas)");
2440 DlRect dl_bounds = display_list->GetBounds();
2442 if (!sk_padded_bounds.
Contains(dl_bounds)) {
2443 FML_LOG(ERROR) <<
"For " << info;
2444 FML_LOG(ERROR) <<
"sk ref: " << sk_bounds;
2445 FML_LOG(ERROR) <<
"dl: " << dl_bounds;
2446 if (!dl_bounds.
Contains(sk_bounds)) {
2447 FML_LOG(ERROR) <<
"DisplayList bounds are too small!";
2451 FML_LOG(ERROR) <<
"###### DisplayList bounds larger than reference!";
2467 EXPECT_EQ(
static_cast<int>(display_list->op_count()),
2468 sk_picture->approximateOpCount())
2470 EXPECT_EQ(
static_cast<int>(display_list->op_count()),
2471 sk_picture->approximateOpCount())
2476 auto dl_builder_result = env.
getResult(base_info, dl_builder_job);
2479 dl_builder_result.get(), dl_result.get(),
2480 info +
" (DlCanvas DL output close to Builder Dl output)",
2481 &dl_bounds, &tolerance, bg,
true);
2484 dl_builder_result.get(), dl_result.get(),
true,
2485 info +
" (DlCanvas DL output matches Builder Dl output)");
2489 info +
" (DisplayList built directly -> surface)",
2490 &dl_bounds, &tolerance, bg,
2493 if (display_list->can_apply_group_opacity()) {
2495 info +
" with Group Opacity", bg);
2511 .
width = test_width_2,
2512 .height = test_height_2,
2514 .scale = test_scale,
2516 auto ref_x2_result = env.
getResult(info_2x, sk_job_x2);
2517 ASSERT_EQ(ref_x2_result->width(), test_width_2) << info;
2518 ASSERT_EQ(ref_x2_result->height(), test_height_2) << info;
2521 auto test_x2_result = env.
getResult(info_2x, dl_job_x2);
2523 info +
" (Both rendered scaled 2x)",
nullptr,
nullptr,
2525 test_width_2, test_height_2,
false);
2530 for (
int i = 0;
i < 32;
i += 8) {
2531 int comp_a = (pixel_a >>
i) & 0xff;
2532 int comp_b = (pixel_b >>
i) & 0xff;
2533 if (std::abs(comp_a - comp_b) > fudge) {
2541 if (env.
format() == PixelFormat::k565PixelFormat) {
2552 const sk_sp<DisplayList>& display_list,
2554 const std::string& info,
2563 auto group_opacity_result = env.
getResult(opacity_info, opacity_job);
2565 ASSERT_EQ(group_opacity_result->width(),
kTestWidth) << info;
2566 ASSERT_EQ(group_opacity_result->height(),
kTestHeight) << info;
2571 int pixels_touched = 0;
2572 int pixels_different = 0;
2584 const uint32_t* ref_row = ref_result->
addr32(0,
y);
2585 const uint32_t* test_row = group_opacity_result->addr32(0,
y);
2587 uint32_t ref_pixel = ref_row[
x];
2588 uint32_t test_pixel = test_row[
x];
2589 if (ref_pixel != bg.
argb() || test_pixel != bg.
argb()) {
2591 for (
int i = 0;
i < 32;
i += 8) {
2592 int ref_comp = (ref_pixel >>
i) & 0xff;
2593 int bg_comp = (bg.
argb() >>
i) & 0xff;
2594 DlScalar faded_comp = bg_comp + (ref_comp - bg_comp) * opacity;
2595 int test_comp = (test_pixel >>
i) & 0xff;
2596 if (std::abs(faded_comp - test_comp) > fudge) {
2597 int diff = std::abs(faded_comp - test_comp);
2598 if (max_diff < diff) {
2608 ASSERT_GT(pixels_touched, 20) << info;
2609 if (pixels_different > 1) {
2610 FML_LOG(ERROR) <<
"max diff == " << max_diff <<
" for " << info;
2612 ASSERT_LE(pixels_different, 1) << info;
2617 const std::string& info,
2619 uint32_t untouched = PremultipliedArgb(bg);
2620 int pixels_touched = 0;
2626 const uint32_t* ref_row = ref_result->
addr32(0,
y);
2628 if (ref_row[
x] != untouched) {
2636 EXPECT_EQ(pixels_oob, 0) << info;
2637 EXPECT_GT(pixels_touched, 0) << info;
2638 return pixels_oob == 0 && pixels_touched > 0;
2645 const uint32_t* ref_row = ref_result->
addr32(0,
y);
2646 const uint32_t* test_row = test_result->
addr32(0,
y);
2648 if (ref_row[
x] != test_row[
x]) {
2649 if (ref_row[
x] == 0) {
2659 const std::string& info) {
2661 info +
" reference rendering");
2667 const std::string& info) {
2668 int w = test_result->
width();
2669 int h = test_result->
height();
2670 EXPECT_EQ(w, ref_result->
width()) << info;
2671 EXPECT_EQ(
h, ref_result->
height()) << info;
2672 int pixels_different = 0;
2673 for (
int y = 0;
y <
h;
y++) {
2674 const uint32_t* ref_row = ref_result->
addr32(0,
y);
2675 const uint32_t* test_row = test_result->
addr32(0,
y);
2676 for (
int x = 0;
x < w;
x++) {
2677 if (ref_row[
x] != test_row[
x]) {
2678 if (should_match && pixels_different < 5) {
2679 FML_LOG(ERROR) << std::hex << ref_row[
x] <<
" != " << test_row[
x];
2686 EXPECT_EQ(pixels_different, 0) << info;
2687 return pixels_different == 0;
2689 EXPECT_NE(pixels_different, 0) << info;
2690 return pixels_different != 0;
2696 const std::string& info,
2700 bool fuzzyCompares =
false,
2703 bool printMismatches =
false) {
2704 uint32_t untouched = PremultipliedArgb(bg);
2705 ASSERT_EQ(test_result->
width(),
width) << info;
2710 int pixels_different = 0;
2717 const uint32_t* ref_row = ref_result->
addr32(0,
y);
2718 const uint32_t* test_row = test_result->
addr32(0,
y);
2720 if (bounds && test_row[
x] != untouched) {
2737 bool match = fuzzyCompares ?
fuzzyCompare(test_row[
x], ref_row[
x], 1)
2738 : test_row[
x] == ref_row[
x];
2740 if (printMismatches && pixels_different < 5) {
2741 FML_LOG(ERROR) <<
"pix[" <<
x <<
", " <<
y
2742 <<
"] mismatch: " << std::hex << test_row[
x]
2743 <<
"(test) != (ref)" << ref_row[
x] << std::dec;
2749 if (pixels_oob > 0) {
2750 FML_LOG(ERROR) <<
"pix bounds["
2753 FML_LOG(ERROR) <<
"dl_bounds[" << bounds <<
"]";
2754 }
else if (bounds) {
2757 ASSERT_EQ(pixels_oob, 0) << info;
2758 ASSERT_EQ(pixels_different, 0) << info;
2768 int pad_left = std::max(0, pixLeft - bounds.
GetLeft());
2769 int pad_top = std::max(0, pixTop - bounds.
GetTop());
2770 int pad_right = std::max(0, bounds.
GetRight() - pixRight);
2771 int pad_bottom = std::max(0, bounds.
GetBottom() - pixBottom);
2775 int pix_width = pix_size.
width;
2776 int pix_height = pix_size.
height;
2777 int worst_pad_x = std::max(pad_left, pad_right);
2778 int worst_pad_y = std::max(pad_top, pad_bottom);
2779 if (tolerance->
overflows(pix_bounds, worst_pad_x, worst_pad_y)) {
2780 FML_LOG(ERROR) <<
"Computed bounds for " << info;
2781 FML_LOG(ERROR) <<
"pix bounds["
2782 << pixLeft <<
", " << pixTop <<
" => "
2783 << pixRight <<
", " << pixBottom
2785 FML_LOG(ERROR) <<
"dl_bounds[" << bounds <<
"]";
2786 FML_LOG(ERROR) <<
"Bounds overly conservative by up to "
2787 << worst_pad_x <<
", " << worst_pad_y
2788 <<
" (" << (worst_pad_x * 100.0 / pix_width)
2789 <<
"%, " << (worst_pad_y * 100.0 / pix_height) <<
"%)";
2790 int pix_area = pix_size.
Area();
2791 int dl_area = bounds.
Area();
2792 FML_LOG(ERROR) <<
"Total overflow area: " << (dl_area - pix_area)
2793 <<
" (+" << (dl_area * 100.0 / pix_area - 100.0)
2802 sk_sp<SkTypeface> face = font.refTypeface();
2804 FML_CHECK(face->countGlyphs() > 0) <<
"No glyphs in font";
2805 return SkTextBlob::MakeFromText(
string.c_str(),
string.
size(), font,
2806 SkTextEncoding::kUTF8);
2823template <
typename BaseT>
2830 if (prefix.length() > str.length()) {
2833 for (
size_t i = 0;
i < prefix.length();
i++) {
2834 if (str[
i] != prefix[
i]) {
2842 bool do_software =
true;
2843 bool do_opengl =
false;
2844 bool do_metal =
false;
2845 std::vector<std::string>
args = ::testing::internal::GetArgvs();
2846 for (
auto p_arg = std::next(
args.begin()); p_arg !=
args.end(); p_arg++) {
2847 std::string arg = *p_arg;
2849 if (arg ==
"--save-impeller-failures") {
2855 arg =
"-" + arg.substr(4);
2858 arg =
"--en" + arg.substr(5);
2860 if (arg ==
"--enable-software") {
2861 do_software = enable;
2862 }
else if (arg ==
"--enable-opengl" || arg ==
"--enable-gl") {
2864 }
else if (arg ==
"--enable-metal") {
2866 }
else if (arg ==
"--enable-impeller") {
2882 std::string providers =
"";
2886 std::string libraries =
" Skia";
2889 libraries +=
" Impeller";
2891 FML_LOG(INFO) <<
"Running tests on [" << providers
2892 <<
" ], and [" << libraries <<
" ]";
2899 <<
" images saved in "
2902 FML_LOG(INFO) <<
" " << filename;
2917 ctx.canvas->drawPaint(ctx.paint);
2920 ctx.canvas->DrawPaint(ctx.paint);
2935 SkColor color = SkColorSetA(SK_ColorMAGENTA, ctx.paint.getAlpha());
2936 ctx.canvas->drawColor(color);
2944 ctx.canvas->DrawColor(
2955 ctx.canvas->drawColor(0x7FFF00FF);
2958 ctx.canvas->DrawColor(
DlColor(0x7FFF00FF));
2983 SkPaint p = ctx.paint;
2984 p.setStyle(SkPaint::kStroke_Style);
2991 ctx.canvas->DrawLine(p1, p2, ctx.paint);
2992 ctx.canvas->DrawLine(p3, p4, ctx.paint);
2993 ctx.canvas->DrawLine(p5, p6, ctx.paint);
2994 ctx.canvas->DrawLine(p7, p8, ctx.paint);
3014 SkPaint p = ctx.paint;
3015 p.setStyle(SkPaint::kStroke_Style);
3021 ctx.canvas->DrawLine(p1, p2, ctx.paint);
3022 ctx.canvas->DrawLine(p3, p4, ctx.paint);
3023 ctx.canvas->DrawLine(p5, p6, ctx.paint);
3044 SkPaint p = ctx.paint;
3045 p.setStyle(SkPaint::kStroke_Style);
3051 ctx.canvas->DrawLine(p1, p2, ctx.paint);
3052 ctx.canvas->DrawLine(p3, p4, ctx.paint);
3053 ctx.canvas->DrawLine(p5, p6, ctx.paint);
3090 SkPaint p = ctx.paint;
3091 p.setStyle(SkPaint::kStroke_Style);
3092 DlScalar intervals[2] = {25.0f, 5.0f};
3093 p.setPathEffect(SkDashPathEffect::Make({intervals, 2}, 0.0f));
3100 ctx.canvas->DrawDashedLine(p1, p2, 25.0f, 5.0f, ctx.paint);
3101 ctx.canvas->DrawDashedLine(p3, p4, 25.0f, 5.0f, ctx.paint);
3102 ctx.canvas->DrawDashedLine(p5, p6, 25.0f, 5.0f, ctx.paint);
3103 ctx.canvas->DrawDashedLine(p7, p8, 25.0f, 5.0f, ctx.paint);
3116 ctx.canvas->drawRect(
ToSkRect(rect), ctx.paint);
3119 ctx.canvas->DrawRect(rect, ctx.paint);
3130 ctx.canvas->drawOval(
ToSkRect(rect), ctx.paint);
3133 ctx.canvas->DrawOval(rect, ctx.paint);
3160 ctx.canvas->drawRRect(
ToSkRRect(rrect), ctx.paint);
3163 ctx.canvas->DrawRoundRect(rrect, ctx.paint);
3184 ctx.canvas->DrawDiffRoundRect(outer, inner, ctx.paint);
3205 path_builder.
Close();
3210 path_builder.
Close();
3217 ctx.canvas->drawPath(
path.GetSkPath(), ctx.paint);
3220 ctx.canvas->DrawPath(
path, ctx.paint);
3234 ctx.canvas->DrawArc(
kRenderBounds, 60, 330,
false, ctx.paint);
3236 kDrawArcNoCenterFlags));
3257 ctx.canvas->DrawArc(
kRenderBounds, 60, 360 - 12,
true, ctx.paint);
3259 kDrawArcWithCenterFlags)
3260 .set_draw_arc_center());
3285 {x0, y0}, {x1, y0}, {x2, y0}, {x3, y0}, {x4, y0}, {x5, y0}, {x6, y0},
3286 {x0, y1}, {x1, y1}, {x2, y1}, {x3, y1}, {x4, y1}, {x5, y1}, {x6, y1},
3287 {x0, y2}, {x1, y2}, {x2, y2}, {x3, y2}, {x4, y2}, {x5, y2}, {x6, y2},
3288 {x0, y3}, {x1, y3}, {x2, y3}, {x3, y3}, {x4, y3}, {x5, y3}, {x6, y3},
3289 {x0, y4}, {x1, y4}, {x2, y4}, {x3, y4}, {x4, y4}, {x5, y4}, {x6, y4},
3290 {x0, y5}, {x1, y5}, {x2, y5}, {x3, y5}, {x4, y5}, {x5, y5}, {x6, y5},
3291 {x0, y6}, {x1, y6}, {x2, y6}, {x3, y6}, {x4, y6}, {x5, y6}, {x6, y6},
3302 SkPaint p = ctx.paint;
3303 p.setStyle(SkPaint::kStroke_Style);
3304 auto mode = SkCanvas::kPoints_PointMode;
3309 ctx.canvas->DrawPoints(
mode, count,
points, ctx.paint);
3311 kDrawPointsAsPointsFlags)
3336 {x0, y0}, {x3, y3}, {x3, y0}, {x0, y3},
3347 ASSERT_TRUE((count & 1) == 0);
3354 SkPaint p = ctx.paint;
3355 p.setStyle(SkPaint::kStroke_Style);
3356 auto mode = SkCanvas::kLines_PointMode;
3361 ctx.canvas->DrawPoints(
mode, count,
points, ctx.paint);
3363 kDrawPointsAsLinesFlags));
3381 const int count1 =
sizeof(points1) /
sizeof(points1[0]);
3389 SkPaint p = ctx.paint;
3390 p.setStyle(SkPaint::kStroke_Style);
3391 auto mode = SkCanvas::kPolygon_PointMode;
3396 ctx.canvas->DrawPoints(
mode, count1, points1, ctx.paint);
3398 kDrawPointsAsPolygonFlags));
3421 const DlColor dl_colors[6] = {
3425 const SkColor sk_colors[6] = {
3426 SK_ColorRED, SK_ColorBLUE, SK_ColorGREEN,
3427 SK_ColorCYAN, SK_ColorYELLOW, SK_ColorMAGENTA,
3429 const std::shared_ptr<DlVertices> dl_vertices =
3431 const auto sk_vertices =
3432 SkVertices::MakeCopy(SkVertices::VertexMode::kTriangles_VertexMode, 6,
3438 ctx.canvas->drawVertices(sk_vertices, SkBlendMode::kSrcOver,
3442 ctx.canvas->DrawVertices(dl_vertices, DlBlendMode::kSrcOver,
3445 kDrawVerticesFlags));
3476 const std::shared_ptr<DlVertices> dl_vertices =
3478 const auto sk_vertices =
3479 SkVertices::MakeCopy(SkVertices::VertexMode::kTriangles_VertexMode, 6,
3485 SkPaint v_paint = ctx.paint;
3486 if (v_paint.getShader() ==
nullptr) {
3487 v_paint.setShader(MakeColorSource(ctx.image));
3489 ctx.canvas->drawVertices(sk_vertices, SkBlendMode::kSrcOver,
3497 ctx.canvas->DrawVertices(dl_vertices, DlBlendMode::kSrcOver,
3500 kDrawVerticesFlags));
3516 kDrawImageWithPaintFlags));
3544 kDrawImageWithPaintFlags));
3556 SkCanvas::kFast_SrcRectConstraint);
3559 ctx.canvas->DrawImageRect(ctx.image, src, dst,
3563 kDrawImageRectWithPaintFlags));
3575 SkCanvas::kFast_SrcRectConstraint);
3578 ctx.canvas->DrawImageRect(ctx.image, src, dst,
3582 kDrawImageRectFlags));
3593 SkCanvas::kFast_SrcRectConstraint);
3596 ctx.canvas->DrawImageRect(ctx.image, src, dst,
3600 kDrawImageRectWithPaintFlags));
3609 ctx.canvas->drawImageNine(ctx.image.get(),
ToSkIRect(src),
3610 ToSkRect(dst), SkFilterMode::kNearest,
3614 ctx.canvas->DrawImageNine(ctx.image, src, dst,
3617 kDrawImageNineWithPaintFlags));
3626 ctx.canvas->drawImageNine(ctx.image.get(),
ToSkIRect(src),
3627 ToSkRect(dst), SkFilterMode::kNearest,
3631 ctx.canvas->DrawImageNine(ctx.image, src, dst,
3634 kDrawImageNineFlags));
3643 ctx.canvas->drawImageNine(ctx.image.get(),
ToSkIRect(src),
3644 ToSkRect(dst), SkFilterMode::kLinear,
3648 ctx.canvas->DrawImageNine(ctx.image, src, dst,
3651 kDrawImageNineWithPaintFlags));
3662 const SkRSXform sk_xform[] = {
3679 relative_rect(0.0f, 0.0f, 0.5f, 0.5f),
3680 relative_rect(0.5f, 0.0f, 1.0f, 0.5f),
3681 relative_rect(0.5f, 0.5f, 1.0f, 1.0f),
3682 relative_rect(0.0f, 0.5f, 0.5f, 1.0f),
3684 const SkColor sk_colors[] = {
3701 ctx.canvas->drawAtlas(ctx.image.get(), {sk_xform, 4},
3702 {ToSkRects(tex), 4}, {sk_colors, 4},
3703 SkBlendMode::kSrcOver, sk_sampling,
nullptr,
3707 ctx.canvas->DrawAtlas(ctx.image, dl_xform, tex, dl_colors, 4,
3708 DlBlendMode::kSrcOver, dl_sampling,
nullptr,
3711 kDrawAtlasWithPaintFlags));
3722 const SkRSXform sk_xform[] = {
3739 relative_rect(0.0f, 0.0f, 0.5f, 0.5f),
3740 relative_rect(0.5f, 0.0f, 1.0f, 0.5f),
3741 relative_rect(0.5f, 0.5f, 1.0f, 1.0f),
3742 relative_rect(0.0f, 0.5f, 0.5f, 1.0f),
3744 const SkColor sk_colors[] = {
3761 ctx.canvas->drawAtlas(ctx.image.get(), {sk_xform, 4},
3762 {ToSkRects(tex), 4}, {sk_colors, 4},
3763 SkBlendMode::kSrcOver, sk_sampling,
nullptr,
3767 ctx.canvas->DrawAtlas(ctx.image, dl_xform, tex, dl_colors, 4,
3768 DlBlendMode::kSrcOver, dl_sampling,
nullptr,
3782 const SkRSXform sk_xform[] = {
3799 relative_rect(0.0f, 0.0f, 0.5f, 0.5f),
3800 relative_rect(0.5f, 0.0f, 1.0f, 0.5f),
3801 relative_rect(0.5f, 0.5f, 1.0f, 1.0f),
3802 relative_rect(0.0f, 0.5f, 0.5f, 1.0f),
3804 const SkColor sk_colors[] = {
3821 ctx.canvas->drawAtlas(ctx.image.get(), {sk_xform, 2},
3822 {ToSkRects(tex), 2}, {sk_colors, 2},
3823 SkBlendMode::kSrcOver, sk_sampling,
nullptr,
3827 ctx.canvas->DrawAtlas(ctx.image, dl_xform, tex, dl_colors, 2,
3828 DlBlendMode::kSrcOver, dl_sampling,
nullptr,
3831 kDrawAtlasWithPaintFlags));
3854 return builder.
Build();
3865 ctx.canvas->DrawDisplayList(display_list);
3867 kDrawDisplayListFlags)
3868 .set_draw_display_list());
3875#if defined(OS_FUCHSIA)
3876 GTEST_SKIP() <<
"Rendering comparisons require a valid default font manager";
3878 sk_sp<SkTextBlob> blob =
3881#ifdef IMPELLER_SUPPORTS_RENDERING
3890 auto paint = ctx.paint;
3891 ctx.canvas->drawTextBlob(blob,
kRenderLeft, render_y_1_3, paint);
3892 ctx.canvas->drawTextBlob(blob,
kRenderLeft, render_y_2_3, paint);
3896 auto paint = ctx.paint;
3897 ctx.canvas->DrawText(skiaText,
kRenderLeft, render_y_1_3, paint);
3898 ctx.canvas->DrawText(skiaText,
kRenderLeft, render_y_2_3, paint);
3901#ifdef IMPELLER_SUPPORTS_RENDERING
3903 auto paint = ctx.paint;
3904 ctx.canvas->DrawText(impellerText,
kRenderLeft, render_y_1_3,
3906 ctx.canvas->DrawText(impellerText,
kRenderLeft, render_y_2_3,
3913 .set_draw_text_blob(),
3937 color, elevation,
false, 1.0);
3940 ctx.canvas->DrawShadow(
path, color, elevation,
false, 1.0);
3961 color, elevation,
true, 1.0);
3964 ctx.canvas->DrawShadow(
path, color, elevation,
true, 1.0);
3985 color, elevation,
false, 1.5);
3988 ctx.canvas->DrawShadow(
path, color, elevation,
false, 1.5);
4005 SkImageFilters::Blur(10.0f, 10.0f, SkTileMode::kDecal,
nullptr);
4006 SkPaint layer_paint;
4007 layer_paint.setImageFilter(layer_filter);
4012 ctx.canvas->drawRect(
ToSkRect(draw_rect), ctx.paint);
4013 ctx.canvas->restore();
4014 ctx.canvas->restore();
4024 ctx.canvas->DrawRect(draw_rect, ctx.paint);
4025 ctx.canvas->Restore();
4026 ctx.canvas->Restore();
4028 kSaveLayerWithPaintFlags);
4029 CaseParameters case_params(
"Filtered SaveLayer with clipped content");
4037 test_params.imp_renderer());
4044 float commutable_color_matrix[]{
4052 float non_commutable_color_matrix[]{
4062 contract_matrix.
Scale({0.9f, 0.9f});
4065 std::vector<DlScalar> opacities = {
4070 std::vector<std::shared_ptr<const DlColorFilter>> color_filters = {
4077 std::vector<std::shared_ptr<DlImageFilter>> image_filters = {
4099 auto test_attributes_env =
4101 const DlPaint& paint_both,
bool same,
bool rev_same,
4102 const std::string& desc1,
const std::string& desc2,
4107 render_content(nested_builder);
4108 auto nested_results = env->getResult(nested_builder.
Build());
4113 render_content(reverse_builder);
4114 auto reverse_results = env->getResult(reverse_builder.
Build());
4118 render_content(combined_builder);
4119 auto combined_results = env->getResult(combined_builder.
Build());
4128 const bool always =
false;
4133 if (always || same) {
4135 nested_results.get(), combined_results.get(),
4136 "nested " + desc1 +
" then " + desc2,
nullptr,
4138 true, combined_results->width(),
4139 combined_results->height(),
true);
4141 if (always || rev_same) {
4143 reverse_results.get(), combined_results.get(),
4144 "nested " + desc2 +
" then " + desc1,
nullptr,
4146 true, combined_results->width(),
4147 combined_results->height(),
true);
4151 auto test_attributes = [test_attributes_env](
DlPaint& paint1,
DlPaint& paint2,
4153 bool same,
bool rev_same,
4154 const std::string& desc1,
4155 const std::string& desc2) {
4158 auto env = std::make_unique<RenderEnvironment>(
4159 provider.get(), PixelFormat::kN32PremulPixelFormat);
4160 test_attributes_env(paint1, paint2, paint_both,
4161 same, rev_same, desc1, desc2, env.get());
4167 for (
size_t cfi = 0; cfi < color_filters.size(); cfi++) {
4168 const auto& color_filter = color_filters[cfi];
4169 std::string cf_desc =
"color filter #" + std::to_string(cfi + 1);
4172 for (
size_t oi = 0; oi < opacities.size(); oi++) {
4174 std::string op_desc =
"opacity " + std::to_string(opacity);
4177 DlPaint combined_paint = nested_paint1;
4180 bool op_then_cf_works = opacity <= 0.0 || opacity >= 1.0 ||
4181 color_filter->can_commute_with_opacity();
4183 test_attributes(nested_paint1, nested_paint2, combined_paint,
true,
4184 op_then_cf_works, cf_desc, op_desc);
4192 for (
size_t oi = 0; oi < opacities.size(); oi++) {
4194 std::string op_desc =
"opacity " + std::to_string(opacity);
4197 for (
size_t ifi = 0; ifi < image_filters.size(); ifi++) {
4198 const auto& image_filter = image_filters[ifi];
4199 std::string if_desc =
"image filter #" + std::to_string(ifi + 1);
4202 DlPaint combined_paint = nested_paint1;
4205 bool if_then_op_works = opacity <= 0.0 || opacity >= 1.0;
4206 test_attributes(nested_paint1, nested_paint2, combined_paint,
true,
4207 if_then_op_works, op_desc, if_desc);
4213 for (
size_t cfi = 0; cfi < color_filters.size(); cfi++) {
4214 const auto& color_filter = color_filters[cfi];
4215 std::string cf_desc =
"color filter #" + std::to_string(cfi + 1);
4218 for (
size_t ifi = 0; ifi < image_filters.size(); ifi++) {
4219 const auto& image_filter = image_filters[ifi];
4220 std::string if_desc =
"image filter #" + std::to_string(ifi + 1);
4223 DlPaint combined_paint = nested_paint1;
4226 test_attributes(nested_paint1, nested_paint2, combined_paint,
true,
false,
4243 "matrix[" + std::to_string(element) +
"] = " + std::to_string(
value);
4244 float original_value = matrix[element];
4245 matrix[element] =
value;
4253 bool is_identity = (dl_filter ==
nullptr || original_value ==
value);
4263 auto display_list1 = builder1.
Build();
4272 auto display_list2 = builder2.
Build();
4276 auto env = std::make_unique<RenderEnvironment>(
4277 provider.get(), PixelFormat::kN32PremulPixelFormat);
4278 auto results1 = env->getResult(display_list1);
4279 auto results2 = env->getResult(display_list2);
4281 results1.get(), results2.get(), is_identity,
4282 desc +
" filter affects rendering");
4283 int modified_transparent_pixels =
4287 modified_transparent_pixels != 0)
4295 for (
int i = 0;
i < 20;
i++) {
4296 test_matrix(
i, -0.25);
4298 test_matrix(
i, 0.25);
4300 test_matrix(
i, 1.25);
4301 test_matrix(
i, SK_ScalarNaN);
4302 test_matrix(
i, SK_ScalarInfinity);
4303 test_matrix(
i, -SK_ScalarInfinity);
4318 "matrix[" + std::to_string(element) +
"] = " + std::to_string(
value);
4319 matrix[element] =
value;
4321 EXPECT_EQ(std::isfinite(
value), filter !=
nullptr);
4334 auto display_list1 = builder1.
Build();
4343 auto display_list2 = builder2.
Build();
4347 auto env = std::make_unique<RenderEnvironment>(
4348 provider.get(), PixelFormat::kN32PremulPixelFormat);
4349 auto results1 = env->getResult(display_list1);
4350 auto results2 = env->getResult(display_list2);
4351 if (!filter || filter->can_commute_with_opacity()) {
4353 results2.get(), results1.get(), desc,
nullptr,
nullptr,
4357 results1.get(), results2.get(),
false, desc);
4365 for (
int i = 0;
i < 20;
i++) {
4366 test_matrix(
i, -0.25);
4368 test_matrix(
i, 0.25);
4370 test_matrix(
i, 1.1);
4371 test_matrix(
i, SK_ScalarNaN);
4372 test_matrix(
i, SK_ScalarInfinity);
4373 test_matrix(
i, -SK_ScalarInfinity);
4377#define FOR_EACH_BLEND_MODE_ENUM(FUNC) \
4410 std::stringstream desc_str;
4412 desc_str <<
"blend[" << mode_string <<
", " << color <<
"]";
4413 std::string desc = desc_str.str();
4427 auto display_list1 = builder1.
Build();
4436 auto display_list2 = builder2.
Build();
4440 auto env = std::make_unique<RenderEnvironment>(
4441 provider.get(), PixelFormat::kN32PremulPixelFormat);
4442 auto results1 = env->getResult(display_list1);
4443 auto results2 = env->getResult(display_list2);
4444 int modified_transparent_pixels =
4448 modified_transparent_pixels != 0)
4461#define TEST_MODE(V) test_mode(DlBlendMode::V);
4468 std::stringstream desc_str;
4470 desc_str <<
"blend[" << mode_string <<
", " << color <<
"]";
4471 std::string desc = desc_str.str();
4491 auto display_list1 = builder1.
Build();
4500 auto display_list2 = builder2.
Build();
4504 auto env = std::make_unique<RenderEnvironment>(
4505 provider.get(), PixelFormat::kN32PremulPixelFormat);
4506 auto results1 = env->getResult(display_list1);
4507 auto results2 = env->getResult(display_list2);
4510 results2.get(), results1.get(), desc,
nullptr,
nullptr,
4514 results1.get(), results2.get(),
false, desc);
4527#define TEST_MODE(V) test_mode(DlBlendMode::V);
4553 const int step = 0x55;
4554 static_assert(step * 3 == 255);
4555 for (
int a = step; a < 256; a += step) {
4556 for (
int r = step; r < 256; r += step) {
4557 for (
int g = step; g < 256; g += step) {
4558 for (
int b = step; b < 256; b += step) {
4565 static constexpr float color_filter_matrix_nomtb[] = {
4566 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
4567 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
4568 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
4569 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
4571 static constexpr float color_filter_matrix_mtb[] = {
4572 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
4573 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
4574 0.0001, 0.0001, 0.0001, 0.9997, 0.0,
4575 0.0001, 0.0001, 0.0001, 0.9997, 0.1,
4585 for (DlColor color : test_dst_colors) {
4587 paint.setColor(ToSkColor4f(color));
4588 paint.setBlendMode(SkBlendMode::kSrc);
4589 canvas->drawRect(SkRect::MakeXYWH(x, 0, 1, 1), paint);
4598 int data_count =
test_data->image()->width();
4600 data_count, data_count,
true, [
this, data_count](SkCanvas* canvas) {
4601 ASSERT_EQ(
test_data->width(), data_count);
4603 for (
int y = 0;
y < data_count;
y++) {
4604 canvas->drawImage(
test_data->image().get(), 0,
y);
4608 data_count, data_count,
true, [
this, data_count](SkCanvas* canvas) {
4609 ASSERT_EQ(
test_data->width(), data_count);
4611 canvas->translate(data_count, 0);
4613 for (
int y = 0;
y < data_count;
y++) {
4614 canvas->drawImage(
test_data->image().get(), 0,
y);
4618 for (
int y = 0;
y < data_count;
y++) {
4619 for (
int x = 0;
x < data_count;
x++) {
4628 static constexpr int kWasNotNop = 0x1;
4629 static constexpr int kWasMTB = 0x2;
4650 const std::function<
void(SkCanvas*)>& renderer) {
4651 auto surface = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(w,
h));
4652 SkCanvas* canvas =
surface->getCanvas();
4654 return std::make_unique<SkRenderResult>(
surface, snapshot);
4659 const sk_sp<DisplayList>& dl,
4660 const std::string& desc) {
4662 bool is_error =
false;
4665 is_error = !dl->modifies_transparent_black();
4667 if (result_color != dst_color) {
4669 is_error = (dl->op_count() == 0u);
4672 FML_LOG(ERROR) << std::hex << dst_color <<
" filters to " << result_color
4679 const std::unique_ptr<RenderResult>& result_data,
4680 const sk_sp<DisplayList>& dl,
4681 const std::string& desc) {
4682 EXPECT_EQ(dst_data->width(), result_data->width());
4683 EXPECT_EQ(dst_data->height(), result_data->height());
4685 for (
int y = 0;
y < dst_data->height();
y++) {
4686 const uint32_t* dst_pixels = dst_data->addr32(0,
y);
4687 const uint32_t* result_pixels = result_data->addr32(0,
y);
4688 for (
int x = 0;
x < dst_data->width();
x++) {
4689 all_flags |= check_color_result(
DlColor(dst_pixels[
x]),
4690 DlColor(result_pixels[
x]), dl, desc);
4697 const sk_sp<DisplayList>& dl,
4698 const std::string& desc) {
4699 if (!dl->modifies_transparent_black()) {
4700 EXPECT_TRUE((all_flags & kWasMTB) == 0);
4701 }
else if ((all_flags & kWasMTB) == 0) {
4702 FML_LOG(INFO) <<
"combination does not affect transparency: " << desc;
4704 if (dl->op_count() == 0u) {
4705 EXPECT_TRUE((all_flags & kWasNotNop) == 0);
4706 }
else if ((all_flags & kWasNotNop) == 0) {
4707 FML_LOG(INFO) <<
"combination could be classified as a nop: " << desc;
4712 std::stringstream desc_stream;
4713 desc_stream <<
" using SkColorFilter::filterColor() with: ";
4715 desc_stream <<
"/" << color;
4716 std::string desc = desc_stream.str();
4720 auto dl = builder.
Build();
4721 if (dl->modifies_transparent_black()) {
4722 ASSERT_TRUE(dl->op_count() != 0u);
4725 auto sk_mode =
static_cast<SkBlendMode
>(
mode);
4726 auto sk_color_filter =
4727 SkColorFilters::Blend(
ToSkColor4f(color),
nullptr, sk_mode);
4728 auto srgb = SkColorSpace::MakeSRGB();
4730 if (sk_color_filter) {
4731 for (
DlColor dst_color : test_dst_colors) {
4734 sk_color_filter->filterColor4f(dst_color_f, srgb.get(), srgb.get())
4736 all_flags |= check_color_result(dst_color, result, dl, desc);
4738 if ((all_flags & kWasMTB) != 0) {
4739 EXPECT_FALSE(sk_color_filter->isAlphaUnchanged());
4742 report_results(all_flags, dl, desc);
4746 std::stringstream desc_stream;
4747 desc_stream <<
" rendering with: ";
4749 desc_stream <<
"/" << color;
4750 std::string desc = desc_stream.str();
4751 auto test_image = test_data->image();
4756 builder.
DrawRect(test_bounds, dl_paint);
4757 auto dl = builder.
Build();
4758 bool dl_is_elided = dl->op_count() == 0u;
4759 bool dl_affects_transparent_pixels = dl->modifies_transparent_black();
4760 ASSERT_TRUE(!dl_is_elided || !dl_affects_transparent_pixels);
4762 auto sk_mode =
static_cast<SkBlendMode
>(
mode);
4764 sk_paint.setBlendMode(sk_mode);
4768 auto result_surface = provider->MakeOffscreenSurface(
4769 test_image->width(), test_image->height(),
4771 SkCanvas* result_canvas = result_surface->sk_surface()->getCanvas();
4772 result_canvas->clear(SK_ColorTRANSPARENT);
4773 result_canvas->drawImage(test_image.get(), 0, 0);
4774 result_canvas->drawRect(
ToSkRect(test_bounds), sk_paint);
4775 if (GrDirectContext* direct_context = GrAsDirectContext(
4776 result_surface->sk_surface()->recordingContext())) {
4777 direct_context->flushAndSubmit();
4778 direct_context->flushAndSubmit(result_surface->sk_surface().get(),
4781 const std::unique_ptr<RenderResult> result_pixels =
4782 std::make_unique<SkRenderResult>(result_surface->sk_surface());
4784 int all_flags = check_image_result(test_data, result_pixels, dl, desc);
4785 report_results(all_flags, dl, desc);
4794 std::stringstream desc_stream;
4795 desc_stream <<
" rendering with: ";
4797 desc_stream <<
"/" << color;
4798 std::string cf_mtb = color_filter
4800 ?
"modifies transparency"
4801 :
"preserves transparency"
4803 desc_stream <<
", CF: " << cf_mtb;
4804 std::string if_mtb = image_filter
4806 ?
"modifies transparency"
4807 :
"preserves transparency"
4809 desc_stream <<
", IF: " << if_mtb;
4810 std::string desc = desc_stream.str();
4819 auto dl = builder.
Build();
4821 int w = test_image_src_data->width();
4822 int h = test_image_src_data->height();
4823 auto sk_mode =
static_cast<SkBlendMode
>(
mode);
4825 sk_paint.setBlendMode(sk_mode);
4827 sk_paint.setColorFilter(
ToSk(color_filter));
4828 sk_paint.setImageFilter(
ToSk(image_filter));
4831 auto result_surface = provider->MakeOffscreenSurface(
4833 SkCanvas* result_canvas = result_surface->sk_surface()->getCanvas();
4834 result_canvas->clear(SK_ColorTRANSPARENT);
4835 result_canvas->drawImage(test_image_dst_data->image(), 0, 0);
4836 result_canvas->drawImage(test_image_src_data->image(), 0, 0,
4837 SkSamplingOptions(), &sk_paint);
4838 if (GrDirectContext* direct_context = GrAsDirectContext(
4839 result_surface->sk_surface()->recordingContext())) {
4840 direct_context->flushAndSubmit();
4841 direct_context->flushAndSubmit(result_surface->sk_surface().get(),
4844 std::unique_ptr<RenderResult> result_pixels =
4845 std::make_unique<SkRenderResult>(result_surface->sk_surface());
4848 check_image_result(test_image_dst_data, result_pixels, dl, desc);
4849 report_results(all_flags, dl, desc);
4856 for (
DlColor color : test_src_colors) {
4857 test_mode_color_via_filter(
mode, color);
4861#define TEST_MODE(V) test_mode_filter(DlBlendMode::V);
4869 for (
DlColor color : test_src_colors) {
4870 test_mode_color_via_rendering(
mode, color);
4874#define TEST_MODE(V) test_mode_render(DlBlendMode::V);
4883 for (
DlColor color : test_src_colors) {
4884 test_attributes_image(
mode, color,
nullptr,
nullptr);
4885 test_attributes_image(
mode, color, color_filter_nomtb.get(),
nullptr);
4886 test_attributes_image(
mode, color, color_filter_mtb.get(),
nullptr);
4887 test_attributes_image(
mode, color,
nullptr, &image_filter_nomtb);
4888 test_attributes_image(
mode, color,
nullptr, &image_filter_mtb);
4892#define TEST_MODE(V) test_mode_render(DlBlendMode::V);
4897#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