Revert "Build DisplayList directly from flutter::Canvas" (flutter/engine#29693)

This commit is contained in:
Jim Graham
2021-11-12 00:01:02 -08:00
committed by GitHub
parent e6db70c084
commit 8b0923d4a5
13 changed files with 2032 additions and 3637 deletions

View File

@@ -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<SetAntiAliasOp>(0, 0, current_anti_alias_ = aa);
void DisplayListBuilder::setAntiAlias(bool aa) {
Push<SetAntiAliasOp>(0, 0, aa);
}
void DisplayListBuilder::onSetDither(bool dither) {
Push<SetDitherOp>(0, 0, current_dither_ = dither);
void DisplayListBuilder::setDither(bool dither) {
Push<SetDitherOp>(0, 0, dither);
}
void DisplayListBuilder::onSetInvertColors(bool invert) {
Push<SetInvertColorsOp>(0, 0, current_invert_colors_ = invert);
void DisplayListBuilder::setInvertColors(bool invert) {
Push<SetInvertColorsOp>(0, 0, invert);
}
void DisplayListBuilder::onSetStrokeCap(SkPaint::Cap cap) {
Push<SetStrokeCapOp>(0, 0, current_stroke_cap_ = cap);
void DisplayListBuilder::setStrokeCap(SkPaint::Cap cap) {
Push<SetStrokeCapOp>(0, 0, cap);
}
void DisplayListBuilder::onSetStrokeJoin(SkPaint::Join join) {
Push<SetStrokeJoinOp>(0, 0, current_stroke_join_ = join);
void DisplayListBuilder::setStrokeJoin(SkPaint::Join join) {
Push<SetStrokeJoinOp>(0, 0, join);
}
void DisplayListBuilder::onSetStyle(SkPaint::Style style) {
Push<SetStyleOp>(0, 0, current_style_ = style);
void DisplayListBuilder::setStyle(SkPaint::Style style) {
Push<SetStyleOp>(0, 0, style);
}
void DisplayListBuilder::onSetStrokeWidth(SkScalar width) {
Push<SetStrokeWidthOp>(0, 0, current_stroke_width_ = width);
void DisplayListBuilder::setStrokeWidth(SkScalar width) {
Push<SetStrokeWidthOp>(0, 0, width);
}
void DisplayListBuilder::onSetStrokeMiter(SkScalar limit) {
Push<SetStrokeMiterOp>(0, 0, current_stroke_miter_ = limit);
void DisplayListBuilder::setStrokeMiter(SkScalar limit) {
Push<SetStrokeMiterOp>(0, 0, limit);
}
void DisplayListBuilder::onSetColor(SkColor color) {
Push<SetColorOp>(0, 0, current_color_ = color);
void DisplayListBuilder::setColor(SkColor color) {
Push<SetColorOp>(0, 0, color);
}
void DisplayListBuilder::onSetBlendMode(SkBlendMode mode) {
current_blender_ = nullptr;
Push<SetBlendModeOp>(0, 0, current_blend_mode_ = mode);
void DisplayListBuilder::setBlendMode(SkBlendMode mode) {
Push<SetBlendModeOp>(0, 0, mode);
}
void DisplayListBuilder::onSetBlender(sk_sp<SkBlender> 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<SetBlenderOp>(0, 0, std::move(blender))
: Push<ClearBlenderOp>(0, 0);
}
void DisplayListBuilder::setBlender(sk_sp<SkBlender> blender) {
blender //
? Push<SetBlenderOp>(0, 0, std::move(blender))
: Push<ClearBlenderOp>(0, 0);
}
void DisplayListBuilder::onSetShader(sk_sp<SkShader> shader) {
(current_shader_ = shader) //
void DisplayListBuilder::setShader(sk_sp<SkShader> shader) {
shader //
? Push<SetShaderOp>(0, 0, std::move(shader))
: Push<ClearShaderOp>(0, 0);
}
void DisplayListBuilder::onSetImageFilter(sk_sp<SkImageFilter> filter) {
(current_image_filter_ = filter) //
void DisplayListBuilder::setImageFilter(sk_sp<SkImageFilter> filter) {
filter //
? Push<SetImageFilterOp>(0, 0, std::move(filter))
: Push<ClearImageFilterOp>(0, 0);
}
void DisplayListBuilder::onSetColorFilter(sk_sp<SkColorFilter> filter) {
(current_color_filter_ = filter) //
void DisplayListBuilder::setColorFilter(sk_sp<SkColorFilter> filter) {
filter //
? Push<SetColorFilterOp>(0, 0, std::move(filter))
: Push<ClearColorFilterOp>(0, 0);
}
void DisplayListBuilder::onSetPathEffect(sk_sp<SkPathEffect> effect) {
(current_path_effect_ = effect) //
void DisplayListBuilder::setPathEffect(sk_sp<SkPathEffect> effect) {
effect //
? Push<SetPathEffectOp>(0, 0, std::move(effect))
: Push<ClearPathEffectOp>(0, 0);
}
void DisplayListBuilder::onSetMaskFilter(sk_sp<SkMaskFilter> filter) {
current_mask_sigma_ = kInvalidSigma;
current_mask_filter_ = filter;
void DisplayListBuilder::setMaskFilter(sk_sp<SkMaskFilter> filter) {
Push<SetMaskFilterOp>(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<SetMaskBlurFilterNormalOp>(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<SkBlendMode> 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<SaveOp>(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<SaveLayerBoundsOp>(0, 1, *bounds, restore_with_paint)
: Push<SaveLayerOp>(0, 1, restore_with_paint);
? Push<SaveLayerBoundsOp>(0, 1, *bounds, with_paint)
: Push<SaveLayerOp>(0, 1, with_paint);
}
void DisplayListBuilder::translate(SkScalar tx, SkScalar ty) {
if (SkScalarIsFinite(tx) && SkScalarIsFinite(ty) &&
(tx != 0.0 || ty != 0.0)) {
Push<TranslateOp>(0, 1, tx, ty);
}
Push<TranslateOp>(0, 1, tx, ty);
}
void DisplayListBuilder::scale(SkScalar sx, SkScalar sy) {
if (SkScalarIsFinite(sx) && SkScalarIsFinite(sy) &&
(sx != 1.0 || sy != 1.0)) {
Push<ScaleOp>(0, 1, sx, sy);
}
Push<ScaleOp>(0, 1, sx, sy);
}
void DisplayListBuilder::rotate(SkScalar degrees) {
if (SkScalarMod(degrees, 360.0) != 0.0) {
Push<RotateOp>(0, 1, degrees);
}
Push<RotateOp>(0, 1, degrees);
}
void DisplayListBuilder::skew(SkScalar sx, SkScalar sy) {
if (SkScalarIsFinite(sx) && SkScalarIsFinite(sy) &&
(sx != 0.0 || sy != 0.0)) {
Push<SkewOp>(0, 1, sx, sy);
}
Push<SkewOp>(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<Transform2DAffineOp>(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<TransformFullPerspectiveOp>(0, 1,
mxx, mxy, mxz, mxt,
myx, myy, myz, myt,
@@ -1452,7 +1368,7 @@ void DisplayListBuilder::drawImageLattice(const sk_sp<SkImage> 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<SkImage> image,
(xDivCount + yDivCount) * sizeof(int) +
cellCount * (sizeof(SkColor) + sizeof(SkCanvas::Lattice::RectType));
SkIRect src = lattice.fBounds ? *lattice.fBounds : image->bounds();
void* pod = this->Push<DrawImageLatticeOp>(
bytes, 1, std::move(image), xDivCount, yDivCount, cellCount, src, dst,
filter, render_with_attributes);
void* pod = this->Push<DrawImageLatticeOp>(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<DrawShadowOp>(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

View File

@@ -5,22 +5,17 @@
#ifndef FLUTTER_FLOW_DISPLAY_LIST_H_
#define FLUTTER_FLOW_DISPLAY_LIST_H_
#include <optional>
#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<SkPathEffect> 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<SkBlender> blender) override {
if (!blender) {
setBlendMode(SkBlendMode::kSrcOver);
} else if (current_blender_ != blender) {
onSetBlender(std::move(blender));
}
}
void setShader(sk_sp<SkShader> shader) override {
if (current_shader_ != shader) {
onSetShader(std::move(shader));
}
}
void setImageFilter(sk_sp<SkImageFilter> filter) override {
if (current_image_filter_ != filter) {
onSetImageFilter(std::move(filter));
}
}
void setColorFilter(sk_sp<SkColorFilter> filter) override {
if (current_color_filter_ != filter) {
onSetColorFilter(std::move(filter));
}
}
void setPathEffect(sk_sp<SkPathEffect> effect) override {
if (current_path_effect_ != effect) {
onSetPathEffect(std::move(effect));
}
}
void setMaskFilter(sk_sp<SkMaskFilter> 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<SkShader> getShader() const { return current_shader_; }
sk_sp<SkColorFilter> getColorFilter() const { return current_color_filter_; }
bool isInvertColors() const { return current_invert_colors_; }
std::optional<SkBlendMode> getBlendMode() const {
if (current_blender_) {
// The setters will turn "Mode" style blenders into "blend_mode"s
return {};
}
return current_blend_mode_;
}
sk_sp<SkBlender> getBlender() const {
return current_blender_ ? current_blender_
: SkBlender::Mode(current_blend_mode_);
}
sk_sp<SkPathEffect> getPathEffect() const { return current_path_effect_; }
sk_sp<SkMaskFilter> getMaskFilter() const { return current_mask_filter_; }
// No utility getter for the utility setter:
// void setMaskBlurFilter (SkBlurStyle style, SkScalar sigma)
sk_sp<SkImageFilter> 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<SkBlender> blender) override;
void setShader(sk_sp<SkShader> shader) override;
void setImageFilter(sk_sp<SkImageFilter> filter) override;
void setColorFilter(sk_sp<SkColorFilter> filter) override;
void setPathEffect(sk_sp<SkPathEffect> effect) override;
void setMaskFilter(sk_sp<SkMaskFilter> 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 <typename T, typename... Args>
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<SkBlender> blender);
void onSetShader(sk_sp<SkShader> shader);
void onSetImageFilter(sk_sp<SkImageFilter> filter);
void onSetColorFilter(sk_sp<SkColorFilter> filter);
void onSetPathEffect(sk_sp<SkPathEffect> effect);
void onSetMaskFilter(sk_sp<SkMaskFilter> 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<SkBlender> current_blender_;
sk_sp<SkShader> current_shader_;
sk_sp<SkColorFilter> current_color_filter_;
sk_sp<SkImageFilter> current_image_filter_;
sk_sp<SkPathEffect> current_path_effect_;
sk_sp<SkMaskFilter> current_mask_filter_;
int current_mask_style_;
SkScalar current_mask_sigma_ = kInvalidSigma;
};
} // namespace flutter

View File

@@ -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<SkBlendMode> 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

View File

@@ -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<SkNoDrawCanvas>,
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<DisplayListBuilder> 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<SkBlender> current_blender_;
sk_sp<SkShader> current_shader_;
sk_sp<SkColorFilter> current_color_filter_;
sk_sp<SkImageFilter> current_image_filter_;
sk_sp<SkPathEffect> current_path_effect_;
sk_sp<SkMaskFilter> current_mask_filter_;
};
} // namespace flutter

File diff suppressed because it is too large Load Diff

View File

@@ -272,99 +272,97 @@ struct DisplayListInvocationGroup {
std::vector<DisplayListInvocationGroup> 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<DisplayListInvocationGroup> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> Build(size_t g_index, size_t v_index) {
DisplayListBuilder builder;
int op_count = 0;
@@ -902,7 +872,7 @@ static sk_sp<DisplayList> 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<DisplayList> 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<DisplayList> 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<DisplayList> 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<SkImageFilter> 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<SkColorFilter> 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<SkMaskFilter> 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<SkBlender> 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<SkShader> 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<SkPathEffect> 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<DisplayList> display_list = builder.Build();
sk_sp<SkSurface> 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<DisplayList> display_list = builder.Build();
sk_sp<SkSurface> 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

View File

@@ -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<SkVertices> vertices,
SkBlendMode mode) {
AccumulateRect(vertices->bounds(), kDrawVerticesFlags);
AccumulateRect(vertices->bounds(), kIsNonGeometric);
}
void DisplayListBoundsCalculator::drawImage(const sk_sp<SkImage> image,
const SkPoint point,
@@ -403,9 +397,8 @@ void DisplayListBoundsCalculator::drawImage(const sk_sp<SkImage> 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<SkImage> image,
@@ -425,10 +417,7 @@ void DisplayListBoundsCalculator::drawImageNine(const sk_sp<SkImage> 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<SkImage> 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<SkImage> atlas,
@@ -460,9 +448,7 @@ void DisplayListBoundsCalculator::drawAtlas(const sk_sp<SkImage> 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<SkPicture> 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<DisplayList> display_list) {
AccumulateRect(display_list->bounds(), kDrawDisplayListFlags);
AccumulateRect(display_list->bounds(), kIsUnfiltered);
}
void DisplayListBoundsCalculator::drawTextBlob(const sk_sp<SkTextBlob> 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()) {
// 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;
}
bounds = p.computeFastBounds(bounds, &bounds);
if ((flags & kIsAnyGeometryMask) != 0) {
if ((flags & kIsDrawnGeometry) != 0) {
FML_DCHECK((flags & (kIsFilledGeometry | kIsStrokedGeometry)) == 0);
flags |= style_flag_;
}
if (flags.is_stroked(style_)) {
// Path effect occurs before stroking...
if (path_effect_) {
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);
}
}
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())) {

View File

@@ -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<std::unique_ptr<LayerData>> 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<SkBlendMode> 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<SkImageFilter> 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

View File

@@ -82,15 +82,6 @@ fml::RefPtr<Canvas> 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> canvas = fml::MakeRefCounted<Canvas>(
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<SkImageFilter> 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<const SkPoint*>(points.data()));
} else if (canvas_) {
SkPaint sk_paint;
canvas_->drawPoints(point_mode,
points.num_elements() / 2, // SkPoints have 2 floats
reinterpret_cast<const SkPoint*>(points.data()),
*paint.paint(sk_paint));
}
canvas_->drawPoints(point_mode,
points.num_elements() / 2, // SkPoints have two floats.
reinterpret_cast<const SkPoint*>(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<const SkRSXform*>(transforms.data()),
reinterpret_cast<const SkRect*>(rects.data()),
reinterpret_cast<const SkColor*>(colors.data()),
rects.num_elements() / 4, // SkRect have four floats.
blend_mode, sampling, reinterpret_cast<const SkRect*>(cull_rect.data()),
with_attributes);
} else if (canvas_) {
SkPaint sk_paint;
canvas_->drawAtlas(
skImage.get(), reinterpret_cast<const SkRSXform*>(transforms.data()),
reinterpret_cast<const SkRect*>(rects.data()),
reinterpret_cast<const SkColor*>(colors.data()),
rects.num_elements() / 4, // SkRect have four floats.
blend_mode, sampling, reinterpret_cast<const SkRect*>(cull_rect.data()),
paint.paint(sk_paint));
}
canvas_->drawAtlas(
skImage.get(), reinterpret_cast<const SkRSXform*>(transforms.data()),
reinterpret_cast<const SkRect*>(rects.data()),
reinterpret_cast<const SkColor*>(colors.data()),
rects.num_elements() / 4, // SkRect have four floats.
blend_mode, sampling, reinterpret_cast<const SkRect*>(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();
}

View File

@@ -23,7 +23,7 @@ class DartLibraryNatives;
namespace flutter {
class CanvasImage;
class Canvas : public RefCountedDartWrappable<Canvas>, DisplayListOpFlags {
class Canvas : public RefCountedDartWrappable<Canvas> {
DEFINE_WRAPPERTYPEINFO();
FML_FRIEND_MAKE_REF_COUNTED(Canvas);
@@ -188,8 +188,8 @@ class Canvas : public RefCountedDartWrappable<Canvas>, 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<DisplayListCanvasRecorder> display_list_recorder_;
DisplayListBuilder* builder() {
return display_list_recorder_->builder().get();
sk_sp<DisplayListBuilder> builder() {
return display_list_recorder_->builder();
}
};

View File

@@ -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<const uint32_t*>(byte_data.data());
const float* float_data = static_cast<const float*>(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<Shader*>::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<ColorFilter*>::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<ImageFilter*>::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<SkBlendMode>(blend_mode));
paint_.setBlendMode(static_cast<SkBlendMode>(blend_mode));
}
uint32_t style = uint_data[kStyleIndex];
if (style) {
paint.setStyle(static_cast<SkPaint::Style>(style));
paint_.setStyle(static_cast<SkPaint::Style>(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<SkPaint::Cap>(stroke_cap));
paint_.setStrokeCap(static_cast<SkPaint::Cap>(stroke_cap));
}
uint32_t stroke_join = uint_data[kStrokeJoinIndex];
if (stroke_join) {
paint.setStrokeJoin(static_cast<SkPaint::Join>(stroke_join));
paint_.setStrokeJoin(static_cast<SkPaint::Join>(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<SkColorFilter> invert_filter =
ColorFilter::MakeColorMatrixFilter255(invert_colors);
sk_sp<SkColorFilter> current_filter = paint.refColorFilter();
sk_sp<SkColorFilter> 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<SkBlurStyle>(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<const uint32_t*>(byte_data.data());
const float* float_data = static_cast<const float*>(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<Shader*>::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<ColorFilter*>::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<ImageFilter*>::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<SkBlendMode>(blend_mode));
}
if (flags.applies_style()) {
uint32_t style = uint_data[kStyleIndex];
builder->setStyle(static_cast<SkPaint::Style>(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<SkPaint::Cap>(stroke_cap));
uint32_t stroke_join = uint_data[kStrokeJoinIndex];
builder->setStrokeJoin(static_cast<SkPaint::Join>(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<SkBlurStyle>(uint_data[kMaskFilterBlurStyleIndex]);
double sigma = float_data[kMaskFilterSigmaIndex];
builder->setMaskBlurFilter(blur_style, sigma);
break;
}
}
return true;
}
} // namespace flutter

View File

@@ -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<Paint>;
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

View File

@@ -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();
}
}