From f73a9f7ec802ebcdf70e16a621b1148df26cf864 Mon Sep 17 00:00:00 2001 From: Jim Graham Date: Thu, 11 Nov 2021 13:29:19 -0800 Subject: [PATCH] Revert "Build DisplayList directly from flutter::Canvas (#29470)" This reverts commit d5cadd28b0bff7d84ce1bd12e29d18ce68fae79b. --- flow/display_list.cc | 345 +-- flow/display_list.h | 468 +--- flow/display_list_canvas.cc | 155 +- flow/display_list_canvas.h | 81 +- flow/display_list_canvas_unittests.cc | 3449 ++++++++++--------------- flow/display_list_unittests.cc | 305 +-- flow/display_list_utils.cc | 157 +- flow/display_list_utils.h | 72 +- lib/ui/painting/canvas.cc | 407 +-- lib/ui/painting/canvas.h | 6 +- lib/ui/painting/paint.cc | 182 +- lib/ui/painting/paint.h | 20 +- lib/ui/text/paragraph_builder.cc | 10 +- 13 files changed, 2026 insertions(+), 3631 deletions(-) diff --git a/flow/display_list.cc b/flow/display_list.cc index ac3af1ca4f7c0..3e3806dab66a4 100644 --- a/flow/display_list.cc +++ b/flow/display_list.cc @@ -7,7 +7,10 @@ #include "flutter/flow/display_list.h" #include "flutter/flow/display_list_canvas.h" #include "flutter/flow/display_list_utils.h" +#include "flutter/fml/logging.h" +#include "third_party/skia/include/core/SkImageFilter.h" +#include "third_party/skia/include/core/SkMaskFilter.h" #include "third_party/skia/include/core/SkPath.h" #include "third_party/skia/include/core/SkRSXform.h" #include "third_party/skia/include/core/SkTextBlob.h" @@ -1082,84 +1085,65 @@ DisplayListBuilder::~DisplayListBuilder() { } } -void DisplayListBuilder::onSetAntiAlias(bool aa) { - Push(0, 0, current_anti_alias_ = aa); +void DisplayListBuilder::setAntiAlias(bool aa) { + Push(0, 0, aa); } -void DisplayListBuilder::onSetDither(bool dither) { - Push(0, 0, current_dither_ = dither); +void DisplayListBuilder::setDither(bool dither) { + Push(0, 0, dither); } -void DisplayListBuilder::onSetInvertColors(bool invert) { - Push(0, 0, current_invert_colors_ = invert); +void DisplayListBuilder::setInvertColors(bool invert) { + Push(0, 0, invert); } -void DisplayListBuilder::onSetStrokeCap(SkPaint::Cap cap) { - Push(0, 0, current_stroke_cap_ = cap); +void DisplayListBuilder::setStrokeCap(SkPaint::Cap cap) { + Push(0, 0, cap); } -void DisplayListBuilder::onSetStrokeJoin(SkPaint::Join join) { - Push(0, 0, current_stroke_join_ = join); +void DisplayListBuilder::setStrokeJoin(SkPaint::Join join) { + Push(0, 0, join); } -void DisplayListBuilder::onSetStyle(SkPaint::Style style) { - Push(0, 0, current_style_ = style); +void DisplayListBuilder::setStyle(SkPaint::Style style) { + Push(0, 0, style); } -void DisplayListBuilder::onSetStrokeWidth(SkScalar width) { - Push(0, 0, current_stroke_width_ = width); +void DisplayListBuilder::setStrokeWidth(SkScalar width) { + Push(0, 0, width); } -void DisplayListBuilder::onSetStrokeMiter(SkScalar limit) { - Push(0, 0, current_stroke_miter_ = limit); +void DisplayListBuilder::setStrokeMiter(SkScalar limit) { + Push(0, 0, limit); } -void DisplayListBuilder::onSetColor(SkColor color) { - Push(0, 0, current_color_ = color); +void DisplayListBuilder::setColor(SkColor color) { + Push(0, 0, color); } -void DisplayListBuilder::onSetBlendMode(SkBlendMode mode) { - current_blender_ = nullptr; - Push(0, 0, current_blend_mode_ = mode); +void DisplayListBuilder::setBlendMode(SkBlendMode mode) { + Push(0, 0, mode); } -void DisplayListBuilder::onSetBlender(sk_sp blender) { - // setBlender(nullptr) should be redirected to setBlendMode(SrcOver) - // by the set method, if not then the following is inefficient but works - FML_DCHECK(blender); - SkPaint p; - p.setBlender(blender); - if (p.asBlendMode()) { - setBlendMode(p.asBlendMode().value()); - } else { - // |current_blender_| supersedes any value of |current_blend_mode_| - (current_blender_ = blender) // - ? Push(0, 0, std::move(blender)) - : Push(0, 0); - } +void DisplayListBuilder::setBlender(sk_sp blender) { + blender // + ? Push(0, 0, std::move(blender)) + : Push(0, 0); } -void DisplayListBuilder::onSetShader(sk_sp shader) { - (current_shader_ = shader) // +void DisplayListBuilder::setShader(sk_sp shader) { + shader // ? Push(0, 0, std::move(shader)) : Push(0, 0); } -void DisplayListBuilder::onSetImageFilter(sk_sp filter) { - (current_image_filter_ = filter) // +void DisplayListBuilder::setImageFilter(sk_sp filter) { + filter // ? Push(0, 0, std::move(filter)) : Push(0, 0); } -void DisplayListBuilder::onSetColorFilter(sk_sp filter) { - (current_color_filter_ = filter) // +void DisplayListBuilder::setColorFilter(sk_sp filter) { + filter // ? Push(0, 0, std::move(filter)) : Push(0, 0); } -void DisplayListBuilder::onSetPathEffect(sk_sp effect) { - (current_path_effect_ = effect) // +void DisplayListBuilder::setPathEffect(sk_sp effect) { + effect // ? Push(0, 0, std::move(effect)) : Push(0, 0); } -void DisplayListBuilder::onSetMaskFilter(sk_sp filter) { - current_mask_sigma_ = kInvalidSigma; - current_mask_filter_ = filter; +void DisplayListBuilder::setMaskFilter(sk_sp filter) { Push(0, 0, std::move(filter)); } -void DisplayListBuilder::onSetMaskBlurFilter(SkBlurStyle style, - SkScalar sigma) { - // Valid sigma is checked by setMaskBlurFilter - FML_DCHECK(mask_sigma_valid(sigma)); - current_mask_filter_ = nullptr; - current_mask_style_ = style; - current_mask_sigma_ = sigma; +void DisplayListBuilder::setMaskBlurFilter(SkBlurStyle style, SkScalar sigma) { switch (style) { case kNormal_SkBlurStyle: Push(0, 0, sigma); @@ -1176,56 +1160,6 @@ void DisplayListBuilder::onSetMaskBlurFilter(SkBlurStyle style, } } -void DisplayListBuilder::setAttributesFromPaint( - const SkPaint& paint, - const DisplayListAttributeFlags flags) { - if (flags.applies_anti_alias()) { - setAntiAlias(paint.isAntiAlias()); - } - if (flags.applies_dither()) { - setDither(paint.isDither()); - } - if (flags.applies_alpha_or_color()) { - setColor(paint.getColor()); - } - if (flags.applies_blend()) { - skstd::optional mode_optional = paint.asBlendMode(); - if (mode_optional) { - setBlendMode(mode_optional.value()); - } else { - setBlender(sk_ref_sp(paint.getBlender())); - } - } - if (flags.applies_style()) { - setStyle(paint.getStyle()); - } - if (flags.is_stroked(paint.getStyle())) { - setStrokeWidth(paint.getStrokeWidth()); - setStrokeMiter(paint.getStrokeMiter()); - setStrokeCap(paint.getStrokeCap()); - setStrokeJoin(paint.getStrokeJoin()); - } - if (flags.applies_shader()) { - setShader(sk_ref_sp(paint.getShader())); - } - if (flags.applies_color_filter()) { - // invert colors is a Flutter::Paint thing, not an SkPaint thing - // we must clear it because it is a second potential color filter - // that is composed with the paint's color filter. - setInvertColors(false); - setColorFilter(sk_ref_sp(paint.getColorFilter())); - } - if (flags.applies_image_filter()) { - setImageFilter(sk_ref_sp(paint.getImageFilter())); - } - if (flags.applies_path_effect()) { - setPathEffect(sk_ref_sp(paint.getPathEffect())); - } - if (flags.applies_mask_filter()) { - setMaskFilter(sk_ref_sp(paint.getMaskFilter())); - } -} - void DisplayListBuilder::save() { save_level_++; Push(0, 1); @@ -1236,36 +1170,24 @@ void DisplayListBuilder::restore() { save_level_--; } } -void DisplayListBuilder::saveLayer(const SkRect* bounds, - bool restore_with_paint) { +void DisplayListBuilder::saveLayer(const SkRect* bounds, bool with_paint) { save_level_++; bounds // - ? Push(0, 1, *bounds, restore_with_paint) - : Push(0, 1, restore_with_paint); + ? Push(0, 1, *bounds, with_paint) + : Push(0, 1, with_paint); } void DisplayListBuilder::translate(SkScalar tx, SkScalar ty) { - if (SkScalarIsFinite(tx) && SkScalarIsFinite(ty) && - (tx != 0.0 || ty != 0.0)) { - Push(0, 1, tx, ty); - } + Push(0, 1, tx, ty); } void DisplayListBuilder::scale(SkScalar sx, SkScalar sy) { - if (SkScalarIsFinite(sx) && SkScalarIsFinite(sy) && - (sx != 1.0 || sy != 1.0)) { - Push(0, 1, sx, sy); - } + Push(0, 1, sx, sy); } void DisplayListBuilder::rotate(SkScalar degrees) { - if (SkScalarMod(degrees, 360.0) != 0.0) { - Push(0, 1, degrees); - } + Push(0, 1, degrees); } void DisplayListBuilder::skew(SkScalar sx, SkScalar sy) { - if (SkScalarIsFinite(sx) && SkScalarIsFinite(sy) && - (sx != 0.0 || sy != 0.0)) { - Push(0, 1, sx, sy); - } + Push(0, 1, sx, sy); } // clang-format off @@ -1274,10 +1196,7 @@ void DisplayListBuilder::skew(SkScalar sx, SkScalar sy) { void DisplayListBuilder::transform2DAffine( SkScalar mxx, SkScalar mxy, SkScalar mxt, SkScalar myx, SkScalar myy, SkScalar myt) { - if (SkScalarsAreFinite(mxx, myx) && - SkScalarsAreFinite(mxy, myy) && - SkScalarsAreFinite(mxt, myt) && - !(mxx == 1 && mxy == 0 && mxt == 0 && + if (!(mxx == 1 && mxy == 0 && mxt == 0 && myx == 0 && myy == 1 && myt == 0)) { Push(0, 1, mxx, mxy, mxt, @@ -1296,10 +1215,7 @@ void DisplayListBuilder::transformFullPerspective( mwx == 0 && mwy == 0 && mwz == 0 && mwt == 1) { transform2DAffine(mxx, mxy, mxt, myx, myy, myt); - } else if (SkScalarsAreFinite(mxx, mxy) && SkScalarsAreFinite(mxz, mxt) && - SkScalarsAreFinite(myx, myy) && SkScalarsAreFinite(myz, myt) && - SkScalarsAreFinite(mzx, mzy) && SkScalarsAreFinite(mzz, mzt) && - SkScalarsAreFinite(mwx, mwy) && SkScalarsAreFinite(mwz, mwt)) { + } else { Push(0, 1, mxx, mxy, mxz, mxt, myx, myy, myz, myt, @@ -1452,7 +1368,7 @@ void DisplayListBuilder::drawImageLattice(const sk_sp image, const SkCanvas::Lattice& lattice, const SkRect& dst, SkFilterMode filter, - bool render_with_attributes) { + bool with_paint) { int xDivCount = lattice.fXCount; int yDivCount = lattice.fYCount; FML_DCHECK((lattice.fRectTypes == nullptr) || (lattice.fColors != nullptr)); @@ -1463,9 +1379,9 @@ void DisplayListBuilder::drawImageLattice(const sk_sp image, (xDivCount + yDivCount) * sizeof(int) + cellCount * (sizeof(SkColor) + sizeof(SkCanvas::Lattice::RectType)); SkIRect src = lattice.fBounds ? *lattice.fBounds : image->bounds(); - void* pod = this->Push( - bytes, 1, std::move(image), xDivCount, yDivCount, cellCount, src, dst, - filter, render_with_attributes); + void* pod = this->Push(bytes, 1, std::move(image), + xDivCount, yDivCount, cellCount, + src, dst, filter, with_paint); CopyV(pod, lattice.fXDivs, xDivCount, lattice.fYDivs, yDivCount, lattice.fColors, cellCount, lattice.fRectTypes, cellCount); } @@ -1547,165 +1463,4 @@ void DisplayListBuilder::drawShadow(const SkPath& path, : Push(0, 1, path, color, elevation, dpr); } -// clang-format off -// Flags common to all primitives that apply colors -#define PAINT_FLAGS (kUsesDither_ | \ - kUsesColor_ | \ - kUsesAlpha_ | \ - kUsesBlend_ | \ - kUsesShader_ | \ - kUsesColorFilter_ | \ - kUsesImageFilter_) - -// Flags common to all primitives that stroke or fill -#define STROKE_OR_FILL_FLAGS (kIsDrawnGeometry_ | \ - kUsesAntiAlias_ | \ - kUsesMaskFilter_ | \ - kUsesPathEffect_) - -// Flags common to primitives that stroke geometry -#define STROKE_FLAGS (kIsStrokedGeometry_ | \ - kUsesAntiAlias_ | \ - kUsesMaskFilter_ | \ - kUsesPathEffect_) - -// Flags common to primitives that render an image with paint attributes -#define IMAGE_FLAGS_BASE (kIsNonGeometric_ | \ - kUsesAlpha_ | \ - kUsesDither_ | \ - kUsesBlend_ | \ - kUsesColorFilter_ | \ - kUsesImageFilter_) -// clang-format on - -const DisplayListAttributeFlags DisplayListOpFlags::kSaveLayerFlags = - DisplayListAttributeFlags(kIgnoresPaint_); - -const DisplayListAttributeFlags DisplayListOpFlags::kSaveLayerWithPaintFlags = - DisplayListAttributeFlags(kIsNonGeometric_ | // - kUsesAlpha_ | // - kUsesBlend_ | // - kUsesColorFilter_ | // - kUsesImageFilter_); - -const DisplayListAttributeFlags DisplayListOpFlags::kDrawColorFlags = - DisplayListAttributeFlags(kFloodsSurface_ | kIgnoresPaint_); - -const DisplayListAttributeFlags DisplayListOpFlags::kDrawPaintFlags = - DisplayListAttributeFlags(PAINT_FLAGS | kFloodsSurface_); - -const DisplayListAttributeFlags DisplayListOpFlags::kDrawHVLineFlags = - DisplayListAttributeFlags(PAINT_FLAGS | STROKE_FLAGS | kMayHaveCaps_); - -const DisplayListAttributeFlags DisplayListOpFlags::kDrawLineFlags = - kDrawHVLineFlags.with(kMayHaveDiagonalCaps_); - -const DisplayListAttributeFlags DisplayListOpFlags::kDrawRectFlags = - DisplayListAttributeFlags(PAINT_FLAGS | STROKE_OR_FILL_FLAGS | - kMayHaveJoins_); - -const DisplayListAttributeFlags DisplayListOpFlags::kDrawOvalFlags = - DisplayListAttributeFlags(PAINT_FLAGS | STROKE_OR_FILL_FLAGS); - -const DisplayListAttributeFlags DisplayListOpFlags::kDrawCircleFlags = - DisplayListAttributeFlags(PAINT_FLAGS | STROKE_OR_FILL_FLAGS); - -const DisplayListAttributeFlags DisplayListOpFlags::kDrawRRectFlags = - DisplayListAttributeFlags(PAINT_FLAGS | STROKE_OR_FILL_FLAGS); - -const DisplayListAttributeFlags DisplayListOpFlags::kDrawDRRectFlags = - DisplayListAttributeFlags(PAINT_FLAGS | STROKE_OR_FILL_FLAGS); - -const DisplayListAttributeFlags DisplayListOpFlags::kDrawPathFlags = - DisplayListAttributeFlags(PAINT_FLAGS | STROKE_OR_FILL_FLAGS | - kMayHaveCaps_ | kMayHaveDiagonalCaps_ | - kMayHaveJoins_ | kMayHaveAcuteJoins_); - -const DisplayListAttributeFlags DisplayListOpFlags::kDrawArcNoCenterFlags = - DisplayListAttributeFlags(PAINT_FLAGS | STROKE_OR_FILL_FLAGS | - kMayHaveCaps_ | kMayHaveDiagonalCaps_); - -const DisplayListAttributeFlags DisplayListOpFlags::kDrawArcWithCenterFlags = - DisplayListAttributeFlags(PAINT_FLAGS | STROKE_OR_FILL_FLAGS | - kMayHaveJoins_ | kMayHaveAcuteJoins_); - -const DisplayListAttributeFlags DisplayListOpFlags::kDrawPointsAsPointsFlags = - DisplayListAttributeFlags(PAINT_FLAGS | STROKE_FLAGS | // - kMayHaveCaps_ | kButtCapIsSquare_); - -const DisplayListAttributeFlags DisplayListOpFlags::kDrawPointsAsLinesFlags = - DisplayListAttributeFlags(PAINT_FLAGS | STROKE_FLAGS | // - kMayHaveCaps_ | kMayHaveDiagonalCaps_); - -// Polygon mode just draws (count-1) separate lines, no joins -const DisplayListAttributeFlags DisplayListOpFlags::kDrawPointsAsPolygonFlags = - DisplayListAttributeFlags(PAINT_FLAGS | STROKE_FLAGS | // - kMayHaveCaps_ | kMayHaveDiagonalCaps_); - -const DisplayListAttributeFlags DisplayListOpFlags::kDrawVerticesFlags = - DisplayListAttributeFlags(kIsNonGeometric_ | // - kUsesDither_ | // - kUsesAlpha_ | // - kUsesShader_ | // - kUsesBlend_ | // - kUsesColorFilter_ | // - kUsesImageFilter_); - -const DisplayListAttributeFlags DisplayListOpFlags::kDrawImageFlags = - DisplayListAttributeFlags(kIgnoresPaint_); - -const DisplayListAttributeFlags DisplayListOpFlags::kDrawImageWithPaintFlags = - DisplayListAttributeFlags(IMAGE_FLAGS_BASE | // - kUsesAntiAlias_ | kUsesMaskFilter_); - -const DisplayListAttributeFlags DisplayListOpFlags::kDrawImageRectFlags = - DisplayListAttributeFlags(kIgnoresPaint_); - -const DisplayListAttributeFlags - DisplayListOpFlags::kDrawImageRectWithPaintFlags = - DisplayListAttributeFlags(IMAGE_FLAGS_BASE | // - kUsesAntiAlias_ | kUsesMaskFilter_); - -const DisplayListAttributeFlags DisplayListOpFlags::kDrawImageNineFlags = - DisplayListAttributeFlags(kIgnoresPaint_); - -const DisplayListAttributeFlags - DisplayListOpFlags::kDrawImageNineWithPaintFlags = - DisplayListAttributeFlags(IMAGE_FLAGS_BASE); - -const DisplayListAttributeFlags DisplayListOpFlags::kDrawImageLatticeFlags = - DisplayListAttributeFlags(kIgnoresPaint_); - -const DisplayListAttributeFlags - DisplayListOpFlags::kDrawImageLatticeWithPaintFlags = - DisplayListAttributeFlags(IMAGE_FLAGS_BASE); - -const DisplayListAttributeFlags DisplayListOpFlags::kDrawAtlasFlags = - DisplayListAttributeFlags(kIgnoresPaint_); - -const DisplayListAttributeFlags DisplayListOpFlags::kDrawAtlasWithPaintFlags = - DisplayListAttributeFlags(IMAGE_FLAGS_BASE); - -const DisplayListAttributeFlags DisplayListOpFlags::kDrawPictureFlags = - DisplayListAttributeFlags(kIgnoresPaint_); - -const DisplayListAttributeFlags DisplayListOpFlags::kDrawPictureWithPaintFlags = - kSaveLayerWithPaintFlags; - -const DisplayListAttributeFlags DisplayListOpFlags::kDrawDisplayListFlags = - DisplayListAttributeFlags(kIgnoresPaint_); - -const DisplayListAttributeFlags DisplayListOpFlags::kDrawTextBlobFlags = - DisplayListAttributeFlags(PAINT_FLAGS | STROKE_OR_FILL_FLAGS | - kMayHaveJoins_) - .without(kUsesAntiAlias_); - -const DisplayListAttributeFlags DisplayListOpFlags::kDrawShadowFlags = - DisplayListAttributeFlags(kIgnoresPaint_); - -#undef PAINT_FLAGS -#undef STROKE_OR_FILL_FLAGS -#undef STROKE_FLAGS -#undef IMAGE_FLAGS_BASE - } // namespace flutter diff --git a/flow/display_list.h b/flow/display_list.h index a3a6b5c70a91a..327ad9df2ea21 100644 --- a/flow/display_list.h +++ b/flow/display_list.h @@ -5,22 +5,17 @@ #ifndef FLUTTER_FLOW_DISPLAY_LIST_H_ #define FLUTTER_FLOW_DISPLAY_LIST_H_ -#include - #include "third_party/skia/include/core/SkBlender.h" #include "third_party/skia/include/core/SkBlurTypes.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkColorFilter.h" #include "third_party/skia/include/core/SkImage.h" #include "third_party/skia/include/core/SkImageFilter.h" -#include "third_party/skia/include/core/SkMaskFilter.h" #include "third_party/skia/include/core/SkPathEffect.h" #include "third_party/skia/include/core/SkPicture.h" #include "third_party/skia/include/core/SkShader.h" #include "third_party/skia/include/core/SkVertices.h" -#include "flutter/fml/logging.h" - // The Flutter DisplayList mechanism encapsulates a persistent sequence of // rendering operations. // @@ -468,278 +463,6 @@ class Dispatcher { SkScalar dpr) = 0; }; -/// The base class for the classes that maintain a list of -/// attributes that might be important for a number of operations -/// including which rendering attributes need to be set before -/// calling a rendering method (all |drawSomething| calls), -/// or for determining which exceptional conditions may need -/// to be accounted for in bounds calculations. -/// This class contains only protected definitions and helper methods -/// for the public classes |DisplayListAttributeFlags| and -/// |DisplayListSpecialGeometryFlags|. -class DisplayListFlags { - protected: - // A drawing operation that is not geometric in nature (but which - // may still apply a MaskFilter - see |kUsesMaskFilter_| below). - static constexpr int kIsNonGeometric_ = 0; - - // A geometric operation that is defined as a fill operation - // regardless of what the current paint Style is set to. - // This flag will automatically assume |kUsesMaskFilter_|. - static constexpr int kIsFilledGeometry_ = 1 << 0; - - // A geometric operation that is defined as a stroke operation - // regardless of what the current paint Style is set to. - // This flag will automatically assume |kUsesMaskFilter_|. - static constexpr int kIsStrokedGeometry_ = 1 << 1; - - // A geometric operation that may be a stroke or fill operation - // depending on the current state of the paint Style attribute. - // This flag will automatically assume |kUsesMaskFilter_|. - static constexpr int kIsDrawnGeometry_ = 1 << 2; - - static constexpr int kIsAnyGeometryMask_ = // - kIsFilledGeometry_ | // - kIsStrokedGeometry_ | // - kIsDrawnGeometry_; - - // A primitive that floods the surface (or clip) with no - // natural bounds, such as |drawColor| or |drawPaint|. - static constexpr int kFloodsSurface_ = 1 << 3; - - static constexpr int kMayHaveCaps_ = 1 << 4; - static constexpr int kMayHaveJoins_ = 1 << 5; - static constexpr int kButtCapIsSquare_ = 1 << 6; - - // A geometric operation which has a path that might have - // end caps that are not rectilinear which means that square - // end caps might project further than half the stroke width - // from the geometry bounds. - // A rectilinear path such as |drawRect| will not have - // diagonal end caps. |drawLine| might have diagonal end - // caps depending on the angle of the line, and more likely - // |drawPath| will often have such end caps. - static constexpr int kMayHaveDiagonalCaps_ = 1 << 7; - - // A geometric operation which has joined vertices that are - // not guaranteed to be smooth (angles of incoming and outgoing) - // segments at some joins may not have the same angle) or - // rectilinear (squares have right angles at the corners, but - // those corners will never extend past the bounding box of - // the geometry pre-transform). - // |drawRect|, |drawOval| and |drawRRect| all have well - // behaved joins, but |drawPath| might have joins that cause - // mitered extensions outside the pre-transformed bounding box. - static constexpr int kMayHaveAcuteJoins_ = 1 << 8; - - static constexpr int kAnySpecialGeometryMask_ = // - kMayHaveCaps_ | kMayHaveJoins_ | kButtCapIsSquare_ | // - kMayHaveDiagonalCaps_ | kMayHaveAcuteJoins_; - - // clang-format off - static constexpr int kUsesAntiAlias_ = 1 << 10; - static constexpr int kUsesDither_ = 1 << 11; - static constexpr int kUsesAlpha_ = 1 << 12; - static constexpr int kUsesColor_ = 1 << 13; - static constexpr int kUsesBlend_ = 1 << 14; - static constexpr int kUsesShader_ = 1 << 15; - static constexpr int kUsesColorFilter_ = 1 << 16; - static constexpr int kUsesPathEffect_ = 1 << 17; - static constexpr int kUsesMaskFilter_ = 1 << 18; - static constexpr int kUsesImageFilter_ = 1 << 19; - - static constexpr int kIgnoresPaint_ = 1 << 30; - // clang-format on - - static constexpr int kAnyAttributeMask_ = // - kUsesAntiAlias_ | kUsesDither_ | kUsesAlpha_ | kUsesColor_ | kUsesBlend_ | - kUsesShader_ | kUsesColorFilter_ | kUsesPathEffect_ | kUsesMaskFilter_ | - kUsesImageFilter_; -}; - -class DisplayListFlagsBase : protected DisplayListFlags { - protected: - DisplayListFlagsBase(int flags) : flags_(flags) {} - - const int flags_; - - bool has_any(int qFlags) const { return (flags_ & qFlags) != 0; } - bool has_all(int qFlags) const { return (flags_ & qFlags) == qFlags; } - bool has_none(int qFlags) const { return (flags_ & qFlags) == 0; } -}; - -/// An attribute class for advertising specific properties of -/// a geometric attribute that can affect the computation of -/// the bounds of the primitive. -class DisplayListSpecialGeometryFlags : DisplayListFlagsBase { - public: - /// The geometry may have segments that end without closing the path. - bool may_have_end_caps() const { return has_any(kMayHaveCaps_); } - - /// The geometry may have segments connect non-continuously. - bool may_have_joins() const { return has_any(kMayHaveJoins_); } - - /// Mainly for drawPoints(PointMode) where Butt caps are rendered as squares. - bool butt_cap_becomes_square() const { return has_any(kButtCapIsSquare_); } - - /// The geometry may have segments that end on a diagonal - /// such that their end caps extend further than the default - /// |strokeWidth * 0.5| margin around the geometry. - bool may_have_diagonal_caps() const { return has_any(kMayHaveDiagonalCaps_); } - - /// The geometry may have segments that meet at vertices at - /// an acute angle such that the miter joins will extend - /// further than the default |strokeWidth * 0.5| margin around - /// the geometry. - bool may_have_acute_joins() const { return has_any(kMayHaveAcuteJoins_); } - - private: - DisplayListSpecialGeometryFlags(int flags) : DisplayListFlagsBase(flags) { - FML_DCHECK((flags & kAnySpecialGeometryMask_) == flags); - } - - const DisplayListSpecialGeometryFlags with(int extra) const { - return extra == 0 ? *this : DisplayListSpecialGeometryFlags(flags_ | extra); - } - - friend class DisplayListAttributeFlags; -}; - -class DisplayListAttributeFlags : DisplayListFlagsBase { - public: - const DisplayListSpecialGeometryFlags WithPathEffect( - sk_sp effect) const { - if (is_geometric() && effect) { - SkPathEffect::DashInfo info; - if (effect->asADash(&info) == SkPathEffect::kDash_DashType) { - // A dash effect has a very simple impact. It cannot introduce any - // miter joins that weren't already present in the original path - // and it does not grow the bounds of the path, but it can add - // end caps to areas that might not have had them before so all - // we need to do is to indicate the potential for diagonal - // end caps and move on. - return special_flags_.with(kMayHaveCaps_ | kMayHaveDiagonalCaps_); - } else { - // An arbitrary path effect can introduce joins at an arbitrary - // angle and may change the geometry of the end caps - return special_flags_.with(kMayHaveCaps_ | kMayHaveDiagonalCaps_ | - kMayHaveJoins_ | kMayHaveAcuteJoins_); - } - } - return special_flags_; - } - - bool ignores_paint() const { return has_any(kIgnoresPaint_); } - - bool applies_anti_alias() const { return has_any(kUsesAntiAlias_); } - bool applies_dither() const { return has_any(kUsesDither_); } - bool applies_color() const { return has_any(kUsesColor_); } - bool applies_alpha() const { return has_any(kUsesAlpha_); } - bool applies_alpha_or_color() const { - return has_any(kUsesAlpha_ | kUsesColor_); - } - - /// The primitive dynamically determines whether it is a stroke or fill - /// operation (or both) based on the setting of the |Style| attribute. - bool applies_style() const { return has_any(kIsDrawnGeometry_); } - /// The primitive can use any of the stroke attributes, such as - /// StrokeWidth, StrokeMiter, StrokeCap, or StrokeJoin. This - /// method will return if the primitive is defined as one that - /// strokes its geometry (such as |drawLine|) or if it is defined - /// as one that honors the Style attribute. If the Style attribute - /// is known then a more accurate answer can be returned from - /// the |is_stroked| method by supplying the actual setting of - /// the style. - // bool applies_stroke_attributes() const { return is_stroked(); } - - bool applies_shader() const { return has_any(kUsesShader_); } - /// The primitive honors the current SkColorFilter, including - /// the related attribute InvertColors - bool applies_color_filter() const { return has_any(kUsesColorFilter_); } - /// The primitive honors the SkBlendMode or SkBlender - bool applies_blend() const { return has_any(kUsesBlend_); } - bool applies_path_effect() const { return has_any(kUsesPathEffect_); } - /// The primitive honors the SkMaskFilter whether set using the - /// filter object or using the convenience method |setMaskBlurFilter| - bool applies_mask_filter() const { return has_any(kUsesMaskFilter_); } - bool applies_image_filter() const { return has_any(kUsesImageFilter_); } - - bool is_geometric() const { return has_any(kIsAnyGeometryMask_); } - bool always_stroked() const { return has_any(kIsStrokedGeometry_); } - bool is_stroked(SkPaint::Style style = SkPaint::Style::kStroke_Style) const { - return ( - has_any(kIsStrokedGeometry_) || - (style != SkPaint::Style::kFill_Style && has_any(kIsDrawnGeometry_))); - } - - bool is_flood() const { return has_any(kFloodsSurface_); } - - private: - DisplayListAttributeFlags(int flags) - : DisplayListFlagsBase(flags), - special_flags_(flags & kAnySpecialGeometryMask_) { - FML_DCHECK((flags & kIsAnyGeometryMask_) == kIsNonGeometric_ || - (flags & kIsAnyGeometryMask_) == kIsFilledGeometry_ || - (flags & kIsAnyGeometryMask_) == kIsStrokedGeometry_ || - (flags & kIsAnyGeometryMask_) == kIsDrawnGeometry_); - FML_DCHECK(((flags & kAnyAttributeMask_) == 0) != - ((flags & kIgnoresPaint_) == 0)); - FML_DCHECK((flags & kIsAnyGeometryMask_) != 0 || - (flags & kAnySpecialGeometryMask_) == 0); - } - - const DisplayListAttributeFlags with(int extra) const { - return extra == 0 ? *this : DisplayListAttributeFlags(flags_ | extra); - } - - const DisplayListAttributeFlags without(int remove) const { - FML_DCHECK(has_all(remove)); - return (flags_ & ~remove); - } - - const DisplayListSpecialGeometryFlags special_flags_; - - friend class DisplayListOpFlags; -}; - -class DisplayListOpFlags : DisplayListFlags { - public: - static const DisplayListAttributeFlags kSaveLayerFlags; - static const DisplayListAttributeFlags kSaveLayerWithPaintFlags; - static const DisplayListAttributeFlags kDrawColorFlags; - static const DisplayListAttributeFlags kDrawPaintFlags; - static const DisplayListAttributeFlags kDrawLineFlags; - // Special case flags for horizonal and vertical lines - static const DisplayListAttributeFlags kDrawHVLineFlags; - static const DisplayListAttributeFlags kDrawRectFlags; - static const DisplayListAttributeFlags kDrawOvalFlags; - static const DisplayListAttributeFlags kDrawCircleFlags; - static const DisplayListAttributeFlags kDrawRRectFlags; - static const DisplayListAttributeFlags kDrawDRRectFlags; - static const DisplayListAttributeFlags kDrawPathFlags; - static const DisplayListAttributeFlags kDrawArcNoCenterFlags; - static const DisplayListAttributeFlags kDrawArcWithCenterFlags; - static const DisplayListAttributeFlags kDrawPointsAsPointsFlags; - static const DisplayListAttributeFlags kDrawPointsAsLinesFlags; - static const DisplayListAttributeFlags kDrawPointsAsPolygonFlags; - static const DisplayListAttributeFlags kDrawVerticesFlags; - static const DisplayListAttributeFlags kDrawImageFlags; - static const DisplayListAttributeFlags kDrawImageWithPaintFlags; - static const DisplayListAttributeFlags kDrawImageRectFlags; - static const DisplayListAttributeFlags kDrawImageRectWithPaintFlags; - static const DisplayListAttributeFlags kDrawImageNineFlags; - static const DisplayListAttributeFlags kDrawImageNineWithPaintFlags; - static const DisplayListAttributeFlags kDrawImageLatticeFlags; - static const DisplayListAttributeFlags kDrawImageLatticeWithPaintFlags; - static const DisplayListAttributeFlags kDrawAtlasFlags; - static const DisplayListAttributeFlags kDrawAtlasWithPaintFlags; - static const DisplayListAttributeFlags kDrawPictureFlags; - static const DisplayListAttributeFlags kDrawPictureWithPaintFlags; - static const DisplayListAttributeFlags kDrawDisplayListFlags; - static const DisplayListAttributeFlags kDrawTextBlobFlags; - static const DisplayListAttributeFlags kDrawShadowFlags; -}; - // The primary class used to build a display list. The list of methods // here matches the list of methods invoked on a |Dispatcher|. // If there is some code that already renders to an SkCanvas object, @@ -750,137 +473,33 @@ class DisplayListBuilder final : public virtual Dispatcher, public SkRefCnt { DisplayListBuilder(const SkRect& cull_rect = kMaxCullRect_); ~DisplayListBuilder(); - void setAntiAlias(bool aa) override { - if (current_anti_alias_ != aa) { - onSetAntiAlias(aa); - } - } - void setDither(bool dither) override { - if (current_dither_ != dither) { - onSetDither(dither); - } - } - void setInvertColors(bool invert) override { - if (current_invert_colors_ != invert) { - onSetInvertColors(invert); - } - } - void setStrokeCap(SkPaint::Cap cap) override { - if (current_stroke_cap_ != cap) { - onSetStrokeCap(cap); - } - } - void setStrokeJoin(SkPaint::Join join) override { - if (current_stroke_join_ != join) { - onSetStrokeJoin(join); - } - } - void setStyle(SkPaint::Style style) override { - if (current_style_ != style) { - onSetStyle(style); - } - } - void setStrokeWidth(SkScalar width) override { - if (current_stroke_width_ != width) { - onSetStrokeWidth(width); - } - } - void setStrokeMiter(SkScalar limit) override { - if (current_stroke_miter_ != limit) { - onSetStrokeMiter(limit); - } - } - void setColor(SkColor color) override { - if (current_color_ != color) { - onSetColor(color); - } - } - void setBlendMode(SkBlendMode mode) override { - if (current_blender_ || current_blend_mode_ != mode) { - onSetBlendMode(mode); - } - } - void setBlender(sk_sp blender) override { - if (!blender) { - setBlendMode(SkBlendMode::kSrcOver); - } else if (current_blender_ != blender) { - onSetBlender(std::move(blender)); - } - } - void setShader(sk_sp shader) override { - if (current_shader_ != shader) { - onSetShader(std::move(shader)); - } - } - void setImageFilter(sk_sp filter) override { - if (current_image_filter_ != filter) { - onSetImageFilter(std::move(filter)); - } - } - void setColorFilter(sk_sp filter) override { - if (current_color_filter_ != filter) { - onSetColorFilter(std::move(filter)); - } - } - void setPathEffect(sk_sp effect) override { - if (current_path_effect_ != effect) { - onSetPathEffect(std::move(effect)); - } - } - void setMaskFilter(sk_sp filter) override { - if (mask_sigma_valid(current_mask_sigma_) || - current_mask_filter_ != filter) { - onSetMaskFilter(std::move(filter)); - } - } - void setMaskBlurFilter(SkBlurStyle style, SkScalar sigma) override { - if (mask_sigma_valid(sigma) && - (current_mask_style_ != style || current_mask_sigma_ != sigma)) { - onSetMaskBlurFilter(style, sigma); - } - } - - bool isAntiAlias() const { return current_anti_alias_; } - bool isDither() const { return current_dither_; } - SkPaint::Style getStyle() const { return current_style_; } - SkColor getColor() const { return current_color_; } - SkScalar getStrokeWidth() const { return current_stroke_width_; } - SkScalar getStrokeMiter() const { return current_stroke_miter_; } - SkPaint::Cap getStrokeCap() const { return current_stroke_cap_; } - SkPaint::Join getStrokeJoin() const { return current_stroke_join_; } - sk_sp getShader() const { return current_shader_; } - sk_sp getColorFilter() const { return current_color_filter_; } - bool isInvertColors() const { return current_invert_colors_; } - std::optional getBlendMode() const { - if (current_blender_) { - // The setters will turn "Mode" style blenders into "blend_mode"s - return {}; - } - return current_blend_mode_; - } - sk_sp getBlender() const { - return current_blender_ ? current_blender_ - : SkBlender::Mode(current_blend_mode_); - } - sk_sp getPathEffect() const { return current_path_effect_; } - sk_sp getMaskFilter() const { return current_mask_filter_; } - // No utility getter for the utility setter: - // void setMaskBlurFilter (SkBlurStyle style, SkScalar sigma) - sk_sp getImageFilter() const { return current_image_filter_; } + void setAntiAlias(bool aa) override; + void setDither(bool dither) override; + void setInvertColors(bool invert) override; + void setStrokeCap(SkPaint::Cap cap) override; + void setStrokeJoin(SkPaint::Join join) override; + void setStyle(SkPaint::Style style) override; + void setStrokeWidth(SkScalar width) override; + void setStrokeMiter(SkScalar limit) override; + void setColor(SkColor color) override; + void setBlendMode(SkBlendMode mode) override; + void setBlender(sk_sp blender) override; + void setShader(sk_sp shader) override; + void setImageFilter(sk_sp filter) override; + void setColorFilter(sk_sp filter) override; + void setPathEffect(sk_sp effect) override; + void setMaskFilter(sk_sp filter) override; + void setMaskBlurFilter(SkBlurStyle style, SkScalar sigma) override; void save() override; - void saveLayer(const SkRect* bounds, bool restore_with_paint) override; + void saveLayer(const SkRect* bounds, bool restoreWithPaint) override; void restore() override; - int getSaveCount() { return save_level_ + 1; } void translate(SkScalar tx, SkScalar ty) override; void scale(SkScalar sx, SkScalar sy) override; void rotate(SkScalar degrees) override; void skew(SkScalar sx, SkScalar sy) override; - void setAttributesFromPaint(const SkPaint& paint, - const DisplayListAttributeFlags flags); - // clang-format off // 2x3 2D affine subset of a 4x4 transform in row major order @@ -895,9 +514,9 @@ class DisplayListBuilder final : public virtual Dispatcher, public SkRefCnt { // clang-format on - void clipRect(const SkRect& rect, SkClipOp clip_op, bool is_aa) override; - void clipRRect(const SkRRect& rrect, SkClipOp clip_op, bool is_aa) override; - void clipPath(const SkPath& path, SkClipOp clip_op, bool is_aa) override; + void clipRect(const SkRect& rect, SkClipOp clip_op, bool isAA) override; + void clipRRect(const SkRRect& rrect, SkClipOp clip_op, bool isAA) override; + void clipPath(const SkPath& path, SkClipOp clip_op, bool isAA) override; void drawPaint() override; void drawColor(SkColor color, SkBlendMode mode) override; @@ -980,51 +599,6 @@ class DisplayListBuilder final : public virtual Dispatcher, public SkRefCnt { template void* Push(size_t extra, int op_inc, Args&&... args); - - // kInvalidSigma is used to indicate that no MaskBlur is currently set. - static constexpr SkScalar kInvalidSigma = 0.0; - bool mask_sigma_valid(SkScalar sigma) { - return SkScalarIsFinite(sigma) && sigma > 0.0; - } - - void onSetAntiAlias(bool aa); - void onSetDither(bool dither); - void onSetInvertColors(bool invert); - void onSetStrokeCap(SkPaint::Cap cap); - void onSetStrokeJoin(SkPaint::Join join); - void onSetStyle(SkPaint::Style style); - void onSetStrokeWidth(SkScalar width); - void onSetStrokeMiter(SkScalar limit); - void onSetColor(SkColor color); - void onSetBlendMode(SkBlendMode mode); - void onSetBlender(sk_sp blender); - void onSetShader(sk_sp shader); - void onSetImageFilter(sk_sp filter); - void onSetColorFilter(sk_sp filter); - void onSetPathEffect(sk_sp effect); - void onSetMaskFilter(sk_sp filter); - void onSetMaskBlurFilter(SkBlurStyle style, SkScalar sigma); - - // These values should match the defaults of the Dart Paint object. - bool current_anti_alias_ = false; - bool current_dither_ = false; - bool current_invert_colors_ = false; - SkColor current_color_ = 0xFF000000; - SkPaint::Style current_style_ = SkPaint::Style::kFill_Style; - SkScalar current_stroke_width_ = 0.0; - SkScalar current_stroke_miter_ = 4.0; - SkPaint::Cap current_stroke_cap_ = SkPaint::Cap::kButt_Cap; - SkPaint::Join current_stroke_join_ = SkPaint::Join::kMiter_Join; - // If |current_blender_| is set then |current_blend_mode_| should be ignored - SkBlendMode current_blend_mode_ = SkBlendMode::kSrcOver; - sk_sp current_blender_; - sk_sp current_shader_; - sk_sp current_color_filter_; - sk_sp current_image_filter_; - sk_sp current_path_effect_; - sk_sp current_mask_filter_; - int current_mask_style_; - SkScalar current_mask_sigma_ = kInvalidSigma; }; } // namespace flutter diff --git a/flow/display_list_canvas.cc b/flow/display_list_canvas.cc index 7f66a37515ec6..72b8574d3c9f1 100644 --- a/flow/display_list_canvas.cc +++ b/flow/display_list_canvas.cc @@ -261,7 +261,7 @@ void DisplayListCanvasRecorder::willSave() { SkCanvas::SaveLayerStrategy DisplayListCanvasRecorder::getSaveLayerStrategy( const SaveLayerRec& rec) { if (rec.fPaint) { - builder_->setAttributesFromPaint(*rec.fPaint, kSaveLayerWithPaintFlags); + RecordPaintAttributes(rec.fPaint, DrawType::kSaveLayerOpType); builder_->saveLayer(rec.fBounds, true); } else { builder_->saveLayer(rec.fBounds, false); @@ -273,28 +273,28 @@ void DisplayListCanvasRecorder::didRestore() { } void DisplayListCanvasRecorder::onDrawPaint(const SkPaint& paint) { - builder_->setAttributesFromPaint(paint, kDrawPaintFlags); + RecordPaintAttributes(&paint, DrawType::kFillOpType); builder_->drawPaint(); } void DisplayListCanvasRecorder::onDrawRect(const SkRect& rect, const SkPaint& paint) { - builder_->setAttributesFromPaint(paint, kDrawRectFlags); + RecordPaintAttributes(&paint, DrawType::kDrawOpType); builder_->drawRect(rect); } void DisplayListCanvasRecorder::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) { - builder_->setAttributesFromPaint(paint, kDrawRRectFlags); + RecordPaintAttributes(&paint, DrawType::kDrawOpType); builder_->drawRRect(rrect); } void DisplayListCanvasRecorder::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) { - builder_->setAttributesFromPaint(paint, kDrawDRRectFlags); + RecordPaintAttributes(&paint, DrawType::kDrawOpType); builder_->drawDRRect(outer, inner); } void DisplayListCanvasRecorder::onDrawOval(const SkRect& rect, const SkPaint& paint) { - builder_->setAttributesFromPaint(paint, kDrawOvalFlags); + RecordPaintAttributes(&paint, DrawType::kDrawOpType); builder_->drawOval(rect); } void DisplayListCanvasRecorder::onDrawArc(const SkRect& rect, @@ -302,15 +302,12 @@ void DisplayListCanvasRecorder::onDrawArc(const SkRect& rect, SkScalar sweepAngle, bool useCenter, const SkPaint& paint) { - builder_->setAttributesFromPaint(paint, - useCenter // - ? kDrawArcWithCenterFlags - : kDrawArcNoCenterFlags); + RecordPaintAttributes(&paint, DrawType::kDrawOpType); builder_->drawArc(rect, startAngle, sweepAngle, useCenter); } void DisplayListCanvasRecorder::onDrawPath(const SkPath& path, const SkPaint& paint) { - builder_->setAttributesFromPaint(paint, kDrawPathFlags); + RecordPaintAttributes(&paint, DrawType::kDrawOpType); builder_->drawPath(path); } @@ -318,17 +315,7 @@ void DisplayListCanvasRecorder::onDrawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) { - switch (mode) { - case SkCanvas::kPoints_PointMode: - builder_->setAttributesFromPaint(paint, kDrawPointsAsPointsFlags); - break; - case SkCanvas::kLines_PointMode: - builder_->setAttributesFromPaint(paint, kDrawPointsAsLinesFlags); - break; - case SkCanvas::kPolygon_PointMode: - builder_->setAttributesFromPaint(paint, kDrawPointsAsPolygonFlags); - break; - } + RecordPaintAttributes(&paint, DrawType::kStrokeOpType); if (mode == SkCanvas::PointMode::kLines_PointMode && count == 2) { builder_->drawLine(pts[0], pts[1]); } else { @@ -343,7 +330,7 @@ void DisplayListCanvasRecorder::onDrawPoints(SkCanvas::PointMode mode, void DisplayListCanvasRecorder::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) { - builder_->setAttributesFromPaint(paint, kDrawVerticesFlags); + RecordPaintAttributes(&paint, DrawType::kDrawOpType); builder_->drawVertices(sk_ref_sp(vertices), mode); } @@ -353,7 +340,7 @@ void DisplayListCanvasRecorder::onDrawImage2(const SkImage* image, const SkSamplingOptions& sampling, const SkPaint* paint) { if (paint != nullptr) { - builder_->setAttributesFromPaint(*paint, kDrawImageWithPaintFlags); + RecordPaintAttributes(paint, DrawType::kImageOpType); } builder_->drawImage(sk_ref_sp(image), SkPoint::Make(dx, dy), sampling, paint != nullptr); @@ -366,7 +353,7 @@ void DisplayListCanvasRecorder::onDrawImageRect2( const SkPaint* paint, SrcRectConstraint constraint) { if (paint != nullptr) { - builder_->setAttributesFromPaint(*paint, kDrawImageRectWithPaintFlags); + RecordPaintAttributes(paint, DrawType::kImageRectOpType); } builder_->drawImageRect(sk_ref_sp(image), src, dst, sampling, paint != nullptr, constraint); @@ -383,7 +370,7 @@ void DisplayListCanvasRecorder::onDrawImageLattice2(const SkImage* image, if (*paint == default_paint) { paint = nullptr; } else { - builder_->setAttributesFromPaint(*paint, kDrawImageLatticeWithPaintFlags); + RecordPaintAttributes(paint, DrawType::kImageOpType); } } builder_->drawImageLattice(sk_ref_sp(image), lattice, dst, filter, @@ -399,7 +386,7 @@ void DisplayListCanvasRecorder::onDrawAtlas2(const SkImage* image, const SkRect* cull, const SkPaint* paint) { if (paint != nullptr) { - builder_->setAttributesFromPaint(*paint, kDrawAtlasWithPaintFlags); + RecordPaintAttributes(paint, DrawType::kImageOpType); } builder_->drawAtlas(sk_ref_sp(image), xform, src, colors, count, mode, sampling, cull, paint != nullptr); @@ -409,7 +396,7 @@ void DisplayListCanvasRecorder::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint) { - builder_->setAttributesFromPaint(paint, kDrawTextBlobFlags); + RecordPaintAttributes(&paint, DrawType::kDrawOpType); builder_->drawTextBlob(sk_ref_sp(blob), x, y); } void DisplayListCanvasRecorder::onDrawShadowRec(const SkPath& path, @@ -424,9 +411,119 @@ void DisplayListCanvasRecorder::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) { if (paint != nullptr) { - builder_->setAttributesFromPaint(*paint, kDrawPictureWithPaintFlags); + RecordPaintAttributes(paint, DrawType::kSaveLayerOpType); } builder_->drawPicture(sk_ref_sp(picture), matrix, paint != nullptr); } +void DisplayListCanvasRecorder::RecordPaintAttributes(const SkPaint* paint, + DrawType type) { + int dataNeeded; + switch (type) { + case DrawType::kDrawOpType: + dataNeeded = kDrawMask_; + break; + case DrawType::kFillOpType: + dataNeeded = kPaintMask_; + break; + case DrawType::kStrokeOpType: + dataNeeded = kStrokeMask_; + break; + case DrawType::kImageOpType: + dataNeeded = kImageMask_; + break; + case DrawType::kImageRectOpType: + dataNeeded = kImageRectMask_; + break; + case DrawType::kSaveLayerOpType: + dataNeeded = kSaveLayerMask_; + break; + default: + FML_DCHECK(false); + return; + } + if (paint == nullptr) { + paint = new SkPaint(); + } + if ((dataNeeded & kAaNeeded_) != 0 && current_aa_ != paint->isAntiAlias()) { + builder_->setAntiAlias(current_aa_ = paint->isAntiAlias()); + } + if ((dataNeeded & kDitherNeeded_) != 0 && + current_dither_ != paint->isDither()) { + builder_->setDither(current_dither_ = paint->isDither()); + } + if ((dataNeeded & kColorNeeded_) != 0 && + current_color_ != paint->getColor()) { + builder_->setColor(current_color_ = paint->getColor()); + } + if ((dataNeeded & kBlendNeeded_)) { + skstd::optional mode_optional = paint->asBlendMode(); + if (mode_optional) { + SkBlendMode mode = mode_optional.value(); + if (current_blender_ || current_blend_ != mode) { + builder_->setBlendMode(current_blend_ = mode); + current_blender_ = nullptr; + } + } else { + if (current_blender_.get() != paint->getBlender()) { + builder_->setBlender(current_blender_ = sk_ref_sp(paint->getBlender())); + } + } + } + // invert colors is a Flutter::Paint thing, not an SkPaint thing + // if ((dataNeeded & invertColorsNeeded_) != 0 && + // currentInvertColors_ != paint->???) { + // currentInvertColors_ = paint->invertColors; + // addOp_(currentInvertColors_ + // ? _CanvasOp.setInvertColors + // : _CanvasOp.clearInvertColors, 0); + // } + if ((dataNeeded & kPaintStyleNeeded_) != 0) { + if (current_style_ != paint->getStyle()) { + builder_->setStyle(current_style_ = paint->getStyle()); + } + if (current_style_ == SkPaint::Style::kStroke_Style) { + dataNeeded |= kStrokeStyleNeeded_; + } + } + if ((dataNeeded & kStrokeStyleNeeded_) != 0) { + if (current_stroke_width_ != paint->getStrokeWidth()) { + builder_->setStrokeWidth(current_stroke_width_ = paint->getStrokeWidth()); + } + if (current_cap_ != paint->getStrokeCap()) { + builder_->setStrokeCap(current_cap_ = paint->getStrokeCap()); + } + if (current_join_ != paint->getStrokeJoin()) { + builder_->setStrokeJoin(current_join_ = paint->getStrokeJoin()); + } + if (current_miter_limit_ != paint->getStrokeMiter()) { + builder_->setStrokeMiter(current_miter_limit_ = paint->getStrokeMiter()); + } + } + if ((dataNeeded & kShaderNeeded_) != 0 && + current_shader_.get() != paint->getShader()) { + builder_->setShader(current_shader_ = sk_ref_sp(paint->getShader())); + } + if ((dataNeeded & kColorFilterNeeded_) != 0 && + current_color_filter_.get() != paint->getColorFilter()) { + builder_->setColorFilter(current_color_filter_ = + sk_ref_sp(paint->getColorFilter())); + } + if ((dataNeeded & kImageFilterNeeded_) != 0 && + current_image_filter_.get() != paint->getImageFilter()) { + builder_->setImageFilter(current_image_filter_ = + sk_ref_sp(paint->getImageFilter())); + } + if ((dataNeeded & kPathEffectNeeded_) != 0 && + current_path_effect_.get() != paint->getPathEffect()) { + builder_->setPathEffect(current_path_effect_ = + sk_ref_sp(paint->getPathEffect())); + } + if ((dataNeeded & kMaskFilterNeeded_) != 0 && + current_mask_filter_.get() != paint->getMaskFilter()) { + builder_->setMaskFilter(current_mask_filter_ = + sk_ref_sp(paint->getMaskFilter())); + } +} + } // namespace flutter diff --git a/flow/display_list_canvas.h b/flow/display_list_canvas.h index d48b7760eaf81..a6ef6902f6b10 100644 --- a/flow/display_list_canvas.h +++ b/flow/display_list_canvas.h @@ -49,9 +49,9 @@ class DisplayListCanvasDispatcher : public virtual Dispatcher, SkScalar mwx, SkScalar mwy, SkScalar mwz, SkScalar mwt) override; // clang-format on - void clipRect(const SkRect& rect, SkClipOp clip_op, bool is_aa) override; - void clipRRect(const SkRRect& rrect, SkClipOp clip_op, bool is_aa) override; - void clipPath(const SkPath& path, SkClipOp clip_op, bool is_aa) override; + void clipRect(const SkRect& rect, SkClipOp clip_op, bool isAA) override; + void clipRRect(const SkRRect& rrect, SkClipOp clip_op, bool isAA) override; + void clipPath(const SkPath& path, SkClipOp clip_op, bool isAA) override; void drawPaint() override; void drawColor(SkColor color, SkBlendMode mode) override; @@ -120,8 +120,7 @@ class DisplayListCanvasDispatcher : public virtual Dispatcher, // Receives all methods on SkCanvas and sends them to a DisplayListBuilder class DisplayListCanvasRecorder : public SkCanvasVirtualEnforcer, - public SkRefCnt, - DisplayListOpFlags { + public SkRefCnt { public: DisplayListCanvasRecorder(const SkRect& bounds); @@ -234,8 +233,80 @@ class DisplayListCanvasRecorder const SkMatrix* matrix, const SkPaint* paint) override; + enum class DrawType { + // The operation will be an image operation + kImageOpType, + // The operation will be an imageRect operation + kImageRectOpType, + // The operation will be a fill or stroke depending on the paint.style + kDrawOpType, + // The operation will be a fill (ignoring paint.style) + kFillOpType, + // The operation will be a stroke (ignoring paint.style) + kStrokeOpType, + // The operation will be a saveLayer with a paint object + kSaveLayerOpType, + }; + + void RecordPaintAttributes(const SkPaint* paint, DrawType type); + private: sk_sp builder_; + + // Mask bits for the various attributes that might be needed for a given + // operation. + // clang-format off + static constexpr int kAaNeeded_ = 1 << 0; + static constexpr int kColorNeeded_ = 1 << 1; + static constexpr int kBlendNeeded_ = 1 << 2; + static constexpr int kInvertColorsNeeded_ = 1 << 3; + static constexpr int kPaintStyleNeeded_ = 1 << 4; + static constexpr int kStrokeStyleNeeded_ = 1 << 5; + static constexpr int kShaderNeeded_ = 1 << 6; + static constexpr int kColorFilterNeeded_ = 1 << 7; + static constexpr int kImageFilterNeeded_ = 1 << 8; + static constexpr int kPathEffectNeeded_ = 1 << 9; + static constexpr int kMaskFilterNeeded_ = 1 << 10; + static constexpr int kDitherNeeded_ = 1 << 11; + // clang-format on + + // Combinations of the above mask bits that are common to typical "draw" + // calls. + // Note that the strokeStyle_ is handled conditionally depending on whether + // the paintStyle_ attribute value is synchronized. It can also be manually + // specified for operations that will be always stroking, like [drawLine]. + static constexpr int kPaintMask_ = kAaNeeded_ | kColorNeeded_ | + kBlendNeeded_ | kInvertColorsNeeded_ | + kColorFilterNeeded_ | kShaderNeeded_ | + kDitherNeeded_ | kImageFilterNeeded_; + static constexpr int kDrawMask_ = kPaintMask_ | kPaintStyleNeeded_ | + kMaskFilterNeeded_ | kPathEffectNeeded_; + static constexpr int kStrokeMask_ = kPaintMask_ | kStrokeStyleNeeded_ | + kMaskFilterNeeded_ | kPathEffectNeeded_; + static constexpr int kImageMask_ = kColorNeeded_ | kBlendNeeded_ | + kInvertColorsNeeded_ | + kColorFilterNeeded_ | kDitherNeeded_ | + kImageFilterNeeded_ | kMaskFilterNeeded_; + static constexpr int kImageRectMask_ = kImageMask_ | kAaNeeded_; + static constexpr int kSaveLayerMask_ = + kColorNeeded_ | kBlendNeeded_ | kInvertColorsNeeded_ | + kColorFilterNeeded_ | kImageFilterNeeded_; + + bool current_aa_ = false; + bool current_dither_ = false; + SkColor current_color_ = 0xFF000000; + SkBlendMode current_blend_ = SkBlendMode::kSrcOver; + SkPaint::Style current_style_ = SkPaint::Style::kFill_Style; + SkScalar current_stroke_width_ = 0.0; + SkScalar current_miter_limit_ = 4.0; + SkPaint::Cap current_cap_ = SkPaint::Cap::kButt_Cap; + SkPaint::Join current_join_ = SkPaint::Join::kMiter_Join; + sk_sp current_blender_; + sk_sp current_shader_; + sk_sp current_color_filter_; + sk_sp current_image_filter_; + sk_sp current_path_effect_; + sk_sp current_mask_filter_; }; } // namespace flutter diff --git a/flow/display_list_canvas_unittests.cc b/flow/display_list_canvas_unittests.cc index 3bc178e6b5e71..9bb35ebd9c77d 100644 --- a/flow/display_list_canvas_unittests.cc +++ b/flow/display_list_canvas_unittests.cc @@ -70,13 +70,11 @@ constexpr SkScalar Miter4DiamondOffsetY = RenderWidth * 0.14; // Render 3 vertical and horizontal diamonds each // designed to break at the tested miter limits // 0.0, 4.0 and 10.0 -// Center is biased by 0.5 to include more pixel centers in the -// thin miters -constexpr SkScalar x_off_0 = RenderCenterX + 0.5; -constexpr SkScalar x_off_l1 = x_off_0 - Miter4DiamondOffsetX; +constexpr SkScalar x_off_0 = RenderCenterX; +constexpr SkScalar x_off_l1 = RenderCenterX - Miter4DiamondOffsetX; constexpr SkScalar x_off_l2 = x_off_l1 - Miter10DiamondOffsetX; constexpr SkScalar x_off_l3 = x_off_l2 - Miter10DiamondOffsetX; -constexpr SkScalar x_off_r1 = x_off_0 + Miter4DiamondOffsetX; +constexpr SkScalar x_off_r1 = RenderCenterX + Miter4DiamondOffsetX; constexpr SkScalar x_off_r2 = x_off_r1 + MiterExtremeDiamondOffsetX; constexpr SkScalar x_off_r3 = x_off_r2 + MiterExtremeDiamondOffsetX; constexpr SkPoint VerticalMiterDiamondPoints[] = { @@ -106,11 +104,11 @@ constexpr SkPoint VerticalMiterDiamondPoints[] = { const int VerticalMiterDiamondPointCount = sizeof(VerticalMiterDiamondPoints) / sizeof(VerticalMiterDiamondPoints[0]); -constexpr SkScalar y_off_0 = RenderCenterY + 0.5; -constexpr SkScalar y_off_u1 = x_off_0 - Miter4DiamondOffsetY; +constexpr SkScalar y_off_0 = RenderCenterY; +constexpr SkScalar y_off_u1 = RenderCenterY - Miter4DiamondOffsetY; constexpr SkScalar y_off_u2 = y_off_u1 - Miter10DiamondOffsetY; constexpr SkScalar y_off_u3 = y_off_u2 - Miter10DiamondOffsetY; -constexpr SkScalar y_off_d1 = x_off_0 + Miter4DiamondOffsetY; +constexpr SkScalar y_off_d1 = RenderCenterY + Miter4DiamondOffsetY; constexpr SkScalar y_off_d2 = y_off_d1 + MiterExtremeDiamondOffsetY; constexpr SkScalar y_off_d3 = y_off_d2 + MiterExtremeDiamondOffsetY; const SkPoint HorizontalMiterDiamondPoints[] = { @@ -155,67 +153,75 @@ const int HorizontalMiterDiamondPointCount = // avoid false bounds overflow notifications. class BoundsTolerance { public: - BoundsTolerance() = default; - BoundsTolerance(const BoundsTolerance&) = default; + BoundsTolerance() : BoundsTolerance(0, 0, 1, 1, 0, 0, 0) {} + BoundsTolerance(SkScalar bounds_pad_x, + SkScalar bounds_pad_y, + SkScalar scale_x, + SkScalar scale_y, + SkScalar absolute_pad_x, + SkScalar absolute_pad_y, + SkScalar discrete_offset) + : bounds_pad_x_(bounds_pad_x), + bounds_pad_y_(bounds_pad_y), + scale_x_(scale_x), + scale_y_(scale_y), + absolute_pad_x_(absolute_pad_x), + absolute_pad_y_(absolute_pad_y), + discrete_offset_(discrete_offset) {} BoundsTolerance addBoundsPadding(SkScalar bounds_pad_x, SkScalar bounds_pad_y) const { - BoundsTolerance copy = BoundsTolerance(*this); - copy.bounds_pad_.offset(bounds_pad_x, bounds_pad_y); - return copy; + return {bounds_pad_x_ + bounds_pad_x, + bounds_pad_y_ + bounds_pad_y, + scale_x_, + scale_y_, + absolute_pad_x_, + absolute_pad_y_, + discrete_offset_}; } - BoundsTolerance mulScale(SkScalar scale_x, SkScalar scale_y) const { - BoundsTolerance copy = BoundsTolerance(*this); - copy.scale_.fX *= scale_x; - copy.scale_.fY *= scale_y; - return copy; + BoundsTolerance addScale(SkScalar scale_x, SkScalar scale_y) const { + return {bounds_pad_x_, // + bounds_pad_y_, // + scale_x_ * scale_x, // + scale_y_ * scale_y, // + absolute_pad_x_, // + absolute_pad_y_, // + discrete_offset_}; } BoundsTolerance addAbsolutePadding(SkScalar absolute_pad_x, SkScalar absolute_pad_y) const { - BoundsTolerance copy = BoundsTolerance(*this); - copy.absolute_pad_.offset(absolute_pad_x, absolute_pad_y); - return copy; + return {bounds_pad_x_, + bounds_pad_y_, + scale_x_, + scale_y_, + absolute_pad_x_ + absolute_pad_x, + absolute_pad_y_ + absolute_pad_y, + discrete_offset_}; } BoundsTolerance addDiscreteOffset(SkScalar discrete_offset) const { - BoundsTolerance copy = BoundsTolerance(*this); - copy.discrete_offset_ += discrete_offset; - return copy; + return {bounds_pad_x_, + bounds_pad_y_, + scale_x_, + scale_y_, + absolute_pad_x_, + absolute_pad_y_, + discrete_offset_ + discrete_offset}; } - BoundsTolerance clip(SkRect clip) const { - BoundsTolerance copy = BoundsTolerance(*this); - if (!copy.clip_.intersect(clip)) { - copy.clip_.setEmpty(); - } - return copy; - } - - static SkRect Scale(const SkRect& rect, const SkPoint& scales) { - SkScalar outset_x = rect.width() * (scales.fX - 1); - SkScalar outset_y = rect.height() * (scales.fY - 1); - return rect.makeOutset(outset_x, outset_y); - } - - bool overflows(SkIRect pix_bounds, + bool overflows(SkISize pix_size, int worst_bounds_pad_x, int worst_bounds_pad_y) const { - SkRect allowed = SkRect::Make(pix_bounds); - allowed.outset(bounds_pad_.fX, bounds_pad_.fY); - allowed = Scale(allowed, scale_); - allowed.outset(absolute_pad_.fX, absolute_pad_.fY); - if (!allowed.intersect(clip_)) { - allowed.setEmpty(); - } - SkIRect rounded = allowed.roundOut(); - int padLeft = std::max(0, pix_bounds.fLeft - rounded.fLeft); - int padTop = std::max(0, pix_bounds.fTop - rounded.fTop); - int padRight = std::max(0, pix_bounds.fRight - rounded.fRight); - int padBottom = std::max(0, pix_bounds.fBottom - rounded.fBottom); - int allowed_pad_x = std::max(padLeft, padRight); - int allowed_pad_y = std::max(padTop, padBottom); + int scaled_bounds_pad_x = + std::ceil((pix_size.width() + bounds_pad_x_) * scale_x_); + int allowed_width = scaled_bounds_pad_x + absolute_pad_x_; + int scaled_bounds_pad_y = + std::ceil((pix_size.height() + bounds_pad_y_) * scale_y_); + int allowed_height = scaled_bounds_pad_y + absolute_pad_y_; + int allowed_pad_x = allowed_width - pix_size.width(); + int allowed_pad_y = allowed_height - pix_size.height(); if (worst_bounds_pad_x > allowed_pad_x || worst_bounds_pad_y > allowed_pad_y) { FML_LOG(ERROR) << "allowed pad: " // @@ -228,301 +234,18 @@ class BoundsTolerance { SkScalar discrete_offset() const { return discrete_offset_; } private: - SkPoint bounds_pad_ = {0, 0}; - SkPoint scale_ = {1, 1}; - SkPoint absolute_pad_ = {0, 0}; - SkRect clip_ = {-1E9, -1E9, 1E9, 1E9}; - - SkScalar discrete_offset_ = 0; -}; - -typedef const std::function CvSetup; -typedef const std::function CvRenderer; -typedef const std::function DlRenderer; -static void EmptyCvRenderer(SkCanvas*, const SkPaint&) {} -static void EmptyDlRenderer(DisplayListBuilder&) {} - -class RenderSurface { - public: - RenderSurface(sk_sp surface) : surface_(surface) {} - ~RenderSurface() { sk_free(addr_); } - - SkCanvas* canvas() { return surface_->getCanvas(); } - - const SkPixmap* pixmap() { - if (!pixmap_.addr()) { - SkImageInfo info = surface_->imageInfo(); - if (info.colorType() != kN32_SkColorType || - !surface_->peekPixels(&pixmap_)) { - info = SkImageInfo::MakeN32Premul(info.dimensions()); - addr_ = malloc(info.computeMinByteSize() * info.height()); - pixmap_.reset(info, addr_, info.minRowBytes()); - EXPECT_TRUE(surface_->readPixels(pixmap_, 0, 0)); - } - } - return &pixmap_; - } - - private: - sk_sp surface_; - SkPixmap pixmap_; - void* addr_ = nullptr; + SkScalar bounds_pad_x_; + SkScalar bounds_pad_y_; + SkScalar scale_x_; + SkScalar scale_y_; + SkScalar absolute_pad_x_; + SkScalar absolute_pad_y_; + + SkScalar discrete_offset_; }; -class RenderEnvironment { - public: - static RenderEnvironment Make565() { - return RenderEnvironment(SkImageInfo::Make({1, 1}, kRGB_565_SkColorType, - kOpaque_SkAlphaType, nullptr)); - } - - static RenderEnvironment MakeN32() { - return RenderEnvironment(SkImageInfo::MakeN32Premul(1, 1)); - } - - RenderSurface MakeSurface(const SkColor bg = SK_ColorTRANSPARENT, - int width = TestWidth, - int height = TestHeight) const { - sk_sp surface = - SkSurface::MakeRaster(info_.makeWH(width, height)); - surface->getCanvas()->clear(bg); - return RenderSurface(surface); - } - - void init_ref(CvRenderer& cv_renderer, SkColor bg = SK_ColorTRANSPARENT) { - init_ref([=](SkCanvas*, SkPaint&) {}, cv_renderer, bg); - } - - void init_ref(CvSetup& cv_setup, - CvRenderer& cv_renderer, - SkColor bg = SK_ColorTRANSPARENT) { - ref_canvas()->clear(bg); - cv_setup(ref_canvas(), ref_paint_); - ref_matrix_ = ref_canvas()->getTotalMatrix(); - ref_clip_ = ref_canvas()->getDeviceClipBounds(); - cv_renderer(ref_canvas(), ref_paint_); - ref_pixmap_ = ref_surface_.pixmap(); - } - - SkCanvas* ref_canvas() { return ref_surface_.canvas(); } - const SkPaint& ref_paint() const { return ref_paint_; } - const SkMatrix& ref_matrix() const { return ref_matrix_; } - const SkIRect& ref_clip_bounds() const { return ref_clip_; } - const SkPixmap* ref_pixmap() const { return ref_pixmap_; } - +class CanvasCompareTester { private: - RenderEnvironment(const SkImageInfo& info) - : info_(info), ref_surface_(MakeSurface()) {} - - const SkImageInfo info_; - - SkPaint ref_paint_; - SkMatrix ref_matrix_; - SkIRect ref_clip_; - RenderSurface ref_surface_; - const SkPixmap* ref_pixmap_ = nullptr; -}; - -class TestParameters { - public: - TestParameters(const CvRenderer& cv_renderer, - const DlRenderer& dl_renderer, - const DisplayListAttributeFlags& flags) - : cv_renderer_(cv_renderer), dl_renderer_(dl_renderer), flags_(flags) {} - - bool uses_paint() const { return !flags_.ignores_paint(); } - - bool should_match(const RenderEnvironment& env, - const SkPaint& paint, - const SkMatrix& matrix, - const SkIRect& device_clip, - bool has_diff_clip, - bool has_mutating_save_layer) const { - if (has_mutating_save_layer) { - return false; - } - if (env.ref_clip_bounds() != device_clip || has_diff_clip) { - return false; - } - if (env.ref_matrix() != matrix && !flags_.is_flood()) { - return false; - } - if (flags_.ignores_paint()) { - return true; - } - const SkPaint& ref_paint = env.ref_paint(); - if (flags_.applies_anti_alias() && // - ref_paint.isAntiAlias() != paint.isAntiAlias()) { - return false; - } - if (flags_.applies_dither() && // - ref_paint.isDither() != paint.isDither()) { - return false; - } - if (flags_.applies_color() && // - ref_paint.getColor() != paint.getColor()) { - return false; - } - if (flags_.applies_alpha() && // - ref_paint.getAlpha() != paint.getAlpha()) { - return false; - } - if (flags_.applies_blend() && // - ref_paint.getBlender() != paint.getBlender()) { - return false; - } - if (flags_.applies_color_filter() && // - ref_paint.getColorFilter() != paint.getColorFilter()) { - return false; - } - if (flags_.applies_mask_filter() && // - ref_paint.getMaskFilter() != paint.getMaskFilter()) { - return false; - } - if (flags_.applies_image_filter() && // - ref_paint.getImageFilter() != paint.getImageFilter()) { - return false; - } - if (flags_.applies_shader() && // - ref_paint.getShader() != paint.getShader()) { - return false; - } - DisplayListSpecialGeometryFlags geo_flags = - flags_.WithPathEffect(paint.refPathEffect()); - if (flags_.applies_path_effect() && // - ref_paint.getPathEffect() != paint.getPathEffect()) { - SkPathEffect::DashInfo info; - if (paint.getPathEffect()->asADash(&info) != - SkPathEffect::kDash_DashType) { - return false; - } - if (!ignores_dashes()) { - return false; - } - } - bool is_stroked = flags_.is_stroked(ref_paint.getStyle()); - if (flags_.is_stroked(paint.getStyle()) != is_stroked) { - return false; - } - if (!is_stroked) { - return true; - } - if (ref_paint.getStrokeWidth() != paint.getStrokeWidth()) { - return false; - } - if (geo_flags.may_have_end_caps() && // - getCap(ref_paint, geo_flags) != getCap(paint, geo_flags)) { - return false; - } - if (geo_flags.may_have_joins()) { - if (ref_paint.getStrokeJoin() != paint.getStrokeJoin()) { - return false; - } - if (ref_paint.getStrokeJoin() == SkPaint::kMiter_Join) { - SkScalar ref_miter = ref_paint.getStrokeMiter(); - SkScalar test_miter = paint.getStrokeMiter(); - // miter limit < 1.4 affects right angles - if (geo_flags.may_have_acute_joins() || // - ref_miter < 1.4 || test_miter < 1.4) { - if (ref_miter != test_miter) { - return false; - } - } - } - } - return true; - } - - SkPaint::Cap getCap(const SkPaint& paint, - DisplayListSpecialGeometryFlags geo_flags) const { - SkPaint::Cap cap = paint.getStrokeCap(); - if (geo_flags.butt_cap_becomes_square() && cap == SkPaint::kButt_Cap) { - return SkPaint::kSquare_Cap; - } - return cap; - } - - const BoundsTolerance adjust(const BoundsTolerance& tolerance, - const SkPaint& paint, - const SkMatrix& matrix) const { - if (is_draw_text_blob() && tolerance.discrete_offset() > 0) { - // drawTextBlob needs just a little more leeway when using a - // discrete path effect. - return tolerance.addBoundsPadding(2, 2); - } - if (is_draw_line()) { - return lineAdjust(tolerance, paint, matrix); - } - if (is_draw_arc_center()) { - if (paint.getStyle() != SkPaint::kFill_Style && - paint.getStrokeJoin() == SkPaint::kMiter_Join) { - // the miter join at the center of an arc does not really affect - // its bounds in any of our test cases, but the bounds code needs - // to take it into account for the cases where it might, so we - // relax our tolerance to reflect the miter bounds padding. - SkScalar miter_pad = - paint.getStrokeMiter() * paint.getStrokeWidth() * 0.5f; - return tolerance.addBoundsPadding(miter_pad, miter_pad); - } - } - return tolerance; - } - - const BoundsTolerance lineAdjust(const BoundsTolerance& tolerance, - const SkPaint& paint, - const SkMatrix& matrix) const { - SkScalar adjust = 0.0; - SkScalar half_width = paint.getStrokeWidth() * 0.5f; - if (tolerance.discrete_offset() > 0) { - // When a discrete path effect is added, the bounds calculations must - // allow for miters in any direction, but a horizontal line will not - // have miters in the horizontal direction, similarly for vertical - // lines, and diagonal lines will have miters off at a "45 degree" - // angle that don't expand the bounds much at all. - // Also, the discrete offset will not move any points parallel with - // the line, so provide tolerance for both miters and offset. - adjust = - half_width * paint.getStrokeMiter() + tolerance.discrete_offset(); - } - DisplayListSpecialGeometryFlags geo_flags = - flags_.WithPathEffect(paint.refPathEffect()); - if (paint.getStrokeCap() == SkPaint::kButt_Cap && - !geo_flags.butt_cap_becomes_square()) { - adjust = std::max(adjust, half_width); - } - if (adjust == 0) { - return tolerance; - } - SkScalar hTolerance; - SkScalar vTolerance; - if (is_horizontal_line()) { - FML_DCHECK(!is_vertical_line()); - hTolerance = adjust; - vTolerance = 0; - } else if (is_vertical_line()) { - hTolerance = 0; - vTolerance = adjust; - } else { - // The perpendicular miters just do not impact the bounds of - // diagonal lines at all as they are aimed in the wrong direction - // to matter. So allow tolerance in both axes. - hTolerance = vTolerance = adjust; - } - BoundsTolerance new_tolerance = - tolerance.addBoundsPadding(hTolerance, vTolerance); - return new_tolerance; - } - - const CvRenderer& cv_renderer() const { return cv_renderer_; } - void render_to(SkCanvas* canvas, SkPaint& paint) const { - cv_renderer_(canvas, paint); - } - - const DlRenderer& dl_renderer() const { return dl_renderer_; } - void render_to(DisplayListBuilder& builder) const { // - dl_renderer_(builder); - } - // If a test is using any shadow operations then we cannot currently // record those in an SkCanvas and play it back into a DisplayList // because internally the operation gets encapsulated in a Skia @@ -530,576 +253,334 @@ class TestParameters { // that use shadows, we can perform a lot of tests, but not the tests // that require SkCanvas->DisplayList transfers. // See: https://bugs.chromium.org/p/skia/issues/detail?id=12125 - bool is_draw_shadows() const { return is_draw_shadows_; } + static bool TestingDrawShadows; // The CPU renders nothing for drawVertices with a Blender. // See: https://bugs.chromium.org/p/skia/issues/detail?id=12200 - bool is_draw_vertices() const { return is_draw_vertices_; } + static bool TestingDrawVertices; // The CPU renders nothing for drawAtlas with a Blender. // See: https://bugs.chromium.org/p/skia/issues/detail?id=12199 - bool is_draw_atlas() const { return is_draw_atlas_; } - // Tests that call drawTextBlob with an sk_ref paint attribute will cause - // those attributes to be stored in an internal Skia cache so we need - // to expect that the |sk_ref.unique()| call will fail in those cases. - // See: (TBD(flar) - file Skia bug) - bool is_draw_text_blob() const { return is_draw_text_blob_; } - bool is_draw_display_list() const { return is_draw_display_list_; } - bool is_draw_line() const { return is_draw_line_; } - bool is_draw_arc_center() const { return is_draw_arc_center_; } - bool is_horizontal_line() const { return is_horizontal_line_; } - bool is_vertical_line() const { return is_vertical_line_; } - bool ignores_dashes() const { return ignores_dashes_; } - - TestParameters& set_draw_shadows() { - is_draw_shadows_ = true; - return *this; - } - TestParameters& set_draw_vertices() { - is_draw_vertices_ = true; - return *this; - } - TestParameters& set_draw_text_blob() { - is_draw_text_blob_ = true; - return *this; - } - TestParameters& set_draw_atlas() { - is_draw_atlas_ = true; - return *this; - } - TestParameters& set_draw_display_list() { - is_draw_display_list_ = true; - return *this; - } - TestParameters& set_draw_line() { - is_draw_line_ = true; - return *this; - } - TestParameters& set_draw_arc_center() { - is_draw_arc_center_ = true; - return *this; - } - TestParameters& set_ignores_dashes() { - ignores_dashes_ = true; - return *this; - } - TestParameters& set_horizontal_line() { - is_horizontal_line_ = true; - return *this; - } - TestParameters& set_vertical_line() { - is_vertical_line_ = true; - return *this; - } + static bool TestingDrawAtlas; - private: - const CvRenderer& cv_renderer_; - const DlRenderer& dl_renderer_; - const DisplayListAttributeFlags& flags_; - - bool is_draw_shadows_ = false; - bool is_draw_vertices_ = false; - bool is_draw_text_blob_ = false; - bool is_draw_atlas_ = false; - bool is_draw_display_list_ = false; - bool is_draw_line_ = false; - bool is_draw_arc_center_ = false; - bool ignores_dashes_ = false; - bool is_horizontal_line_ = false; - bool is_vertical_line_ = false; -}; - -class CaseParameters { public: - CaseParameters(std::string info) - : CaseParameters(info, EmptyCvRenderer, EmptyDlRenderer) {} - - CaseParameters(std::string info, CvSetup cv_setup, DlRenderer dl_setup) - : CaseParameters(info, - cv_setup, - dl_setup, - EmptyCvRenderer, - EmptyDlRenderer, - SK_ColorTRANSPARENT, - false, - false) {} - - CaseParameters(std::string info, - CvSetup cv_setup, - DlRenderer dl_setup, - CvRenderer cv_restore, - DlRenderer dl_restore, - SkColor bg, - bool has_diff_clip, - bool has_mutating_save_layer) - : info_(info), - bg_(bg), - cv_setup_(cv_setup), - dl_setup_(dl_setup), - cv_restore_(cv_restore), - dl_restore_(dl_restore), - has_diff_clip_(has_diff_clip), - has_mutating_save_layer_(has_mutating_save_layer) {} - - CaseParameters with_restore(CvRenderer cv_restore, - DlRenderer dl_restore, - bool mutating_layer) { - return CaseParameters(info_, cv_setup_, dl_setup_, cv_restore, dl_restore, - bg_, has_diff_clip_, mutating_layer); - } + typedef const std::function CvRenderer; + typedef const std::function DlRenderer; + typedef const std::function + ToleranceAdjuster; - CaseParameters with_bg(SkColor bg) { - return CaseParameters(info_, cv_setup_, dl_setup_, cv_restore_, dl_restore_, - bg, has_diff_clip_, has_mutating_save_layer_); + static BoundsTolerance DefaultTolerance; + static const BoundsTolerance DefaultAdjuster(const BoundsTolerance& tolerance, + const SkPaint& paint, + const SkMatrix& matrix) { + return tolerance; } - CaseParameters with_diff_clip() { - return CaseParameters(info_, cv_setup_, dl_setup_, cv_restore_, dl_restore_, - bg_, true, has_mutating_save_layer_); + // All of the tests should eventually use this method except for the + // tests that call |RenderNoAttributes| because they do not use the + // SkPaint object. + // But there are a couple of conditions beyond our control which require + // the use of one of the variant methods below (|RenderShadows|, + // |RenderVertices|, |RenderAtlas|). + static void RenderAll(CvRenderer& cv_renderer, + DlRenderer& dl_renderer, + ToleranceAdjuster& adjuster = DefaultAdjuster, + const BoundsTolerance& tolerance = DefaultTolerance) { + RenderNoAttributes(cv_renderer, dl_renderer, adjuster, tolerance); + RenderWithAttributes(cv_renderer, dl_renderer, adjuster, tolerance); } - std::string info() const { return info_; } - SkColor bg() const { return bg_; } - bool has_diff_clip() const { return has_diff_clip_; } - bool has_mutating_save_layer() const { return has_mutating_save_layer_; } - - CvSetup cv_setup() const { return cv_setup_; } - DlRenderer dl_setup() const { return dl_setup_; } - CvRenderer cv_restore() const { return cv_restore_; } - DlRenderer dl_restore() const { return dl_restore_; } - - const SkPaint render_to(SkCanvas* canvas, // - const TestParameters& testP) const { - SkPaint paint; - cv_setup_(canvas, paint); - testP.render_to(canvas, paint); - cv_restore_(canvas, paint); - return paint; + // Used by the tests that render shadows to deal with a condition where + // we cannot recapture the shadow information from an SkCanvas stream + // due to the DrawShadowRec used by Skia is not properly exported. + // See: https://bugs.chromium.org/p/skia/issues/detail?id=12125 + static void RenderShadows( + CvRenderer& cv_renderer, + DlRenderer& dl_renderer, + ToleranceAdjuster& adjuster = DefaultAdjuster, + const BoundsTolerance& tolerance = DefaultTolerance) { + TestingDrawShadows = true; + RenderNoAttributes(cv_renderer, dl_renderer, adjuster, tolerance); + TestingDrawShadows = false; } - void render_to(DisplayListBuilder& builder, - const TestParameters& testP) const { - dl_setup_(builder); - testP.render_to(builder); - dl_restore_(builder); + // Used by the tests that call drawVertices to avoid using an SkBlender + // during testing because the CPU renderer appears not to render anything. + // See: https://bugs.chromium.org/p/skia/issues/detail?id=12200 + static void RenderVertices(CvRenderer& cv_renderer, DlRenderer& dl_renderer) { + TestingDrawVertices = true; + RenderAll(cv_renderer, dl_renderer); + TestingDrawVertices = false; } - private: - const std::string info_; - const SkColor bg_; - const CvSetup cv_setup_; - const DlRenderer dl_setup_; - const CvRenderer cv_restore_; - const DlRenderer dl_restore_; - const bool has_diff_clip_; - const bool has_mutating_save_layer_; -}; - -class CanvasCompareTester { - public: - static BoundsTolerance DefaultTolerance; + // Used by the tests that call drawAtlas to avoid using an SkBlender + // during testing because the CPU renderer appears not to render anything. + // See: https://bugs.chromium.org/p/skia/issues/detail?id=12199 + static void RenderAtlas(CvRenderer& cv_renderer, DlRenderer& dl_renderer) { + TestingDrawAtlas = true; + RenderAll(cv_renderer, dl_renderer); + TestingDrawAtlas = false; + } - static void RenderAll(const TestParameters& params, - const BoundsTolerance& tolerance = DefaultTolerance) { - RenderEnvironment env = RenderEnvironment::MakeN32(); - env.init_ref(params.cv_renderer()); - RenderWithTransforms(params, env, tolerance); - RenderWithClips(params, env, tolerance); - RenderWithSaveRestore(params, env, tolerance); - // Only test attributes if the canvas version uses the paint object - if (params.uses_paint()) { - RenderWithAttributes(params, env, tolerance); - } + // Used by the tests that call a draw method that does not take a paint + // call. Those tests could use |RenderAll| but there would be a lot of + // wasted test runs that prepare an SkPaint that is never used. + static void RenderNoAttributes( + CvRenderer& cv_renderer, + DlRenderer& dl_renderer, + ToleranceAdjuster& adjuster = DefaultAdjuster, + const BoundsTolerance& tolerance = DefaultTolerance) { + RenderWith([=](SkCanvas*, SkPaint& p) {}, // + [=](DisplayListBuilder& d) {}, // + cv_renderer, dl_renderer, adjuster, tolerance, "Base Test"); + RenderWithTransforms(cv_renderer, dl_renderer, adjuster, tolerance); + RenderWithClips(cv_renderer, dl_renderer, adjuster, tolerance); + RenderWithSaveRestore(cv_renderer, dl_renderer, adjuster, tolerance); } - static void RenderWithSaveRestore(const TestParameters& testP, - const RenderEnvironment& env, + static void RenderWithSaveRestore(CvRenderer& cv_renderer, + DlRenderer& dl_renderer, + ToleranceAdjuster& adjuster, const BoundsTolerance& tolerance) { - SkRect clip = SkRect::MakeXYWH(RenderCenterX - 1, RenderCenterY - 1, 2, 2); - SkRect rect = SkRect::MakeXYWH(RenderCenterX, RenderCenterY, 10, 10); + SkRect clip = SkRect::MakeLTRB(0, 0, 10, 10); + SkRect rect = SkRect::MakeLTRB(5, 5, 15, 15); SkColor alpha_layer_color = SkColorSetARGB(0x7f, 0x00, 0xff, 0xff); SkColor default_color = SkPaint().getColor(); - CvRenderer cv_restore = [=](SkCanvas* cv, const SkPaint& p) { - // Draw another primitive to disable peephole optimizations - cv->drawRect(RenderBounds.makeOffset(500, 500), p); + CvRenderer cv_restored = [=](SkCanvas* cv, SkPaint& p) { + // Draw more than one primitive to disable peephole optimizations + cv->drawRect(RenderBounds.makeOutset(5, 5), p); + cv_renderer(cv, p); cv->restore(); }; - DlRenderer dl_restore = [=](DisplayListBuilder& b) { - // Draw another primitive to disable peephole optimizations - b.drawRect(RenderBounds.makeOffset(500, 500)); + DlRenderer dl_restored = [=](DisplayListBuilder& b) { + // Draw more than one primitive to disable peephole optimizations + b.drawRect(RenderBounds.makeOutset(5, 5)); + dl_renderer(b); b.restore(); }; - SkRect layer_bounds = RenderBounds.makeInset(15, 15); - RenderWith(testP, env, tolerance, - CaseParameters( - "With prior save/clip/restore", - [=](SkCanvas* cv, SkPaint& p) { - cv->save(); - cv->clipRect(clip, SkClipOp::kIntersect, false); - SkPaint p2; - cv->drawRect(rect, p2); - p2.setBlendMode(SkBlendMode::kClear); - cv->drawRect(rect, p2); - cv->restore(); - }, - [=](DisplayListBuilder& b) { - b.save(); - b.clipRect(clip, SkClipOp::kIntersect, false); - b.drawRect(rect); - b.setBlendMode(SkBlendMode::kClear); - b.drawRect(rect); - b.setBlendMode(SkBlendMode::kSrcOver); - b.restore(); - })); - RenderWith(testP, env, tolerance, - CaseParameters( - "saveLayer no paint, no bounds", - [=](SkCanvas* cv, SkPaint& p) { // - cv->saveLayer(nullptr, nullptr); - }, - [=](DisplayListBuilder& b) { // - b.saveLayer(nullptr, false); - }) - .with_restore(cv_restore, dl_restore, false)); - RenderWith(testP, env, tolerance, - CaseParameters( - "saveLayer no paint, with bounds", - [=](SkCanvas* cv, SkPaint& p) { // - cv->saveLayer(layer_bounds, nullptr); - }, - [=](DisplayListBuilder& b) { // - b.saveLayer(&layer_bounds, false); - }) - .with_restore(cv_restore, dl_restore, true)); - RenderWith(testP, env, tolerance, - CaseParameters( - "saveLayer with alpha, no bounds", - [=](SkCanvas* cv, SkPaint& p) { - SkPaint save_p; - save_p.setColor(alpha_layer_color); - cv->saveLayer(nullptr, &save_p); - }, - [=](DisplayListBuilder& b) { - b.setColor(alpha_layer_color); - b.saveLayer(nullptr, true); - b.setColor(default_color); - }) - .with_restore(cv_restore, dl_restore, true)); - RenderWith(testP, env, tolerance, - CaseParameters( - "saveLayer with alpha and bounds", - [=](SkCanvas* cv, SkPaint& p) { - SkPaint save_p; - save_p.setColor(alpha_layer_color); - cv->saveLayer(layer_bounds, &save_p); - }, - [=](DisplayListBuilder& b) { - b.setColor(alpha_layer_color); - b.saveLayer(&layer_bounds, true); - b.setColor(default_color); - }) - .with_restore(cv_restore, dl_restore, true)); + RenderWith( + [=](SkCanvas* cv, SkPaint& p) { + cv->save(); + cv->clipRect(clip, SkClipOp::kIntersect, false); + cv->drawRect(rect, p); + cv->restore(); + }, + [=](DisplayListBuilder& b) { + b.save(); + b.clipRect(clip, SkClipOp::kIntersect, false); + b.drawRect(rect); + b.restore(); + }, + cv_renderer, dl_renderer, adjuster, tolerance, + "With prior save/clip/restore"); + RenderWith( + [=](SkCanvas* cv, SkPaint& p) { // + cv->saveLayer(nullptr, nullptr); + }, + [=](DisplayListBuilder& b) { // + b.saveLayer(nullptr, false); + }, + cv_restored, dl_restored, adjuster, tolerance, + "saveLayer no paint, no bounds"); + RenderWith( + [=](SkCanvas* cv, SkPaint& p) { // + cv->saveLayer(RenderBounds, nullptr); + }, + [=](DisplayListBuilder& b) { // + b.saveLayer(&RenderBounds, false); + }, + cv_restored, dl_restored, adjuster, tolerance, + "saveLayer no paint, with bounds"); + RenderWith( + [=](SkCanvas* cv, SkPaint& p) { + SkPaint save_p; + save_p.setColor(alpha_layer_color); + cv->saveLayer(nullptr, &save_p); + }, + [=](DisplayListBuilder& b) { + b.setColor(alpha_layer_color); + b.saveLayer(nullptr, true); + b.setColor(default_color); + }, + cv_restored, dl_restored, adjuster, tolerance, + "saveLayer with alpha, no bounds"); + RenderWith( + [=](SkCanvas* cv, SkPaint& p) { + SkPaint save_p; + save_p.setColor(alpha_layer_color); + cv->saveLayer(RenderBounds, &save_p); + }, + [=](DisplayListBuilder& b) { + b.setColor(alpha_layer_color); + b.saveLayer(&RenderBounds, true); + b.setColor(default_color); + }, + cv_restored, dl_restored, adjuster, tolerance, + "saveLayer with alpha and bounds"); { - // clang-format off - constexpr float rotate_alpha_color_matrix[20] = { - 0, 1, 0, 0 , 0, - 0, 0, 1, 0 , 0, - 1, 0, 0, 0 , 0, - 0, 0, 0, 0.5, 0, - }; - // clang-format on - sk_sp filter = - SkColorFilters::Matrix(rotate_alpha_color_matrix); - { - RenderWith(testP, env, tolerance, - CaseParameters( - "saveLayer ColorFilter, no bounds", - [=](SkCanvas* cv, SkPaint& p) { - SkPaint save_p; - save_p.setColorFilter(filter); - cv->saveLayer(nullptr, &save_p); - p.setStrokeWidth(5.0); - }, - [=](DisplayListBuilder& b) { - b.setColorFilter(filter); - b.saveLayer(nullptr, true); - b.setColorFilter(nullptr); - b.setStrokeWidth(5.0); - }) - .with_restore(cv_restore, dl_restore, true)); - } - EXPECT_TRUE(filter->unique()) - << "saveLayer ColorFilter, no bounds Cleanup"; - { - RenderWith(testP, env, tolerance, - CaseParameters( - "saveLayer ColorFilter and bounds", - [=](SkCanvas* cv, SkPaint& p) { - SkPaint save_p; - save_p.setColorFilter(filter); - cv->saveLayer(RenderBounds, &save_p); - p.setStrokeWidth(5.0); - }, - [=](DisplayListBuilder& b) { - b.setColorFilter(filter); - b.saveLayer(&RenderBounds, true); - b.setColorFilter(nullptr); - b.setStrokeWidth(5.0); - }) - .with_restore(cv_restore, dl_restore, true)); - } - EXPECT_TRUE(filter->unique()) - << "saveLayer ColorFilter and bounds Cleanup"; - } - { - sk_sp filter = SkImageFilters::Arithmetic( - 0.1, 0.1, 0.1, 0.25, true, nullptr, nullptr); + sk_sp filter = + SkImageFilters::Blur(5.0, 5.0, SkTileMode::kDecal, nullptr, nullptr); + BoundsTolerance blur5Tolerance = tolerance.addBoundsPadding(4, 4); { - RenderWith(testP, env, tolerance, - CaseParameters( - "saveLayer ImageFilter, no bounds", - [=](SkCanvas* cv, SkPaint& p) { - SkPaint save_p; - save_p.setImageFilter(filter); - cv->saveLayer(nullptr, &save_p); - p.setStrokeWidth(5.0); - }, - [=](DisplayListBuilder& b) { - b.setImageFilter(filter); - b.saveLayer(nullptr, true); - b.setImageFilter(nullptr); - b.setStrokeWidth(5.0); - }) - .with_restore(cv_restore, dl_restore, true)); + RenderWith( + [=](SkCanvas* cv, SkPaint& p) { + SkPaint save_p; + save_p.setImageFilter(filter); + cv->saveLayer(nullptr, &save_p); + p.setStrokeWidth(5.0); + }, + [=](DisplayListBuilder& b) { + b.setImageFilter(filter); + b.saveLayer(nullptr, true); + b.setImageFilter(nullptr); + b.setStrokeWidth(5.0); + }, + cv_restored, dl_restored, adjuster, blur5Tolerance, + "saveLayer ImageFilter, no bounds"); } - EXPECT_TRUE(filter->unique()) + ASSERT_TRUE(filter->unique()) << "saveLayer ImageFilter, no bounds Cleanup"; { - RenderWith(testP, env, tolerance, - CaseParameters( - "saveLayer ImageFilter and bounds", - [=](SkCanvas* cv, SkPaint& p) { - SkPaint save_p; - save_p.setImageFilter(filter); - cv->saveLayer(RenderBounds, &save_p); - p.setStrokeWidth(5.0); - }, - [=](DisplayListBuilder& b) { - b.setImageFilter(filter); - b.saveLayer(&RenderBounds, true); - b.setImageFilter(nullptr); - b.setStrokeWidth(5.0); - }) - .with_restore(cv_restore, dl_restore, true)); + RenderWith( + [=](SkCanvas* cv, SkPaint& p) { + SkPaint save_p; + save_p.setImageFilter(filter); + cv->saveLayer(RenderBounds, &save_p); + p.setStrokeWidth(5.0); + }, + [=](DisplayListBuilder& b) { + b.setImageFilter(filter); + b.saveLayer(&RenderBounds, true); + b.setImageFilter(nullptr); + b.setStrokeWidth(5.0); + }, + cv_restored, dl_restored, adjuster, blur5Tolerance, + "saveLayer ImageFilter and bounds"); } - EXPECT_TRUE(filter->unique()) + ASSERT_TRUE(filter->unique()) << "saveLayer ImageFilter and bounds Cleanup"; } } - static void RenderWithAttributes(const TestParameters& testP, - const RenderEnvironment& env, + static void RenderWithAttributes(CvRenderer& cv_renderer, + DlRenderer& dl_renderer, + ToleranceAdjuster& adjuster, const BoundsTolerance& tolerance) { - RenderWith(testP, env, tolerance, CaseParameters("Defaults Test")); - - { - // CPU renderer with default line width of 0 does not show antialiasing - // for stroked primitives, so we make a new reference with a non-trivial - // stroke width to demonstrate the differences - RenderEnvironment aa_env = RenderEnvironment::MakeN32(); - // Tweak the bounds tolerance for the displacement of 1/10 of a pixel - const BoundsTolerance aa_tolerance = tolerance.addBoundsPadding(1, 1); - CvSetup cv_aa_setup = [=](SkCanvas* cv, SkPaint& p) { - cv->translate(0.1, 0.1); - p.setStrokeWidth(5.0); - }; - DlRenderer dl_aa_setup = [=](DisplayListBuilder& b) { - b.translate(0.1, 0.1); - b.setStrokeWidth(5.0); - }; - aa_env.init_ref(cv_aa_setup, testP.cv_renderer()); - RenderWith(testP, aa_env, aa_tolerance, - CaseParameters( - "AntiAlias == True", - [=](SkCanvas* cv, SkPaint& p) { - cv_aa_setup(cv, p); - p.setAntiAlias(true); - }, - [=](DisplayListBuilder& b) { - dl_aa_setup(b); - b.setAntiAlias(true); - })); - RenderWith(testP, aa_env, aa_tolerance, - CaseParameters( - "AntiAlias == False", - [=](SkCanvas* cv, SkPaint& p) { - cv_aa_setup(cv, p); - p.setAntiAlias(false); - }, - [=](DisplayListBuilder& b) { - dl_aa_setup(b); - b.setAntiAlias(false); - })); - } - - { - // The CPU renderer does not always dither for solid colors and we - // need to use a non-default color (default is black) on an opaque - // surface, so we use a shader instead of a color. Also, thin stroked - // primitives (mainly drawLine and drawPoints) do not show much - // dithering so we use a non-trivial stroke width as well. - RenderEnvironment dither_env = RenderEnvironment::Make565(); - SkColor dither_bg = SK_ColorBLACK; - CvSetup cv_dither_setup = [=](SkCanvas*, SkPaint& p) { - p.setShader(testImageShader); - p.setAlpha(0xf0); - p.setStrokeWidth(5.0); - }; - DlRenderer dl_dither_setup = [=](DisplayListBuilder& b) { - b.setShader(testImageShader); - b.setColor(SkColor(0xf0000000)); - b.setStrokeWidth(5.0); - }; - dither_env.init_ref(cv_dither_setup, testP.cv_renderer(), dither_bg); - RenderWith(testP, dither_env, tolerance, - CaseParameters( - "Dither == True", - [=](SkCanvas* cv, SkPaint& p) { - cv_dither_setup(cv, p); - p.setDither(true); - }, - [=](DisplayListBuilder& b) { - dl_dither_setup(b); - b.setDither(true); - }) - .with_bg(dither_bg)); - RenderWith(testP, dither_env, tolerance, - CaseParameters( - "Dither = False", - [=](SkCanvas* cv, SkPaint& p) { - cv_dither_setup(cv, p); - p.setDither(false); - }, - [=](DisplayListBuilder& b) { - dl_dither_setup(b); - b.setDither(false); - }) - .with_bg(dither_bg)); - } - EXPECT_TRUE(testImageShader->unique()) << "Dither Cleanup"; - - RenderWith(testP, env, tolerance, - CaseParameters( - "Color == Blue", - [=](SkCanvas*, SkPaint& p) { p.setColor(SK_ColorBLUE); }, - [=](DisplayListBuilder& b) { b.setColor(SK_ColorBLUE); })); - RenderWith(testP, env, tolerance, - CaseParameters( - "Color == Green", - [=](SkCanvas*, SkPaint& p) { p.setColor(SK_ColorGREEN); }, - [=](DisplayListBuilder& b) { b.setColor(SK_ColorGREEN); })); - - RenderWithStrokes(testP, env, tolerance); + RenderWith([=](SkCanvas*, SkPaint& p) {}, // + [=](DisplayListBuilder& d) {}, // + cv_renderer, dl_renderer, adjuster, tolerance, "Base Test"); + + RenderWith([=](SkCanvas*, SkPaint& p) { p.setAntiAlias(true); }, // + [=](DisplayListBuilder& b) { b.setAntiAlias(true); }, // + cv_renderer, dl_renderer, adjuster, tolerance, + "AntiAlias == True"); + RenderWith([=](SkCanvas*, SkPaint& p) { p.setAntiAlias(false); }, // + [=](DisplayListBuilder& b) { b.setAntiAlias(false); }, // + cv_renderer, dl_renderer, adjuster, tolerance, + "AntiAlias == False"); + + RenderWith([=](SkCanvas*, SkPaint& p) { p.setDither(true); }, // + [=](DisplayListBuilder& b) { b.setDither(true); }, // + cv_renderer, dl_renderer, adjuster, tolerance, "Dither == True"); + RenderWith([=](SkCanvas*, SkPaint& p) { p.setDither(false); }, // + [=](DisplayListBuilder& b) { b.setDither(false); }, // + cv_renderer, dl_renderer, adjuster, tolerance, "Dither = False"); + + RenderWith([=](SkCanvas*, SkPaint& p) { p.setColor(SK_ColorBLUE); }, // + [=](DisplayListBuilder& b) { b.setColor(SK_ColorBLUE); }, // + cv_renderer, dl_renderer, adjuster, tolerance, "Color == Blue"); + RenderWith([=](SkCanvas*, SkPaint& p) { p.setColor(SK_ColorGREEN); }, // + [=](DisplayListBuilder& b) { b.setColor(SK_ColorGREEN); }, // + cv_renderer, dl_renderer, adjuster, tolerance, "Color == Green"); + + RenderWithStrokes(cv_renderer, dl_renderer, adjuster, tolerance); { // half opaque cyan SkColor blendableColor = SkColorSetARGB(0x7f, 0x00, 0xff, 0xff); SkColor bg = SK_ColorWHITE; - RenderWith(testP, env, tolerance, - CaseParameters( - "Blend == SrcIn", - [=](SkCanvas*, SkPaint& p) { - p.setBlendMode(SkBlendMode::kSrcIn); - p.setColor(blendableColor); - }, - [=](DisplayListBuilder& b) { - b.setBlendMode(SkBlendMode::kSrcIn); - b.setColor(blendableColor); - }) - .with_bg(bg)); - RenderWith(testP, env, tolerance, - CaseParameters( - "Blend == DstIn", - [=](SkCanvas*, SkPaint& p) { - p.setBlendMode(SkBlendMode::kDstIn); - p.setColor(blendableColor); - }, - [=](DisplayListBuilder& b) { - b.setBlendMode(SkBlendMode::kDstIn); - b.setColor(blendableColor); - }) - .with_bg(bg)); + RenderWith( + [=](SkCanvas*, SkPaint& p) { + p.setBlendMode(SkBlendMode::kSrcIn); + p.setColor(blendableColor); + }, + [=](DisplayListBuilder& b) { + b.setBlendMode(SkBlendMode::kSrcIn); + b.setColor(blendableColor); + }, + cv_renderer, dl_renderer, adjuster, tolerance, "Blend == SrcIn", &bg); + RenderWith( + [=](SkCanvas*, SkPaint& p) { + p.setBlendMode(SkBlendMode::kDstIn); + p.setColor(blendableColor); + }, + [=](DisplayListBuilder& b) { + b.setBlendMode(SkBlendMode::kDstIn); + b.setColor(blendableColor); + }, + cv_renderer, dl_renderer, adjuster, tolerance, "Blend == DstIn", &bg); } - if (!(testP.is_draw_atlas() || testP.is_draw_vertices())) { + if (!(TestingDrawAtlas || TestingDrawVertices)) { sk_sp blender = SkBlenders::Arithmetic(0.25, 0.25, 0.25, 0.25, false); { - RenderWith(testP, env, tolerance, - CaseParameters( - "ImageFilter == Blender Arithmetic 0.25-false", - [=](SkCanvas*, SkPaint& p) { p.setBlender(blender); }, - [=](DisplayListBuilder& b) { b.setBlender(blender); })); + RenderWith([=](SkCanvas*, SkPaint& p) { p.setBlender(blender); }, + [=](DisplayListBuilder& b) { b.setBlender(blender); }, + cv_renderer, dl_renderer, adjuster, tolerance, + "ImageFilter == Blender Arithmetic 0.25-false"); } - EXPECT_TRUE(blender->unique()) << "Blender Cleanup"; + ASSERT_TRUE(blender->unique()) << "Blender Cleanup"; blender = SkBlenders::Arithmetic(0.25, 0.25, 0.25, 0.25, true); { - RenderWith(testP, env, tolerance, - CaseParameters( - "ImageFilter == Blender Arithmetic 0.25-true", - [=](SkCanvas*, SkPaint& p) { p.setBlender(blender); }, - [=](DisplayListBuilder& b) { b.setBlender(blender); })); + RenderWith([=](SkCanvas*, SkPaint& p) { p.setBlender(blender); }, + [=](DisplayListBuilder& b) { b.setBlender(blender); }, + cv_renderer, dl_renderer, adjuster, tolerance, + "ImageFilter == Blender Arithmetic 0.25-true"); } - EXPECT_TRUE(blender->unique()) << "Blender Cleanup"; + ASSERT_TRUE(blender->unique()) << "Blender Cleanup"; } { - // Being able to see a blur requires some non-default attributes, - // like a non-trivial stroke width and a shader rather than a color - // (for drawPaint) so we create a new environment for these tests. - RenderEnvironment blur_env = RenderEnvironment::MakeN32(); - CvSetup cv_blur_setup = [=](SkCanvas*, SkPaint& p) { - p.setShader(testImageShader); - p.setStrokeWidth(5.0); - }; - DlRenderer dl_blur_setup = [=](DisplayListBuilder& b) { - b.setShader(testImageShader); - b.setStrokeWidth(5.0); - }; - blur_env.init_ref(cv_blur_setup, testP.cv_renderer()); sk_sp filter = SkImageFilters::Blur(5.0, 5.0, SkTileMode::kDecal, nullptr, nullptr); BoundsTolerance blur5Tolerance = tolerance.addBoundsPadding(4, 4); { - RenderWith(testP, blur_env, blur5Tolerance, - CaseParameters( - "ImageFilter == Decal Blur 5", - [=](SkCanvas* cv, SkPaint& p) { - cv_blur_setup(cv, p); - p.setImageFilter(filter); - }, - [=](DisplayListBuilder& b) { - dl_blur_setup(b); - b.setImageFilter(filter); - })); + RenderWith( + [=](SkCanvas*, SkPaint& p) { + // Provide some non-trivial stroke size to get blurred + p.setStrokeWidth(5.0); + p.setImageFilter(filter); + }, + [=](DisplayListBuilder& b) { + // Provide some non-trivial stroke size to get blurred + b.setStrokeWidth(5.0); + b.setImageFilter(filter); + }, + cv_renderer, dl_renderer, adjuster, blur5Tolerance, + "ImageFilter == Decal Blur 5"); } - EXPECT_TRUE(filter->unique()) << "ImageFilter Cleanup"; + ASSERT_TRUE(filter->unique()) << "ImageFilter Cleanup"; filter = SkImageFilters::Blur(5.0, 5.0, SkTileMode::kClamp, nullptr, nullptr); { - RenderWith(testP, blur_env, blur5Tolerance, - CaseParameters( - "ImageFilter == Clamp Blur 5", - [=](SkCanvas* cv, SkPaint& p) { - cv_blur_setup(cv, p); - p.setImageFilter(filter); - }, - [=](DisplayListBuilder& b) { - dl_blur_setup(b); - b.setImageFilter(filter); - })); + RenderWith( + [=](SkCanvas*, SkPaint& p) { + // Provide some non-trivial stroke size to get blurred + p.setStrokeWidth(5.0); + p.setImageFilter(filter); + }, + [=](DisplayListBuilder& b) { + // Provide some non-trivial stroke size to get blurred + b.setStrokeWidth(5.0); + b.setImageFilter(filter); + }, + cv_renderer, dl_renderer, adjuster, blur5Tolerance, + "ImageFilter == Clamp Blur 5"); } - EXPECT_TRUE(filter->unique()) << "ImageFilter Cleanup"; + ASSERT_TRUE(filter->unique()) << "ImageFilter Cleanup"; } { @@ -1120,37 +601,35 @@ class CanvasCompareTester { sk_sp filter = SkColorFilters::Matrix(rotate_color_matrix); { SkColor bg = SK_ColorWHITE; - RenderWith(testP, env, tolerance, - CaseParameters( - "ColorFilter == RotateRGB", - [=](SkCanvas*, SkPaint& p) { - p.setColor(SK_ColorYELLOW); - p.setColorFilter(filter); - }, - [=](DisplayListBuilder& b) { - b.setColor(SK_ColorYELLOW); - b.setColorFilter(filter); - }) - .with_bg(bg)); + RenderWith( + [=](SkCanvas*, SkPaint& p) { + p.setColor(SK_ColorYELLOW); + p.setColorFilter(filter); + }, + [=](DisplayListBuilder& b) { + b.setColor(SK_ColorYELLOW); + b.setColorFilter(filter); + }, + cv_renderer, dl_renderer, adjuster, tolerance, + "ColorFilter == RotateRGB", &bg); } - EXPECT_TRUE(filter->unique()) << "ColorFilter == RotateRGB Cleanup"; + ASSERT_TRUE(filter->unique()) << "ColorFilter == RotateRGB Cleanup"; filter = SkColorFilters::Matrix(invert_color_matrix); { SkColor bg = SK_ColorWHITE; - RenderWith(testP, env, tolerance, - CaseParameters( - "ColorFilter == Invert", - [=](SkCanvas*, SkPaint& p) { - p.setColor(SK_ColorYELLOW); - p.setColorFilter(filter); - }, - [=](DisplayListBuilder& b) { - b.setColor(SK_ColorYELLOW); - b.setInvertColors(true); - }) - .with_bg(bg)); + RenderWith( + [=](SkCanvas*, SkPaint& p) { + p.setColor(SK_ColorYELLOW); + p.setColorFilter(filter); + }, + [=](DisplayListBuilder& b) { + b.setColor(SK_ColorYELLOW); + b.setInvertColors(true); + }, + cv_renderer, dl_renderer, adjuster, tolerance, + "ColorFilter == Invert", &bg); } - EXPECT_TRUE(filter->unique()) << "ColorFilter == Invert Cleanup"; + ASSERT_TRUE(filter->unique()) << "ColorFilter == Invert Cleanup"; } { @@ -1158,60 +637,58 @@ class CanvasCompareTester { { // Discrete path effects need a stroke width for drawPointsAsPoints // to do something realistic - // And a Discrete(3, 5) effect produces miters that are near - // maximal for a miter limit of 3.0. - BoundsTolerance discrete_tolerance = + RenderWith( + [=](SkCanvas*, SkPaint& p) { + p.setStrokeWidth(5.0); + // A Discrete(3, 5) effect produces miters that are near + // maximal for a miter limit of 3.0. + p.setStrokeMiter(3.0); + p.setPathEffect(effect); + }, + [=](DisplayListBuilder& b) { + b.setStrokeWidth(5.0); + // A Discrete(3, 5) effect produces miters that are near + // maximal for a miter limit of 3.0. + b.setStrokeMiter(3.0); + b.setPathEffect(effect); + }, + cv_renderer, dl_renderer, adjuster, tolerance // register the discrete offset so adjusters can compensate .addDiscreteOffset(5) // the miters in the 3-5 discrete effect don't always fill // their conservative bounds, so tolerate a couple of pixels - .addBoundsPadding(2, 2); - RenderWith(testP, env, discrete_tolerance, - CaseParameters( - "PathEffect == Discrete-3-5", - [=](SkCanvas*, SkPaint& p) { - p.setStrokeWidth(5.0); - p.setStrokeMiter(3.0); - p.setPathEffect(effect); - }, - [=](DisplayListBuilder& b) { - b.setStrokeWidth(5.0); - b.setStrokeMiter(3.0); - b.setPathEffect(effect); - })); + .addBoundsPadding(2, 2), + "PathEffect == Discrete-3-5"); } - EXPECT_TRUE(testP.is_draw_text_blob() || effect->unique()) - << "PathEffect == Discrete-3-5 Cleanup"; + ASSERT_TRUE(effect->unique()) << "PathEffect == Discrete-3-5 Cleanup"; effect = SkDiscretePathEffect::Make(2, 3); { - // Discrete path effects need a stroke width for drawPointsAsPoints - // to do something realistic - // And a Discrete(2, 3) effect produces miters that are near - // maximal for a miter limit of 2.5. - BoundsTolerance discrete_tolerance = + RenderWith( + [=](SkCanvas*, SkPaint& p) { + p.setStrokeWidth(5.0); + // A Discrete(2, 3) effect produces miters that are near + // maximal for a miter limit of 2.5. + p.setStrokeMiter(2.5); + p.setPathEffect(effect); + }, + [=](DisplayListBuilder& b) { + b.setStrokeWidth(5.0); + // A Discrete(2, 3) effect produces miters that are near + // maximal for a miter limit of 2.5. + b.setStrokeMiter(2.5); + b.setPathEffect(effect); + }, + cv_renderer, dl_renderer, adjuster, tolerance // register the discrete offset so adjusters can compensate .addDiscreteOffset(3) // the miters in the 3-5 discrete effect don't always fill // their conservative bounds, so tolerate a couple of pixels - .addBoundsPadding(2, 2); - RenderWith(testP, env, discrete_tolerance, - CaseParameters( - "PathEffect == Discrete-2-3", - [=](SkCanvas*, SkPaint& p) { - p.setStrokeWidth(5.0); - p.setStrokeMiter(2.5); - p.setPathEffect(effect); - }, - [=](DisplayListBuilder& b) { - b.setStrokeWidth(5.0); - b.setStrokeMiter(2.5); - b.setPathEffect(effect); - })); + .addBoundsPadding(2, 2), + "PathEffect == Discrete-2-3"); } - EXPECT_TRUE(testP.is_draw_text_blob() || effect->unique()) - << "PathEffect == Discrete-2-3 Cleanup"; + ASSERT_TRUE(effect->unique()) << "PathEffect == Discrete-2-3 Cleanup"; } { @@ -1219,35 +696,37 @@ class CanvasCompareTester { SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, 5.0); BoundsTolerance blur5Tolerance = tolerance.addBoundsPadding(4, 4); { - // Stroked primitives need some non-trivial stroke size to be blurred - RenderWith(testP, env, blur5Tolerance, - CaseParameters( - "MaskFilter == Blur 5", - [=](SkCanvas*, SkPaint& p) { - p.setStrokeWidth(5.0); - p.setMaskFilter(filter); - }, - [=](DisplayListBuilder& b) { - b.setStrokeWidth(5.0); - b.setMaskFilter(filter); - })); + RenderWith( + [=](SkCanvas*, SkPaint& p) { + // Provide some non-trivial stroke size to get blurred + p.setStrokeWidth(5.0); + p.setMaskFilter(filter); + }, + [=](DisplayListBuilder& b) { + // Provide some non-trivial stroke size to get blurred + b.setStrokeWidth(5.0); + b.setMaskFilter(filter); + }, + cv_renderer, dl_renderer, adjuster, blur5Tolerance, + "MaskFilter == Blur 5"); } - EXPECT_TRUE(testP.is_draw_text_blob() || filter->unique()) - << "MaskFilter == Blur 5 Cleanup"; + ASSERT_TRUE(filter->unique()) << "MaskFilter == Blur 5 Cleanup"; { - RenderWith(testP, env, blur5Tolerance, - CaseParameters( - "MaskFilter == Blur(Normal, 5.0)", - [=](SkCanvas*, SkPaint& p) { - p.setStrokeWidth(5.0); - p.setMaskFilter(filter); - }, - [=](DisplayListBuilder& b) { - b.setStrokeWidth(5.0); - b.setMaskBlurFilter(kNormal_SkBlurStyle, 5.0); - })); + RenderWith( + [=](SkCanvas*, SkPaint& p) { + // Provide some non-trivial stroke size to get blurred + p.setStrokeWidth(5.0); + p.setMaskFilter(filter); + }, + [=](DisplayListBuilder& b) { + // Provide some non-trivial stroke size to get blurred + b.setStrokeWidth(5.0); + b.setMaskBlurFilter(kNormal_SkBlurStyle, 5.0); + }, + cv_renderer, dl_renderer, adjuster, blur5Tolerance, + "MaskFilter == Blur(Normal, 5.0)"); } - EXPECT_TRUE(testP.is_draw_text_blob() || filter->unique()) + ASSERT_TRUE(filter->unique()) << "MaskFilter == Blur(Normal, 5.0) Cleanup"; } @@ -1258,7 +737,7 @@ class CanvasCompareTester { }; SkColor colors[] = { SK_ColorGREEN, - SkColorSetA(SK_ColorYELLOW, 0x7f), + SK_ColorYELLOW, SK_ColorBLUE, }; float stops[] = { @@ -1269,260 +748,241 @@ class CanvasCompareTester { sk_sp shader = SkGradientShader::MakeLinear( end_points, colors, stops, 3, SkTileMode::kMirror, 0, nullptr); { - RenderWith(testP, env, tolerance, - CaseParameters( - "LinearGradient GYB", - [=](SkCanvas*, SkPaint& p) { p.setShader(shader); }, - [=](DisplayListBuilder& b) { b.setShader(shader); })); + RenderWith([=](SkCanvas*, SkPaint& p) { p.setShader(shader); }, + [=](DisplayListBuilder& b) { b.setShader(shader); }, + cv_renderer, dl_renderer, adjuster, tolerance, + "LinearGradient GYB"); } - EXPECT_TRUE(shader->unique()) << "LinearGradient GYB Cleanup"; + ASSERT_TRUE(shader->unique()) << "LinearGradient GYB Cleanup"; } } - static void RenderWithStrokes(const TestParameters& testP, - const RenderEnvironment env, + static void RenderWithStrokes(CvRenderer& cv_renderer, + DlRenderer& dl_renderer, + ToleranceAdjuster& adjuster, const BoundsTolerance& tolerance_in) { // The test cases were generated with geometry that will try to fill // out the various miter limits used for testing, but they can be off // by a couple of pixels so we will relax bounds testing for strokes by // a couple of pixels. BoundsTolerance tolerance = tolerance_in.addBoundsPadding(2, 2); - RenderWith(testP, env, tolerance, - CaseParameters( - "Fill", - [=](SkCanvas*, SkPaint& p) { // - p.setStyle(SkPaint::kFill_Style); - }, - [=](DisplayListBuilder& b) { // - b.setStyle(SkPaint::kFill_Style); - })); - RenderWith(testP, env, tolerance, - CaseParameters( - "Stroke + defaults", - [=](SkCanvas*, SkPaint& p) { // - p.setStyle(SkPaint::kStroke_Style); - }, - [=](DisplayListBuilder& b) { // - b.setStyle(SkPaint::kStroke_Style); - })); - - RenderWith(testP, env, tolerance, - CaseParameters( - "Fill + unnecessary StrokeWidth 10", - [=](SkCanvas*, SkPaint& p) { - p.setStyle(SkPaint::kFill_Style); - p.setStrokeWidth(10.0); - }, - [=](DisplayListBuilder& b) { - b.setStyle(SkPaint::kFill_Style); - b.setStrokeWidth(10.0); - })); - - RenderEnvironment stroke_base_env = RenderEnvironment::MakeN32(); - CvSetup cv_stroke_setup = [=](SkCanvas*, SkPaint& p) { - p.setStyle(SkPaint::kStroke_Style); - p.setStrokeWidth(5.0); - }; - stroke_base_env.init_ref(cv_stroke_setup, testP.cv_renderer()); - - RenderWith(testP, stroke_base_env, tolerance, - CaseParameters( - "Stroke Width 10", - [=](SkCanvas*, SkPaint& p) { - p.setStyle(SkPaint::kStroke_Style); - p.setStrokeWidth(10.0); - }, - [=](DisplayListBuilder& b) { - b.setStyle(SkPaint::kStroke_Style); - b.setStrokeWidth(10.0); - })); - RenderWith(testP, stroke_base_env, tolerance, - CaseParameters( - "Stroke Width 5", - [=](SkCanvas*, SkPaint& p) { - p.setStyle(SkPaint::kStroke_Style); - p.setStrokeWidth(5.0); - }, - [=](DisplayListBuilder& b) { - b.setStyle(SkPaint::kStroke_Style); - b.setStrokeWidth(5.0); - })); - - RenderWith(testP, stroke_base_env, tolerance, - CaseParameters( - "Stroke Width 5, Square Cap", - [=](SkCanvas*, SkPaint& p) { - p.setStyle(SkPaint::kStroke_Style); - p.setStrokeWidth(5.0); - p.setStrokeCap(SkPaint::kSquare_Cap); - }, - [=](DisplayListBuilder& b) { - b.setStyle(SkPaint::kStroke_Style); - b.setStrokeWidth(5.0); - b.setStrokeCap(SkPaint::kSquare_Cap); - })); - RenderWith(testP, stroke_base_env, tolerance, - CaseParameters( - "Stroke Width 5, Round Cap", - [=](SkCanvas*, SkPaint& p) { - p.setStyle(SkPaint::kStroke_Style); - p.setStrokeWidth(5.0); - p.setStrokeCap(SkPaint::kRound_Cap); - }, - [=](DisplayListBuilder& b) { - b.setStyle(SkPaint::kStroke_Style); - b.setStrokeWidth(5.0); - b.setStrokeCap(SkPaint::kRound_Cap); - })); - - RenderWith(testP, stroke_base_env, tolerance, - CaseParameters( - "Stroke Width 5, Bevel Join", - [=](SkCanvas*, SkPaint& p) { - p.setStyle(SkPaint::kStroke_Style); - p.setStrokeWidth(5.0); - p.setStrokeJoin(SkPaint::kBevel_Join); - }, - [=](DisplayListBuilder& b) { - b.setStyle(SkPaint::kStroke_Style); - b.setStrokeWidth(5.0); - b.setStrokeJoin(SkPaint::kBevel_Join); - })); - RenderWith(testP, stroke_base_env, tolerance, - CaseParameters( - "Stroke Width 5, Round Join", - [=](SkCanvas*, SkPaint& p) { - p.setStyle(SkPaint::kStroke_Style); - p.setStrokeWidth(5.0); - p.setStrokeJoin(SkPaint::kRound_Join); - }, - [=](DisplayListBuilder& b) { - b.setStyle(SkPaint::kStroke_Style); - b.setStrokeWidth(5.0); - b.setStrokeJoin(SkPaint::kRound_Join); - })); - - RenderWith(testP, stroke_base_env, tolerance, - CaseParameters( - "Stroke Width 5, Miter 10", - [=](SkCanvas*, SkPaint& p) { - p.setStyle(SkPaint::kStroke_Style); - p.setStrokeWidth(5.0); - p.setStrokeMiter(10.0); - p.setStrokeJoin(SkPaint::kMiter_Join); - }, - [=](DisplayListBuilder& b) { - b.setStyle(SkPaint::kStroke_Style); - b.setStrokeWidth(5.0); - b.setStrokeMiter(10.0); - b.setStrokeJoin(SkPaint::kMiter_Join); - })); - - RenderWith(testP, stroke_base_env, tolerance, - CaseParameters( - "Stroke Width 5, Miter 0", - [=](SkCanvas*, SkPaint& p) { - p.setStyle(SkPaint::kStroke_Style); - p.setStrokeWidth(5.0); - p.setStrokeMiter(0.0); - p.setStrokeJoin(SkPaint::kMiter_Join); - }, - [=](DisplayListBuilder& b) { - b.setStyle(SkPaint::kStroke_Style); - b.setStrokeWidth(5.0); - b.setStrokeMiter(0.0); - b.setStrokeJoin(SkPaint::kMiter_Join); - })); + RenderWith( // + [=](SkCanvas*, SkPaint& p) { p.setStyle(SkPaint::kFill_Style); }, + [=](DisplayListBuilder& b) { b.setStyle(SkPaint::kFill_Style); }, + cv_renderer, dl_renderer, adjuster, tolerance, "Fill"); + RenderWith( + [=](SkCanvas*, SkPaint& p) { p.setStyle(SkPaint::kStroke_Style); }, + [=](DisplayListBuilder& b) { b.setStyle(SkPaint::kStroke_Style); }, + cv_renderer, dl_renderer, adjuster, tolerance, "Stroke + defaults"); + + RenderWith( + [=](SkCanvas*, SkPaint& p) { + p.setStyle(SkPaint::kFill_Style); + p.setStrokeWidth(10.0); + }, + [=](DisplayListBuilder& b) { + b.setStyle(SkPaint::kFill_Style); + b.setStrokeWidth(10.0); + }, + cv_renderer, dl_renderer, adjuster, tolerance, + "Fill + unnecessary StrokeWidth 10"); + + RenderWith( + [=](SkCanvas*, SkPaint& p) { + p.setStyle(SkPaint::kStroke_Style); + p.setStrokeWidth(10.0); + }, + [=](DisplayListBuilder& b) { + b.setStyle(SkPaint::kStroke_Style); + b.setStrokeWidth(10.0); + }, + cv_renderer, dl_renderer, adjuster, tolerance, "Stroke Width 10"); + RenderWith( + [=](SkCanvas*, SkPaint& p) { + p.setStyle(SkPaint::kStroke_Style); + p.setStrokeWidth(5.0); + }, + [=](DisplayListBuilder& b) { + b.setStyle(SkPaint::kStroke_Style); + b.setStrokeWidth(5.0); + }, + cv_renderer, dl_renderer, adjuster, tolerance, "Stroke Width 5"); + + RenderWith( + [=](SkCanvas*, SkPaint& p) { + p.setStyle(SkPaint::kStroke_Style); + p.setStrokeWidth(5.0); + p.setStrokeCap(SkPaint::kButt_Cap); + }, + [=](DisplayListBuilder& b) { + b.setStyle(SkPaint::kStroke_Style); + b.setStrokeWidth(5.0); + b.setStrokeCap(SkPaint::kButt_Cap); + }, + cv_renderer, dl_renderer, adjuster, tolerance, + "Stroke Width 5, Butt Cap"); + RenderWith( + [=](SkCanvas*, SkPaint& p) { + p.setStyle(SkPaint::kStroke_Style); + p.setStrokeWidth(5.0); + p.setStrokeCap(SkPaint::kRound_Cap); + }, + [=](DisplayListBuilder& b) { + b.setStyle(SkPaint::kStroke_Style); + b.setStrokeWidth(5.0); + b.setStrokeCap(SkPaint::kRound_Cap); + }, + cv_renderer, dl_renderer, adjuster, tolerance, + "Stroke Width 5, Round Cap"); + + RenderWith( + [=](SkCanvas*, SkPaint& p) { + p.setStyle(SkPaint::kStroke_Style); + p.setStrokeWidth(5.0); + p.setStrokeJoin(SkPaint::kBevel_Join); + }, + [=](DisplayListBuilder& b) { + b.setStyle(SkPaint::kStroke_Style); + b.setStrokeWidth(5.0); + b.setStrokeJoin(SkPaint::kBevel_Join); + }, + cv_renderer, dl_renderer, adjuster, tolerance, + "Stroke Width 5, Bevel Join"); + RenderWith( + [=](SkCanvas*, SkPaint& p) { + p.setStyle(SkPaint::kStroke_Style); + p.setStrokeWidth(5.0); + p.setStrokeJoin(SkPaint::kRound_Join); + }, + [=](DisplayListBuilder& b) { + b.setStyle(SkPaint::kStroke_Style); + b.setStrokeWidth(5.0); + b.setStrokeJoin(SkPaint::kRound_Join); + }, + cv_renderer, dl_renderer, adjuster, tolerance, + "Stroke Width 5, Round Join"); + + RenderWith( + [=](SkCanvas*, SkPaint& p) { + p.setStyle(SkPaint::kStroke_Style); + p.setStrokeWidth(5.0); + p.setStrokeMiter(10.0); + p.setStrokeJoin(SkPaint::kMiter_Join); + // AA helps fill in the peaks of the really thin miters better + // for bounds accuracy testing + p.setAntiAlias(true); + }, + [=](DisplayListBuilder& b) { + b.setStyle(SkPaint::kStroke_Style); + b.setStrokeWidth(5.0); + b.setStrokeMiter(10.0); + b.setStrokeJoin(SkPaint::kMiter_Join); + // AA helps fill in the peaks of the really thin miters better + // for bounds accuracy testing + b.setAntiAlias(true); + }, + cv_renderer, dl_renderer, adjuster, tolerance, + "Stroke Width 5, Miter 10"); + + RenderWith( + [=](SkCanvas*, SkPaint& p) { + p.setStyle(SkPaint::kStroke_Style); + p.setStrokeWidth(5.0); + p.setStrokeMiter(0.0); + p.setStrokeJoin(SkPaint::kMiter_Join); + }, + [=](DisplayListBuilder& b) { + b.setStyle(SkPaint::kStroke_Style); + b.setStrokeWidth(5.0); + b.setStrokeMiter(0.0); + b.setStrokeJoin(SkPaint::kMiter_Join); + }, + cv_renderer, dl_renderer, adjuster, tolerance, + "Stroke Width 5, Miter 0"); { const SkScalar TestDashes1[] = {29.0, 2.0}; const SkScalar TestDashes2[] = {17.0, 1.5}; sk_sp effect = SkDashPathEffect::Make(TestDashes1, 2, 0.0f); { - RenderWith(testP, stroke_base_env, tolerance, - CaseParameters( - "PathEffect == Dash-29-2", - [=](SkCanvas*, SkPaint& p) { - // Need stroke style to see dashing properly - p.setStyle(SkPaint::kStroke_Style); - // Provide some non-trivial stroke size to get dashed - p.setStrokeWidth(5.0); - p.setPathEffect(effect); - }, - [=](DisplayListBuilder& b) { - // Need stroke style to see dashing properly - b.setStyle(SkPaint::kStroke_Style); - // Provide some non-trivial stroke size to get dashed - b.setStrokeWidth(5.0); - b.setPathEffect(effect); - })); + RenderWith( + [=](SkCanvas*, SkPaint& p) { + // Need stroke style to see dashing properly + p.setStyle(SkPaint::kStroke_Style); + // Provide some non-trivial stroke size to get dashed + p.setStrokeWidth(5.0); + p.setPathEffect(effect); + }, + [=](DisplayListBuilder& b) { + // Need stroke style to see dashing properly + b.setStyle(SkPaint::kStroke_Style); + // Provide some non-trivial stroke size to get dashed + b.setStrokeWidth(5.0); + b.setPathEffect(effect); + }, + cv_renderer, dl_renderer, adjuster, tolerance, + "PathEffect == Dash-29-2"); } - EXPECT_TRUE(testP.is_draw_text_blob() || effect->unique()) - << "PathEffect == Dash-29-2 Cleanup"; + ASSERT_TRUE(effect->unique()) << "PathEffect == Dash-29-2 Cleanup"; effect = SkDashPathEffect::Make(TestDashes2, 2, 0.0f); { - RenderWith(testP, stroke_base_env, tolerance, - CaseParameters( - "PathEffect == Dash-17-1.5", - [=](SkCanvas*, SkPaint& p) { - // Need stroke style to see dashing properly - p.setStyle(SkPaint::kStroke_Style); - // Provide some non-trivial stroke size to get dashed - p.setStrokeWidth(5.0); - p.setPathEffect(effect); - }, - [=](DisplayListBuilder& b) { - // Need stroke style to see dashing properly - b.setStyle(SkPaint::kStroke_Style); - // Provide some non-trivial stroke size to get dashed - b.setStrokeWidth(5.0); - b.setPathEffect(effect); - })); + RenderWith( + [=](SkCanvas*, SkPaint& p) { + // Need stroke style to see dashing properly + p.setStyle(SkPaint::kStroke_Style); + // Provide some non-trivial stroke size to get dashed + p.setStrokeWidth(5.0); + p.setPathEffect(effect); + }, + [=](DisplayListBuilder& b) { + // Need stroke style to see dashing properly + b.setStyle(SkPaint::kStroke_Style); + // Provide some non-trivial stroke size to get dashed + b.setStrokeWidth(5.0); + b.setPathEffect(effect); + }, + cv_renderer, dl_renderer, adjuster, tolerance, + "PathEffect == Dash-17-1.5"); } - EXPECT_TRUE(testP.is_draw_text_blob() || effect->unique()) - << "PathEffect == Dash-17-1.5 Cleanup"; + ASSERT_TRUE(effect->unique()) << "PathEffect == Dash-17-1.5 Cleanup"; } } - static void RenderWithTransforms(const TestParameters& testP, - const RenderEnvironment& env, + static void RenderWithTransforms(CvRenderer& cv_renderer, + DlRenderer& dl_renderer, + ToleranceAdjuster& adjuster, const BoundsTolerance& tolerance) { - // If the rendering method does not fill the corners of the original - // bounds, then the estimate under rotation or skewing will be off - // so we scale the padding by about 5% to compensate. - BoundsTolerance skewed_tolerance = tolerance.mulScale(1.05, 1.05); - RenderWith(testP, env, tolerance, - CaseParameters( - "Translate 5, 10", // - [=](SkCanvas* c, SkPaint&) { c->translate(5, 10); }, - [=](DisplayListBuilder& b) { b.translate(5, 10); })); - RenderWith(testP, env, tolerance, - CaseParameters( - "Scale +5%", // - [=](SkCanvas* c, SkPaint&) { c->scale(1.05, 1.05); }, - [=](DisplayListBuilder& b) { b.scale(1.05, 1.05); })); - RenderWith(testP, env, skewed_tolerance, - CaseParameters( - "Rotate 5 degrees", // - [=](SkCanvas* c, SkPaint&) { c->rotate(5); }, - [=](DisplayListBuilder& b) { b.rotate(5); })); - RenderWith(testP, env, skewed_tolerance, - CaseParameters( - "Skew 5%", // - [=](SkCanvas* c, SkPaint&) { c->skew(0.05, 0.05); }, - [=](DisplayListBuilder& b) { b.skew(0.05, 0.05); })); + // If there is bounds padding for some conservative bounds overestimate + // then that padding will be even more pronounced in rotated or skewed + // coordinate systems so we scale the padding by about 5% to compensate. + BoundsTolerance skewed_tolerance = tolerance.addScale(1.05, 1.05); + RenderWith([=](SkCanvas* c, SkPaint&) { c->translate(5, 10); }, // + [=](DisplayListBuilder& b) { b.translate(5, 10); }, // + cv_renderer, dl_renderer, adjuster, tolerance, + "Translate 5, 10"); + RenderWith([=](SkCanvas* c, SkPaint&) { c->scale(1.05, 1.05); }, // + [=](DisplayListBuilder& b) { b.scale(1.05, 1.05); }, // + cv_renderer, dl_renderer, adjuster, tolerance, // + "Scale +5%"); + RenderWith([=](SkCanvas* c, SkPaint&) { c->rotate(5); }, // + [=](DisplayListBuilder& b) { b.rotate(5); }, // + cv_renderer, dl_renderer, adjuster, skewed_tolerance, + "Rotate 5 degrees"); + RenderWith([=](SkCanvas* c, SkPaint&) { c->skew(0.05, 0.05); }, // + [=](DisplayListBuilder& b) { b.skew(0.05, 0.05); }, // + cv_renderer, dl_renderer, adjuster, skewed_tolerance, // + "Skew 5%"); { SkMatrix tx = SkMatrix::MakeAll(1.10, 0.10, 5, // 0.05, 1.05, 10, // 0, 0, 1); - RenderWith(testP, env, skewed_tolerance, - CaseParameters( - "Transform 2D Affine", - [=](SkCanvas* c, SkPaint&) { c->concat(tx); }, - [=](DisplayListBuilder& b) { - b.transform2DAffine(tx[0], tx[1], tx[2], // - tx[3], tx[4], tx[5]); - })); + RenderWith([=](SkCanvas* c, SkPaint&) { c->concat(tx); }, // + [=](DisplayListBuilder& b) { + b.transform2DAffine(tx[0], tx[1], tx[2], // + tx[3], tx[4], tx[5]); + }, // + cv_renderer, dl_renderer, adjuster, skewed_tolerance, + "Transform 2D Affine"); } { SkM44 m44 = SkM44(1, 0, 0, RenderCenterX, // @@ -1532,222 +992,207 @@ class CanvasCompareTester { m44.preConcat(SkM44::Rotate({1, 0, 0}, M_PI / 60)); // 3 degrees around X m44.preConcat(SkM44::Rotate({0, 1, 0}, M_PI / 45)); // 4 degrees around Y m44.preTranslate(-RenderCenterX, -RenderCenterY); - RenderWith( - testP, env, skewed_tolerance, - CaseParameters( - "Transform Full Perspective", - [=](SkCanvas* c, SkPaint&) { c->concat(m44); }, // - [=](DisplayListBuilder& b) { - b.transformFullPerspective( - m44.rc(0, 0), m44.rc(0, 1), m44.rc(0, 2), m44.rc(0, 3), - m44.rc(1, 0), m44.rc(1, 1), m44.rc(1, 2), m44.rc(1, 3), - m44.rc(2, 0), m44.rc(2, 1), m44.rc(2, 2), m44.rc(2, 3), - m44.rc(3, 0), m44.rc(3, 1), m44.rc(3, 2), m44.rc(3, 3)); - })); + RenderWith([=](SkCanvas* c, SkPaint&) { c->concat(m44); }, // + [=](DisplayListBuilder& b) { + b.transformFullPerspective( + m44.rc(0, 0), m44.rc(0, 1), m44.rc(0, 2), m44.rc(0, 3), + m44.rc(1, 0), m44.rc(1, 1), m44.rc(1, 2), m44.rc(1, 3), + m44.rc(2, 0), m44.rc(2, 1), m44.rc(2, 2), m44.rc(2, 3), + m44.rc(3, 0), m44.rc(3, 1), m44.rc(3, 2), m44.rc(3, 3)); + }, // + cv_renderer, dl_renderer, adjuster, skewed_tolerance, + "Transform Full Perspective"); } } - static void RenderWithClips(const TestParameters& testP, - const RenderEnvironment& env, + static void RenderWithClips(CvRenderer& cv_renderer, + DlRenderer& dl_renderer, + ToleranceAdjuster& diff_adjuster, const BoundsTolerance& diff_tolerance) { SkRect r_clip = RenderBounds.makeInset(15.5, 15.5); - BoundsTolerance intersect_tolerance = diff_tolerance.clip(r_clip); - RenderWith(testP, env, intersect_tolerance, - CaseParameters( - "Hard ClipRect inset by 15.5", - [=](SkCanvas* c, SkPaint&) { - c->clipRect(r_clip, SkClipOp::kIntersect, false); - }, - [=](DisplayListBuilder& b) { - b.clipRect(r_clip, SkClipOp::kIntersect, false); - })); - RenderWith(testP, env, intersect_tolerance, - CaseParameters( - "AntiAlias ClipRect inset by 15.5", - [=](SkCanvas* c, SkPaint&) { - c->clipRect(r_clip, SkClipOp::kIntersect, true); - }, - [=](DisplayListBuilder& b) { - b.clipRect(r_clip, SkClipOp::kIntersect, true); - })); - RenderWith(testP, env, diff_tolerance, - CaseParameters( - "Hard ClipRect Diff, inset by 15.5", - [=](SkCanvas* c, SkPaint&) { - c->clipRect(r_clip, SkClipOp::kDifference, false); - }, - [=](DisplayListBuilder& b) { - b.clipRect(r_clip, SkClipOp::kDifference, false); - }) - .with_diff_clip()); + // For kIntersect clips we can be really strict on tolerance + ToleranceAdjuster& intersect_adjuster = DefaultAdjuster; + BoundsTolerance& intersect_tolerance = DefaultTolerance; + RenderWith( + [=](SkCanvas* c, SkPaint&) { + c->clipRect(r_clip, SkClipOp::kIntersect, false); + }, + [=](DisplayListBuilder& b) { + b.clipRect(r_clip, SkClipOp::kIntersect, false); + }, + cv_renderer, dl_renderer, intersect_adjuster, intersect_tolerance, + "Hard ClipRect inset by 15.5"); + RenderWith( + [=](SkCanvas* c, SkPaint&) { + c->clipRect(r_clip, SkClipOp::kIntersect, true); + }, + [=](DisplayListBuilder& b) { + b.clipRect(r_clip, SkClipOp::kIntersect, true); + }, + cv_renderer, dl_renderer, intersect_adjuster, intersect_tolerance, + "AntiAlias ClipRect inset by 15.5"); + RenderWith( + [=](SkCanvas* c, SkPaint&) { + c->clipRect(r_clip, SkClipOp::kDifference, false); + }, + [=](DisplayListBuilder& b) { + b.clipRect(r_clip, SkClipOp::kDifference, false); + }, + cv_renderer, dl_renderer, diff_adjuster, diff_tolerance, + "Hard ClipRect Diff, inset by 15.5"); SkRRect rr_clip = SkRRect::MakeRectXY(r_clip, 1.8, 2.7); - RenderWith(testP, env, intersect_tolerance, - CaseParameters( - "Hard ClipRRect inset by 15.5", - [=](SkCanvas* c, SkPaint&) { - c->clipRRect(rr_clip, SkClipOp::kIntersect, false); - }, - [=](DisplayListBuilder& b) { - b.clipRRect(rr_clip, SkClipOp::kIntersect, false); - })); - RenderWith(testP, env, intersect_tolerance, - CaseParameters( - "AntiAlias ClipRRect inset by 15.5", - [=](SkCanvas* c, SkPaint&) { - c->clipRRect(rr_clip, SkClipOp::kIntersect, true); - }, - [=](DisplayListBuilder& b) { - b.clipRRect(rr_clip, SkClipOp::kIntersect, true); - })); - RenderWith(testP, env, diff_tolerance, - CaseParameters( - "Hard ClipRRect Diff, inset by 15.5", - [=](SkCanvas* c, SkPaint&) { - c->clipRRect(rr_clip, SkClipOp::kDifference, false); - }, - [=](DisplayListBuilder& b) { - b.clipRRect(rr_clip, SkClipOp::kDifference, false); - }) - .with_diff_clip()); + RenderWith( + [=](SkCanvas* c, SkPaint&) { + c->clipRRect(rr_clip, SkClipOp::kIntersect, false); + }, + [=](DisplayListBuilder& b) { + b.clipRRect(rr_clip, SkClipOp::kIntersect, false); + }, + cv_renderer, dl_renderer, intersect_adjuster, intersect_tolerance, + "Hard ClipRRect inset by 15.5"); + RenderWith( + [=](SkCanvas* c, SkPaint&) { + c->clipRRect(rr_clip, SkClipOp::kIntersect, true); + }, + [=](DisplayListBuilder& b) { + b.clipRRect(rr_clip, SkClipOp::kIntersect, true); + }, + cv_renderer, dl_renderer, intersect_adjuster, intersect_tolerance, + "AntiAlias ClipRRect inset by 15.5"); + RenderWith( + [=](SkCanvas* c, SkPaint&) { + c->clipRRect(rr_clip, SkClipOp::kDifference, false); + }, + [=](DisplayListBuilder& b) { + b.clipRRect(rr_clip, SkClipOp::kDifference, false); + }, + cv_renderer, dl_renderer, diff_adjuster, diff_tolerance, + "Hard ClipRRect Diff, inset by 15.5"); SkPath path_clip = SkPath(); path_clip.setFillType(SkPathFillType::kEvenOdd); path_clip.addRect(r_clip); path_clip.addCircle(RenderCenterX, RenderCenterY, 1.0); - RenderWith(testP, env, intersect_tolerance, - CaseParameters( - "Hard ClipPath inset by 15.5", - [=](SkCanvas* c, SkPaint&) { - c->clipPath(path_clip, SkClipOp::kIntersect, false); - }, - [=](DisplayListBuilder& b) { - b.clipPath(path_clip, SkClipOp::kIntersect, false); - })); - RenderWith(testP, env, intersect_tolerance, - CaseParameters( - "AntiAlias ClipPath inset by 15.5", - [=](SkCanvas* c, SkPaint&) { - c->clipPath(path_clip, SkClipOp::kIntersect, true); - }, - [=](DisplayListBuilder& b) { - b.clipPath(path_clip, SkClipOp::kIntersect, true); - })); - RenderWith(testP, env, diff_tolerance, - CaseParameters( - "Hard ClipPath Diff, inset by 15.5", - [=](SkCanvas* c, SkPaint&) { - c->clipPath(path_clip, SkClipOp::kDifference, false); - }, - [=](DisplayListBuilder& b) { - b.clipPath(path_clip, SkClipOp::kDifference, false); - }) - .with_diff_clip()); + RenderWith( + [=](SkCanvas* c, SkPaint&) { + c->clipPath(path_clip, SkClipOp::kIntersect, false); + }, + [=](DisplayListBuilder& b) { + b.clipPath(path_clip, SkClipOp::kIntersect, false); + }, + cv_renderer, dl_renderer, intersect_adjuster, intersect_tolerance, + "Hard ClipPath inset by 15.5"); + RenderWith( + [=](SkCanvas* c, SkPaint&) { + c->clipPath(path_clip, SkClipOp::kIntersect, true); + }, + [=](DisplayListBuilder& b) { + b.clipPath(path_clip, SkClipOp::kIntersect, true); + }, + cv_renderer, dl_renderer, intersect_adjuster, intersect_tolerance, + "AntiAlias ClipPath inset by 15.5"); + RenderWith( + [=](SkCanvas* c, SkPaint&) { + c->clipPath(path_clip, SkClipOp::kDifference, false); + }, + [=](DisplayListBuilder& b) { + b.clipPath(path_clip, SkClipOp::kDifference, false); + }, + cv_renderer, dl_renderer, diff_adjuster, diff_tolerance, + "Hard ClipPath Diff, inset by 15.5"); } - static sk_sp getSkPicture(const TestParameters& testP, - const CaseParameters& caseP) { + static sk_sp getSkPicture(CvRenderer& cv_setup, + CvRenderer& cv_render) { SkPictureRecorder recorder; SkRTreeFactory rtree_factory; SkCanvas* cv = recorder.beginRecording(TestBounds, &rtree_factory); - caseP.render_to(cv, testP); + SkPaint p; + cv_setup(cv, p); + cv_render(cv, p); return recorder.finishRecordingAsPicture(); } - static void RenderWith(const TestParameters& testP, - const RenderEnvironment& env, + static void RenderWith(CvRenderer& cv_setup, + DlRenderer& dl_setup, + CvRenderer& cv_render, + DlRenderer& dl_render, + ToleranceAdjuster& adjuster, const BoundsTolerance& tolerance_in, - const CaseParameters& caseP) { - // sk_surface is a direct rendering via SkCanvas to SkSurface + const std::string info, + const SkColor* bg = nullptr) { + // surface1 is direct rendering via SkCanvas to SkSurface // DisplayList mechanisms are not involved in this operation - const std::string info = caseP.info(); - const SkColor bg = caseP.bg(); - RenderSurface sk_surface = env.MakeSurface(bg); - SkCanvas* sk_canvas = sk_surface.canvas(); - SkPaint sk_paint; - caseP.cv_setup()(sk_canvas, sk_paint); - SkMatrix sk_matrix = sk_canvas->getTotalMatrix(); - SkIRect sk_clip = sk_canvas->getDeviceClipBounds(); - const BoundsTolerance tolerance = - testP.adjust(tolerance_in, sk_paint, sk_canvas->getTotalMatrix()); - testP.render_to(sk_canvas, sk_paint); - caseP.cv_restore()(sk_canvas, sk_paint); - const sk_sp sk_picture = getSkPicture(testP, caseP); - SkRect sk_bounds = sk_picture->cullRect(); - const SkPixmap* sk_pixels = sk_surface.pixmap(); - ASSERT_EQ(sk_pixels->width(), TestWidth) << info; - ASSERT_EQ(sk_pixels->height(), TestHeight) << info; - ASSERT_EQ(sk_pixels->info().bytesPerPixel(), 4) << info; - checkPixels(sk_pixels, sk_bounds, info + " (Skia reference)", bg); - - if (testP.should_match(env, sk_paint, sk_matrix, sk_clip, - caseP.has_diff_clip(), - caseP.has_mutating_save_layer())) { - quickCompareToReference(env.ref_pixmap(), sk_pixels, true, - info + " (attribute has no effect)"); - } else { - quickCompareToReference(env.ref_pixmap(), sk_pixels, false, - info + " (attribute affects rendering)"); - } + sk_sp ref_surface = makeSurface(bg); + SkPaint paint1; + cv_setup(ref_surface->getCanvas(), paint1); + const BoundsTolerance tolerance = adjuster( + tolerance_in, paint1, ref_surface->getCanvas()->getTotalMatrix()); + cv_render(ref_surface->getCanvas(), paint1); + sk_sp ref_picture = getSkPicture(cv_setup, cv_render); + SkRect ref_bounds = ref_picture->cullRect(); + SkPixmap ref_pixels; + ASSERT_TRUE(ref_surface->peekPixels(&ref_pixels)) << info; + ASSERT_EQ(ref_pixels.width(), TestWidth) << info; + ASSERT_EQ(ref_pixels.height(), TestHeight) << info; + ASSERT_EQ(ref_pixels.info().bytesPerPixel(), 4) << info; + checkPixels(&ref_pixels, ref_bounds, info + " (Skia reference)", bg); { // This sequence plays the provided equivalently constructed // DisplayList onto the SkCanvas of the surface // DisplayList => direct rendering - RenderSurface dl_surface = env.MakeSurface(bg); + sk_sp test_surface = makeSurface(bg); DisplayListBuilder builder(TestBounds); - caseP.render_to(builder, testP); + dl_setup(builder); + dl_render(builder); sk_sp display_list = builder.Build(); SkRect dl_bounds = display_list->bounds(); - if (!sk_bounds.roundOut().contains(dl_bounds)) { + if (!ref_bounds.roundOut().contains(dl_bounds)) { FML_LOG(ERROR) << "For " << info; - FML_LOG(ERROR) << "sk ref: " // - << sk_bounds.fLeft << ", " << sk_bounds.fTop << " => " - << sk_bounds.fRight << ", " << sk_bounds.fBottom; + FML_LOG(ERROR) << "ref: " // + << ref_bounds.fLeft << ", " << ref_bounds.fTop << " => " + << ref_bounds.fRight << ", " << ref_bounds.fBottom; FML_LOG(ERROR) << "dl: " // << dl_bounds.fLeft << ", " << dl_bounds.fTop << " => " << dl_bounds.fRight << ", " << dl_bounds.fBottom; - if (!dl_bounds.contains(sk_bounds)) { + if (!dl_bounds.contains(ref_bounds)) { FML_LOG(ERROR) << "DisplayList bounds are too small!"; } - if (!sk_bounds.roundOut().contains(dl_bounds.roundOut())) { + if (!ref_bounds.roundOut().contains(dl_bounds.roundOut())) { FML_LOG(ERROR) << "###### DisplayList bounds larger than reference!"; } } - // This EXPECT sometimes triggers, but when it triggers and I examine - // the ref_bounds, they are always unnecessarily large and since the - // pixel OOB tests in the compare method do not trigger, we will trust - // the DL bounds. + // This sometimes triggers, but when it triggers and I examine + // the ref_bounds, they are always unnecessarily large and + // since the pixel OOB tests in the compare method do not + // trigger, we will trust the DL bounds. // EXPECT_TRUE(dl_bounds.contains(ref_bounds)) << info; - // When we are drawing a DisplayList, the display_list built above - // will contain just a single drawDisplayList call plus the case - // attribute. The sk_picture will, however, contain a list of all - // of the embedded calls in the display list and so the op counts - // will not be equal between the two. - if (!testP.is_draw_display_list()) { - EXPECT_EQ(display_list->op_count(), sk_picture->approximateOpCount()) - << info; - } + EXPECT_EQ(display_list->op_count(), ref_picture->approximateOpCount()) + << info; - display_list->RenderTo(dl_surface.canvas()); - compareToReference(dl_surface.pixmap(), sk_pixels, + display_list->RenderTo(test_surface->getCanvas()); + compareToReference(test_surface.get(), &ref_pixels, info + " (DisplayList built directly -> surface)", &dl_bounds, &tolerance, bg); } // This test cannot work if the rendering is using shadows until // we can access the Skia ShadowRec via public headers. - if (!testP.is_draw_shadows()) { + if (!TestingDrawShadows) { // This sequence renders SkCanvas calls to a DisplayList and then // plays them back on SkCanvas to SkSurface // SkCanvas calls => DisplayList => rendering - RenderSurface cv_dl_surface = env.MakeSurface(bg); + sk_sp test_surface = makeSurface(bg); DisplayListCanvasRecorder dl_recorder(TestBounds); - caseP.render_to(&dl_recorder, testP); - dl_recorder.builder()->Build()->RenderTo(cv_dl_surface.canvas()); - compareToReference(cv_dl_surface.pixmap(), sk_pixels, + SkPaint test_paint; + cv_setup(&dl_recorder, test_paint); + cv_render(&dl_recorder, test_paint); + dl_recorder.builder()->Build()->RenderTo(test_surface->getCanvas()); + compareToReference(test_surface.get(), &ref_pixels, info + " (Skia calls -> DisplayList -> surface)", - nullptr, nullptr, bg); + nullptr, nullptr, nullptr); } { @@ -1760,41 +1205,41 @@ class CanvasCompareTester { const int TestHeight2 = TestHeight * 2; const SkScalar TestScale = 2.0; - SkPictureRecorder sk_x2_recorder; - SkCanvas* ref_canvas = sk_x2_recorder.beginRecording(TestBounds); + SkPictureRecorder sk_recorder; + SkCanvas* ref_canvas = sk_recorder.beginRecording(TestBounds); SkPaint ref_paint; - caseP.render_to(ref_canvas, testP); - sk_sp ref_x2_picture = - sk_x2_recorder.finishRecordingAsPicture(); - RenderSurface ref_x2_surface = - env.MakeSurface(bg, TestWidth2, TestHeight2); - SkCanvas* ref_x2_canvas = ref_x2_surface.canvas(); - ref_x2_canvas->scale(TestScale, TestScale); - ref_x2_picture->playback(ref_x2_canvas); - const SkPixmap* ref_x2_pixels = ref_x2_surface.pixmap(); - ASSERT_EQ(ref_x2_pixels->width(), TestWidth2) << info; - ASSERT_EQ(ref_x2_pixels->height(), TestHeight2) << info; - ASSERT_EQ(ref_x2_pixels->info().bytesPerPixel(), 4) << info; - - DisplayListBuilder builder_x2(TestBounds); - caseP.render_to(builder_x2, testP); - sk_sp display_list_x2 = builder_x2.Build(); - RenderSurface test_x2_surface = - env.MakeSurface(bg, TestWidth2, TestHeight2); - SkCanvas* test_x2_canvas = test_x2_surface.canvas(); - test_x2_canvas->scale(TestScale, TestScale); - display_list_x2->RenderTo(test_x2_canvas); - compareToReference(test_x2_surface.pixmap(), ref_x2_pixels, + cv_setup(ref_canvas, ref_paint); + cv_render(ref_canvas, ref_paint); + sk_sp ref_picture = sk_recorder.finishRecordingAsPicture(); + sk_sp ref_surface2 = makeSurface(bg, TestWidth2, TestHeight2); + SkCanvas* ref_canvas2 = ref_surface2->getCanvas(); + ref_canvas2->scale(TestScale, TestScale); + ref_picture->playback(ref_canvas2); + SkPixmap ref_pixels2; + ASSERT_TRUE(ref_surface2->peekPixels(&ref_pixels2)) << info; + ASSERT_EQ(ref_pixels2.width(), TestWidth2) << info; + ASSERT_EQ(ref_pixels2.height(), TestHeight2) << info; + ASSERT_EQ(ref_pixels2.info().bytesPerPixel(), 4) << info; + + DisplayListBuilder builder(TestBounds); + dl_setup(builder); + dl_render(builder); + sk_sp display_list = builder.Build(); + sk_sp test_surface = makeSurface(bg, TestWidth2, TestHeight2); + SkCanvas* test_canvas = test_surface->getCanvas(); + test_canvas->scale(TestScale, TestScale); + display_list->RenderTo(test_canvas); + compareToReference(test_surface.get(), &ref_pixels2, info + " (Both rendered scaled 2x)", nullptr, nullptr, - bg, TestWidth2, TestHeight2, false); + nullptr, TestWidth2, TestHeight2, false); } } - static void checkPixels(const SkPixmap* ref_pixels, + static void checkPixels(SkPixmap* ref_pixels, SkRect ref_bounds, const std::string info, - const SkColor bg) { - SkPMColor untouched = SkPreMultiplyColor(bg); + const SkColor* bg) { + SkPMColor untouched = (bg) ? SkPreMultiplyColor(*bg) : 0; int pixels_touched = 0; int pixels_oob = 0; SkIRect i_bounds = ref_bounds.roundOut(); @@ -1813,45 +1258,21 @@ class CanvasCompareTester { ASSERT_GT(pixels_touched, 0) << info; } - static void quickCompareToReference(const SkPixmap* ref_pixels, - const SkPixmap* test_pixels, - bool should_match, - const std::string info) { - ASSERT_EQ(test_pixels->width(), ref_pixels->width()) << info; - ASSERT_EQ(test_pixels->height(), ref_pixels->height()) << info; - ASSERT_EQ(test_pixels->info().bytesPerPixel(), 4) << info; - ASSERT_EQ(ref_pixels->info().bytesPerPixel(), 4) << info; - int pixels_different = 0; - for (int y = 0; y < test_pixels->height(); y++) { - const uint32_t* ref_row = ref_pixels->addr32(0, y); - const uint32_t* test_row = test_pixels->addr32(0, y); - for (int x = 0; x < test_pixels->width(); x++) { - if (ref_row[x] != test_row[x]) { - pixels_different++; - } - } - } - if (should_match) { - ASSERT_EQ(pixels_different, 0) << info; - } else { - ASSERT_NE(pixels_different, 0) << info; - } - } - - static void compareToReference(const SkPixmap* test_pixels, - const SkPixmap* ref_pixels, + static void compareToReference(SkSurface* test_surface, + SkPixmap* reference, const std::string info, SkRect* bounds, const BoundsTolerance* tolerance, - const SkColor bg, + const SkColor* bg, int width = TestWidth, int height = TestHeight, bool printMismatches = false) { - SkPMColor untouched = SkPreMultiplyColor(bg); - ASSERT_EQ(test_pixels->width(), width) << info; - ASSERT_EQ(test_pixels->height(), height) << info; - ASSERT_EQ(test_pixels->info().bytesPerPixel(), 4) << info; - ASSERT_EQ(ref_pixels->info().bytesPerPixel(), 4) << info; + SkPMColor untouched = (bg) ? SkPreMultiplyColor(*bg) : 0; + SkPixmap test_pixels; + ASSERT_TRUE(test_surface->peekPixels(&test_pixels)) << info; + ASSERT_EQ(test_pixels.width(), width) << info; + ASSERT_EQ(test_pixels.height(), height) << info; + ASSERT_EQ(test_pixels.info().bytesPerPixel(), 4) << info; SkIRect i_bounds = bounds ? bounds->roundOut() : SkIRect::MakeWH(width, height); @@ -1862,8 +1283,8 @@ class CanvasCompareTester { int maxX = 0; int maxY = 0; for (int y = 0; y < height; y++) { - const uint32_t* ref_row = ref_pixels->addr32(0, y); - const uint32_t* test_row = test_pixels->addr32(0, y); + const uint32_t* ref_row = reference->addr32(0, y); + const uint32_t* test_row = test_pixels.addr32(0, y); for (int x = 0; x < width; x++) { if (bounds && test_row[x] != untouched) { if (minX > x) @@ -1915,14 +1336,12 @@ class CanvasCompareTester { int pad_top = std::max(0, pixTop - bounds.fTop); int pad_right = std::max(0, bounds.fRight - pixRight); int pad_bottom = std::max(0, bounds.fBottom - pixBottom); - SkIRect pix_bounds = - SkIRect::MakeLTRB(pixLeft, pixTop, pixRight, pixBottom); - SkISize pix_size = pix_bounds.size(); - int pixWidth = pix_size.width(); - int pixHeight = pix_size.height(); + int pixWidth = pixRight - pixLeft; + int pixHeight = pixBottom - pixTop; + SkISize pixSize = SkISize::Make(pixWidth, pixHeight); int worst_pad_x = std::max(pad_left, pad_right); int worst_pad_y = std::max(pad_top, pad_bottom); - if (tolerance->overflows(pix_bounds, worst_pad_x, worst_pad_y)) { + if (tolerance->overflows(pixSize, worst_pad_x, worst_pad_y)) { FML_LOG(ERROR) << "Overflow for " << info; FML_LOG(ERROR) << "pix bounds[" // << pixLeft << ", " << pixTop << " => " // @@ -1937,7 +1356,7 @@ class CanvasCompareTester { << worst_pad_x << ", " << worst_pad_y // << " (" << (worst_pad_x * 100.0 / pixWidth) // << "%, " << (worst_pad_y * 100.0 / pixHeight) << "%)"; - int pix_area = pix_size.area(); + int pix_area = pixSize.area(); int dl_area = bounds.width() * bounds.height(); FML_LOG(ERROR) << "Total overflow area: " << (dl_area - pix_area) // << " (+" << (dl_area * 100.0 / pix_area - 100.0) << "%)"; @@ -1945,6 +1364,16 @@ class CanvasCompareTester { } } + static sk_sp makeSurface(const SkColor* bg, + int width = TestWidth, + int height = TestHeight) { + sk_sp surface = SkSurface::MakeRasterN32Premul(width, height); + if (bg) { + surface->getCanvas()->drawColor(*bg); + } + return surface; + } + static const sk_sp testImage; static const sk_sp makeTestImage() { sk_sp surface = @@ -1952,7 +1381,7 @@ class CanvasCompareTester { SkCanvas* canvas = surface->getCanvas(); SkPaint p0, p1; p0.setStyle(SkPaint::kFill_Style); - p0.setColor(SkColorSetARGB(0xff, 0x00, 0xfe, 0x00)); // off-green + p0.setColor(SK_ColorGREEN); p1.setStyle(SkPaint::kFill_Style); p1.setColor(SK_ColorBLUE); // Some pixels need some transparency for DstIn testing @@ -1967,8 +1396,6 @@ class CanvasCompareTester { return surface->makeImageSnapshot(); } - static const sk_sp testImageShader; - static sk_sp MakeTextBlob(std::string string, SkScalar font_height) { SkFont font(SkTypeface::MakeFromName("ahem", SkFontStyle::Normal()), @@ -1978,203 +1405,230 @@ class CanvasCompareTester { } }; +bool CanvasCompareTester::TestingDrawShadows = false; +bool CanvasCompareTester::TestingDrawVertices = false; +bool CanvasCompareTester::TestingDrawAtlas = false; BoundsTolerance CanvasCompareTester::DefaultTolerance = BoundsTolerance().addAbsolutePadding(1, 1); -const sk_sp CanvasCompareTester::testImage = makeTestImage(); -const sk_sp CanvasCompareTester::testImageShader = - makeTestImage()->makeShader(SkTileMode::kRepeat, - SkTileMode::kRepeat, - SkSamplingOptions()); - -// Eventually this bare bones testing::Test fixture will subsume the -// CanvasCompareTester and the TestParameters could then become just -// configuration calls made upon the fixture. -template -class DisplayListCanvasTestBase : public BaseT, protected DisplayListOpFlags { - public: - DisplayListCanvasTestBase() = default; +const sk_sp CanvasCompareTester::testImage = + CanvasCompareTester::makeTestImage(); - private: - FML_DISALLOW_COPY_AND_ASSIGN(DisplayListCanvasTestBase); -}; -using DisplayListCanvas = DisplayListCanvasTestBase<::testing::Test>; +TEST(DisplayListCanvas, DrawPaint) { + CanvasCompareTester::RenderAll( + [=](SkCanvas* canvas, SkPaint& paint) { // + canvas->drawPaint(paint); + }, + [=](DisplayListBuilder& builder) { // + builder.drawPaint(); + }); +} -TEST_F(DisplayListCanvas, DrawPaint) { - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { // - canvas->drawPaint(paint); - }, - [=](DisplayListBuilder& builder) { // - builder.drawPaint(); - }, - kDrawPaintFlags)); +TEST(DisplayListCanvas, DrawColor) { + CanvasCompareTester::RenderNoAttributes( // + [=](SkCanvas* canvas, SkPaint& paint) { // + canvas->drawColor(SK_ColorMAGENTA); + }, + [=](DisplayListBuilder& builder) { // + builder.drawColor(SK_ColorMAGENTA, SkBlendMode::kSrcOver); + }); } -TEST_F(DisplayListCanvas, DrawColor) { - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { - canvas->drawColor(SK_ColorMAGENTA); - }, - [=](DisplayListBuilder& builder) { - builder.drawColor(SK_ColorMAGENTA, SkBlendMode::kSrcOver); - }, - kDrawColorFlags)); +BoundsTolerance lineTolerance(const BoundsTolerance& tolerance, + const SkPaint& paint, + const SkMatrix& matrix, + bool is_horizontal, + bool is_vertical, + bool ignores_butt_cap) { + SkScalar adjust = 0.0; + SkScalar half_width = paint.getStrokeWidth() * 0.5f; + if (tolerance.discrete_offset() > 0) { + // When a discrete path effect is added, the bounds calculations must allow + // for miters in any direction, but a horizontal line will not have + // miters in the horizontal direction, similarly for vertical + // lines, and diagonal lines will have miters off at a "45 degree" angle + // that don't expand the bounds much at all. + // Also, the discrete offset will not move any points parallel with + // the line, so provide tolerance for both miters and offset. + adjust = half_width * paint.getStrokeMiter() + tolerance.discrete_offset(); + } + if (paint.getStrokeCap() == SkPaint::kButt_Cap && !ignores_butt_cap) { + adjust = std::max(adjust, half_width); + } + if (adjust == 0) { + return CanvasCompareTester::DefaultAdjuster(tolerance, paint, matrix); + } + SkScalar hTolerance; + SkScalar vTolerance; + if (is_horizontal) { + FML_DCHECK(!is_vertical); + hTolerance = adjust; + vTolerance = 0; + } else if (is_vertical) { + hTolerance = 0; + vTolerance = adjust; + } else { + // The perpendicular miters just do not impact the bounds of + // diagonal lines at all as they are aimed in the wrong direction + // to matter. So allow tolerance in both axes. + hTolerance = vTolerance = adjust; + } + BoundsTolerance new_tolerance = + tolerance.addBoundsPadding(hTolerance, vTolerance); + return CanvasCompareTester::DefaultAdjuster(new_tolerance, paint, matrix); +} + +// For drawing horizontal lines +BoundsTolerance hLineTolerance(const BoundsTolerance& tolerance, + const SkPaint& paint, + const SkMatrix& matrix) { + return lineTolerance(tolerance, paint, matrix, true, false, false); } -TEST_F(DisplayListCanvas, DrawDiagonalLines) { +// For drawing vertical lines +BoundsTolerance vLineTolerance(const BoundsTolerance& tolerance, + const SkPaint& paint, + const SkMatrix& matrix) { + return lineTolerance(tolerance, paint, matrix, false, true, false); +} + +// For drawing diagonal lines +BoundsTolerance dLineTolerance(const BoundsTolerance& tolerance, + const SkPaint& paint, + const SkMatrix& matrix) { + return lineTolerance(tolerance, paint, matrix, false, false, false); +} + +// For drawing individual points (drawPoints(Point_Mode)) +BoundsTolerance pointsTolerance(const BoundsTolerance& tolerance, + const SkPaint& paint, + const SkMatrix& matrix) { + return lineTolerance(tolerance, paint, matrix, false, false, true); +} + +TEST(DisplayListCanvas, DrawDiagonalLines) { SkPoint p1 = SkPoint::Make(RenderLeft, RenderTop); SkPoint p2 = SkPoint::Make(RenderRight, RenderBottom); SkPoint p3 = SkPoint::Make(RenderLeft, RenderBottom); SkPoint p4 = SkPoint::Make(RenderRight, RenderTop); - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { // - // Skia requires kStroke style on horizontal and vertical - // lines to get the bounds correct. - // See https://bugs.chromium.org/p/skia/issues/detail?id=12446 - SkPaint p = paint; - p.setStyle(SkPaint::kStroke_Style); - canvas->drawLine(p1, p2, p); - canvas->drawLine(p3, p4, p); - }, - [=](DisplayListBuilder& builder) { // - builder.drawLine(p1, p2); - builder.drawLine(p3, p4); - }, - kDrawLineFlags) - .set_draw_line()); + CanvasCompareTester::RenderAll( + [=](SkCanvas* canvas, SkPaint& paint) { // + // Skia requires kStroke style on horizontal and vertical + // lines to get the bounds correct. + // See https://bugs.chromium.org/p/skia/issues/detail?id=12446 + SkPaint p = paint; + p.setStyle(SkPaint::kStroke_Style); + canvas->drawLine(p1, p2, p); + canvas->drawLine(p3, p4, p); + }, + [=](DisplayListBuilder& builder) { // + builder.drawLine(p1, p2); + builder.drawLine(p3, p4); + }, + dLineTolerance); } -TEST_F(DisplayListCanvas, DrawHorizontalLine) { +TEST(DisplayListCanvas, DrawHorizontalLine) { SkPoint p1 = SkPoint::Make(RenderLeft, RenderCenterY); SkPoint p2 = SkPoint::Make(RenderRight, RenderCenterY); - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { // - // Skia requires kStroke style on horizontal and vertical - // lines to get the bounds correct. - // See https://bugs.chromium.org/p/skia/issues/detail?id=12446 - SkPaint p = paint; - p.setStyle(SkPaint::kStroke_Style); - canvas->drawLine(p1, p2, p); - }, - [=](DisplayListBuilder& builder) { // - builder.drawLine(p1, p2); - }, - kDrawHVLineFlags) - .set_draw_line() - .set_horizontal_line()); + CanvasCompareTester::RenderAll( + [=](SkCanvas* canvas, SkPaint& paint) { // + // Skia requires kStroke style on horizontal and vertical + // lines to get the bounds correct. + // See https://bugs.chromium.org/p/skia/issues/detail?id=12446 + SkPaint p = paint; + p.setStyle(SkPaint::kStroke_Style); + canvas->drawLine(p1, p2, p); + }, + [=](DisplayListBuilder& builder) { // + builder.drawLine(p1, p2); + }, + hLineTolerance); } -TEST_F(DisplayListCanvas, DrawVerticalLine) { +TEST(DisplayListCanvas, DrawVerticalLine) { SkPoint p1 = SkPoint::Make(RenderCenterX, RenderTop); SkPoint p2 = SkPoint::Make(RenderCenterY, RenderBottom); - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { // - // Skia requires kStroke style on horizontal and vertical - // lines to get the bounds correct. - // See https://bugs.chromium.org/p/skia/issues/detail?id=12446 - SkPaint p = paint; - p.setStyle(SkPaint::kStroke_Style); - canvas->drawLine(p1, p2, p); - }, - [=](DisplayListBuilder& builder) { // - builder.drawLine(p1, p2); - }, - kDrawHVLineFlags) - .set_draw_line() - .set_vertical_line()); + CanvasCompareTester::RenderAll( + [=](SkCanvas* canvas, SkPaint& paint) { // + // Skia requires kStroke style on horizontal and vertical + // lines to get the bounds correct. + // See https://bugs.chromium.org/p/skia/issues/detail?id=12446 + SkPaint p = paint; + p.setStyle(SkPaint::kStroke_Style); + canvas->drawLine(p1, p2, p); + }, + [=](DisplayListBuilder& builder) { // + builder.drawLine(p1, p2); + }, + vLineTolerance); } -TEST_F(DisplayListCanvas, DrawRect) { - // Bounds are offset by 0.5 pixels to induce AA - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { // - canvas->drawRect(RenderBounds.makeOffset(0.5, 0.5), paint); - }, - [=](DisplayListBuilder& builder) { // - builder.drawRect(RenderBounds.makeOffset(0.5, 0.5)); - }, - kDrawRectFlags)); +TEST(DisplayListCanvas, DrawRect) { + CanvasCompareTester::RenderAll( + [=](SkCanvas* canvas, SkPaint& paint) { // + canvas->drawRect(RenderBounds, paint); + }, + [=](DisplayListBuilder& builder) { // + builder.drawRect(RenderBounds); + }); } -TEST_F(DisplayListCanvas, DrawOval) { +TEST(DisplayListCanvas, DrawOval) { SkRect rect = RenderBounds.makeInset(0, 10); - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { // - canvas->drawOval(rect, paint); - }, - [=](DisplayListBuilder& builder) { // - builder.drawOval(rect); - }, - kDrawOvalFlags)); + CanvasCompareTester::RenderAll( + [=](SkCanvas* canvas, SkPaint& paint) { // + canvas->drawOval(rect, paint); + }, + [=](DisplayListBuilder& builder) { // + builder.drawOval(rect); + }); } -TEST_F(DisplayListCanvas, DrawCircle) { - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { // - canvas->drawCircle(TestCenter, RenderRadius, paint); - }, - [=](DisplayListBuilder& builder) { // - builder.drawCircle(TestCenter, RenderRadius); - }, - kDrawCircleFlags)); +TEST(DisplayListCanvas, DrawCircle) { + CanvasCompareTester::RenderAll( + [=](SkCanvas* canvas, SkPaint& paint) { // + canvas->drawCircle(TestCenter, RenderRadius, paint); + }, + [=](DisplayListBuilder& builder) { // + builder.drawCircle(TestCenter, RenderRadius); + }); } -TEST_F(DisplayListCanvas, DrawRRect) { +TEST(DisplayListCanvas, DrawRRect) { SkRRect rrect = SkRRect::MakeRectXY(RenderBounds, RenderCornerRadius, RenderCornerRadius); - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { // - canvas->drawRRect(rrect, paint); - }, - [=](DisplayListBuilder& builder) { // - builder.drawRRect(rrect); - }, - kDrawRRectFlags)); + CanvasCompareTester::RenderAll( + [=](SkCanvas* canvas, SkPaint& paint) { // + canvas->drawRRect(rrect, paint); + }, + [=](DisplayListBuilder& builder) { // + builder.drawRRect(rrect); + }); } -TEST_F(DisplayListCanvas, DrawDRRect) { +TEST(DisplayListCanvas, DrawDRRect) { SkRRect outer = SkRRect::MakeRectXY(RenderBounds, RenderCornerRadius, RenderCornerRadius); SkRect innerBounds = RenderBounds.makeInset(30.0, 30.0); SkRRect inner = SkRRect::MakeRectXY(innerBounds, RenderCornerRadius, RenderCornerRadius); - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { // - canvas->drawDRRect(outer, inner, paint); - }, - [=](DisplayListBuilder& builder) { // - builder.drawDRRect(outer, inner); - }, - kDrawDRRectFlags)); + CanvasCompareTester::RenderAll( + [=](SkCanvas* canvas, SkPaint& paint) { // + canvas->drawDRRect(outer, inner, paint); + }, + [=](DisplayListBuilder& builder) { // + builder.drawDRRect(outer, inner); + }); } -TEST_F(DisplayListCanvas, DrawPath) { +TEST(DisplayListCanvas, DrawPath) { SkPath path; - - // unclosed lines to show some caps - path.moveTo(RenderLeft + 15, RenderTop + 15); - path.lineTo(RenderRight - 15, RenderBottom - 15); - path.moveTo(RenderLeft + 15, RenderBottom - 15); - path.lineTo(RenderRight - 15, RenderTop + 15); - path.addRect(RenderBounds); - - // miter diamonds horizontally and vertically to show miters path.moveTo(VerticalMiterDiamondPoints[0]); for (int i = 1; i < VerticalMiterDiamondPointCount; i++) { path.lineTo(VerticalMiterDiamondPoints[i]); @@ -2185,61 +1639,43 @@ TEST_F(DisplayListCanvas, DrawPath) { path.lineTo(HorizontalMiterDiamondPoints[i]); } path.close(); - - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { // - canvas->drawPath(path, paint); - }, - [=](DisplayListBuilder& builder) { // - builder.drawPath(path); - }, - kDrawPathFlags)); + CanvasCompareTester::RenderAll( + [=](SkCanvas* canvas, SkPaint& paint) { // + canvas->drawPath(path, paint); + }, + [=](DisplayListBuilder& builder) { // + builder.drawPath(path); + }); } -TEST_F(DisplayListCanvas, DrawArc) { - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { // - canvas->drawArc(RenderBounds, 60, 330, false, paint); - }, - [=](DisplayListBuilder& builder) { // - builder.drawArc(RenderBounds, 60, 330, false); - }, - kDrawArcNoCenterFlags)); +TEST(DisplayListCanvas, DrawArc) { + CanvasCompareTester::RenderAll( + [=](SkCanvas* canvas, SkPaint& paint) { // + canvas->drawArc(RenderBounds, 60, 330, false, paint); + }, + [=](DisplayListBuilder& builder) { // + builder.drawArc(RenderBounds, 60, 330, false); + }); } -TEST_F(DisplayListCanvas, DrawArcCenter) { - // Center arcs that inscribe nearly a whole circle except for a small - // arc extent gap have 2 angles that may appear or disappear at the - // various miter limits tested (0, 4, and 10). - // The center angle here is 12 degrees which shows a miter - // at limit=10, but not 0 or 4. - // The arcs at the corners where it turns in towards the - // center show miters at 4 and 10, but not 0. - // Limit == 0, neither corner does a miter - // Limit == 4, only the edge "turn-in" corners miter - // Limit == 10, edge and center corners all miter - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { // - canvas->drawArc(RenderBounds, 60, 360 - 12, true, paint); - }, - [=](DisplayListBuilder& builder) { // - builder.drawArc(RenderBounds, 60, 360 - 12, true); - }, - kDrawArcWithCenterFlags) - .set_draw_arc_center()); +TEST(DisplayListCanvas, DrawArcCenter) { + CanvasCompareTester::RenderAll( + [=](SkCanvas* canvas, SkPaint& paint) { // + canvas->drawArc(RenderBounds, 60, 330, true, paint); + }, + [=](DisplayListBuilder& builder) { // + builder.drawArc(RenderBounds, 60, 330, true); + }); } -TEST_F(DisplayListCanvas, DrawPointsAsPoints) { +TEST(DisplayListCanvas, DrawPointsAsPoints) { // The +/- 16 points are designed to fall just inside the clips // that are tested against so we avoid lots of undrawn pixels // in the accumulated bounds. const SkScalar x0 = RenderLeft; const SkScalar x1 = RenderLeft + 16; const SkScalar x2 = (RenderLeft + RenderCenterX) * 0.5; - const SkScalar x3 = RenderCenterX + 0.1; + const SkScalar x3 = RenderCenterX; const SkScalar x4 = (RenderRight + RenderCenterX) * 0.5; const SkScalar x5 = RenderRight - 16; const SkScalar x6 = RenderRight; @@ -2247,7 +1683,7 @@ TEST_F(DisplayListCanvas, DrawPointsAsPoints) { const SkScalar y0 = RenderTop; const SkScalar y1 = RenderTop + 16; const SkScalar y2 = (RenderTop + RenderCenterY) * 0.5; - const SkScalar y3 = RenderCenterY + 0.1; + const SkScalar y3 = RenderCenterY; const SkScalar y4 = (RenderBottom + RenderCenterY) * 0.5; const SkScalar y5 = RenderBottom - 16; const SkScalar y6 = RenderBottom; @@ -2265,25 +1701,22 @@ TEST_F(DisplayListCanvas, DrawPointsAsPoints) { // clang-format on const int count = sizeof(points) / sizeof(points[0]); - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { // - // Skia requires kStroke style on horizontal and vertical - // lines to get the bounds correct. - // See https://bugs.chromium.org/p/skia/issues/detail?id=12446 - SkPaint p = paint; - p.setStyle(SkPaint::kStroke_Style); - canvas->drawPoints(SkCanvas::kPoints_PointMode, count, points, p); - }, - [=](DisplayListBuilder& builder) { // - builder.drawPoints(SkCanvas::kPoints_PointMode, count, points); - }, - kDrawPointsAsPointsFlags) - .set_draw_line() - .set_ignores_dashes()); + CanvasCompareTester::RenderAll( + [=](SkCanvas* canvas, SkPaint& paint) { // + // Skia requires kStroke style on horizontal and vertical + // lines to get the bounds correct. + // See https://bugs.chromium.org/p/skia/issues/detail?id=12446 + SkPaint p = paint; + p.setStyle(SkPaint::kStroke_Style); + canvas->drawPoints(SkCanvas::kPoints_PointMode, count, points, p); + }, + [=](DisplayListBuilder& builder) { // + builder.drawPoints(SkCanvas::kPoints_PointMode, count, points); + }, + pointsTolerance); } -TEST_F(DisplayListCanvas, DrawPointsAsLines) { +TEST(DisplayListCanvas, DrawPointsAsLines) { const SkScalar x0 = RenderLeft + 1; const SkScalar x1 = RenderLeft + 16; const SkScalar x2 = RenderRight - 16; @@ -2315,23 +1748,21 @@ TEST_F(DisplayListCanvas, DrawPointsAsLines) { const int count = sizeof(points) / sizeof(points[0]); ASSERT_TRUE((count & 1) == 0); - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { // - // Skia requires kStroke style on horizontal and vertical - // lines to get the bounds correct. - // See https://bugs.chromium.org/p/skia/issues/detail?id=12446 - SkPaint p = paint; - p.setStyle(SkPaint::kStroke_Style); - canvas->drawPoints(SkCanvas::kLines_PointMode, count, points, p); - }, - [=](DisplayListBuilder& builder) { // - builder.drawPoints(SkCanvas::kLines_PointMode, count, points); - }, - kDrawPointsAsLinesFlags)); + CanvasCompareTester::RenderAll( + [=](SkCanvas* canvas, SkPaint& paint) { // + // Skia requires kStroke style on horizontal and vertical + // lines to get the bounds correct. + // See https://bugs.chromium.org/p/skia/issues/detail?id=12446 + SkPaint p = paint; + p.setStyle(SkPaint::kStroke_Style); + canvas->drawPoints(SkCanvas::kLines_PointMode, count, points, p); + }, + [=](DisplayListBuilder& builder) { // + builder.drawPoints(SkCanvas::kLines_PointMode, count, points); + }); } -TEST_F(DisplayListCanvas, DrawPointsAsPolygon) { +TEST(DisplayListCanvas, DrawPointsAsPolygon) { const SkPoint points1[] = { // RenderBounds box with a diagonal SkPoint::Make(RenderLeft, RenderTop), @@ -2343,24 +1774,21 @@ TEST_F(DisplayListCanvas, DrawPointsAsPolygon) { }; const int count1 = sizeof(points1) / sizeof(points1[0]); - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { // - // Skia requires kStroke style on horizontal and vertical - // lines to get the bounds correct. - // See https://bugs.chromium.org/p/skia/issues/detail?id=12446 - SkPaint p = paint; - p.setStyle(SkPaint::kStroke_Style); - canvas->drawPoints(SkCanvas::kPolygon_PointMode, count1, points1, - p); - }, - [=](DisplayListBuilder& builder) { // - builder.drawPoints(SkCanvas::kPolygon_PointMode, count1, points1); - }, - kDrawPointsAsPolygonFlags)); + CanvasCompareTester::RenderAll( + [=](SkCanvas* canvas, SkPaint& paint) { // + // Skia requires kStroke style on horizontal and vertical + // lines to get the bounds correct. + // See https://bugs.chromium.org/p/skia/issues/detail?id=12446 + SkPaint p = paint; + p.setStyle(SkPaint::kStroke_Style); + canvas->drawPoints(SkCanvas::kPolygon_PointMode, count1, points1, p); + }, + [=](DisplayListBuilder& builder) { // + builder.drawPoints(SkCanvas::kPolygon_PointMode, count1, points1); + }); } -TEST_F(DisplayListCanvas, DrawVerticesWithColors) { +TEST(DisplayListCanvas, DrawVerticesWithColors) { // Cover as many sides of the box with only 6 vertices: // +----------+ // |xxxxxxxxxx| @@ -2386,21 +1814,17 @@ TEST_F(DisplayListCanvas, DrawVerticesWithColors) { }; const sk_sp vertices = SkVertices::MakeCopy( SkVertices::kTriangles_VertexMode, 6, pts, nullptr, colors); - - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { // - canvas->drawVertices(vertices.get(), SkBlendMode::kSrcOver, paint); - }, - [=](DisplayListBuilder& builder) { // - builder.drawVertices(vertices, SkBlendMode::kSrcOver); - }, - kDrawVerticesFlags) - .set_draw_vertices()); - EXPECT_TRUE(vertices->unique()); + CanvasCompareTester::RenderVertices( + [=](SkCanvas* canvas, SkPaint& paint) { // + canvas->drawVertices(vertices.get(), SkBlendMode::kSrcOver, paint); + }, + [=](DisplayListBuilder& builder) { // + builder.drawVertices(vertices, SkBlendMode::kSrcOver); + }); + ASSERT_TRUE(vertices->unique()); } -TEST_F(DisplayListCanvas, DrawVerticesWithImage) { +TEST(DisplayListCanvas, DrawVerticesWithImage) { // Cover as many sides of the box with only 6 vertices: // +----------+ // |xxxxxxxxxx| @@ -2430,267 +1854,226 @@ TEST_F(DisplayListCanvas, DrawVerticesWithImage) { }; const sk_sp vertices = SkVertices::MakeCopy( SkVertices::kTriangles_VertexMode, 6, pts, tex, nullptr); - - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { // - SkPaint v_paint = paint; - if (v_paint.getShader() == nullptr) { - v_paint.setShader(CanvasCompareTester::testImageShader); - } - canvas->drawVertices(vertices.get(), SkBlendMode::kSrcOver, - v_paint); - }, - [=](DisplayListBuilder& builder) { // - if (builder.getShader() == nullptr) { - builder.setShader(CanvasCompareTester::testImageShader); - } - builder.drawVertices(vertices, SkBlendMode::kSrcOver); - }, - kDrawVerticesFlags) - .set_draw_vertices()); - - EXPECT_TRUE(vertices->unique()); - EXPECT_TRUE(CanvasCompareTester::testImageShader->unique()); + const sk_sp shader = CanvasCompareTester::testImage->makeShader( + SkTileMode::kRepeat, SkTileMode::kRepeat, SkSamplingOptions()); + CanvasCompareTester::RenderVertices( + [=](SkCanvas* canvas, SkPaint& paint) { // + paint.setShader(shader); + canvas->drawVertices(vertices.get(), SkBlendMode::kSrcOver, paint); + }, + [=](DisplayListBuilder& builder) { // + builder.setShader(shader); + builder.drawVertices(vertices, SkBlendMode::kSrcOver); + }); + ASSERT_TRUE(vertices->unique()); + ASSERT_TRUE(shader->unique()); } -TEST_F(DisplayListCanvas, DrawImageNearest) { - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { // - canvas->drawImage(CanvasCompareTester::testImage, // - RenderLeft, RenderTop, - DisplayList::NearestSampling, &paint); - }, - [=](DisplayListBuilder& builder) { // - builder.drawImage(CanvasCompareTester::testImage, - SkPoint::Make(RenderLeft, RenderTop), - DisplayList::NearestSampling, true); - }, - kDrawImageWithPaintFlags)); +TEST(DisplayListCanvas, DrawImageNearest) { + CanvasCompareTester::RenderAll( + [=](SkCanvas* canvas, SkPaint& paint) { // + canvas->drawImage(CanvasCompareTester::testImage, RenderLeft, RenderTop, + DisplayList::NearestSampling, &paint); + }, + [=](DisplayListBuilder& builder) { // + builder.drawImage(CanvasCompareTester::testImage, + SkPoint::Make(RenderLeft, RenderTop), + DisplayList::NearestSampling, true); + }); } -TEST_F(DisplayListCanvas, DrawImageNearestNoPaint) { - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { // - canvas->drawImage(CanvasCompareTester::testImage, // - RenderLeft, RenderTop, - DisplayList::NearestSampling, nullptr); - }, - [=](DisplayListBuilder& builder) { // - builder.drawImage(CanvasCompareTester::testImage, - SkPoint::Make(RenderLeft, RenderTop), - DisplayList::NearestSampling, false); - }, - kDrawImageFlags)); +TEST(DisplayListCanvas, DrawImageNearestNoPaint) { + CanvasCompareTester::RenderAll( + [=](SkCanvas* canvas, SkPaint& paint) { // + canvas->drawImage(CanvasCompareTester::testImage, RenderLeft, RenderTop, + DisplayList::NearestSampling, nullptr); + }, + [=](DisplayListBuilder& builder) { // + builder.drawImage(CanvasCompareTester::testImage, + SkPoint::Make(RenderLeft, RenderTop), + DisplayList::NearestSampling, false); + }); } -TEST_F(DisplayListCanvas, DrawImageLinear) { - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { // - canvas->drawImage(CanvasCompareTester::testImage, // - RenderLeft, RenderTop, - DisplayList::LinearSampling, &paint); - }, - [=](DisplayListBuilder& builder) { // - builder.drawImage(CanvasCompareTester::testImage, - SkPoint::Make(RenderLeft, RenderTop), - DisplayList::LinearSampling, true); - }, - kDrawImageWithPaintFlags)); +TEST(DisplayListCanvas, DrawImageLinear) { + CanvasCompareTester::RenderAll( + [=](SkCanvas* canvas, SkPaint& paint) { // + canvas->drawImage(CanvasCompareTester::testImage, RenderLeft, RenderTop, + DisplayList::LinearSampling, &paint); + }, + [=](DisplayListBuilder& builder) { // + builder.drawImage(CanvasCompareTester::testImage, + SkPoint::Make(RenderLeft, RenderTop), + DisplayList::LinearSampling, true); + }); } -TEST_F(DisplayListCanvas, DrawImageRectNearest) { +TEST(DisplayListCanvas, DrawImageRectNearest) { SkRect src = SkRect::MakeIWH(RenderWidth, RenderHeight).makeInset(5, 5); - SkRect dst = RenderBounds.makeInset(10.5, 10.5); - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { // - canvas->drawImageRect(CanvasCompareTester::testImage, src, dst, - DisplayList::NearestSampling, &paint, - SkCanvas::kFast_SrcRectConstraint); - }, - [=](DisplayListBuilder& builder) { // - builder.drawImageRect(CanvasCompareTester::testImage, src, dst, - DisplayList::NearestSampling, true); - }, - kDrawImageRectWithPaintFlags)); + SkRect dst = RenderBounds.makeInset(15.5, 10.5); + CanvasCompareTester::RenderAll( + [=](SkCanvas* canvas, SkPaint& paint) { // + canvas->drawImageRect(CanvasCompareTester::testImage, src, dst, + DisplayList::NearestSampling, &paint, + SkCanvas::kFast_SrcRectConstraint); + }, + [=](DisplayListBuilder& builder) { // + builder.drawImageRect(CanvasCompareTester::testImage, src, dst, + DisplayList::NearestSampling, true); + }); } -TEST_F(DisplayListCanvas, DrawImageRectNearestNoPaint) { +TEST(DisplayListCanvas, DrawImageRectNearestNoPaint) { SkRect src = SkRect::MakeIWH(RenderWidth, RenderHeight).makeInset(5, 5); - SkRect dst = RenderBounds.makeInset(10.5, 10.5); - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { // - canvas->drawImageRect(CanvasCompareTester::testImage, src, dst, - DisplayList::NearestSampling, nullptr, - SkCanvas::kFast_SrcRectConstraint); - }, - [=](DisplayListBuilder& builder) { // - builder.drawImageRect(CanvasCompareTester::testImage, src, dst, - DisplayList::NearestSampling, false); - }, - kDrawImageRectFlags)); + SkRect dst = RenderBounds.makeInset(15.5, 10.5); + CanvasCompareTester::RenderAll( + [=](SkCanvas* canvas, SkPaint& paint) { // + canvas->drawImageRect(CanvasCompareTester::testImage, src, dst, + DisplayList::NearestSampling, nullptr, + SkCanvas::kFast_SrcRectConstraint); + }, + [=](DisplayListBuilder& builder) { // + builder.drawImageRect(CanvasCompareTester::testImage, src, dst, + DisplayList::NearestSampling, false); + }); } -TEST_F(DisplayListCanvas, DrawImageRectLinear) { +TEST(DisplayListCanvas, DrawImageRectLinear) { SkRect src = SkRect::MakeIWH(RenderWidth, RenderHeight).makeInset(5, 5); - SkRect dst = RenderBounds.makeInset(10.5, 10.5); - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { // - canvas->drawImageRect(CanvasCompareTester::testImage, src, dst, - DisplayList::LinearSampling, &paint, - SkCanvas::kFast_SrcRectConstraint); - }, - [=](DisplayListBuilder& builder) { // - builder.drawImageRect(CanvasCompareTester::testImage, src, dst, - DisplayList::LinearSampling, true); - }, - kDrawImageRectWithPaintFlags)); + SkRect dst = RenderBounds.makeInset(15.5, 10.5); + CanvasCompareTester::RenderAll( + [=](SkCanvas* canvas, SkPaint& paint) { // + canvas->drawImageRect(CanvasCompareTester::testImage, src, dst, + DisplayList::LinearSampling, &paint, + SkCanvas::kFast_SrcRectConstraint); + }, + [=](DisplayListBuilder& builder) { // + builder.drawImageRect(CanvasCompareTester::testImage, src, dst, + DisplayList::LinearSampling, true); + }); } -TEST_F(DisplayListCanvas, DrawImageNineNearest) { - SkIRect src = SkIRect::MakeWH(RenderWidth, RenderHeight).makeInset(25, 25); - SkRect dst = RenderBounds.makeInset(10.5, 10.5); - sk_sp image = CanvasCompareTester::testImage; - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { - canvas->drawImageNine(image.get(), src, dst, SkFilterMode::kNearest, - &paint); - }, - [=](DisplayListBuilder& builder) { - builder.drawImageNine(image, src, dst, SkFilterMode::kNearest, - true); - }, - kDrawImageNineWithPaintFlags)); +TEST(DisplayListCanvas, DrawImageNineNearest) { + SkIRect src = SkIRect::MakeWH(RenderWidth, RenderHeight).makeInset(5, 5); + SkRect dst = RenderBounds.makeInset(15.5, 10.5); + CanvasCompareTester::RenderAll( + [=](SkCanvas* canvas, SkPaint& paint) { // + canvas->drawImageNine(CanvasCompareTester::testImage.get(), src, dst, + SkFilterMode::kNearest, &paint); + }, + [=](DisplayListBuilder& builder) { // + builder.drawImageNine(CanvasCompareTester::testImage, src, dst, + SkFilterMode::kNearest, true); + }); } -TEST_F(DisplayListCanvas, DrawImageNineNearestNoPaint) { - SkIRect src = SkIRect::MakeWH(RenderWidth, RenderHeight).makeInset(25, 25); - SkRect dst = RenderBounds.makeInset(10.5, 10.5); - sk_sp image = CanvasCompareTester::testImage; - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { - canvas->drawImageNine(image.get(), src, dst, SkFilterMode::kNearest, - nullptr); - }, - [=](DisplayListBuilder& builder) { - builder.drawImageNine(image, src, dst, SkFilterMode::kNearest, - false); - }, - kDrawImageNineFlags)); +TEST(DisplayListCanvas, DrawImageNineNearestNoPaint) { + SkIRect src = SkIRect::MakeWH(RenderWidth, RenderHeight).makeInset(5, 5); + SkRect dst = RenderBounds.makeInset(15.5, 10.5); + CanvasCompareTester::RenderAll( + [=](SkCanvas* canvas, SkPaint& paint) { // + canvas->drawImageNine(CanvasCompareTester::testImage.get(), src, dst, + SkFilterMode::kNearest, nullptr); + }, + [=](DisplayListBuilder& builder) { // + builder.drawImageNine(CanvasCompareTester::testImage, src, dst, + SkFilterMode::kNearest, false); + }); } -TEST_F(DisplayListCanvas, DrawImageNineLinear) { - SkIRect src = SkIRect::MakeWH(RenderWidth, RenderHeight).makeInset(25, 25); - SkRect dst = RenderBounds.makeInset(10.5, 10.5); - sk_sp image = CanvasCompareTester::testImage; - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { - canvas->drawImageNine(image.get(), src, dst, SkFilterMode::kLinear, - &paint); - }, - [=](DisplayListBuilder& builder) { - builder.drawImageNine(image, src, dst, SkFilterMode::kLinear, true); - }, - kDrawImageNineWithPaintFlags)); +TEST(DisplayListCanvas, DrawImageNineLinear) { + SkIRect src = SkIRect::MakeWH(RenderWidth, RenderHeight).makeInset(5, 5); + SkRect dst = RenderBounds.makeInset(15.5, 10.5); + CanvasCompareTester::RenderAll( + [=](SkCanvas* canvas, SkPaint& paint) { // + canvas->drawImageNine(CanvasCompareTester::testImage.get(), src, dst, + SkFilterMode::kLinear, &paint); + }, + [=](DisplayListBuilder& builder) { // + builder.drawImageNine(CanvasCompareTester::testImage, src, dst, + SkFilterMode::kLinear, true); + }); } -TEST_F(DisplayListCanvas, DrawImageLatticeNearest) { - const SkRect dst = RenderBounds.makeInset(10.5, 10.5); +TEST(DisplayListCanvas, DrawImageLatticeNearest) { + const SkRect dst = RenderBounds.makeInset(15.5, 10.5); const int divX[] = { - RenderWidth * 1 / 4, - RenderWidth * 2 / 4, - RenderWidth * 3 / 4, + (RenderLeft + RenderCenterX) / 2, + RenderCenterX, + (RenderRight + RenderCenterX) / 2, }; const int divY[] = { - RenderHeight * 1 / 4, - RenderHeight * 2 / 4, - RenderHeight * 3 / 4, + (RenderTop + RenderCenterY) / 2, + RenderCenterY, + (RenderBottom + RenderCenterY) / 2, }; SkCanvas::Lattice lattice = { divX, divY, nullptr, 3, 3, nullptr, nullptr, }; - sk_sp image = CanvasCompareTester::testImage; - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { - canvas->drawImageLattice(image.get(), lattice, dst, - SkFilterMode::kNearest, &paint); - }, - [=](DisplayListBuilder& builder) { - builder.drawImageLattice(image, lattice, dst, - SkFilterMode::kNearest, true); - }, - kDrawImageLatticeWithPaintFlags)); + CanvasCompareTester::RenderAll( + [=](SkCanvas* canvas, SkPaint& paint) { // + canvas->drawImageLattice(CanvasCompareTester::testImage.get(), lattice, + dst, SkFilterMode::kNearest, &paint); + }, + [=](DisplayListBuilder& builder) { // + builder.drawImageLattice(CanvasCompareTester::testImage, lattice, // + dst, SkFilterMode::kNearest, true); + }); } -TEST_F(DisplayListCanvas, DrawImageLatticeNearestNoPaint) { - const SkRect dst = RenderBounds.makeInset(10.5, 10.5); +TEST(DisplayListCanvas, DrawImageLatticeNearestNoPaint) { + const SkRect dst = RenderBounds.makeInset(15.5, 10.5); const int divX[] = { - RenderWidth * 1 / 4, - RenderWidth * 2 / 4, - RenderWidth * 3 / 4, + (RenderLeft + RenderCenterX) / 2, + RenderCenterX, + (RenderRight + RenderCenterX) / 2, }; const int divY[] = { - RenderHeight * 1 / 4, - RenderHeight * 2 / 4, - RenderHeight * 3 / 4, + (RenderTop + RenderCenterY) / 2, + RenderCenterY, + (RenderBottom + RenderCenterY) / 2, }; SkCanvas::Lattice lattice = { divX, divY, nullptr, 3, 3, nullptr, nullptr, }; - sk_sp image = CanvasCompareTester::testImage; - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { - canvas->drawImageLattice(image.get(), lattice, dst, - SkFilterMode::kNearest, nullptr); - }, - [=](DisplayListBuilder& builder) { - builder.drawImageLattice(image, lattice, dst, - SkFilterMode::kNearest, false); - }, - kDrawImageLatticeFlags)); + CanvasCompareTester::RenderAll( + [=](SkCanvas* canvas, SkPaint& paint) { // + canvas->drawImageLattice(CanvasCompareTester::testImage.get(), lattice, + dst, SkFilterMode::kNearest, nullptr); + }, + [=](DisplayListBuilder& builder) { // + builder.drawImageLattice(CanvasCompareTester::testImage, lattice, // + dst, SkFilterMode::kNearest, false); + }); } -TEST_F(DisplayListCanvas, DrawImageLatticeLinear) { - const SkRect dst = RenderBounds.makeInset(10.5, 10.5); +TEST(DisplayListCanvas, DrawImageLatticeLinear) { + const SkRect dst = RenderBounds.makeInset(15.5, 10.5); const int divX[] = { - RenderWidth / 4, - RenderWidth / 2, - RenderWidth * 3 / 4, + (RenderLeft + RenderCenterX) / 2, + RenderCenterX, + (RenderRight + RenderCenterX) / 2, }; const int divY[] = { - RenderHeight / 4, - RenderHeight / 2, - RenderHeight * 3 / 4, + (RenderTop + RenderCenterY) / 2, + RenderCenterY, + (RenderBottom + RenderCenterY) / 2, }; SkCanvas::Lattice lattice = { divX, divY, nullptr, 3, 3, nullptr, nullptr, }; - sk_sp image = CanvasCompareTester::testImage; - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { - canvas->drawImageLattice(image.get(), lattice, dst, - SkFilterMode::kLinear, &paint); - }, - [=](DisplayListBuilder& builder) { - builder.drawImageLattice(image, lattice, dst, SkFilterMode::kLinear, - true); - }, - kDrawImageLatticeWithPaintFlags)); + CanvasCompareTester::RenderAll( + [=](SkCanvas* canvas, SkPaint& paint) { // + canvas->drawImageLattice(CanvasCompareTester::testImage.get(), lattice, + dst, SkFilterMode::kLinear, &paint); + }, + [=](DisplayListBuilder& builder) { // + builder.drawImageLattice(CanvasCompareTester::testImage, lattice, // + dst, SkFilterMode::kLinear, true); + }); } -TEST_F(DisplayListCanvas, DrawAtlasNearest) { +TEST(DisplayListCanvas, DrawAtlasNearest) { const SkRSXform xform[] = { // clang-format off { 1.2f, 0.0f, RenderLeft, RenderTop}, @@ -2714,22 +2097,20 @@ TEST_F(DisplayListCanvas, DrawAtlasNearest) { SK_ColorMAGENTA, }; const sk_sp image = CanvasCompareTester::testImage; - const SkSamplingOptions sampling = DisplayList::NearestSampling; - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { - canvas->drawAtlas(image.get(), xform, tex, colors, 4, - SkBlendMode::kSrcOver, sampling, nullptr, &paint); - }, - [=](DisplayListBuilder& builder) { - builder.drawAtlas(image, xform, tex, colors, 4, // - SkBlendMode::kSrcOver, sampling, nullptr, true); - }, - kDrawAtlasWithPaintFlags) - .set_draw_atlas()); + CanvasCompareTester::RenderAtlas( + [=](SkCanvas* canvas, SkPaint& paint) { + canvas->drawAtlas(image.get(), xform, tex, colors, 4, + SkBlendMode::kSrcOver, DisplayList::NearestSampling, + nullptr, &paint); + }, + [=](DisplayListBuilder& builder) { + builder.drawAtlas(image, xform, tex, colors, 4, // + SkBlendMode::kSrcOver, DisplayList::NearestSampling, + nullptr, true); + }); } -TEST_F(DisplayListCanvas, DrawAtlasNearestNoPaint) { +TEST(DisplayListCanvas, DrawAtlasNearestNoPaint) { const SkRSXform xform[] = { // clang-format off { 1.2f, 0.0f, RenderLeft, RenderTop}, @@ -2753,24 +2134,20 @@ TEST_F(DisplayListCanvas, DrawAtlasNearestNoPaint) { SK_ColorMAGENTA, }; const sk_sp image = CanvasCompareTester::testImage; - const SkSamplingOptions sampling = DisplayList::NearestSampling; - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { - canvas->drawAtlas(image.get(), xform, tex, colors, 4, - SkBlendMode::kSrcOver, sampling, // - nullptr, nullptr); - }, - [=](DisplayListBuilder& builder) { - builder.drawAtlas(image, xform, tex, colors, 4, // - SkBlendMode::kSrcOver, sampling, // - nullptr, false); - }, - kDrawAtlasFlags) - .set_draw_atlas()); + CanvasCompareTester::RenderAtlas( + [=](SkCanvas* canvas, SkPaint& paint) { + canvas->drawAtlas(image.get(), xform, tex, colors, 4, + SkBlendMode::kSrcOver, DisplayList::NearestSampling, + nullptr, nullptr); + }, + [=](DisplayListBuilder& builder) { + builder.drawAtlas(image, xform, tex, colors, 4, // + SkBlendMode::kSrcOver, DisplayList::NearestSampling, + nullptr, false); + }); } -TEST_F(DisplayListCanvas, DrawAtlasLinear) { +TEST(DisplayListCanvas, DrawAtlasLinear) { const SkRSXform xform[] = { // clang-format off { 1.2f, 0.0f, RenderLeft, RenderTop}, @@ -2794,19 +2171,17 @@ TEST_F(DisplayListCanvas, DrawAtlasLinear) { SK_ColorMAGENTA, }; const sk_sp image = CanvasCompareTester::testImage; - const SkSamplingOptions sampling = DisplayList::LinearSampling; - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { - canvas->drawAtlas(image.get(), xform, tex, colors, 2, // - SkBlendMode::kSrcOver, sampling, nullptr, &paint); - }, - [=](DisplayListBuilder& builder) { - builder.drawAtlas(image, xform, tex, colors, 2, // - SkBlendMode::kSrcOver, sampling, nullptr, true); - }, - kDrawAtlasWithPaintFlags) - .set_draw_atlas()); + CanvasCompareTester::RenderAtlas( + [=](SkCanvas* canvas, SkPaint& paint) { + canvas->drawAtlas(image.get(), xform, tex, colors, 2, // + SkBlendMode::kSrcOver, DisplayList::LinearSampling, + nullptr, &paint); + }, + [=](DisplayListBuilder& builder) { + builder.drawAtlas(image, xform, tex, colors, 2, // + SkBlendMode::kSrcOver, DisplayList::LinearSampling, + nullptr, true); + }); } sk_sp makeTestPicture() { @@ -2814,86 +2189,91 @@ sk_sp makeTestPicture() { SkCanvas* cv = recorder.beginRecording(RenderBounds); SkPaint p; p.setStyle(SkPaint::kFill_Style); - p.setColor(SK_ColorRED); - cv->drawRect({RenderLeft, RenderTop, RenderCenterX, RenderCenterY}, p); - p.setColor(SK_ColorBLUE); - cv->drawRect({RenderCenterX, RenderTop, RenderRight, RenderCenterY}, p); - p.setColor(SK_ColorGREEN); - cv->drawRect({RenderLeft, RenderCenterY, RenderCenterX, RenderBottom}, p); - p.setColor(SK_ColorYELLOW); - cv->drawRect({RenderCenterX, RenderCenterY, RenderRight, RenderBottom}, p); + SkScalar x_coords[] = { + RenderLeft, + RenderCenterX, + RenderRight, + }; + SkScalar y_coords[] = { + RenderTop, + RenderCenterY, + RenderBottom, + }; + SkColor colors[][2] = { + { + SK_ColorRED, + SK_ColorBLUE, + }, + { + SK_ColorGREEN, + SK_ColorYELLOW, + }, + }; + for (int j = 0; j < 2; j++) { + for (int i = 0; i < 2; i++) { + SkRect rect = { + x_coords[i], + y_coords[j], + x_coords[i + 1], + y_coords[j + 1], + }; + p.setColor(colors[i][j]); + cv->drawOval(rect, p); + } + } return recorder.finishRecordingAsPicture(); } -TEST_F(DisplayListCanvas, DrawPicture) { +TEST(DisplayListCanvas, DrawPicture) { sk_sp picture = makeTestPicture(); - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { // - canvas->drawPicture(picture, nullptr, nullptr); - }, - [=](DisplayListBuilder& builder) { // - builder.drawPicture(picture, nullptr, false); - }, - kDrawPictureFlags)); + CanvasCompareTester::RenderNoAttributes( + [=](SkCanvas* canvas, SkPaint& paint) { // + canvas->drawPicture(picture, nullptr, nullptr); + }, + [=](DisplayListBuilder& builder) { // + builder.drawPicture(picture, nullptr, false); + }); } -TEST_F(DisplayListCanvas, DrawPictureWithMatrix) { +TEST(DisplayListCanvas, DrawPictureWithMatrix) { sk_sp picture = makeTestPicture(); SkMatrix matrix = SkMatrix::Scale(0.95, 0.95); - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { // - canvas->drawPicture(picture, &matrix, nullptr); - }, - [=](DisplayListBuilder& builder) { // - builder.drawPicture(picture, &matrix, false); - }, - kDrawPictureFlags)); + CanvasCompareTester::RenderNoAttributes( + [=](SkCanvas* canvas, SkPaint& paint) { // + canvas->drawPicture(picture, &matrix, nullptr); + }, + [=](DisplayListBuilder& builder) { // + builder.drawPicture(picture, &matrix, false); + }); } -TEST_F(DisplayListCanvas, DrawPictureWithPaint) { +TEST(DisplayListCanvas, DrawPictureWithPaint) { sk_sp picture = makeTestPicture(); - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { // - canvas->drawPicture(picture, nullptr, &paint); - }, - [=](DisplayListBuilder& builder) { // - builder.drawPicture(picture, nullptr, true); - }, - kDrawPictureWithPaintFlags)); + CanvasCompareTester::RenderAll( + [=](SkCanvas* canvas, SkPaint& paint) { // + canvas->drawPicture(picture, nullptr, &paint); + }, + [=](DisplayListBuilder& builder) { // + builder.drawPicture(picture, nullptr, true); + }); } -sk_sp makeTestDisplayList() { +TEST(DisplayListCanvas, DrawDisplayList) { DisplayListBuilder builder; builder.setStyle(SkPaint::kFill_Style); - builder.setColor(SK_ColorRED); - builder.drawRect({RenderLeft, RenderTop, RenderCenterX, RenderCenterY}); builder.setColor(SK_ColorBLUE); - builder.drawRect({RenderCenterX, RenderTop, RenderRight, RenderCenterY}); - builder.setColor(SK_ColorGREEN); - builder.drawRect({RenderLeft, RenderCenterY, RenderCenterX, RenderBottom}); - builder.setColor(SK_ColorYELLOW); - builder.drawRect({RenderCenterX, RenderCenterY, RenderRight, RenderBottom}); - return builder.Build(); -} - -TEST_F(DisplayListCanvas, DrawDisplayList) { - sk_sp display_list = makeTestDisplayList(); - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { // - display_list->RenderTo(canvas); - }, - [=](DisplayListBuilder& builder) { // - builder.drawDisplayList(display_list); - }, - kDrawDisplayListFlags) - .set_draw_display_list()); + builder.drawOval(RenderBounds); + sk_sp display_list = builder.Build(); + CanvasCompareTester::RenderNoAttributes( + [=](SkCanvas* canvas, SkPaint& paint) { // + display_list->RenderTo(canvas); + }, + [=](DisplayListBuilder& builder) { // + builder.drawDisplayList(display_list); + }); } -TEST_F(DisplayListCanvas, DrawTextBlob) { +TEST(DisplayListCanvas, DrawTextBlob) { // TODO(https://github.com/flutter/flutter/issues/82202): Remove once the // performance overlay can use Fuchsia's font manager instead of the empty // default. @@ -2902,31 +2282,38 @@ TEST_F(DisplayListCanvas, DrawTextBlob) { #endif // OS_FUCHSIA sk_sp blob = CanvasCompareTester::MakeTextBlob("Testing", RenderHeight * 0.33f); - SkScalar RenderY1_3 = RenderTop + RenderHeight * 0.3; - SkScalar RenderY2_3 = RenderTop + RenderHeight * 0.6; - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { // - canvas->drawTextBlob(blob, RenderLeft, RenderY1_3, paint); - canvas->drawTextBlob(blob, RenderLeft, RenderY2_3, paint); - canvas->drawTextBlob(blob, RenderLeft, RenderBottom, paint); - }, - [=](DisplayListBuilder& builder) { // - builder.drawTextBlob(blob, RenderLeft, RenderY1_3); - builder.drawTextBlob(blob, RenderLeft, RenderY2_3); - builder.drawTextBlob(blob, RenderLeft, RenderBottom); - }, - kDrawTextBlobFlags) - .set_draw_text_blob(), + SkScalar RenderY1_3 = RenderTop + RenderHeight * 0.33; + SkScalar RenderY2_3 = RenderTop + RenderHeight * 0.66; + CanvasCompareTester::RenderNoAttributes( + [=](SkCanvas* canvas, SkPaint& paint) { // + canvas->drawTextBlob(blob, RenderLeft, RenderY1_3, paint); + canvas->drawTextBlob(blob, RenderLeft, RenderY2_3, paint); + canvas->drawTextBlob(blob, RenderLeft, RenderBottom, paint); + }, + [=](DisplayListBuilder& builder) { // + builder.drawTextBlob(blob, RenderLeft, RenderY1_3); + builder.drawTextBlob(blob, RenderLeft, RenderY2_3); + builder.drawTextBlob(blob, RenderLeft, RenderBottom); + }, + CanvasCompareTester::DefaultAdjuster, // From examining the bounds differential for the "Default" case, the - // SkTextBlob adds a padding of ~32 on the left, ~30 on the right, - // ~12 on top and ~8 on the bottom, so we add 33h & 13v allowed + // SkTextBlob adds a padding of ~31 on the left, ~30 on the right, + // ~12 on top and ~8 on the bottom, so we add 32h & 13v allowed // padding to the tolerance - CanvasCompareTester::DefaultTolerance.addBoundsPadding(33, 13)); - EXPECT_TRUE(blob->unique()); + CanvasCompareTester::DefaultTolerance.addBoundsPadding(32, 13)); +} + +const BoundsTolerance shadowTolerance(const BoundsTolerance& tolerance, + const SkPaint& paint, + const SkMatrix& matrix) { + // Shadow primitives could use just a little more horizontal bounds + // tolerance when drawn with a perspective transform. + return CanvasCompareTester::DefaultAdjuster( + matrix.hasPerspective() ? tolerance.addScale(1.04, 1.0) : tolerance, + paint, matrix); } -TEST_F(DisplayListCanvas, DrawShadow) { +TEST(DisplayListCanvas, DrawShadow) { SkPath path; path.addRoundRect( { @@ -2939,21 +2326,19 @@ TEST_F(DisplayListCanvas, DrawShadow) { const SkColor color = SK_ColorDKGRAY; const SkScalar elevation = 5; - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { // - PhysicalShapeLayer::DrawShadow(canvas, path, color, elevation, - false, 1.0); - }, - [=](DisplayListBuilder& builder) { // - builder.drawShadow(path, color, elevation, false, 1.0); - }, - kDrawShadowFlags) - .set_draw_shadows(), + CanvasCompareTester::RenderShadows( + [=](SkCanvas* canvas, SkPaint& paint) { // + PhysicalShapeLayer::DrawShadow(canvas, path, color, elevation, false, + 1.0); + }, + [=](DisplayListBuilder& builder) { // + builder.drawShadow(path, color, elevation, false, 1.0); + }, + shadowTolerance, CanvasCompareTester::DefaultTolerance.addBoundsPadding(3, 3)); } -TEST_F(DisplayListCanvas, DrawShadowTransparentOccluder) { +TEST(DisplayListCanvas, DrawShadowTransparentOccluder) { SkPath path; path.addRoundRect( { @@ -2966,21 +2351,19 @@ TEST_F(DisplayListCanvas, DrawShadowTransparentOccluder) { const SkColor color = SK_ColorDKGRAY; const SkScalar elevation = 5; - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { // - PhysicalShapeLayer::DrawShadow(canvas, path, color, elevation, true, - 1.0); - }, - [=](DisplayListBuilder& builder) { // - builder.drawShadow(path, color, elevation, true, 1.0); - }, - kDrawShadowFlags) - .set_draw_shadows(), + CanvasCompareTester::RenderShadows( + [=](SkCanvas* canvas, SkPaint& paint) { // + PhysicalShapeLayer::DrawShadow(canvas, path, color, elevation, true, + 1.0); + }, + [=](DisplayListBuilder& builder) { // + builder.drawShadow(path, color, elevation, true, 1.0); + }, + shadowTolerance, CanvasCompareTester::DefaultTolerance.addBoundsPadding(3, 3)); } -TEST_F(DisplayListCanvas, DrawShadowDpr) { +TEST(DisplayListCanvas, DrawShadowDpr) { SkPath path; path.addRoundRect( { @@ -2993,17 +2376,15 @@ TEST_F(DisplayListCanvas, DrawShadowDpr) { const SkColor color = SK_ColorDKGRAY; const SkScalar elevation = 5; - CanvasCompareTester::RenderAll( // - TestParameters( - [=](SkCanvas* canvas, const SkPaint& paint) { // - PhysicalShapeLayer::DrawShadow(canvas, path, color, elevation, - false, 1.5); - }, - [=](DisplayListBuilder& builder) { // - builder.drawShadow(path, color, elevation, false, 1.5); - }, - kDrawShadowFlags) - .set_draw_shadows(), + CanvasCompareTester::RenderShadows( + [=](SkCanvas* canvas, SkPaint& paint) { // + PhysicalShapeLayer::DrawShadow(canvas, path, color, elevation, false, + 1.5); + }, + [=](DisplayListBuilder& builder) { // + builder.drawShadow(path, color, elevation, false, 1.5); + }, + shadowTolerance, CanvasCompareTester::DefaultTolerance.addBoundsPadding(3, 3)); } diff --git a/flow/display_list_unittests.cc b/flow/display_list_unittests.cc index e789c7e8990a5..8339a60c91aff 100644 --- a/flow/display_list_unittests.cc +++ b/flow/display_list_unittests.cc @@ -272,99 +272,97 @@ struct DisplayListInvocationGroup { std::vector allGroups = { { "SetAntiAlias", { + {0, 8, 0, 0, [](DisplayListBuilder& b) {b.setAntiAlias(false);}}, {0, 8, 0, 0, [](DisplayListBuilder& b) {b.setAntiAlias(true);}}, - {0, 0, 0, 0, [](DisplayListBuilder& b) {b.setAntiAlias(false);}}, } }, { "SetDither", { + {0, 8, 0, 0, [](DisplayListBuilder& b) {b.setDither(false);}}, {0, 8, 0, 0, [](DisplayListBuilder& b) {b.setDither(true);}}, - {0, 0, 0, 0, [](DisplayListBuilder& b) {b.setDither(false);}}, } }, { "SetInvertColors", { + {0, 8, 0, 0, [](DisplayListBuilder& b) {b.setInvertColors(false);}}, {0, 8, 0, 0, [](DisplayListBuilder& b) {b.setInvertColors(true);}}, - {0, 0, 0, 0, [](DisplayListBuilder& b) {b.setInvertColors(false);}}, } }, { "SetStrokeCap", { + {0, 8, 0, 0, [](DisplayListBuilder& b) {b.setStrokeCap(SkPaint::kButt_Cap);}}, {0, 8, 0, 0, [](DisplayListBuilder& b) {b.setStrokeCap(SkPaint::kRound_Cap);}}, {0, 8, 0, 0, [](DisplayListBuilder& b) {b.setStrokeCap(SkPaint::kSquare_Cap);}}, - {0, 0, 0, 0, [](DisplayListBuilder& b) {b.setStrokeCap(SkPaint::kButt_Cap);}}, } }, { "SetStrokeJoin", { {0, 8, 0, 0, [](DisplayListBuilder& b) {b.setStrokeJoin(SkPaint::kBevel_Join);}}, {0, 8, 0, 0, [](DisplayListBuilder& b) {b.setStrokeJoin(SkPaint::kRound_Join);}}, - {0, 0, 0, 0, [](DisplayListBuilder& b) {b.setStrokeJoin(SkPaint::kMiter_Join);}}, + {0, 8, 0, 0, [](DisplayListBuilder& b) {b.setStrokeJoin(SkPaint::kMiter_Join);}}, } }, { "SetStyle", { + {0, 8, 0, 0, [](DisplayListBuilder& b) {b.setStyle(SkPaint::kFill_Style);}}, {0, 8, 0, 0, [](DisplayListBuilder& b) {b.setStyle(SkPaint::kStroke_Style);}}, - {0, 8, 0, 0, [](DisplayListBuilder& b) {b.setStyle(SkPaint::kStrokeAndFill_Style);}}, - {0, 0, 0, 0, [](DisplayListBuilder& b) {b.setStyle(SkPaint::kFill_Style);}}, } }, { "SetStrokeWidth", { - {0, 8, 0, 0, [](DisplayListBuilder& b) {b.setStrokeWidth(1.0);}}, + {0, 8, 0, 0, [](DisplayListBuilder& b) {b.setStrokeWidth(0.0);}}, {0, 8, 0, 0, [](DisplayListBuilder& b) {b.setStrokeWidth(5.0);}}, - {0, 0, 0, 0, [](DisplayListBuilder& b) {b.setStrokeWidth(0.0);}}, } }, { "SetStrokeMiter", { {0, 8, 0, 0, [](DisplayListBuilder& b) {b.setStrokeMiter(0.0);}}, {0, 8, 0, 0, [](DisplayListBuilder& b) {b.setStrokeMiter(5.0);}}, - {0, 0, 0, 0, [](DisplayListBuilder& b) {b.setStrokeMiter(4.0);}}, } }, { "SetColor", { {0, 8, 0, 0, [](DisplayListBuilder& b) {b.setColor(SK_ColorGREEN);}}, {0, 8, 0, 0, [](DisplayListBuilder& b) {b.setColor(SK_ColorBLUE);}}, - {0, 0, 0, 0, [](DisplayListBuilder& b) {b.setColor(SK_ColorBLACK);}}, } }, - { "SetBlendModeOrBlender", { + { "SetBlendMode", { {0, 8, 0, 0, [](DisplayListBuilder& b) {b.setBlendMode(SkBlendMode::kSrcIn);}}, {0, 8, 0, 0, [](DisplayListBuilder& b) {b.setBlendMode(SkBlendMode::kDstIn);}}, + } + }, + { "SetBlender", { + {0, 8, 0, 0, [](DisplayListBuilder& b) {b.setBlender(nullptr);}}, {0, 16, 0, 0, [](DisplayListBuilder& b) {b.setBlender(TestBlender1);}}, {0, 16, 0, 0, [](DisplayListBuilder& b) {b.setBlender(TestBlender2);}}, {0, 16, 0, 0, [](DisplayListBuilder& b) {b.setBlender(TestBlender3);}}, - {0, 0, 0, 0, [](DisplayListBuilder& b) {b.setBlendMode(SkBlendMode::kSrcOver);}}, - {0, 0, 0, 0, [](DisplayListBuilder& b) {b.setBlender(nullptr);}}, } }, { "SetShader", { + {0, 8, 0, 0, [](DisplayListBuilder& b) {b.setShader(nullptr);}}, {0, 16, 0, 0, [](DisplayListBuilder& b) {b.setShader(TestShader1);}}, {0, 16, 0, 0, [](DisplayListBuilder& b) {b.setShader(TestShader2);}}, {0, 16, 0, 0, [](DisplayListBuilder& b) {b.setShader(TestShader3);}}, - {0, 0, 0, 0, [](DisplayListBuilder& b) {b.setShader(nullptr);}}, } }, { "SetImageFilter", { + {0, 8, 0, 0, [](DisplayListBuilder& b) {b.setImageFilter(nullptr);}}, {0, 16, 0, 0, [](DisplayListBuilder& b) {b.setImageFilter(TestImageFilter1);}}, {0, 16, 0, 0, [](DisplayListBuilder& b) {b.setImageFilter(TestImageFilter2);}}, - {0, 0, 0, 0, [](DisplayListBuilder& b) {b.setImageFilter(nullptr);}}, } }, { "SetColorFilter", { + {0, 8, 0, 0, [](DisplayListBuilder& b) {b.setColorFilter(nullptr);}}, {0, 16, 0, 0, [](DisplayListBuilder& b) {b.setColorFilter(TestColorFilter1);}}, {0, 16, 0, 0, [](DisplayListBuilder& b) {b.setColorFilter(TestColorFilter2);}}, - {0, 0, 0, 0, [](DisplayListBuilder& b) {b.setColorFilter(nullptr);}}, } }, { "SetPathEffect", { + {0, 8, 0, 0, [](DisplayListBuilder& b) {b.setPathEffect(nullptr);}}, {0, 16, 0, 0, [](DisplayListBuilder& b) {b.setPathEffect(TestPathEffect1);}}, {0, 16, 0, 0, [](DisplayListBuilder& b) {b.setPathEffect(TestPathEffect2);}}, - {0, 0, 0, 0, [](DisplayListBuilder& b) {b.setPathEffect(nullptr);}}, } }, { "SetMaskFilter", { + {0, 16, 0, 0, [](DisplayListBuilder& b) {b.setMaskFilter(nullptr);}}, {0, 16, 0, 0, [](DisplayListBuilder& b) {b.setMaskFilter(TestMaskFilter);}}, {0, 8, 0, 0, [](DisplayListBuilder& b) {b.setMaskBlurFilter(kNormal_SkBlurStyle, 3.0);}}, {0, 8, 0, 0, [](DisplayListBuilder& b) {b.setMaskBlurFilter(kNormal_SkBlurStyle, 5.0);}}, {0, 8, 0, 0, [](DisplayListBuilder& b) {b.setMaskBlurFilter(kSolid_SkBlurStyle, 3.0);}}, {0, 8, 0, 0, [](DisplayListBuilder& b) {b.setMaskBlurFilter(kInner_SkBlurStyle, 3.0);}}, {0, 8, 0, 0, [](DisplayListBuilder& b) {b.setMaskBlurFilter(kOuter_SkBlurStyle, 3.0);}}, - {0, 0, 0, 0, [](DisplayListBuilder& b) {b.setMaskFilter(nullptr);}}, } }, { "Save(Layer)+Restore", { @@ -378,34 +376,33 @@ std::vector allGroups = { }, { "Translate", { // cv.translate(0, 0) is ignored + {1, 16, 0, 0, [](DisplayListBuilder& b) {b.translate(0, 0);}}, {1, 16, 1, 16, [](DisplayListBuilder& b) {b.translate(10, 10);}}, {1, 16, 1, 16, [](DisplayListBuilder& b) {b.translate(10, 15);}}, {1, 16, 1, 16, [](DisplayListBuilder& b) {b.translate(15, 10);}}, - {0, 0, 0, 0, [](DisplayListBuilder& b) {b.translate(0, 0);}}, } }, { "Scale", { // cv.scale(1, 1) is ignored + {1, 16, 0, 0, [](DisplayListBuilder& b) {b.scale(1, 1);}}, {1, 16, 1, 16, [](DisplayListBuilder& b) {b.scale(2, 2);}}, {1, 16, 1, 16, [](DisplayListBuilder& b) {b.scale(2, 3);}}, {1, 16, 1, 16, [](DisplayListBuilder& b) {b.scale(3, 2);}}, - {0, 0, 0, 0, [](DisplayListBuilder& b) {b.scale(1, 1);}}, } }, { "Rotate", { // cv.rotate(0) is ignored, otherwise expressed as concat(rotmatrix) + {1, 8, 0, 0, [](DisplayListBuilder& b) {b.rotate(0);}}, {1, 8, 1, 32, [](DisplayListBuilder& b) {b.rotate(30);}}, {1, 8, 1, 32, [](DisplayListBuilder& b) {b.rotate(45);}}, - {0, 0, 0, 0, [](DisplayListBuilder& b) {b.rotate(0);}}, - {0, 0, 0, 0, [](DisplayListBuilder& b) {b.rotate(360);}}, } }, { "Skew", { // cv.skew(0, 0) is ignored, otherwise expressed as concat(skewmatrix) + {1, 16, 0, 0, [](DisplayListBuilder& b) {b.skew(0, 0);}}, {1, 16, 1, 32, [](DisplayListBuilder& b) {b.skew(0.1, 0.1);}}, {1, 16, 1, 32, [](DisplayListBuilder& b) {b.skew(0.1, 0.2);}}, {1, 16, 1, 32, [](DisplayListBuilder& b) {b.skew(0.2, 0.1);}}, - {0, 0, 0, 0, [](DisplayListBuilder& b) {b.skew(0, 0);}}, } }, { "Transform2DAffine", { @@ -836,9 +833,7 @@ TEST(DisplayList, SingleOpDisplayListsCompareToEachOther) { sk_sp listB = listsB[j]; auto desc = group.op_name + "(variant " + std::to_string(i + 1) + " ==? variant " + std::to_string(j + 1) + ")"; - if (i == j || - (group.variants[i].is_empty() && group.variants[j].is_empty())) { - // They are the same variant, or both variants are NOPs + if (i == j) { ASSERT_EQ(listA->op_count(false), listB->op_count(false)) << desc; ASSERT_EQ(listA->bytes(false), listB->bytes(false)) << desc; ASSERT_EQ(listA->op_count(true), listB->op_count(true)) << desc; @@ -857,31 +852,6 @@ TEST(DisplayList, SingleOpDisplayListsCompareToEachOther) { } } -TEST(DisplayList, FullRotationsAreNop) { - DisplayListBuilder builder; - builder.rotate(0); - builder.rotate(360); - builder.rotate(720); - builder.rotate(1080); - builder.rotate(1440); - sk_sp dl = builder.Build(); - ASSERT_EQ(dl->bytes(false), sizeof(DisplayList)); - ASSERT_EQ(dl->bytes(true), sizeof(DisplayList)); - ASSERT_EQ(dl->op_count(false), 0); - ASSERT_EQ(dl->op_count(true), 0); -} - -TEST(DisplayList, AllBlendModeNops) { - DisplayListBuilder builder; - builder.setBlendMode(SkBlendMode::kSrcOver); - builder.setBlender(nullptr); - sk_sp dl = builder.Build(); - ASSERT_EQ(dl->bytes(false), sizeof(DisplayList)); - ASSERT_EQ(dl->bytes(true), sizeof(DisplayList)); - ASSERT_EQ(dl->op_count(false), 0); - ASSERT_EQ(dl->op_count(true), 0); -} - static sk_sp Build(size_t g_index, size_t v_index) { DisplayListBuilder builder; int op_count = 0; @@ -902,7 +872,7 @@ static sk_sp Build(size_t g_index, size_t v_index) { name = "Default"; } else { name = allGroups[g_index].op_name; - if (v_index >= allGroups[g_index].variants.size()) { + if (v_index < 0) { name += " skipped"; } else { name += " variant " + std::to_string(v_index + 1); @@ -919,12 +889,12 @@ TEST(DisplayList, DisplayListsWithVaryingOpComparisons) { for (size_t gi = 0; gi < allGroups.size(); gi++) { DisplayListInvocationGroup& group = allGroups[gi]; sk_sp missing_dl = Build(gi, group.variants.size()); - auto desc = "[Group " + group.op_name + " omitted]"; + auto desc = "[Group " + std::to_string(gi + 1) + " omitted]"; ASSERT_TRUE(missing_dl->Equals(*missing_dl)) << desc << " == itself"; ASSERT_FALSE(missing_dl->Equals(*default_dl)) << desc << " != Default"; ASSERT_FALSE(default_dl->Equals(*missing_dl)) << "Default != " << desc; for (size_t vi = 0; vi < group.variants.size(); vi++) { - auto desc = "[Group " + group.op_name + " variant " + + auto desc = "[Group " + std::to_string(gi + 1) + " variant " + std::to_string(vi + 1) + "]"; sk_sp variant_dl = Build(gi, vi); ASSERT_TRUE(variant_dl->Equals(*variant_dl)) << desc << " == itself"; @@ -1147,230 +1117,5 @@ TEST(DisplayList, NestedOpCountMetricsSameAsSkPicture) { ASSERT_EQ(display_list->op_count(true), 36); } -class AttributeRefTester { - public: - virtual void setRefToPaint(SkPaint& paint) const = 0; - virtual void setRefToDisplayList(DisplayListBuilder& builder) const = 0; - virtual bool ref_is_unique() const = 0; - - void testDisplayList() { - { - DisplayListBuilder builder; - setRefToDisplayList(builder); - builder.drawRect(SkRect::MakeLTRB(50, 50, 100, 100)); - ASSERT_FALSE(ref_is_unique()); - } - ASSERT_TRUE(ref_is_unique()); - } - void testPaint() { - { - SkPaint paint; - setRefToPaint(paint); - ASSERT_FALSE(ref_is_unique()); - } - ASSERT_TRUE(ref_is_unique()); - } - void testCanvasRecorder() { - { - sk_sp display_list; - { - DisplayListCanvasRecorder recorder(SkRect::MakeLTRB(0, 0, 200, 200)); - { - { - SkPaint paint; - setRefToPaint(paint); - recorder.drawRect(SkRect::MakeLTRB(50, 50, 100, 100), paint); - ASSERT_FALSE(ref_is_unique()); - } - ASSERT_FALSE(ref_is_unique()); - } - display_list = recorder.Build(); - ASSERT_FALSE(ref_is_unique()); - } - ASSERT_FALSE(ref_is_unique()); - } - ASSERT_TRUE(ref_is_unique()); - } - - void test() { - testDisplayList(); - testPaint(); - testCanvasRecorder(); - } -}; - -TEST(DisplayList, DisplayListImageFilterRefHandling) { - class ImageFilterRefTester : public virtual AttributeRefTester { - public: - void setRefToPaint(SkPaint& paint) const override { - paint.setImageFilter(image_filter); - } - void setRefToDisplayList(DisplayListBuilder& builder) const override { - builder.setImageFilter(image_filter); - } - bool ref_is_unique() const override { return image_filter->unique(); } - - private: - sk_sp image_filter = SkImageFilters::Blur(2.0, 2.0, nullptr); - }; - - ImageFilterRefTester tester; - tester.test(); - ASSERT_TRUE(tester.ref_is_unique()); -} - -TEST(DisplayList, DisplayListColorFilterRefHandling) { - class ColorFilterRefTester : public virtual AttributeRefTester { - public: - void setRefToPaint(SkPaint& paint) const override { - paint.setColorFilter(color_filter); - } - void setRefToDisplayList(DisplayListBuilder& builder) const override { - builder.setColorFilter(color_filter); - } - bool ref_is_unique() const override { return color_filter->unique(); } - - private: - sk_sp color_filter = - SkColorFilters::Blend(SK_ColorBLUE, SkBlendMode::kSrcIn); - }; - - ColorFilterRefTester tester; - tester.test(); - ASSERT_TRUE(tester.ref_is_unique()); -} - -TEST(DisplayList, DisplayListMaskFilterRefHandling) { - class MaskFilterRefTester : public virtual AttributeRefTester { - public: - void setRefToPaint(SkPaint& paint) const override { - paint.setMaskFilter(mask_filter); - } - void setRefToDisplayList(DisplayListBuilder& builder) const override { - builder.setMaskFilter(mask_filter); - } - bool ref_is_unique() const override { return mask_filter->unique(); } - - private: - sk_sp mask_filter = - SkMaskFilter::MakeBlur(SkBlurStyle::kNormal_SkBlurStyle, 2.0); - }; - - MaskFilterRefTester tester; - tester.test(); - ASSERT_TRUE(tester.ref_is_unique()); -} - -TEST(DisplayList, DisplayListBlenderRefHandling) { - class BlenderRefTester : public virtual AttributeRefTester { - public: - void setRefToPaint(SkPaint& paint) const override { - paint.setBlender(blender); - } - void setRefToDisplayList(DisplayListBuilder& builder) const override { - builder.setBlender(blender); - } - bool ref_is_unique() const override { return blender->unique(); } - - private: - sk_sp blender = - SkBlenders::Arithmetic(0.25, 0.25, 0.25, 0.25, true); - }; - - BlenderRefTester tester; - tester.test(); - ASSERT_TRUE(tester.ref_is_unique()); -} - -TEST(DisplayList, DisplayListShaderRefHandling) { - class ShaderRefTester : public virtual AttributeRefTester { - public: - void setRefToPaint(SkPaint& paint) const override { - paint.setShader(shader); - } - void setRefToDisplayList(DisplayListBuilder& builder) const override { - builder.setShader(shader); - } - bool ref_is_unique() const override { return shader->unique(); } - - private: - sk_sp shader = SkShaders::Color(SK_ColorBLUE); - }; - - ShaderRefTester tester; - tester.test(); - ASSERT_TRUE(tester.ref_is_unique()); -} - -TEST(DisplayList, DisplayListPathEffectRefHandling) { - class PathEffectRefTester : public virtual AttributeRefTester { - public: - void setRefToPaint(SkPaint& paint) const override { - paint.setPathEffect(path_effect); - } - void setRefToDisplayList(DisplayListBuilder& builder) const override { - builder.setPathEffect(path_effect); - } - bool ref_is_unique() const override { return path_effect->unique(); } - - private: - sk_sp path_effect = - SkDashPathEffect::Make(TestDashes1, 2, 0.0); - }; - - PathEffectRefTester tester; - tester.test(); - ASSERT_TRUE(tester.ref_is_unique()); -} - -TEST(DisplayList, DisplayListFullPerspectiveTransformHandling) { - // SkM44 constructor takes row-major order - SkM44 sk_matrix = SkM44( - // clang-format off - 1, 2, 3, 4, - 5, 6, 7, 8, - 9, 10, 11, 12, - 13, 14, 15, 16 - // clang-format on - ); - - { // First test == - DisplayListBuilder builder; - // builder.transformFullPerspective takes row-major order - builder.transformFullPerspective( - // clang-format off - 1, 2, 3, 4, - 5, 6, 7, 8, - 9, 10, 11, 12, - 13, 14, 15, 16 - // clang-format on - ); - sk_sp display_list = builder.Build(); - sk_sp surface = SkSurface::MakeRasterN32Premul(10, 10); - SkCanvas* canvas = surface->getCanvas(); - display_list->RenderTo(canvas); - SkM44 dl_matrix = canvas->getLocalToDevice(); - ASSERT_EQ(sk_matrix, dl_matrix); - } - { // Next test != - DisplayListBuilder builder; - // builder.transformFullPerspective takes row-major order - builder.transformFullPerspective( - // clang-format off - 1, 5, 9, 13, - 2, 6, 7, 11, - 3, 7, 11, 15, - 4, 8, 12, 16 - // clang-format on - ); - sk_sp display_list = builder.Build(); - sk_sp surface = SkSurface::MakeRasterN32Premul(10, 10); - SkCanvas* canvas = surface->getCanvas(); - display_list->RenderTo(canvas); - SkM44 dl_matrix = canvas->getLocalToDevice(); - ASSERT_NE(sk_matrix, dl_matrix); - } -} - } // namespace testing } // namespace flutter diff --git a/flow/display_list_utils.cc b/flow/display_list_utils.cc index 6cf86f16707ee..b6d86fa533894 100644 --- a/flow/display_list_utils.cc +++ b/flow/display_list_utils.cc @@ -234,7 +234,8 @@ void DisplayListBoundsCalculator::setStrokeJoin(SkPaint::Join join) { join_is_miter_ = (join == SkPaint::kMiter_Join); } void DisplayListBoundsCalculator::setStyle(SkPaint::Style style) { - style_ = style; + style_flag_ = (style == SkPaint::kFill_Style) ? kIsFilledGeometry // + : kIsStrokedGeometry; } void DisplayListBoundsCalculator::setStrokeWidth(SkScalar width) { half_stroke_width_ = std::max(width * 0.5f, kMinStrokeWidth); @@ -289,9 +290,7 @@ void DisplayListBoundsCalculator::saveLayer(const SkRect* bounds, // Accumulate the layer in its own coordinate system and then // filter and transform its bounds on restore. SkMatrixDispatchHelper::reset(); - if (bounds) { - clipRect(*bounds, SkClipOp::kIntersect, false); - } + ClipBoundsDispatchHelper::reset(bounds); } void DisplayListBoundsCalculator::restore() { if (layer_infos_.size() > 1) { @@ -311,7 +310,7 @@ void DisplayListBoundsCalculator::restore() { // modifications based on the attributes that were in place // when it was instantiated. Modifying it further base on the // current attributes would mix attribute states. - AccumulateRect(layer_bounds, kSaveLayerFlags); + AccumulateRect(layer_bounds, kIsUnfiltered); } if (layer_unbounded) { AccumulateUnbounded(); @@ -328,35 +327,39 @@ void DisplayListBoundsCalculator::drawColor(SkColor color, SkBlendMode mode) { void DisplayListBoundsCalculator::drawLine(const SkPoint& p0, const SkPoint& p1) { SkRect bounds = SkRect::MakeLTRB(p0.fX, p0.fY, p1.fX, p1.fY).makeSorted(); - DisplayListAttributeFlags flags = - (bounds.width() > 0.0f && bounds.height() > 0.0f) ? kDrawLineFlags - : kDrawHVLineFlags; - AccumulateRect(bounds, flags); + int cap_flag = kIsStrokedGeometry; + if (bounds.width() > 0.0f && bounds.height() > 0.0f) { + cap_flag |= kGeometryMayHaveDiagonalEndCaps; + } + AccumulateRect(bounds, cap_flag); } void DisplayListBoundsCalculator::drawRect(const SkRect& rect) { - AccumulateRect(rect, kDrawRectFlags); + AccumulateRect(rect, kIsDrawnGeometry); } void DisplayListBoundsCalculator::drawOval(const SkRect& bounds) { - AccumulateRect(bounds, kDrawOvalFlags); + AccumulateRect(bounds, kIsDrawnGeometry); } void DisplayListBoundsCalculator::drawCircle(const SkPoint& center, SkScalar radius) { AccumulateRect(SkRect::MakeLTRB(center.fX - radius, center.fY - radius, center.fX + radius, center.fY + radius), - kDrawCircleFlags); + kIsDrawnGeometry); } void DisplayListBoundsCalculator::drawRRect(const SkRRect& rrect) { - AccumulateRect(rrect.getBounds(), kDrawRRectFlags); + AccumulateRect(rrect.getBounds(), kIsDrawnGeometry); } void DisplayListBoundsCalculator::drawDRRect(const SkRRect& outer, const SkRRect& inner) { - AccumulateRect(outer.getBounds(), kDrawDRRectFlags); + AccumulateRect(outer.getBounds(), kIsDrawnGeometry); } void DisplayListBoundsCalculator::drawPath(const SkPath& path) { if (path.isInverseFillType()) { AccumulateUnbounded(); } else { - AccumulateRect(path.getBounds(), kDrawPathFlags); + AccumulateRect(path.getBounds(), // + (kIsDrawnGeometry | // + kGeometryMayHaveDiagonalEndCaps | // + kGeometryMayHaveProblematicJoins)); } } void DisplayListBoundsCalculator::drawArc(const SkRect& bounds, @@ -366,10 +369,7 @@ void DisplayListBoundsCalculator::drawArc(const SkRect& bounds, // This could be tighter if we compute where the start and end // angles are and then also consider the quadrants swept and // the center if specified. - AccumulateRect(bounds, - useCenter // - ? kDrawArcWithCenterFlags - : kDrawArcNoCenterFlags); + AccumulateRect(bounds, kIsDrawnGeometry | kGeometryMayHaveDiagonalEndCaps); } void DisplayListBoundsCalculator::drawPoints(SkCanvas::PointMode mode, uint32_t count, @@ -379,23 +379,17 @@ void DisplayListBoundsCalculator::drawPoints(SkCanvas::PointMode mode, for (size_t i = 0; i < count; i++) { ptBounds.accumulate(pts[i]); } - SkRect point_bounds = ptBounds.bounds(); - switch (mode) { - case SkCanvas::kPoints_PointMode: - AccumulateRect(point_bounds, kDrawPointsAsPointsFlags); - break; - case SkCanvas::kLines_PointMode: - AccumulateRect(point_bounds, kDrawPointsAsLinesFlags); - break; - case SkCanvas::kPolygon_PointMode: - AccumulateRect(point_bounds, kDrawPointsAsPolygonFlags); - break; + int flags = kIsStrokedGeometry; + if (mode != SkCanvas::kPoints_PointMode) { + flags |= kGeometryMayHaveDiagonalEndCaps; + // Even Polygon mode just draws (count-1) separate lines, no joins } + AccumulateRect(ptBounds.bounds(), flags); } } void DisplayListBoundsCalculator::drawVertices(const sk_sp vertices, SkBlendMode mode) { - AccumulateRect(vertices->bounds(), kDrawVerticesFlags); + AccumulateRect(vertices->bounds(), kIsNonGeometric); } void DisplayListBoundsCalculator::drawImage(const sk_sp image, const SkPoint point, @@ -403,9 +397,8 @@ void DisplayListBoundsCalculator::drawImage(const sk_sp image, bool render_with_attributes) { SkRect bounds = SkRect::MakeXYWH(point.fX, point.fY, // image->width(), image->height()); - DisplayListAttributeFlags flags = render_with_attributes // - ? kDrawImageWithPaintFlags - : kDrawImageFlags; + int flags = render_with_attributes ? kIsNonGeometric | kApplyMaskFilter + : kIsUnfiltered; AccumulateRect(bounds, flags); } void DisplayListBoundsCalculator::drawImageRect( @@ -415,9 +408,8 @@ void DisplayListBoundsCalculator::drawImageRect( const SkSamplingOptions& sampling, bool render_with_attributes, SkCanvas::SrcRectConstraint constraint) { - DisplayListAttributeFlags flags = render_with_attributes - ? kDrawImageRectWithPaintFlags - : kDrawImageRectFlags; + int flags = render_with_attributes ? kIsNonGeometric | kApplyMaskFilter + : kIsUnfiltered; AccumulateRect(dst, flags); } void DisplayListBoundsCalculator::drawImageNine(const sk_sp image, @@ -425,10 +417,7 @@ void DisplayListBoundsCalculator::drawImageNine(const sk_sp image, const SkRect& dst, SkFilterMode filter, bool render_with_attributes) { - DisplayListAttributeFlags flags = render_with_attributes - ? kDrawImageNineWithPaintFlags - : kDrawImageNineFlags; - AccumulateRect(dst, flags); + AccumulateRect(dst, render_with_attributes ? kIsNonGeometric : kIsUnfiltered); } void DisplayListBoundsCalculator::drawImageLattice( const sk_sp image, @@ -436,9 +425,8 @@ void DisplayListBoundsCalculator::drawImageLattice( const SkRect& dst, SkFilterMode filter, bool render_with_attributes) { - DisplayListAttributeFlags flags = render_with_attributes - ? kDrawImageLatticeWithPaintFlags - : kDrawImageLatticeFlags; + int flags = render_with_attributes ? kIsNonGeometric | kApplyMaskFilter + : kIsUnfiltered; AccumulateRect(dst, flags); } void DisplayListBoundsCalculator::drawAtlas(const sk_sp atlas, @@ -460,9 +448,7 @@ void DisplayListBoundsCalculator::drawAtlas(const sk_sp atlas, } } if (atlasBounds.is_not_empty()) { - DisplayListAttributeFlags flags = render_with_attributes // - ? kDrawAtlasWithPaintFlags - : kDrawAtlasFlags; + int flags = render_with_attributes ? kIsNonGeometric : kIsUnfiltered; AccumulateRect(atlasBounds.bounds(), flags); } } @@ -476,19 +462,17 @@ void DisplayListBoundsCalculator::drawPicture(const sk_sp picture, if (pic_matrix) { pic_matrix->mapRect(&bounds); } - DisplayListAttributeFlags flags = render_with_attributes // - ? kDrawPictureWithPaintFlags - : kDrawPictureFlags; - AccumulateRect(bounds, flags); + AccumulateRect(bounds, + render_with_attributes ? kIsNonGeometric : kIsUnfiltered); } void DisplayListBoundsCalculator::drawDisplayList( const sk_sp display_list) { - AccumulateRect(display_list->bounds(), kDrawDisplayListFlags); + AccumulateRect(display_list->bounds(), kIsUnfiltered); } void DisplayListBoundsCalculator::drawTextBlob(const sk_sp blob, SkScalar x, SkScalar y) { - AccumulateRect(blob->bounds().makeOffset(x, y), kDrawTextBlobFlags); + AccumulateRect(blob->bounds().makeOffset(x, y), kIsFilledGeometry); } void DisplayListBoundsCalculator::drawShadow(const SkPath& path, const SkColor color, @@ -497,7 +481,7 @@ void DisplayListBoundsCalculator::drawShadow(const SkPath& path, SkScalar dpr) { SkRect shadow_bounds = PhysicalShapeLayer::ComputeShadowBounds(path, elevation, dpr, matrix()); - AccumulateRect(shadow_bounds, kDrawShadowFlags); + AccumulateRect(shadow_bounds, kIsUnfiltered); } bool DisplayListBoundsCalculator::ComputeFilteredBounds(SkRect& bounds, @@ -511,41 +495,64 @@ bool DisplayListBoundsCalculator::ComputeFilteredBounds(SkRect& bounds, return true; } -bool DisplayListBoundsCalculator::AdjustBoundsForPaint( - SkRect& bounds, - DisplayListAttributeFlags flags) { - if (flags.ignores_paint()) { +bool DisplayListBoundsCalculator::AdjustBoundsForPaint(SkRect& bounds, + int flags) { + if ((flags & kIsUnfiltered) != 0) { + FML_DCHECK(flags == kIsUnfiltered); return true; } - if (flags.is_geometric()) { + if ((flags & kIsAnyGeometryMask) != 0) { + if ((flags & kIsDrawnGeometry) != 0) { + FML_DCHECK((flags & (kIsFilledGeometry | kIsStrokedGeometry)) == 0); + flags |= style_flag_; + } + // Path effect occurs before stroking... - DisplayListSpecialGeometryFlags special_flags = - flags.WithPathEffect(path_effect_); if (path_effect_) { - SkPaint p; - p.setPathEffect(path_effect_); - if (!p.canComputeFastBounds()) { - return false; + SkPathEffect::DashInfo info; + if (path_effect_->asADash(&info) == SkPathEffect::kDash_DashType) { + // A dash effect has a very simple impact. It cannot introduce any + // miter joins that weren't already present in the original path + // and it does not grow the bounds of the path, but it can add + // end caps to areas that might not have had them before so all + // we need to do is to indicate the potential for diagonal + // end caps and move on. + flags |= kGeometryMayHaveDiagonalEndCaps; + } else { + SkPaint p; + p.setPathEffect(path_effect_); + if (!p.canComputeFastBounds()) { + return false; + } + bounds = p.computeFastBounds(bounds, &bounds); + flags |= (kGeometryMayHaveDiagonalEndCaps | + kGeometryMayHaveProblematicJoins); } - bounds = p.computeFastBounds(bounds, &bounds); } - if (flags.is_stroked(style_)) { + if ((flags & kIsStrokedGeometry) != 0) { + FML_DCHECK((flags & kIsFilledGeometry) == 0); // Determine the max multiplier to the stroke width first. SkScalar pad = 1.0f; - if (join_is_miter_ && special_flags.may_have_acute_joins()) { + if (join_is_miter_ && (flags & kGeometryMayHaveProblematicJoins) != 0) { pad = std::max(pad, miter_limit_); } - if (cap_is_square_ && special_flags.may_have_diagonal_caps()) { + if (cap_is_square_ && (flags & kGeometryMayHaveDiagonalEndCaps) != 0) { pad = std::max(pad, SK_ScalarSqrt2); } pad *= half_stroke_width_; bounds.outset(pad, pad); + } else { + FML_DCHECK((flags & kIsStrokedGeometry) == 0); } + flags |= kApplyMaskFilter; + } else { + FML_DCHECK((flags & (kGeometryMayHaveDiagonalEndCaps | + kGeometryMayHaveProblematicJoins)) == 0); } - if (flags.applies_mask_filter()) { + if ((flags & kApplyMaskFilter) != 0) { if (mask_filter_) { SkPaint p; p.setMaskFilter(mask_filter_); @@ -559,11 +566,7 @@ bool DisplayListBoundsCalculator::AdjustBoundsForPaint( } } - if (flags.applies_image_filter()) { - return ComputeFilteredBounds(bounds, image_filter_.get()); - } - - return true; + return ComputeFilteredBounds(bounds, image_filter_.get()); } void DisplayListBoundsCalculator::AccumulateUnbounded() { @@ -573,9 +576,7 @@ void DisplayListBoundsCalculator::AccumulateUnbounded() { layer_infos_.back()->set_unbounded(); } } -void DisplayListBoundsCalculator::AccumulateRect( - SkRect& rect, - DisplayListAttributeFlags flags) { +void DisplayListBoundsCalculator::AccumulateRect(SkRect& rect, int flags) { if (AdjustBoundsForPaint(rect, flags)) { matrix().mapRect(&rect); if (!has_clip() || rect.intersect(clip_bounds())) { diff --git a/flow/display_list_utils.h b/flow/display_list_utils.h index 779c48fd56583..495a62f294fc7 100644 --- a/flow/display_list_utils.h +++ b/flow/display_list_utils.h @@ -65,9 +65,9 @@ class IgnoreAttributeDispatchHelper : public virtual Dispatcher { // A utility class that will ignore all Dispatcher methods relating // to setting a clip. class IgnoreClipDispatchHelper : public virtual Dispatcher { - void clipRect(const SkRect& rect, SkClipOp clip_op, bool is_aa) override {} - void clipRRect(const SkRRect& rrect, SkClipOp clip_op, bool is_aa) override {} - void clipPath(const SkPath& path, SkClipOp clip_op, bool is_aa) override {} + void clipRect(const SkRect& rect, SkClipOp clip_op, bool isAA) override {} + void clipRRect(const SkRRect& rrect, SkClipOp clip_op, bool isAA) override {} + void clipPath(const SkPath& path, SkClipOp clip_op, bool isAA) override {} }; // A utility class that will ignore all Dispatcher methods relating @@ -267,8 +267,7 @@ class DisplayListBoundsCalculator final : public virtual Dispatcher, public virtual IgnoreAttributeDispatchHelper, public virtual SkMatrixDispatchHelper, - public virtual ClipBoundsDispatchHelper, - DisplayListOpFlags { + public virtual ClipBoundsDispatchHelper { public: // Construct a Calculator to determine the bounds of a list of // DisplayList dispatcher method calls. Since 2 of the method calls @@ -532,6 +531,61 @@ class DisplayListBoundsCalculator final std::vector> layer_infos_; + // A drawing operation that is not geometric in nature (but which + // may still apply a MaskFilter - see |kApplyMaskFilter| below). + static constexpr int kIsNonGeometric = 0x00; + + // A geometric operation that is defined as a fill operation + // regardless of what the current paint Style is set to. + // This flag will automatically assume |kApplyMaskFilter|. + static constexpr int kIsFilledGeometry = 0x01; + + // A geometric operation that is defined as a stroke operation + // regardless of what the current paint Style is set to. + // This flag will automatically assume |kApplyMaskFilter|. + static constexpr int kIsStrokedGeometry = 0x02; + + // A geometric operation that may be a stroke or fill operation + // depending on the current state of the paint Style attribute. + // This flag will automatically assume |kApplyMaskFilter|. + static constexpr int kIsDrawnGeometry = 0x04; + + static constexpr int kIsAnyGeometryMask = // + kIsFilledGeometry | // + kIsStrokedGeometry | // + kIsDrawnGeometry; + + // A geometric operation which has a path that might have + // end caps that are not rectilinear which means that square + // end caps might project further than half the stroke width + // from the geometry bounds. + // A rectilinear path such as |drawRect| will not have + // diagonal end caps. |drawLine| might have diagonal end + // caps depending on the angle of the line, and more likely + // |drawPath| will often have such end caps. + static constexpr int kGeometryMayHaveDiagonalEndCaps = 0x08; + + // A geometric operation which has joined vertices that are + // not guaranteed to be smooth (angles of incoming and outgoing) + // segments at some joins may not have the same angle) or + // rectilinear (squares have right angles at the corners, but + // those corners will never extend past the bounding box of + // the geometry pre-transform). + // |drawRect|, |drawOval| and |drawRRect| all have well + // behaved joins, but |drawPath| might have joins that cause + // mitered extensions outside the pre-transformed bounding box. + static constexpr int kGeometryMayHaveProblematicJoins = 0x10; + + // Some operations are inherently non-geometric and yet have the + // mask filter applied anyway. + // |drawImage| variants behave this way. + static constexpr int kApplyMaskFilter = 0x20; + + // In very rare circumstances the ImageFilter is ignored. + // This is one of the few flags that turns off a step in + // estimating the bounds, rather than turning on any steps. + static constexpr int kIsUnfiltered = 0x40; + static constexpr SkScalar kMinStrokeWidth = 0.01; skstd::optional blend_mode_ = SkBlendMode::kSrcOver; @@ -539,7 +593,7 @@ class DisplayListBoundsCalculator final SkScalar half_stroke_width_ = kMinStrokeWidth; SkScalar miter_limit_ = 4.0; - SkPaint::Style style_ = SkPaint::Style::kFill_Style; + int style_flag_ = kIsFilledGeometry; bool join_is_miter_ = true; bool cap_is_square_ = false; sk_sp image_filter_; @@ -550,14 +604,14 @@ class DisplayListBoundsCalculator final bool paint_nops_on_transparency(); static bool ComputeFilteredBounds(SkRect& rect, SkImageFilter* filter); - bool AdjustBoundsForPaint(SkRect& bounds, DisplayListAttributeFlags flags); + bool AdjustBoundsForPaint(SkRect& bounds, int flags); void AccumulateUnbounded(); - void AccumulateRect(const SkRect& rect, DisplayListAttributeFlags flags) { + void AccumulateRect(const SkRect& rect, int flags) { SkRect bounds = rect; AccumulateRect(bounds, flags); } - void AccumulateRect(SkRect& rect, DisplayListAttributeFlags flags); + void AccumulateRect(SkRect& rect, int flags); }; } // namespace flutter diff --git a/lib/ui/painting/canvas.cc b/lib/ui/painting/canvas.cc index 6e31a060caaba..a6075d054d68e 100644 --- a/lib/ui/painting/canvas.cc +++ b/lib/ui/painting/canvas.cc @@ -82,15 +82,6 @@ fml::RefPtr Canvas::Create(PictureRecorder* recorder, ToDart("Canvas constructor called with non-genuine PictureRecorder.")); return nullptr; } - - // This call will implicitly initialize the |canvas_| field with an SkCanvas - // whether or not we are using display_list. Now that all of the code here - // in canvas.cc will direct calls to the DisplayListBuilder we could almost - // stop initializing that field for the display list case. Unfortunately, - // the text code in paragraph.cc still needs to present its output to an - // SkCanvas* which means without significant work to the internals of the - // paragraph code, we are going to continue to need the canvas adapter and - // field and getter. fml::RefPtr canvas = fml::MakeRefCounted( recorder->BeginRecording(SkRect::MakeLTRB(left, top, right, bottom))); recorder->set_canvas(canvas); @@ -103,27 +94,19 @@ Canvas::Canvas(SkCanvas* canvas) : canvas_(canvas) {} Canvas::~Canvas() {} void Canvas::save() { - if (display_list_recorder_) { - builder()->save(); - } else if (canvas_) { - canvas_->save(); + if (!canvas_) { + return; } + canvas_->save(); } void Canvas::saveLayerWithoutBounds(const Paint& paint, const PaintData& paint_data) { - FML_DCHECK(paint.isNotNull()); - if (display_list_recorder_) { - bool restore_with_paint = - paint.sync_to(builder(), kSaveLayerWithPaintFlags); - FML_DCHECK(restore_with_paint); - TRACE_EVENT0("flutter", "ui.Canvas::saveLayer (Recorded)"); - builder()->saveLayer(nullptr, restore_with_paint); - } else if (canvas_) { - SkPaint sk_paint; - TRACE_EVENT0("flutter", "ui.Canvas::saveLayer (Recorded)"); - canvas_->saveLayer(nullptr, paint.paint(sk_paint)); + if (!canvas_) { + return; } + TRACE_EVENT0("flutter", "ui.Canvas::saveLayer (Recorded)"); + canvas_->saveLayer(nullptr, paint.paint()); } void Canvas::saveLayer(double left, @@ -132,88 +115,64 @@ void Canvas::saveLayer(double left, double bottom, const Paint& paint, const PaintData& paint_data) { - FML_DCHECK(paint.isNotNull()); - SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom); - if (display_list_recorder_) { - bool restore_with_paint = - paint.sync_to(builder(), kSaveLayerWithPaintFlags); - FML_DCHECK(restore_with_paint); - TRACE_EVENT0("flutter", "ui.Canvas::saveLayer (Recorded)"); - builder()->saveLayer(&bounds, restore_with_paint); - } else if (canvas_) { - SkPaint sk_paint; - TRACE_EVENT0("flutter", "ui.Canvas::saveLayer (Recorded)"); - canvas_->saveLayer(&bounds, paint.paint(sk_paint)); + if (!canvas_) { + return; } + TRACE_EVENT0("flutter", "ui.Canvas::saveLayer (Recorded)"); + SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom); + canvas_->saveLayer(&bounds, paint.paint()); } void Canvas::restore() { - if (display_list_recorder_) { - builder()->restore(); - } else if (canvas_) { - canvas_->restore(); + if (!canvas_) { + return; } + canvas_->restore(); } int Canvas::getSaveCount() { - if (display_list_recorder_) { - return builder()->getSaveCount(); - } else if (canvas_) { - return canvas_->getSaveCount(); - } else { + if (!canvas_) { return 0; } + return canvas_->getSaveCount(); } void Canvas::translate(double dx, double dy) { - if (display_list_recorder_) { - builder()->translate(dx, dy); - } else if (canvas_) { - canvas_->translate(dx, dy); + if (!canvas_) { + return; } + canvas_->translate(dx, dy); } void Canvas::scale(double sx, double sy) { - if (display_list_recorder_) { - builder()->scale(sx, sy); - } else if (canvas_) { - canvas_->scale(sx, sy); + if (!canvas_) { + return; } + canvas_->scale(sx, sy); } void Canvas::rotate(double radians) { - if (display_list_recorder_) { - builder()->rotate(radians * 180.0 / M_PI); - } else if (canvas_) { - canvas_->rotate(radians * 180.0 / M_PI); + if (!canvas_) { + return; } + canvas_->rotate(radians * 180.0 / M_PI); } void Canvas::skew(double sx, double sy) { - if (display_list_recorder_) { - builder()->skew(sx, sy); - } else if (canvas_) { - canvas_->skew(sx, sy); + if (!canvas_) { + return; } + canvas_->skew(sx, sy); } void Canvas::transform(const tonic::Float64List& matrix4) { - // The Float array stored by Dart Matrix4 is in column-major order - // Both DisplayList and SkM44 constructor take row-major matrix order - if (display_list_recorder_) { - // clang-format off - builder()->transformFullPerspective( - matrix4[ 0], matrix4[ 4], matrix4[ 8], matrix4[12], - matrix4[ 1], matrix4[ 5], matrix4[ 9], matrix4[13], - matrix4[ 2], matrix4[ 6], matrix4[10], matrix4[14], - matrix4[ 3], matrix4[ 7], matrix4[11], matrix4[15]); - // clang-format on - } else if (canvas_) { - canvas_->concat(SkM44(matrix4[0], matrix4[4], matrix4[8], matrix4[12], - matrix4[1], matrix4[5], matrix4[9], matrix4[13], - matrix4[2], matrix4[6], matrix4[10], matrix4[14], - matrix4[3], matrix4[7], matrix4[11], matrix4[15])); + if (!canvas_) { + return; } + canvas_->concat(SkM44(matrix4[0], matrix4[4], matrix4[8], matrix4[12], + matrix4[1], matrix4[5], matrix4[9], matrix4[13], + matrix4[2], matrix4[6], matrix4[10], matrix4[14], + matrix4[3], matrix4[7], matrix4[11], matrix4[15])); } void Canvas::clipRect(double left, @@ -222,42 +181,37 @@ void Canvas::clipRect(double left, double bottom, SkClipOp clipOp, bool doAntiAlias) { - if (display_list_recorder_) { - builder()->clipRect(SkRect::MakeLTRB(left, top, right, bottom), clipOp, - doAntiAlias); - } else if (canvas_) { - canvas_->clipRect(SkRect::MakeLTRB(left, top, right, bottom), clipOp, - doAntiAlias); + if (!canvas_) { + return; } + canvas_->clipRect(SkRect::MakeLTRB(left, top, right, bottom), clipOp, + doAntiAlias); } void Canvas::clipRRect(const RRect& rrect, bool doAntiAlias) { - if (display_list_recorder_) { - builder()->clipRRect(rrect.sk_rrect, SkClipOp::kIntersect, doAntiAlias); - } else if (canvas_) { - canvas_->clipRRect(rrect.sk_rrect, doAntiAlias); + if (!canvas_) { + return; } + canvas_->clipRRect(rrect.sk_rrect, doAntiAlias); } void Canvas::clipPath(const CanvasPath* path, bool doAntiAlias) { + if (!canvas_) { + return; + } if (!path) { Dart_ThrowException( ToDart("Canvas.clipPath called with non-genuine Path.")); return; } - if (display_list_recorder_) { - builder()->clipPath(path->path(), SkClipOp::kIntersect, doAntiAlias); - } else if (canvas_) { - canvas_->clipPath(path->path(), doAntiAlias); - } + canvas_->clipPath(path->path(), doAntiAlias); } void Canvas::drawColor(SkColor color, SkBlendMode blend_mode) { - if (display_list_recorder_) { - builder()->drawColor(color, blend_mode); - } else if (canvas_) { - canvas_->drawColor(color, blend_mode); + if (!canvas_) { + return; } + canvas_->drawColor(color, blend_mode); } void Canvas::drawLine(double x1, @@ -266,38 +220,24 @@ void Canvas::drawLine(double x1, double y2, const Paint& paint, const PaintData& paint_data) { - FML_DCHECK(paint.isNotNull()); - if (display_list_recorder_) { - paint.sync_to(builder(), kDrawLineFlags); - builder()->drawLine(SkPoint::Make(x1, y1), SkPoint::Make(x2, y2)); - } else if (canvas_) { - SkPaint sk_paint; - canvas_->drawLine(x1, y1, x2, y2, *paint.paint(sk_paint)); + if (!canvas_) { + return; } + canvas_->drawLine(x1, y1, x2, y2, *paint.paint()); } void Canvas::drawPaint(const Paint& paint, const PaintData& paint_data) { - FML_DCHECK(paint.isNotNull()); - if (display_list_recorder_) { - paint.sync_to(builder(), kDrawPaintFlags); - sk_sp filter = builder()->getImageFilter(); - if (filter && !filter->asColorFilter(nullptr)) { - // drawPaint does an implicit saveLayer if an SkImageFilter is - // present that cannot be replaced by an SkColorFilter. - TRACE_EVENT0("flutter", "ui.Canvas::saveLayer (Recorded)"); - } - builder()->drawPaint(); - } else if (canvas_) { - SkPaint sk_paint; - paint.paint(sk_paint); - SkImageFilter* filter = sk_paint.getImageFilter(); - if (filter && !filter->asColorFilter(nullptr)) { - // drawPaint does an implicit saveLayer if an SkImageFilter is - // present that cannot be replaced by an SkColorFilter. - TRACE_EVENT0("flutter", "ui.Canvas::saveLayer (Recorded)"); - } - canvas_->drawPaint(sk_paint); + if (!canvas_) { + return; } + const SkPaint* sk_paint = paint.paint(); + SkImageFilter* filter = sk_paint->getImageFilter(); + if (filter && !filter->asColorFilter(nullptr)) { + // drawPaint does an implicit saveLayer if an SkImageFilter is + // present that cannot be replaced by an SkColorFilter. + TRACE_EVENT0("flutter", "ui.Canvas::saveLayer (Recorded)"); + } + canvas_->drawPaint(*paint.paint()); } void Canvas::drawRect(double left, @@ -306,42 +246,29 @@ void Canvas::drawRect(double left, double bottom, const Paint& paint, const PaintData& paint_data) { - FML_DCHECK(paint.isNotNull()); - if (display_list_recorder_) { - paint.sync_to(builder(), kDrawRectFlags); - builder()->drawRect(SkRect::MakeLTRB(left, top, right, bottom)); - } else if (canvas_) { - SkPaint sk_paint; - canvas_->drawRect(SkRect::MakeLTRB(left, top, right, bottom), - *paint.paint(sk_paint)); + if (!canvas_) { + return; } + canvas_->drawRect(SkRect::MakeLTRB(left, top, right, bottom), *paint.paint()); } void Canvas::drawRRect(const RRect& rrect, const Paint& paint, const PaintData& paint_data) { - FML_DCHECK(paint.isNotNull()); - if (display_list_recorder_) { - paint.sync_to(builder(), kDrawRRectFlags); - builder()->drawRRect(rrect.sk_rrect); - } else if (canvas_) { - SkPaint sk_paint; - canvas_->drawRRect(rrect.sk_rrect, *paint.paint(sk_paint)); + if (!canvas_) { + return; } + canvas_->drawRRect(rrect.sk_rrect, *paint.paint()); } void Canvas::drawDRRect(const RRect& outer, const RRect& inner, const Paint& paint, const PaintData& paint_data) { - FML_DCHECK(paint.isNotNull()); - if (display_list_recorder_) { - paint.sync_to(builder(), kDrawDRRectFlags); - builder()->drawDRRect(outer.sk_rrect, inner.sk_rrect); - } else if (canvas_) { - SkPaint sk_paint; - canvas_->drawDRRect(outer.sk_rrect, inner.sk_rrect, *paint.paint(sk_paint)); + if (!canvas_) { + return; } + canvas_->drawDRRect(outer.sk_rrect, inner.sk_rrect, *paint.paint()); } void Canvas::drawOval(double left, @@ -350,15 +277,10 @@ void Canvas::drawOval(double left, double bottom, const Paint& paint, const PaintData& paint_data) { - FML_DCHECK(paint.isNotNull()); - if (display_list_recorder_) { - paint.sync_to(builder(), kDrawOvalFlags); - builder()->drawOval(SkRect::MakeLTRB(left, top, right, bottom)); - } else if (canvas_) { - SkPaint sk_paint; - canvas_->drawOval(SkRect::MakeLTRB(left, top, right, bottom), - *paint.paint(sk_paint)); + if (!canvas_) { + return; } + canvas_->drawOval(SkRect::MakeLTRB(left, top, right, bottom), *paint.paint()); } void Canvas::drawCircle(double x, @@ -366,14 +288,10 @@ void Canvas::drawCircle(double x, double radius, const Paint& paint, const PaintData& paint_data) { - FML_DCHECK(paint.isNotNull()); - if (display_list_recorder_) { - paint.sync_to(builder(), kDrawCircleFlags); - builder()->drawCircle(SkPoint::Make(x, y), radius); - } else if (canvas_) { - SkPaint sk_paint; - canvas_->drawCircle(x, y, radius, *paint.paint(sk_paint)); + if (!canvas_) { + return; } + canvas_->drawCircle(x, y, radius, *paint.paint()); } void Canvas::drawArc(double left, @@ -385,39 +303,26 @@ void Canvas::drawArc(double left, bool useCenter, const Paint& paint, const PaintData& paint_data) { - FML_DCHECK(paint.isNotNull()); - if (display_list_recorder_) { - paint.sync_to(builder(), - useCenter // - ? kDrawArcWithCenterFlags - : kDrawArcNoCenterFlags); - builder()->drawArc(SkRect::MakeLTRB(left, top, right, bottom), - startAngle * 180.0 / M_PI, sweepAngle * 180.0 / M_PI, - useCenter); - } else if (canvas_) { - SkPaint sk_paint; - canvas_->drawArc(SkRect::MakeLTRB(left, top, right, bottom), - startAngle * 180.0 / M_PI, sweepAngle * 180.0 / M_PI, - useCenter, *paint.paint(sk_paint)); + if (!canvas_) { + return; } + canvas_->drawArc(SkRect::MakeLTRB(left, top, right, bottom), + startAngle * 180.0 / M_PI, sweepAngle * 180.0 / M_PI, + useCenter, *paint.paint()); } void Canvas::drawPath(const CanvasPath* path, const Paint& paint, const PaintData& paint_data) { - FML_DCHECK(paint.isNotNull()); + if (!canvas_) { + return; + } if (!path) { Dart_ThrowException( ToDart("Canvas.drawPath called with non-genuine Path.")); return; } - if (display_list_recorder_) { - paint.sync_to(builder(), kDrawPathFlags); - builder()->drawPath(path->path()); - } else if (canvas_) { - SkPaint sk_paint; - canvas_->drawPath(path->path(), *paint.paint(sk_paint)); - } + canvas_->drawPath(path->path(), *paint.paint()); } void Canvas::drawImage(const CanvasImage* image, @@ -426,21 +331,16 @@ void Canvas::drawImage(const CanvasImage* image, const Paint& paint, const PaintData& paint_data, int filterQualityIndex) { - FML_DCHECK(paint.isNotNull()); + if (!canvas_) { + return; + } if (!image) { Dart_ThrowException( ToDart("Canvas.drawImage called with non-genuine Image.")); return; } auto sampling = ImageFilter::SamplingFromIndex(filterQualityIndex); - if (display_list_recorder_) { - bool with_attributes = paint.sync_to(builder(), kDrawImageWithPaintFlags); - builder()->drawImage(image->image(), SkPoint::Make(x, y), sampling, - with_attributes); - } else if (canvas_) { - SkPaint sk_paint; - canvas_->drawImage(image->image(), x, y, sampling, paint.paint(sk_paint)); - } + canvas_->drawImage(image->image(), x, y, sampling, paint.paint()); } void Canvas::drawImageRect(const CanvasImage* image, @@ -455,7 +355,9 @@ void Canvas::drawImageRect(const CanvasImage* image, const Paint& paint, const PaintData& paint_data, int filterQualityIndex) { - FML_DCHECK(paint.isNotNull()); + if (!canvas_) { + return; + } if (!image) { Dart_ThrowException( ToDart("Canvas.drawImageRect called with non-genuine Image.")); @@ -464,18 +366,8 @@ void Canvas::drawImageRect(const CanvasImage* image, SkRect src = SkRect::MakeLTRB(src_left, src_top, src_right, src_bottom); SkRect dst = SkRect::MakeLTRB(dst_left, dst_top, dst_right, dst_bottom); auto sampling = ImageFilter::SamplingFromIndex(filterQualityIndex); - if (display_list_recorder_) { - bool with_attributes = - paint.sync_to(builder(), kDrawImageRectWithPaintFlags); - builder()->drawImageRect(image->image(), src, dst, sampling, - with_attributes, - SkCanvas::kFast_SrcRectConstraint); - } else if (canvas_) { - SkPaint sk_paint; - canvas_->drawImageRect(image->image(), src, dst, sampling, - paint.paint(sk_paint), - SkCanvas::kFast_SrcRectConstraint); - } + canvas_->drawImageRect(image->image(), src, dst, sampling, paint.paint(), + SkCanvas::kFast_SrcRectConstraint); } void Canvas::drawImageNine(const CanvasImage* image, @@ -490,7 +382,9 @@ void Canvas::drawImageNine(const CanvasImage* image, const Paint& paint, const PaintData& paint_data, int bitmapSamplingIndex) { - FML_DCHECK(paint.isNotNull()); + if (!canvas_) { + return; + } if (!image) { Dart_ThrowException( ToDart("Canvas.drawImageNine called with non-genuine Image.")); @@ -503,33 +397,35 @@ void Canvas::drawImageNine(const CanvasImage* image, SkRect dst = SkRect::MakeLTRB(dst_left, dst_top, dst_right, dst_bottom); auto filter = ImageFilter::FilterModeFromIndex(bitmapSamplingIndex); if (display_list_recorder_) { - bool with_attributes = - paint.sync_to(builder(), kDrawImageNineWithPaintFlags); - builder()->drawImageNine(image->image(), icenter, dst, filter, - with_attributes); - } else if (canvas_) { - SkPaint sk_paint; + // SkCanvas turns a simple 2-rect DrawImageNine operation into a + // drawImageLattice operation which has arrays to allocate and + // pass along. For simplicity, we will bypass the canvas and ask + // the recorder to record our paint attributes and record a much + // simpler DrawImageNineOp record directly. + display_list_recorder_->RecordPaintAttributes( + paint.paint(), DisplayListCanvasRecorder::DrawType::kImageOpType); + builder()->drawImageNine(image->image(), icenter, dst, filter, true); + } else { canvas_->drawImageNine(image->image().get(), icenter, dst, filter, - paint.paint(sk_paint)); + paint.paint()); } } void Canvas::drawPicture(Picture* picture) { + if (!canvas_) { + return; + } if (!picture) { Dart_ThrowException( ToDart("Canvas.drawPicture called with non-genuine Picture.")); return; } if (picture->picture()) { - if (display_list_recorder_) { - builder()->drawPicture(picture->picture(), nullptr, false); - } else if (canvas_) { - canvas_->drawPicture(picture->picture().get()); - } + canvas_->drawPicture(picture->picture().get()); } else if (picture->display_list()) { if (display_list_recorder_) { builder()->drawDisplayList(picture->display_list()); - } else if (canvas_) { + } else { picture->display_list()->RenderTo(canvas_); } } else { @@ -541,52 +437,32 @@ void Canvas::drawPoints(const Paint& paint, const PaintData& paint_data, SkCanvas::PointMode point_mode, const tonic::Float32List& points) { + if (!canvas_) { + return; + } + static_assert(sizeof(SkPoint) == sizeof(float) * 2, "SkPoint doesn't use floats."); - FML_DCHECK(paint.isNotNull()); - if (display_list_recorder_) { - switch (point_mode) { - case SkCanvas::kPoints_PointMode: - paint.sync_to(builder(), kDrawPointsAsPointsFlags); - break; - case SkCanvas::kLines_PointMode: - paint.sync_to(builder(), kDrawPointsAsLinesFlags); - break; - case SkCanvas::kPolygon_PointMode: - paint.sync_to(builder(), kDrawPointsAsPolygonFlags); - break; - } - builder()->drawPoints(point_mode, - points.num_elements() / 2, // SkPoints have 2 floats - reinterpret_cast(points.data())); - } else if (canvas_) { - SkPaint sk_paint; - canvas_->drawPoints(point_mode, - points.num_elements() / 2, // SkPoints have 2 floats - reinterpret_cast(points.data()), - *paint.paint(sk_paint)); - } + canvas_->drawPoints(point_mode, + points.num_elements() / 2, // SkPoints have two floats. + reinterpret_cast(points.data()), + *paint.paint()); } void Canvas::drawVertices(const Vertices* vertices, SkBlendMode blend_mode, const Paint& paint, const PaintData& paint_data) { + if (!canvas_) { + return; + } if (!vertices) { Dart_ThrowException( ToDart("Canvas.drawVertices called with non-genuine Vertices.")); return; } - FML_DCHECK(paint.isNotNull()); - if (display_list_recorder_) { - paint.sync_to(builder(), kDrawVerticesFlags); - builder()->drawVertices(vertices->vertices(), blend_mode); - } else if (canvas_) { - SkPaint sk_paint; - canvas_->drawVertices(vertices->vertices(), blend_mode, - *paint.paint(sk_paint)); - } + canvas_->drawVertices(vertices->vertices(), blend_mode, *paint.paint()); } void Canvas::drawAtlas(const Paint& paint, @@ -598,6 +474,9 @@ void Canvas::drawAtlas(const Paint& paint, const tonic::Int32List& colors, SkBlendMode blend_mode, const tonic::Float32List& cull_rect) { + if (!canvas_) { + return; + } if (!atlas) { Dart_ThrowException( ToDart("Canvas.drawAtlas or Canvas.drawRawAtlas called with " @@ -614,26 +493,13 @@ void Canvas::drawAtlas(const Paint& paint, auto sampling = ImageFilter::SamplingFromIndex(filterQualityIndex); - FML_DCHECK(paint.isNotNull()); - if (display_list_recorder_) { - bool with_attributes = paint.sync_to(builder(), kDrawAtlasWithPaintFlags); - builder()->drawAtlas( - skImage, reinterpret_cast(transforms.data()), - reinterpret_cast(rects.data()), - reinterpret_cast(colors.data()), - rects.num_elements() / 4, // SkRect have four floats. - blend_mode, sampling, reinterpret_cast(cull_rect.data()), - with_attributes); - } else if (canvas_) { - SkPaint sk_paint; - canvas_->drawAtlas( - skImage.get(), reinterpret_cast(transforms.data()), - reinterpret_cast(rects.data()), - reinterpret_cast(colors.data()), - rects.num_elements() / 4, // SkRect have four floats. - blend_mode, sampling, reinterpret_cast(cull_rect.data()), - paint.paint(sk_paint)); - } + canvas_->drawAtlas( + skImage.get(), reinterpret_cast(transforms.data()), + reinterpret_cast(rects.data()), + reinterpret_cast(colors.data()), + rects.num_elements() / 4, // SkRect have four floats. + blend_mode, sampling, reinterpret_cast(cull_rect.data()), + paint.paint()); } void Canvas::drawShadow(const CanvasPath* path, @@ -660,7 +526,7 @@ void Canvas::drawShadow(const CanvasPath* path, // See: https://bugs.chromium.org/p/skia/issues/detail?id=12125 builder()->drawShadow(path->path(), color, elevation, transparentOccluder, dpr); - } else if (canvas_) { + } else { flutter::PhysicalShapeLayer::DrawShadow( canvas_, path->path(), color, elevation, transparentOccluder, dpr); } @@ -668,7 +534,6 @@ void Canvas::drawShadow(const CanvasPath* path, void Canvas::Invalidate() { canvas_ = nullptr; - display_list_recorder_ = nullptr; if (dart_wrapper()) { ClearDartWrapper(); } diff --git a/lib/ui/painting/canvas.h b/lib/ui/painting/canvas.h index 8e8fd107f9377..ca328d310dbb6 100644 --- a/lib/ui/painting/canvas.h +++ b/lib/ui/painting/canvas.h @@ -23,7 +23,7 @@ class DartLibraryNatives; namespace flutter { class CanvasImage; -class Canvas : public RefCountedDartWrappable, DisplayListOpFlags { +class Canvas : public RefCountedDartWrappable { DEFINE_WRAPPERTYPEINFO(); FML_FRIEND_MAKE_REF_COUNTED(Canvas); @@ -188,8 +188,8 @@ class Canvas : public RefCountedDartWrappable, DisplayListOpFlags { // paint attributes from an SkPaint and an operation type as well as access // to the raw DisplayListBuilder for emitting custom rendering operations. sk_sp display_list_recorder_; - DisplayListBuilder* builder() { - return display_list_recorder_->builder().get(); + sk_sp builder() { + return display_list_recorder_->builder(); } }; diff --git a/lib/ui/painting/paint.cc b/lib/ui/painting/paint.cc index 25e3913cfc323..ee3c322418729 100644 --- a/lib/ui/painting/paint.cc +++ b/lib/ui/painting/paint.cc @@ -65,31 +65,28 @@ constexpr float invert_colors[20] = { // Must be kept in sync with the MaskFilter private constants in painting.dart. enum MaskFilterType { Null, Blur }; -Paint::Paint(Dart_Handle paint_objects, Dart_Handle paint_data) - : paint_objects_(paint_objects), paint_data_(paint_data) {} - -const SkPaint* Paint::paint(SkPaint& paint) const { - if (isNull()) { - return nullptr; +Paint::Paint(Dart_Handle paint_objects, Dart_Handle paint_data) { + is_null_ = Dart_IsNull(paint_data); + if (is_null_) { + return; } - FML_DCHECK(paint == SkPaint()); - tonic::DartByteData byte_data(paint_data_); + tonic::DartByteData byte_data(paint_data); FML_CHECK(byte_data.length_in_bytes() == kDataByteCount); const uint32_t* uint_data = static_cast(byte_data.data()); const float* float_data = static_cast(byte_data.data()); Dart_Handle values[kObjectCount]; - if (!Dart_IsNull(paint_objects_)) { - FML_DCHECK(Dart_IsList(paint_objects_)); + if (!Dart_IsNull(paint_objects)) { + FML_DCHECK(Dart_IsList(paint_objects)); intptr_t length = 0; - Dart_ListLength(paint_objects_, &length); + Dart_ListLength(paint_objects, &length); FML_CHECK(length == kObjectCount); if (Dart_IsError( - Dart_ListGetRange(paint_objects_, 0, kObjectCount, values))) { - return nullptr; + Dart_ListGetRange(paint_objects, 0, kObjectCount, values))) { + return; } Dart_Handle shader = values[kShaderIndex]; @@ -97,75 +94,75 @@ const SkPaint* Paint::paint(SkPaint& paint) const { Shader* decoded = tonic::DartConverter::FromDart(shader); auto sampling = ImageFilter::SamplingFromIndex(uint_data[kFilterQualityIndex]); - paint.setShader(decoded->shader(sampling)); + paint_.setShader(decoded->shader(sampling)); } Dart_Handle color_filter = values[kColorFilterIndex]; if (!Dart_IsNull(color_filter)) { ColorFilter* decoded_color_filter = tonic::DartConverter::FromDart(color_filter); - paint.setColorFilter(decoded_color_filter->filter()); + paint_.setColorFilter(decoded_color_filter->filter()); } Dart_Handle image_filter = values[kImageFilterIndex]; if (!Dart_IsNull(image_filter)) { ImageFilter* decoded = tonic::DartConverter::FromDart(image_filter); - paint.setImageFilter(decoded->filter()); + paint_.setImageFilter(decoded->filter()); } } - paint.setAntiAlias(uint_data[kIsAntiAliasIndex] == 0); + paint_.setAntiAlias(uint_data[kIsAntiAliasIndex] == 0); uint32_t encoded_color = uint_data[kColorIndex]; if (encoded_color) { SkColor color = encoded_color ^ kColorDefault; - paint.setColor(color); + paint_.setColor(color); } uint32_t encoded_blend_mode = uint_data[kBlendModeIndex]; if (encoded_blend_mode) { uint32_t blend_mode = encoded_blend_mode ^ kBlendModeDefault; - paint.setBlendMode(static_cast(blend_mode)); + paint_.setBlendMode(static_cast(blend_mode)); } uint32_t style = uint_data[kStyleIndex]; if (style) { - paint.setStyle(static_cast(style)); + paint_.setStyle(static_cast(style)); } float stroke_width = float_data[kStrokeWidthIndex]; if (stroke_width != 0.0) { - paint.setStrokeWidth(stroke_width); + paint_.setStrokeWidth(stroke_width); } uint32_t stroke_cap = uint_data[kStrokeCapIndex]; if (stroke_cap) { - paint.setStrokeCap(static_cast(stroke_cap)); + paint_.setStrokeCap(static_cast(stroke_cap)); } uint32_t stroke_join = uint_data[kStrokeJoinIndex]; if (stroke_join) { - paint.setStrokeJoin(static_cast(stroke_join)); + paint_.setStrokeJoin(static_cast(stroke_join)); } float stroke_miter_limit = float_data[kStrokeMiterLimitIndex]; if (stroke_miter_limit != 0.0) { - paint.setStrokeMiter(stroke_miter_limit + kStrokeMiterLimitDefault); + paint_.setStrokeMiter(stroke_miter_limit + kStrokeMiterLimitDefault); } if (uint_data[kInvertColorIndex]) { sk_sp invert_filter = ColorFilter::MakeColorMatrixFilter255(invert_colors); - sk_sp current_filter = paint.refColorFilter(); + sk_sp current_filter = paint_.refColorFilter(); if (current_filter) { invert_filter = invert_filter->makeComposed(current_filter); } - paint.setColorFilter(invert_filter); + paint_.setColorFilter(invert_filter); } if (uint_data[kDitherIndex]) { - paint.setDither(true); + paint_.setDither(true); } switch (uint_data[kMaskFilterIndex]) { @@ -175,138 +172,9 @@ const SkPaint* Paint::paint(SkPaint& paint) const { SkBlurStyle blur_style = static_cast(uint_data[kMaskFilterBlurStyleIndex]); double sigma = float_data[kMaskFilterSigmaIndex]; - paint.setMaskFilter(SkMaskFilter::MakeBlur(blur_style, sigma)); + paint_.setMaskFilter(SkMaskFilter::MakeBlur(blur_style, sigma)); break; } - - return &paint; -} - -bool Paint::sync_to(DisplayListBuilder* builder, - const DisplayListAttributeFlags& flags) const { - if (isNull()) { - return false; - } - tonic::DartByteData byte_data(paint_data_); - FML_CHECK(byte_data.length_in_bytes() == kDataByteCount); - - const uint32_t* uint_data = static_cast(byte_data.data()); - const float* float_data = static_cast(byte_data.data()); - - Dart_Handle values[kObjectCount]; - if (Dart_IsNull(paint_objects_)) { - if (flags.applies_shader()) { - builder->setShader(nullptr); - } - if (flags.applies_color_filter()) { - builder->setColorFilter(nullptr); - } - if (flags.applies_image_filter()) { - builder->setImageFilter(nullptr); - } - } else { - FML_DCHECK(Dart_IsList(paint_objects_)); - intptr_t length = 0; - Dart_ListLength(paint_objects_, &length); - - FML_CHECK(length == kObjectCount); - if (Dart_IsError( - Dart_ListGetRange(paint_objects_, 0, kObjectCount, values))) { - return false; - } - - if (flags.applies_shader()) { - Dart_Handle shader = values[kShaderIndex]; - if (Dart_IsNull(shader)) { - builder->setShader(nullptr); - } else { - Shader* decoded = tonic::DartConverter::FromDart(shader); - auto sampling = - ImageFilter::SamplingFromIndex(uint_data[kFilterQualityIndex]); - builder->setShader(decoded->shader(sampling)); - } - } - - if (flags.applies_color_filter()) { - Dart_Handle color_filter = values[kColorFilterIndex]; - if (Dart_IsNull(color_filter)) { - builder->setColorFilter(nullptr); - } else { - ColorFilter* decoded_color_filter = - tonic::DartConverter::FromDart(color_filter); - builder->setColorFilter(decoded_color_filter->filter()); - } - } - - if (flags.applies_image_filter()) { - Dart_Handle image_filter = values[kImageFilterIndex]; - if (Dart_IsNull(image_filter)) { - builder->setImageFilter(nullptr); - } else { - ImageFilter* decoded = - tonic::DartConverter::FromDart(image_filter); - builder->setImageFilter(decoded->filter()); - } - } - } - - if (flags.applies_anti_alias()) { - builder->setAntiAlias(uint_data[kIsAntiAliasIndex] == 0); - } - - if (flags.applies_alpha_or_color()) { - uint32_t encoded_color = uint_data[kColorIndex]; - builder->setColor(encoded_color ^ kColorDefault); - } - - if (flags.applies_blend()) { - uint32_t encoded_blend_mode = uint_data[kBlendModeIndex]; - uint32_t blend_mode = encoded_blend_mode ^ kBlendModeDefault; - builder->setBlendMode(static_cast(blend_mode)); - } - - if (flags.applies_style()) { - uint32_t style = uint_data[kStyleIndex]; - builder->setStyle(static_cast(style)); - } - - if (flags.is_stroked(builder->getStyle())) { - float stroke_width = float_data[kStrokeWidthIndex]; - builder->setStrokeWidth(stroke_width); - - float stroke_miter_limit = float_data[kStrokeMiterLimitIndex]; - builder->setStrokeMiter(stroke_miter_limit + kStrokeMiterLimitDefault); - - uint32_t stroke_cap = uint_data[kStrokeCapIndex]; - builder->setStrokeCap(static_cast(stroke_cap)); - - uint32_t stroke_join = uint_data[kStrokeJoinIndex]; - builder->setStrokeJoin(static_cast(stroke_join)); - } - - if (flags.applies_color_filter()) { - builder->setInvertColors(uint_data[kInvertColorIndex] != 0); - } - - if (flags.applies_dither()) { - builder->setDither(uint_data[kDitherIndex] != 0); - } - - if (flags.applies_mask_filter()) { - switch (uint_data[kMaskFilterIndex]) { - case Null: - builder->setMaskFilter(nullptr); - break; - case Blur: - SkBlurStyle blur_style = - static_cast(uint_data[kMaskFilterBlurStyleIndex]); - double sigma = float_data[kMaskFilterSigmaIndex]; - builder->setMaskBlurFilter(blur_style, sigma); - break; - } - } - - return true; } } // namespace flutter diff --git a/lib/ui/painting/paint.h b/lib/ui/painting/paint.h index 63943003ef28d..2c6eef8455af2 100644 --- a/lib/ui/painting/paint.h +++ b/lib/ui/painting/paint.h @@ -8,8 +8,6 @@ #include "third_party/skia/include/core/SkPaint.h" #include "third_party/tonic/converter/dart_converter.h" -#include "flow/display_list.h" - namespace flutter { class Paint { @@ -17,25 +15,13 @@ class Paint { Paint() = default; Paint(Dart_Handle paint_objects, Dart_Handle paint_data); - const SkPaint* paint(SkPaint& paint) const; - - /// Synchronize the Dart properties to the display list according - /// to the attribute flags that indicate which properties are needed. - /// The return value indicates if the paint was non-null and can - /// either be DCHECKed or used to indicate to the DisplayList - /// draw operation whether or not to use the synchronized attributes - /// (mainly the drawImage and saveLayer methods). - bool sync_to(DisplayListBuilder* builder, - const DisplayListAttributeFlags& flags) const; - - bool isNull() const { return Dart_IsNull(paint_data_); } - bool isNotNull() const { return !Dart_IsNull(paint_data_); } + const SkPaint* paint() const { return is_null_ ? nullptr : &paint_; } private: friend struct tonic::DartConverter; - Dart_Handle paint_objects_; - Dart_Handle paint_data_; + SkPaint paint_; + bool is_null_ = true; }; // The PaintData argument is a placeholder to receive encoded data for Paint diff --git a/lib/ui/text/paragraph_builder.cc b/lib/ui/text/paragraph_builder.cc index 793af6601c699..2ef379a2fe8c7 100644 --- a/lib/ui/text/paragraph_builder.cc +++ b/lib/ui/text/paragraph_builder.cc @@ -452,19 +452,17 @@ void ParagraphBuilder::pushStyle(tonic::Int32List& encoded, if (mask & tsBackgroundMask) { Paint background(background_objects, background_data); - if (background.isNotNull()) { - SkPaint sk_paint; + if (background.paint()) { style.has_background = true; - style.background = *background.paint(sk_paint); + style.background = *background.paint(); } } if (mask & tsForegroundMask) { Paint foreground(foreground_objects, foreground_data); - if (foreground.isNotNull()) { - SkPaint sk_paint; + if (foreground.paint()) { style.has_foreground = true; - style.foreground = *foreground.paint(sk_paint); + style.foreground = *foreground.paint(); } }