Build DisplayList directly from flutter::Canvas (flutter/engine#29470)
This commit is contained in:
@@ -7,10 +7,7 @@
|
||||
#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"
|
||||
@@ -1085,65 +1082,84 @@ DisplayListBuilder::~DisplayListBuilder() {
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayListBuilder::setAntiAlias(bool aa) {
|
||||
Push<SetAntiAliasOp>(0, 0, aa);
|
||||
void DisplayListBuilder::onSetAntiAlias(bool aa) {
|
||||
Push<SetAntiAliasOp>(0, 0, current_anti_alias_ = aa);
|
||||
}
|
||||
void DisplayListBuilder::setDither(bool dither) {
|
||||
Push<SetDitherOp>(0, 0, dither);
|
||||
void DisplayListBuilder::onSetDither(bool dither) {
|
||||
Push<SetDitherOp>(0, 0, current_dither_ = dither);
|
||||
}
|
||||
void DisplayListBuilder::setInvertColors(bool invert) {
|
||||
Push<SetInvertColorsOp>(0, 0, invert);
|
||||
void DisplayListBuilder::onSetInvertColors(bool invert) {
|
||||
Push<SetInvertColorsOp>(0, 0, current_invert_colors_ = invert);
|
||||
}
|
||||
void DisplayListBuilder::setStrokeCap(SkPaint::Cap cap) {
|
||||
Push<SetStrokeCapOp>(0, 0, cap);
|
||||
void DisplayListBuilder::onSetStrokeCap(SkPaint::Cap cap) {
|
||||
Push<SetStrokeCapOp>(0, 0, current_stroke_cap_ = cap);
|
||||
}
|
||||
void DisplayListBuilder::setStrokeJoin(SkPaint::Join join) {
|
||||
Push<SetStrokeJoinOp>(0, 0, join);
|
||||
void DisplayListBuilder::onSetStrokeJoin(SkPaint::Join join) {
|
||||
Push<SetStrokeJoinOp>(0, 0, current_stroke_join_ = join);
|
||||
}
|
||||
void DisplayListBuilder::setStyle(SkPaint::Style style) {
|
||||
Push<SetStyleOp>(0, 0, style);
|
||||
void DisplayListBuilder::onSetStyle(SkPaint::Style style) {
|
||||
Push<SetStyleOp>(0, 0, current_style_ = style);
|
||||
}
|
||||
void DisplayListBuilder::setStrokeWidth(SkScalar width) {
|
||||
Push<SetStrokeWidthOp>(0, 0, width);
|
||||
void DisplayListBuilder::onSetStrokeWidth(SkScalar width) {
|
||||
Push<SetStrokeWidthOp>(0, 0, current_stroke_width_ = width);
|
||||
}
|
||||
void DisplayListBuilder::setStrokeMiter(SkScalar limit) {
|
||||
Push<SetStrokeMiterOp>(0, 0, limit);
|
||||
void DisplayListBuilder::onSetStrokeMiter(SkScalar limit) {
|
||||
Push<SetStrokeMiterOp>(0, 0, current_stroke_miter_ = limit);
|
||||
}
|
||||
void DisplayListBuilder::setColor(SkColor color) {
|
||||
Push<SetColorOp>(0, 0, color);
|
||||
void DisplayListBuilder::onSetColor(SkColor color) {
|
||||
Push<SetColorOp>(0, 0, current_color_ = color);
|
||||
}
|
||||
void DisplayListBuilder::setBlendMode(SkBlendMode mode) {
|
||||
Push<SetBlendModeOp>(0, 0, mode);
|
||||
void DisplayListBuilder::onSetBlendMode(SkBlendMode mode) {
|
||||
current_blender_ = nullptr;
|
||||
Push<SetBlendModeOp>(0, 0, current_blend_mode_ = mode);
|
||||
}
|
||||
void DisplayListBuilder::setBlender(sk_sp<SkBlender> blender) {
|
||||
blender //
|
||||
? Push<SetBlenderOp>(0, 0, std::move(blender))
|
||||
: Push<ClearBlenderOp>(0, 0);
|
||||
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::setShader(sk_sp<SkShader> shader) {
|
||||
shader //
|
||||
void DisplayListBuilder::onSetShader(sk_sp<SkShader> shader) {
|
||||
(current_shader_ = shader) //
|
||||
? Push<SetShaderOp>(0, 0, std::move(shader))
|
||||
: Push<ClearShaderOp>(0, 0);
|
||||
}
|
||||
void DisplayListBuilder::setImageFilter(sk_sp<SkImageFilter> filter) {
|
||||
filter //
|
||||
void DisplayListBuilder::onSetImageFilter(sk_sp<SkImageFilter> filter) {
|
||||
(current_image_filter_ = filter) //
|
||||
? Push<SetImageFilterOp>(0, 0, std::move(filter))
|
||||
: Push<ClearImageFilterOp>(0, 0);
|
||||
}
|
||||
void DisplayListBuilder::setColorFilter(sk_sp<SkColorFilter> filter) {
|
||||
filter //
|
||||
void DisplayListBuilder::onSetColorFilter(sk_sp<SkColorFilter> filter) {
|
||||
(current_color_filter_ = filter) //
|
||||
? Push<SetColorFilterOp>(0, 0, std::move(filter))
|
||||
: Push<ClearColorFilterOp>(0, 0);
|
||||
}
|
||||
void DisplayListBuilder::setPathEffect(sk_sp<SkPathEffect> effect) {
|
||||
effect //
|
||||
void DisplayListBuilder::onSetPathEffect(sk_sp<SkPathEffect> effect) {
|
||||
(current_path_effect_ = effect) //
|
||||
? Push<SetPathEffectOp>(0, 0, std::move(effect))
|
||||
: Push<ClearPathEffectOp>(0, 0);
|
||||
}
|
||||
void DisplayListBuilder::setMaskFilter(sk_sp<SkMaskFilter> filter) {
|
||||
void DisplayListBuilder::onSetMaskFilter(sk_sp<SkMaskFilter> filter) {
|
||||
current_mask_sigma_ = kInvalidSigma;
|
||||
current_mask_filter_ = filter;
|
||||
Push<SetMaskFilterOp>(0, 0, std::move(filter));
|
||||
}
|
||||
void DisplayListBuilder::setMaskBlurFilter(SkBlurStyle style, SkScalar sigma) {
|
||||
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;
|
||||
switch (style) {
|
||||
case kNormal_SkBlurStyle:
|
||||
Push<SetMaskBlurFilterNormalOp>(0, 0, sigma);
|
||||
@@ -1160,6 +1176,56 @@ void DisplayListBuilder::setMaskBlurFilter(SkBlurStyle style, SkScalar sigma) {
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -1170,24 +1236,36 @@ void DisplayListBuilder::restore() {
|
||||
save_level_--;
|
||||
}
|
||||
}
|
||||
void DisplayListBuilder::saveLayer(const SkRect* bounds, bool with_paint) {
|
||||
void DisplayListBuilder::saveLayer(const SkRect* bounds,
|
||||
bool restore_with_paint) {
|
||||
save_level_++;
|
||||
bounds //
|
||||
? Push<SaveLayerBoundsOp>(0, 1, *bounds, with_paint)
|
||||
: Push<SaveLayerOp>(0, 1, with_paint);
|
||||
? Push<SaveLayerBoundsOp>(0, 1, *bounds, restore_with_paint)
|
||||
: Push<SaveLayerOp>(0, 1, restore_with_paint);
|
||||
}
|
||||
|
||||
void DisplayListBuilder::translate(SkScalar tx, SkScalar ty) {
|
||||
Push<TranslateOp>(0, 1, tx, ty);
|
||||
if (SkScalarIsFinite(tx) && SkScalarIsFinite(ty) &&
|
||||
(tx != 0.0 || ty != 0.0)) {
|
||||
Push<TranslateOp>(0, 1, tx, ty);
|
||||
}
|
||||
}
|
||||
void DisplayListBuilder::scale(SkScalar sx, SkScalar sy) {
|
||||
Push<ScaleOp>(0, 1, sx, sy);
|
||||
if (SkScalarIsFinite(sx) && SkScalarIsFinite(sy) &&
|
||||
(sx != 1.0 || sy != 1.0)) {
|
||||
Push<ScaleOp>(0, 1, sx, sy);
|
||||
}
|
||||
}
|
||||
void DisplayListBuilder::rotate(SkScalar degrees) {
|
||||
Push<RotateOp>(0, 1, degrees);
|
||||
if (SkScalarMod(degrees, 360.0) != 0.0) {
|
||||
Push<RotateOp>(0, 1, degrees);
|
||||
}
|
||||
}
|
||||
void DisplayListBuilder::skew(SkScalar sx, SkScalar sy) {
|
||||
Push<SkewOp>(0, 1, sx, sy);
|
||||
if (SkScalarIsFinite(sx) && SkScalarIsFinite(sy) &&
|
||||
(sx != 0.0 || sy != 0.0)) {
|
||||
Push<SkewOp>(0, 1, sx, sy);
|
||||
}
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
@@ -1196,7 +1274,10 @@ void DisplayListBuilder::skew(SkScalar sx, SkScalar sy) {
|
||||
void DisplayListBuilder::transform2DAffine(
|
||||
SkScalar mxx, SkScalar mxy, SkScalar mxt,
|
||||
SkScalar myx, SkScalar myy, SkScalar myt) {
|
||||
if (!(mxx == 1 && mxy == 0 && mxt == 0 &&
|
||||
if (SkScalarsAreFinite(mxx, myx) &&
|
||||
SkScalarsAreFinite(mxy, myy) &&
|
||||
SkScalarsAreFinite(mxt, myt) &&
|
||||
!(mxx == 1 && mxy == 0 && mxt == 0 &&
|
||||
myx == 0 && myy == 1 && myt == 0)) {
|
||||
Push<Transform2DAffineOp>(0, 1,
|
||||
mxx, mxy, mxt,
|
||||
@@ -1215,7 +1296,10 @@ void DisplayListBuilder::transformFullPerspective(
|
||||
mwx == 0 && mwy == 0 && mwz == 0 && mwt == 1) {
|
||||
transform2DAffine(mxx, mxy, mxt,
|
||||
myx, myy, myt);
|
||||
} else {
|
||||
} 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)) {
|
||||
Push<TransformFullPerspectiveOp>(0, 1,
|
||||
mxx, mxy, mxz, mxt,
|
||||
myx, myy, myz, myt,
|
||||
@@ -1368,7 +1452,7 @@ void DisplayListBuilder::drawImageLattice(const sk_sp<SkImage> image,
|
||||
const SkCanvas::Lattice& lattice,
|
||||
const SkRect& dst,
|
||||
SkFilterMode filter,
|
||||
bool with_paint) {
|
||||
bool render_with_attributes) {
|
||||
int xDivCount = lattice.fXCount;
|
||||
int yDivCount = lattice.fYCount;
|
||||
FML_DCHECK((lattice.fRectTypes == nullptr) || (lattice.fColors != nullptr));
|
||||
@@ -1379,9 +1463,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, with_paint);
|
||||
void* pod = this->Push<DrawImageLatticeOp>(
|
||||
bytes, 1, std::move(image), xDivCount, yDivCount, cellCount, src, dst,
|
||||
filter, render_with_attributes);
|
||||
CopyV(pod, lattice.fXDivs, xDivCount, lattice.fYDivs, yDivCount,
|
||||
lattice.fColors, cellCount, lattice.fRectTypes, cellCount);
|
||||
}
|
||||
@@ -1463,4 +1547,165 @@ 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
|
||||
|
||||
@@ -5,17 +5,22 @@
|
||||
#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.
|
||||
//
|
||||
@@ -463,6 +468,278 @@ 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,
|
||||
@@ -473,33 +750,137 @@ class DisplayListBuilder final : public virtual Dispatcher, public SkRefCnt {
|
||||
DisplayListBuilder(const SkRect& cull_rect = kMaxCullRect_);
|
||||
~DisplayListBuilder();
|
||||
|
||||
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 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 save() override;
|
||||
void saveLayer(const SkRect* bounds, bool restoreWithPaint) override;
|
||||
void saveLayer(const SkRect* bounds, bool restore_with_paint) 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
|
||||
@@ -514,9 +895,9 @@ class DisplayListBuilder final : public virtual Dispatcher, public SkRefCnt {
|
||||
|
||||
// clang-format on
|
||||
|
||||
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 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 drawPaint() override;
|
||||
void drawColor(SkColor color, SkBlendMode mode) override;
|
||||
@@ -599,6 +980,51 @@ 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
|
||||
|
||||
@@ -261,7 +261,7 @@ void DisplayListCanvasRecorder::willSave() {
|
||||
SkCanvas::SaveLayerStrategy DisplayListCanvasRecorder::getSaveLayerStrategy(
|
||||
const SaveLayerRec& rec) {
|
||||
if (rec.fPaint) {
|
||||
RecordPaintAttributes(rec.fPaint, DrawType::kSaveLayerOpType);
|
||||
builder_->setAttributesFromPaint(*rec.fPaint, kSaveLayerWithPaintFlags);
|
||||
builder_->saveLayer(rec.fBounds, true);
|
||||
} else {
|
||||
builder_->saveLayer(rec.fBounds, false);
|
||||
@@ -273,28 +273,28 @@ void DisplayListCanvasRecorder::didRestore() {
|
||||
}
|
||||
|
||||
void DisplayListCanvasRecorder::onDrawPaint(const SkPaint& paint) {
|
||||
RecordPaintAttributes(&paint, DrawType::kFillOpType);
|
||||
builder_->setAttributesFromPaint(paint, kDrawPaintFlags);
|
||||
builder_->drawPaint();
|
||||
}
|
||||
void DisplayListCanvasRecorder::onDrawRect(const SkRect& rect,
|
||||
const SkPaint& paint) {
|
||||
RecordPaintAttributes(&paint, DrawType::kDrawOpType);
|
||||
builder_->setAttributesFromPaint(paint, kDrawRectFlags);
|
||||
builder_->drawRect(rect);
|
||||
}
|
||||
void DisplayListCanvasRecorder::onDrawRRect(const SkRRect& rrect,
|
||||
const SkPaint& paint) {
|
||||
RecordPaintAttributes(&paint, DrawType::kDrawOpType);
|
||||
builder_->setAttributesFromPaint(paint, kDrawRRectFlags);
|
||||
builder_->drawRRect(rrect);
|
||||
}
|
||||
void DisplayListCanvasRecorder::onDrawDRRect(const SkRRect& outer,
|
||||
const SkRRect& inner,
|
||||
const SkPaint& paint) {
|
||||
RecordPaintAttributes(&paint, DrawType::kDrawOpType);
|
||||
builder_->setAttributesFromPaint(paint, kDrawDRRectFlags);
|
||||
builder_->drawDRRect(outer, inner);
|
||||
}
|
||||
void DisplayListCanvasRecorder::onDrawOval(const SkRect& rect,
|
||||
const SkPaint& paint) {
|
||||
RecordPaintAttributes(&paint, DrawType::kDrawOpType);
|
||||
builder_->setAttributesFromPaint(paint, kDrawOvalFlags);
|
||||
builder_->drawOval(rect);
|
||||
}
|
||||
void DisplayListCanvasRecorder::onDrawArc(const SkRect& rect,
|
||||
@@ -302,12 +302,15 @@ void DisplayListCanvasRecorder::onDrawArc(const SkRect& rect,
|
||||
SkScalar sweepAngle,
|
||||
bool useCenter,
|
||||
const SkPaint& paint) {
|
||||
RecordPaintAttributes(&paint, DrawType::kDrawOpType);
|
||||
builder_->setAttributesFromPaint(paint,
|
||||
useCenter //
|
||||
? kDrawArcWithCenterFlags
|
||||
: kDrawArcNoCenterFlags);
|
||||
builder_->drawArc(rect, startAngle, sweepAngle, useCenter);
|
||||
}
|
||||
void DisplayListCanvasRecorder::onDrawPath(const SkPath& path,
|
||||
const SkPaint& paint) {
|
||||
RecordPaintAttributes(&paint, DrawType::kDrawOpType);
|
||||
builder_->setAttributesFromPaint(paint, kDrawPathFlags);
|
||||
builder_->drawPath(path);
|
||||
}
|
||||
|
||||
@@ -315,7 +318,17 @@ void DisplayListCanvasRecorder::onDrawPoints(SkCanvas::PointMode mode,
|
||||
size_t count,
|
||||
const SkPoint pts[],
|
||||
const SkPaint& paint) {
|
||||
RecordPaintAttributes(&paint, DrawType::kStrokeOpType);
|
||||
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;
|
||||
}
|
||||
if (mode == SkCanvas::PointMode::kLines_PointMode && count == 2) {
|
||||
builder_->drawLine(pts[0], pts[1]);
|
||||
} else {
|
||||
@@ -330,7 +343,7 @@ void DisplayListCanvasRecorder::onDrawPoints(SkCanvas::PointMode mode,
|
||||
void DisplayListCanvasRecorder::onDrawVerticesObject(const SkVertices* vertices,
|
||||
SkBlendMode mode,
|
||||
const SkPaint& paint) {
|
||||
RecordPaintAttributes(&paint, DrawType::kDrawOpType);
|
||||
builder_->setAttributesFromPaint(paint, kDrawVerticesFlags);
|
||||
builder_->drawVertices(sk_ref_sp(vertices), mode);
|
||||
}
|
||||
|
||||
@@ -340,7 +353,7 @@ void DisplayListCanvasRecorder::onDrawImage2(const SkImage* image,
|
||||
const SkSamplingOptions& sampling,
|
||||
const SkPaint* paint) {
|
||||
if (paint != nullptr) {
|
||||
RecordPaintAttributes(paint, DrawType::kImageOpType);
|
||||
builder_->setAttributesFromPaint(*paint, kDrawImageWithPaintFlags);
|
||||
}
|
||||
builder_->drawImage(sk_ref_sp(image), SkPoint::Make(dx, dy), sampling,
|
||||
paint != nullptr);
|
||||
@@ -353,7 +366,7 @@ void DisplayListCanvasRecorder::onDrawImageRect2(
|
||||
const SkPaint* paint,
|
||||
SrcRectConstraint constraint) {
|
||||
if (paint != nullptr) {
|
||||
RecordPaintAttributes(paint, DrawType::kImageRectOpType);
|
||||
builder_->setAttributesFromPaint(*paint, kDrawImageRectWithPaintFlags);
|
||||
}
|
||||
builder_->drawImageRect(sk_ref_sp(image), src, dst, sampling,
|
||||
paint != nullptr, constraint);
|
||||
@@ -370,7 +383,7 @@ void DisplayListCanvasRecorder::onDrawImageLattice2(const SkImage* image,
|
||||
if (*paint == default_paint) {
|
||||
paint = nullptr;
|
||||
} else {
|
||||
RecordPaintAttributes(paint, DrawType::kImageOpType);
|
||||
builder_->setAttributesFromPaint(*paint, kDrawImageLatticeWithPaintFlags);
|
||||
}
|
||||
}
|
||||
builder_->drawImageLattice(sk_ref_sp(image), lattice, dst, filter,
|
||||
@@ -386,7 +399,7 @@ void DisplayListCanvasRecorder::onDrawAtlas2(const SkImage* image,
|
||||
const SkRect* cull,
|
||||
const SkPaint* paint) {
|
||||
if (paint != nullptr) {
|
||||
RecordPaintAttributes(paint, DrawType::kImageOpType);
|
||||
builder_->setAttributesFromPaint(*paint, kDrawAtlasWithPaintFlags);
|
||||
}
|
||||
builder_->drawAtlas(sk_ref_sp(image), xform, src, colors, count, mode,
|
||||
sampling, cull, paint != nullptr);
|
||||
@@ -396,7 +409,7 @@ void DisplayListCanvasRecorder::onDrawTextBlob(const SkTextBlob* blob,
|
||||
SkScalar x,
|
||||
SkScalar y,
|
||||
const SkPaint& paint) {
|
||||
RecordPaintAttributes(&paint, DrawType::kDrawOpType);
|
||||
builder_->setAttributesFromPaint(paint, kDrawTextBlobFlags);
|
||||
builder_->drawTextBlob(sk_ref_sp(blob), x, y);
|
||||
}
|
||||
void DisplayListCanvasRecorder::onDrawShadowRec(const SkPath& path,
|
||||
@@ -411,119 +424,9 @@ void DisplayListCanvasRecorder::onDrawPicture(const SkPicture* picture,
|
||||
const SkMatrix* matrix,
|
||||
const SkPaint* paint) {
|
||||
if (paint != nullptr) {
|
||||
RecordPaintAttributes(paint, DrawType::kSaveLayerOpType);
|
||||
builder_->setAttributesFromPaint(*paint, kDrawPictureWithPaintFlags);
|
||||
}
|
||||
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
|
||||
|
||||
@@ -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 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 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 drawPaint() override;
|
||||
void drawColor(SkColor color, SkBlendMode mode) override;
|
||||
@@ -120,7 +120,8 @@ class DisplayListCanvasDispatcher : public virtual Dispatcher,
|
||||
// Receives all methods on SkCanvas and sends them to a DisplayListBuilder
|
||||
class DisplayListCanvasRecorder
|
||||
: public SkCanvasVirtualEnforcer<SkNoDrawCanvas>,
|
||||
public SkRefCnt {
|
||||
public SkRefCnt,
|
||||
DisplayListOpFlags {
|
||||
public:
|
||||
DisplayListCanvasRecorder(const SkRect& bounds);
|
||||
|
||||
@@ -233,80 +234,8 @@ 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
@@ -272,97 +272,99 @@ 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, 8, 0, 0, [](DisplayListBuilder& b) {b.setStrokeJoin(SkPaint::kMiter_Join);}},
|
||||
{0, 0, 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(0.0);}},
|
||||
{0, 8, 0, 0, [](DisplayListBuilder& b) {b.setStrokeWidth(1.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);}},
|
||||
}
|
||||
},
|
||||
{ "SetBlendMode", {
|
||||
{ "SetBlendModeOrBlender", {
|
||||
{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", {
|
||||
@@ -376,33 +378,34 @@ 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", {
|
||||
@@ -833,7 +836,9 @@ 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) {
|
||||
if (i == j ||
|
||||
(group.variants[i].is_empty() && group.variants[j].is_empty())) {
|
||||
// They are the same variant, or both variants are NOPs
|
||||
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;
|
||||
@@ -852,6 +857,31 @@ 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;
|
||||
@@ -872,7 +902,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 < 0) {
|
||||
if (v_index >= allGroups[g_index].variants.size()) {
|
||||
name += " skipped";
|
||||
} else {
|
||||
name += " variant " + std::to_string(v_index + 1);
|
||||
@@ -889,12 +919,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 " + std::to_string(gi + 1) + " omitted]";
|
||||
auto desc = "[Group " + group.op_name + " 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 " + std::to_string(gi + 1) + " variant " +
|
||||
auto desc = "[Group " + group.op_name + " variant " +
|
||||
std::to_string(vi + 1) + "]";
|
||||
sk_sp<DisplayList> variant_dl = Build(gi, vi);
|
||||
ASSERT_TRUE(variant_dl->Equals(*variant_dl)) << desc << " == itself";
|
||||
@@ -1117,5 +1147,230 @@ 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
|
||||
|
||||
@@ -234,8 +234,7 @@ void DisplayListBoundsCalculator::setStrokeJoin(SkPaint::Join join) {
|
||||
join_is_miter_ = (join == SkPaint::kMiter_Join);
|
||||
}
|
||||
void DisplayListBoundsCalculator::setStyle(SkPaint::Style style) {
|
||||
style_flag_ = (style == SkPaint::kFill_Style) ? kIsFilledGeometry //
|
||||
: kIsStrokedGeometry;
|
||||
style_ = style;
|
||||
}
|
||||
void DisplayListBoundsCalculator::setStrokeWidth(SkScalar width) {
|
||||
half_stroke_width_ = std::max(width * 0.5f, kMinStrokeWidth);
|
||||
@@ -290,7 +289,9 @@ 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();
|
||||
ClipBoundsDispatchHelper::reset(bounds);
|
||||
if (bounds) {
|
||||
clipRect(*bounds, SkClipOp::kIntersect, false);
|
||||
}
|
||||
}
|
||||
void DisplayListBoundsCalculator::restore() {
|
||||
if (layer_infos_.size() > 1) {
|
||||
@@ -310,7 +311,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, kIsUnfiltered);
|
||||
AccumulateRect(layer_bounds, kSaveLayerFlags);
|
||||
}
|
||||
if (layer_unbounded) {
|
||||
AccumulateUnbounded();
|
||||
@@ -327,39 +328,35 @@ 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();
|
||||
int cap_flag = kIsStrokedGeometry;
|
||||
if (bounds.width() > 0.0f && bounds.height() > 0.0f) {
|
||||
cap_flag |= kGeometryMayHaveDiagonalEndCaps;
|
||||
}
|
||||
AccumulateRect(bounds, cap_flag);
|
||||
DisplayListAttributeFlags flags =
|
||||
(bounds.width() > 0.0f && bounds.height() > 0.0f) ? kDrawLineFlags
|
||||
: kDrawHVLineFlags;
|
||||
AccumulateRect(bounds, flags);
|
||||
}
|
||||
void DisplayListBoundsCalculator::drawRect(const SkRect& rect) {
|
||||
AccumulateRect(rect, kIsDrawnGeometry);
|
||||
AccumulateRect(rect, kDrawRectFlags);
|
||||
}
|
||||
void DisplayListBoundsCalculator::drawOval(const SkRect& bounds) {
|
||||
AccumulateRect(bounds, kIsDrawnGeometry);
|
||||
AccumulateRect(bounds, kDrawOvalFlags);
|
||||
}
|
||||
void DisplayListBoundsCalculator::drawCircle(const SkPoint& center,
|
||||
SkScalar radius) {
|
||||
AccumulateRect(SkRect::MakeLTRB(center.fX - radius, center.fY - radius,
|
||||
center.fX + radius, center.fY + radius),
|
||||
kIsDrawnGeometry);
|
||||
kDrawCircleFlags);
|
||||
}
|
||||
void DisplayListBoundsCalculator::drawRRect(const SkRRect& rrect) {
|
||||
AccumulateRect(rrect.getBounds(), kIsDrawnGeometry);
|
||||
AccumulateRect(rrect.getBounds(), kDrawRRectFlags);
|
||||
}
|
||||
void DisplayListBoundsCalculator::drawDRRect(const SkRRect& outer,
|
||||
const SkRRect& inner) {
|
||||
AccumulateRect(outer.getBounds(), kIsDrawnGeometry);
|
||||
AccumulateRect(outer.getBounds(), kDrawDRRectFlags);
|
||||
}
|
||||
void DisplayListBoundsCalculator::drawPath(const SkPath& path) {
|
||||
if (path.isInverseFillType()) {
|
||||
AccumulateUnbounded();
|
||||
} else {
|
||||
AccumulateRect(path.getBounds(), //
|
||||
(kIsDrawnGeometry | //
|
||||
kGeometryMayHaveDiagonalEndCaps | //
|
||||
kGeometryMayHaveProblematicJoins));
|
||||
AccumulateRect(path.getBounds(), kDrawPathFlags);
|
||||
}
|
||||
}
|
||||
void DisplayListBoundsCalculator::drawArc(const SkRect& bounds,
|
||||
@@ -369,7 +366,10 @@ 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, kIsDrawnGeometry | kGeometryMayHaveDiagonalEndCaps);
|
||||
AccumulateRect(bounds,
|
||||
useCenter //
|
||||
? kDrawArcWithCenterFlags
|
||||
: kDrawArcNoCenterFlags);
|
||||
}
|
||||
void DisplayListBoundsCalculator::drawPoints(SkCanvas::PointMode mode,
|
||||
uint32_t count,
|
||||
@@ -379,17 +379,23 @@ void DisplayListBoundsCalculator::drawPoints(SkCanvas::PointMode mode,
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
ptBounds.accumulate(pts[i]);
|
||||
}
|
||||
int flags = kIsStrokedGeometry;
|
||||
if (mode != SkCanvas::kPoints_PointMode) {
|
||||
flags |= kGeometryMayHaveDiagonalEndCaps;
|
||||
// Even Polygon mode just draws (count-1) separate lines, no joins
|
||||
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;
|
||||
}
|
||||
AccumulateRect(ptBounds.bounds(), flags);
|
||||
}
|
||||
}
|
||||
void DisplayListBoundsCalculator::drawVertices(const sk_sp<SkVertices> vertices,
|
||||
SkBlendMode mode) {
|
||||
AccumulateRect(vertices->bounds(), kIsNonGeometric);
|
||||
AccumulateRect(vertices->bounds(), kDrawVerticesFlags);
|
||||
}
|
||||
void DisplayListBoundsCalculator::drawImage(const sk_sp<SkImage> image,
|
||||
const SkPoint point,
|
||||
@@ -397,8 +403,9 @@ void DisplayListBoundsCalculator::drawImage(const sk_sp<SkImage> image,
|
||||
bool render_with_attributes) {
|
||||
SkRect bounds = SkRect::MakeXYWH(point.fX, point.fY, //
|
||||
image->width(), image->height());
|
||||
int flags = render_with_attributes ? kIsNonGeometric | kApplyMaskFilter
|
||||
: kIsUnfiltered;
|
||||
DisplayListAttributeFlags flags = render_with_attributes //
|
||||
? kDrawImageWithPaintFlags
|
||||
: kDrawImageFlags;
|
||||
AccumulateRect(bounds, flags);
|
||||
}
|
||||
void DisplayListBoundsCalculator::drawImageRect(
|
||||
@@ -408,8 +415,9 @@ void DisplayListBoundsCalculator::drawImageRect(
|
||||
const SkSamplingOptions& sampling,
|
||||
bool render_with_attributes,
|
||||
SkCanvas::SrcRectConstraint constraint) {
|
||||
int flags = render_with_attributes ? kIsNonGeometric | kApplyMaskFilter
|
||||
: kIsUnfiltered;
|
||||
DisplayListAttributeFlags flags = render_with_attributes
|
||||
? kDrawImageRectWithPaintFlags
|
||||
: kDrawImageRectFlags;
|
||||
AccumulateRect(dst, flags);
|
||||
}
|
||||
void DisplayListBoundsCalculator::drawImageNine(const sk_sp<SkImage> image,
|
||||
@@ -417,7 +425,10 @@ void DisplayListBoundsCalculator::drawImageNine(const sk_sp<SkImage> image,
|
||||
const SkRect& dst,
|
||||
SkFilterMode filter,
|
||||
bool render_with_attributes) {
|
||||
AccumulateRect(dst, render_with_attributes ? kIsNonGeometric : kIsUnfiltered);
|
||||
DisplayListAttributeFlags flags = render_with_attributes
|
||||
? kDrawImageNineWithPaintFlags
|
||||
: kDrawImageNineFlags;
|
||||
AccumulateRect(dst, flags);
|
||||
}
|
||||
void DisplayListBoundsCalculator::drawImageLattice(
|
||||
const sk_sp<SkImage> image,
|
||||
@@ -425,8 +436,9 @@ void DisplayListBoundsCalculator::drawImageLattice(
|
||||
const SkRect& dst,
|
||||
SkFilterMode filter,
|
||||
bool render_with_attributes) {
|
||||
int flags = render_with_attributes ? kIsNonGeometric | kApplyMaskFilter
|
||||
: kIsUnfiltered;
|
||||
DisplayListAttributeFlags flags = render_with_attributes
|
||||
? kDrawImageLatticeWithPaintFlags
|
||||
: kDrawImageLatticeFlags;
|
||||
AccumulateRect(dst, flags);
|
||||
}
|
||||
void DisplayListBoundsCalculator::drawAtlas(const sk_sp<SkImage> atlas,
|
||||
@@ -448,7 +460,9 @@ void DisplayListBoundsCalculator::drawAtlas(const sk_sp<SkImage> atlas,
|
||||
}
|
||||
}
|
||||
if (atlasBounds.is_not_empty()) {
|
||||
int flags = render_with_attributes ? kIsNonGeometric : kIsUnfiltered;
|
||||
DisplayListAttributeFlags flags = render_with_attributes //
|
||||
? kDrawAtlasWithPaintFlags
|
||||
: kDrawAtlasFlags;
|
||||
AccumulateRect(atlasBounds.bounds(), flags);
|
||||
}
|
||||
}
|
||||
@@ -462,17 +476,19 @@ void DisplayListBoundsCalculator::drawPicture(const sk_sp<SkPicture> picture,
|
||||
if (pic_matrix) {
|
||||
pic_matrix->mapRect(&bounds);
|
||||
}
|
||||
AccumulateRect(bounds,
|
||||
render_with_attributes ? kIsNonGeometric : kIsUnfiltered);
|
||||
DisplayListAttributeFlags flags = render_with_attributes //
|
||||
? kDrawPictureWithPaintFlags
|
||||
: kDrawPictureFlags;
|
||||
AccumulateRect(bounds, flags);
|
||||
}
|
||||
void DisplayListBoundsCalculator::drawDisplayList(
|
||||
const sk_sp<DisplayList> display_list) {
|
||||
AccumulateRect(display_list->bounds(), kIsUnfiltered);
|
||||
AccumulateRect(display_list->bounds(), kDrawDisplayListFlags);
|
||||
}
|
||||
void DisplayListBoundsCalculator::drawTextBlob(const sk_sp<SkTextBlob> blob,
|
||||
SkScalar x,
|
||||
SkScalar y) {
|
||||
AccumulateRect(blob->bounds().makeOffset(x, y), kIsFilledGeometry);
|
||||
AccumulateRect(blob->bounds().makeOffset(x, y), kDrawTextBlobFlags);
|
||||
}
|
||||
void DisplayListBoundsCalculator::drawShadow(const SkPath& path,
|
||||
const SkColor color,
|
||||
@@ -481,7 +497,7 @@ void DisplayListBoundsCalculator::drawShadow(const SkPath& path,
|
||||
SkScalar dpr) {
|
||||
SkRect shadow_bounds =
|
||||
PhysicalShapeLayer::ComputeShadowBounds(path, elevation, dpr, matrix());
|
||||
AccumulateRect(shadow_bounds, kIsUnfiltered);
|
||||
AccumulateRect(shadow_bounds, kDrawShadowFlags);
|
||||
}
|
||||
|
||||
bool DisplayListBoundsCalculator::ComputeFilteredBounds(SkRect& bounds,
|
||||
@@ -495,64 +511,41 @@ bool DisplayListBoundsCalculator::ComputeFilteredBounds(SkRect& bounds,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DisplayListBoundsCalculator::AdjustBoundsForPaint(SkRect& bounds,
|
||||
int flags) {
|
||||
if ((flags & kIsUnfiltered) != 0) {
|
||||
FML_DCHECK(flags == kIsUnfiltered);
|
||||
bool DisplayListBoundsCalculator::AdjustBoundsForPaint(
|
||||
SkRect& bounds,
|
||||
DisplayListAttributeFlags flags) {
|
||||
if (flags.ignores_paint()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((flags & kIsAnyGeometryMask) != 0) {
|
||||
if ((flags & kIsDrawnGeometry) != 0) {
|
||||
FML_DCHECK((flags & (kIsFilledGeometry | kIsStrokedGeometry)) == 0);
|
||||
flags |= style_flag_;
|
||||
}
|
||||
|
||||
if (flags.is_geometric()) {
|
||||
// Path effect occurs before stroking...
|
||||
DisplayListSpecialGeometryFlags special_flags =
|
||||
flags.WithPathEffect(path_effect_);
|
||||
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);
|
||||
SkPaint p;
|
||||
p.setPathEffect(path_effect_);
|
||||
if (!p.canComputeFastBounds()) {
|
||||
return false;
|
||||
}
|
||||
bounds = p.computeFastBounds(bounds, &bounds);
|
||||
}
|
||||
|
||||
if ((flags & kIsStrokedGeometry) != 0) {
|
||||
FML_DCHECK((flags & kIsFilledGeometry) == 0);
|
||||
if (flags.is_stroked(style_)) {
|
||||
// Determine the max multiplier to the stroke width first.
|
||||
SkScalar pad = 1.0f;
|
||||
if (join_is_miter_ && (flags & kGeometryMayHaveProblematicJoins) != 0) {
|
||||
if (join_is_miter_ && special_flags.may_have_acute_joins()) {
|
||||
pad = std::max(pad, miter_limit_);
|
||||
}
|
||||
if (cap_is_square_ && (flags & kGeometryMayHaveDiagonalEndCaps) != 0) {
|
||||
if (cap_is_square_ && special_flags.may_have_diagonal_caps()) {
|
||||
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 & kApplyMaskFilter) != 0) {
|
||||
if (flags.applies_mask_filter()) {
|
||||
if (mask_filter_) {
|
||||
SkPaint p;
|
||||
p.setMaskFilter(mask_filter_);
|
||||
@@ -566,7 +559,11 @@ bool DisplayListBoundsCalculator::AdjustBoundsForPaint(SkRect& bounds,
|
||||
}
|
||||
}
|
||||
|
||||
return ComputeFilteredBounds(bounds, image_filter_.get());
|
||||
if (flags.applies_image_filter()) {
|
||||
return ComputeFilteredBounds(bounds, image_filter_.get());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DisplayListBoundsCalculator::AccumulateUnbounded() {
|
||||
@@ -576,7 +573,9 @@ void DisplayListBoundsCalculator::AccumulateUnbounded() {
|
||||
layer_infos_.back()->set_unbounded();
|
||||
}
|
||||
}
|
||||
void DisplayListBoundsCalculator::AccumulateRect(SkRect& rect, int flags) {
|
||||
void DisplayListBoundsCalculator::AccumulateRect(
|
||||
SkRect& rect,
|
||||
DisplayListAttributeFlags flags) {
|
||||
if (AdjustBoundsForPaint(rect, flags)) {
|
||||
matrix().mapRect(&rect);
|
||||
if (!has_clip() || rect.intersect(clip_bounds())) {
|
||||
|
||||
@@ -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 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 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 {}
|
||||
};
|
||||
|
||||
// A utility class that will ignore all Dispatcher methods relating
|
||||
@@ -267,7 +267,8 @@ class DisplayListBoundsCalculator final
|
||||
: public virtual Dispatcher,
|
||||
public virtual IgnoreAttributeDispatchHelper,
|
||||
public virtual SkMatrixDispatchHelper,
|
||||
public virtual ClipBoundsDispatchHelper {
|
||||
public virtual ClipBoundsDispatchHelper,
|
||||
DisplayListOpFlags {
|
||||
public:
|
||||
// Construct a Calculator to determine the bounds of a list of
|
||||
// DisplayList dispatcher method calls. Since 2 of the method calls
|
||||
@@ -531,61 +532,6 @@ 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;
|
||||
@@ -593,7 +539,7 @@ class DisplayListBoundsCalculator final
|
||||
|
||||
SkScalar half_stroke_width_ = kMinStrokeWidth;
|
||||
SkScalar miter_limit_ = 4.0;
|
||||
int style_flag_ = kIsFilledGeometry;
|
||||
SkPaint::Style style_ = SkPaint::Style::kFill_Style;
|
||||
bool join_is_miter_ = true;
|
||||
bool cap_is_square_ = false;
|
||||
sk_sp<SkImageFilter> image_filter_;
|
||||
@@ -604,14 +550,14 @@ class DisplayListBoundsCalculator final
|
||||
bool paint_nops_on_transparency();
|
||||
|
||||
static bool ComputeFilteredBounds(SkRect& rect, SkImageFilter* filter);
|
||||
bool AdjustBoundsForPaint(SkRect& bounds, int flags);
|
||||
bool AdjustBoundsForPaint(SkRect& bounds, DisplayListAttributeFlags flags);
|
||||
|
||||
void AccumulateUnbounded();
|
||||
void AccumulateRect(const SkRect& rect, int flags) {
|
||||
void AccumulateRect(const SkRect& rect, DisplayListAttributeFlags flags) {
|
||||
SkRect bounds = rect;
|
||||
AccumulateRect(bounds, flags);
|
||||
}
|
||||
void AccumulateRect(SkRect& rect, int flags);
|
||||
void AccumulateRect(SkRect& rect, DisplayListAttributeFlags flags);
|
||||
};
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
@@ -82,6 +82,15 @@ 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);
|
||||
@@ -94,19 +103,27 @@ Canvas::Canvas(SkCanvas* canvas) : canvas_(canvas) {}
|
||||
Canvas::~Canvas() {}
|
||||
|
||||
void Canvas::save() {
|
||||
if (!canvas_) {
|
||||
return;
|
||||
if (display_list_recorder_) {
|
||||
builder()->save();
|
||||
} else if (canvas_) {
|
||||
canvas_->save();
|
||||
}
|
||||
canvas_->save();
|
||||
}
|
||||
|
||||
void Canvas::saveLayerWithoutBounds(const Paint& paint,
|
||||
const PaintData& paint_data) {
|
||||
if (!canvas_) {
|
||||
return;
|
||||
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));
|
||||
}
|
||||
TRACE_EVENT0("flutter", "ui.Canvas::saveLayer (Recorded)");
|
||||
canvas_->saveLayer(nullptr, paint.paint());
|
||||
}
|
||||
|
||||
void Canvas::saveLayer(double left,
|
||||
@@ -115,64 +132,88 @@ void Canvas::saveLayer(double left,
|
||||
double bottom,
|
||||
const Paint& paint,
|
||||
const PaintData& paint_data) {
|
||||
if (!canvas_) {
|
||||
return;
|
||||
}
|
||||
TRACE_EVENT0("flutter", "ui.Canvas::saveLayer (Recorded)");
|
||||
FML_DCHECK(paint.isNotNull());
|
||||
SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom);
|
||||
canvas_->saveLayer(&bounds, paint.paint());
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
void Canvas::restore() {
|
||||
if (!canvas_) {
|
||||
return;
|
||||
if (display_list_recorder_) {
|
||||
builder()->restore();
|
||||
} else if (canvas_) {
|
||||
canvas_->restore();
|
||||
}
|
||||
canvas_->restore();
|
||||
}
|
||||
|
||||
int Canvas::getSaveCount() {
|
||||
if (!canvas_) {
|
||||
if (display_list_recorder_) {
|
||||
return builder()->getSaveCount();
|
||||
} else if (canvas_) {
|
||||
return canvas_->getSaveCount();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return canvas_->getSaveCount();
|
||||
}
|
||||
|
||||
void Canvas::translate(double dx, double dy) {
|
||||
if (!canvas_) {
|
||||
return;
|
||||
if (display_list_recorder_) {
|
||||
builder()->translate(dx, dy);
|
||||
} else if (canvas_) {
|
||||
canvas_->translate(dx, dy);
|
||||
}
|
||||
canvas_->translate(dx, dy);
|
||||
}
|
||||
|
||||
void Canvas::scale(double sx, double sy) {
|
||||
if (!canvas_) {
|
||||
return;
|
||||
if (display_list_recorder_) {
|
||||
builder()->scale(sx, sy);
|
||||
} else if (canvas_) {
|
||||
canvas_->scale(sx, sy);
|
||||
}
|
||||
canvas_->scale(sx, sy);
|
||||
}
|
||||
|
||||
void Canvas::rotate(double radians) {
|
||||
if (!canvas_) {
|
||||
return;
|
||||
if (display_list_recorder_) {
|
||||
builder()->rotate(radians * 180.0 / M_PI);
|
||||
} else if (canvas_) {
|
||||
canvas_->rotate(radians * 180.0 / M_PI);
|
||||
}
|
||||
canvas_->rotate(radians * 180.0 / M_PI);
|
||||
}
|
||||
|
||||
void Canvas::skew(double sx, double sy) {
|
||||
if (!canvas_) {
|
||||
return;
|
||||
if (display_list_recorder_) {
|
||||
builder()->skew(sx, sy);
|
||||
} else if (canvas_) {
|
||||
canvas_->skew(sx, sy);
|
||||
}
|
||||
canvas_->skew(sx, sy);
|
||||
}
|
||||
|
||||
void Canvas::transform(const tonic::Float64List& matrix4) {
|
||||
if (!canvas_) {
|
||||
return;
|
||||
// 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]));
|
||||
}
|
||||
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,
|
||||
@@ -181,37 +222,42 @@ void Canvas::clipRect(double left,
|
||||
double bottom,
|
||||
SkClipOp clipOp,
|
||||
bool doAntiAlias) {
|
||||
if (!canvas_) {
|
||||
return;
|
||||
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);
|
||||
}
|
||||
canvas_->clipRect(SkRect::MakeLTRB(left, top, right, bottom), clipOp,
|
||||
doAntiAlias);
|
||||
}
|
||||
|
||||
void Canvas::clipRRect(const RRect& rrect, bool doAntiAlias) {
|
||||
if (!canvas_) {
|
||||
return;
|
||||
if (display_list_recorder_) {
|
||||
builder()->clipRRect(rrect.sk_rrect, SkClipOp::kIntersect, doAntiAlias);
|
||||
} else if (canvas_) {
|
||||
canvas_->clipRRect(rrect.sk_rrect, doAntiAlias);
|
||||
}
|
||||
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;
|
||||
}
|
||||
canvas_->clipPath(path->path(), doAntiAlias);
|
||||
if (display_list_recorder_) {
|
||||
builder()->clipPath(path->path(), SkClipOp::kIntersect, doAntiAlias);
|
||||
} else if (canvas_) {
|
||||
canvas_->clipPath(path->path(), doAntiAlias);
|
||||
}
|
||||
}
|
||||
|
||||
void Canvas::drawColor(SkColor color, SkBlendMode blend_mode) {
|
||||
if (!canvas_) {
|
||||
return;
|
||||
if (display_list_recorder_) {
|
||||
builder()->drawColor(color, blend_mode);
|
||||
} else if (canvas_) {
|
||||
canvas_->drawColor(color, blend_mode);
|
||||
}
|
||||
canvas_->drawColor(color, blend_mode);
|
||||
}
|
||||
|
||||
void Canvas::drawLine(double x1,
|
||||
@@ -220,24 +266,38 @@ void Canvas::drawLine(double x1,
|
||||
double y2,
|
||||
const Paint& paint,
|
||||
const PaintData& paint_data) {
|
||||
if (!canvas_) {
|
||||
return;
|
||||
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));
|
||||
}
|
||||
canvas_->drawLine(x1, y1, x2, y2, *paint.paint());
|
||||
}
|
||||
|
||||
void Canvas::drawPaint(const Paint& paint, const PaintData& paint_data) {
|
||||
if (!canvas_) {
|
||||
return;
|
||||
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);
|
||||
}
|
||||
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,
|
||||
@@ -246,29 +306,42 @@ void Canvas::drawRect(double left,
|
||||
double bottom,
|
||||
const Paint& paint,
|
||||
const PaintData& paint_data) {
|
||||
if (!canvas_) {
|
||||
return;
|
||||
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));
|
||||
}
|
||||
canvas_->drawRect(SkRect::MakeLTRB(left, top, right, bottom), *paint.paint());
|
||||
}
|
||||
|
||||
void Canvas::drawRRect(const RRect& rrect,
|
||||
const Paint& paint,
|
||||
const PaintData& paint_data) {
|
||||
if (!canvas_) {
|
||||
return;
|
||||
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));
|
||||
}
|
||||
canvas_->drawRRect(rrect.sk_rrect, *paint.paint());
|
||||
}
|
||||
|
||||
void Canvas::drawDRRect(const RRect& outer,
|
||||
const RRect& inner,
|
||||
const Paint& paint,
|
||||
const PaintData& paint_data) {
|
||||
if (!canvas_) {
|
||||
return;
|
||||
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));
|
||||
}
|
||||
canvas_->drawDRRect(outer.sk_rrect, inner.sk_rrect, *paint.paint());
|
||||
}
|
||||
|
||||
void Canvas::drawOval(double left,
|
||||
@@ -277,10 +350,15 @@ void Canvas::drawOval(double left,
|
||||
double bottom,
|
||||
const Paint& paint,
|
||||
const PaintData& paint_data) {
|
||||
if (!canvas_) {
|
||||
return;
|
||||
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));
|
||||
}
|
||||
canvas_->drawOval(SkRect::MakeLTRB(left, top, right, bottom), *paint.paint());
|
||||
}
|
||||
|
||||
void Canvas::drawCircle(double x,
|
||||
@@ -288,10 +366,14 @@ void Canvas::drawCircle(double x,
|
||||
double radius,
|
||||
const Paint& paint,
|
||||
const PaintData& paint_data) {
|
||||
if (!canvas_) {
|
||||
return;
|
||||
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));
|
||||
}
|
||||
canvas_->drawCircle(x, y, radius, *paint.paint());
|
||||
}
|
||||
|
||||
void Canvas::drawArc(double left,
|
||||
@@ -303,26 +385,39 @@ void Canvas::drawArc(double left,
|
||||
bool useCenter,
|
||||
const Paint& paint,
|
||||
const PaintData& paint_data) {
|
||||
if (!canvas_) {
|
||||
return;
|
||||
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));
|
||||
}
|
||||
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) {
|
||||
if (!canvas_) {
|
||||
return;
|
||||
}
|
||||
FML_DCHECK(paint.isNotNull());
|
||||
if (!path) {
|
||||
Dart_ThrowException(
|
||||
ToDart("Canvas.drawPath called with non-genuine Path."));
|
||||
return;
|
||||
}
|
||||
canvas_->drawPath(path->path(), *paint.paint());
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
void Canvas::drawImage(const CanvasImage* image,
|
||||
@@ -331,16 +426,21 @@ void Canvas::drawImage(const CanvasImage* image,
|
||||
const Paint& paint,
|
||||
const PaintData& paint_data,
|
||||
int filterQualityIndex) {
|
||||
if (!canvas_) {
|
||||
return;
|
||||
}
|
||||
FML_DCHECK(paint.isNotNull());
|
||||
if (!image) {
|
||||
Dart_ThrowException(
|
||||
ToDart("Canvas.drawImage called with non-genuine Image."));
|
||||
return;
|
||||
}
|
||||
auto sampling = ImageFilter::SamplingFromIndex(filterQualityIndex);
|
||||
canvas_->drawImage(image->image(), x, y, sampling, paint.paint());
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
void Canvas::drawImageRect(const CanvasImage* image,
|
||||
@@ -355,9 +455,7 @@ void Canvas::drawImageRect(const CanvasImage* image,
|
||||
const Paint& paint,
|
||||
const PaintData& paint_data,
|
||||
int filterQualityIndex) {
|
||||
if (!canvas_) {
|
||||
return;
|
||||
}
|
||||
FML_DCHECK(paint.isNotNull());
|
||||
if (!image) {
|
||||
Dart_ThrowException(
|
||||
ToDart("Canvas.drawImageRect called with non-genuine Image."));
|
||||
@@ -366,8 +464,18 @@ 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);
|
||||
canvas_->drawImageRect(image->image(), src, dst, sampling, paint.paint(),
|
||||
SkCanvas::kFast_SrcRectConstraint);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void Canvas::drawImageNine(const CanvasImage* image,
|
||||
@@ -382,9 +490,7 @@ void Canvas::drawImageNine(const CanvasImage* image,
|
||||
const Paint& paint,
|
||||
const PaintData& paint_data,
|
||||
int bitmapSamplingIndex) {
|
||||
if (!canvas_) {
|
||||
return;
|
||||
}
|
||||
FML_DCHECK(paint.isNotNull());
|
||||
if (!image) {
|
||||
Dart_ThrowException(
|
||||
ToDart("Canvas.drawImageNine called with non-genuine Image."));
|
||||
@@ -397,35 +503,33 @@ 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_) {
|
||||
// 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 {
|
||||
bool with_attributes =
|
||||
paint.sync_to(builder(), kDrawImageNineWithPaintFlags);
|
||||
builder()->drawImageNine(image->image(), icenter, dst, filter,
|
||||
with_attributes);
|
||||
} else if (canvas_) {
|
||||
SkPaint sk_paint;
|
||||
canvas_->drawImageNine(image->image().get(), icenter, dst, filter,
|
||||
paint.paint());
|
||||
paint.paint(sk_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()) {
|
||||
canvas_->drawPicture(picture->picture().get());
|
||||
if (display_list_recorder_) {
|
||||
builder()->drawPicture(picture->picture(), nullptr, false);
|
||||
} else if (canvas_) {
|
||||
canvas_->drawPicture(picture->picture().get());
|
||||
}
|
||||
} else if (picture->display_list()) {
|
||||
if (display_list_recorder_) {
|
||||
builder()->drawDisplayList(picture->display_list());
|
||||
} else {
|
||||
} else if (canvas_) {
|
||||
picture->display_list()->RenderTo(canvas_);
|
||||
}
|
||||
} else {
|
||||
@@ -437,32 +541,52 @@ 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.");
|
||||
|
||||
canvas_->drawPoints(point_mode,
|
||||
points.num_elements() / 2, // SkPoints have two floats.
|
||||
reinterpret_cast<const SkPoint*>(points.data()),
|
||||
*paint.paint());
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
canvas_->drawVertices(vertices->vertices(), blend_mode, *paint.paint());
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
void Canvas::drawAtlas(const Paint& paint,
|
||||
@@ -474,9 +598,6 @@ 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 "
|
||||
@@ -493,13 +614,26 @@ void Canvas::drawAtlas(const Paint& paint,
|
||||
|
||||
auto sampling = ImageFilter::SamplingFromIndex(filterQualityIndex);
|
||||
|
||||
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());
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
void Canvas::drawShadow(const CanvasPath* path,
|
||||
@@ -526,7 +660,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 {
|
||||
} else if (canvas_) {
|
||||
flutter::PhysicalShapeLayer::DrawShadow(
|
||||
canvas_, path->path(), color, elevation, transparentOccluder, dpr);
|
||||
}
|
||||
@@ -534,6 +668,7 @@ void Canvas::drawShadow(const CanvasPath* path,
|
||||
|
||||
void Canvas::Invalidate() {
|
||||
canvas_ = nullptr;
|
||||
display_list_recorder_ = nullptr;
|
||||
if (dart_wrapper()) {
|
||||
ClearDartWrapper();
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ class DartLibraryNatives;
|
||||
namespace flutter {
|
||||
class CanvasImage;
|
||||
|
||||
class Canvas : public RefCountedDartWrappable<Canvas> {
|
||||
class Canvas : public RefCountedDartWrappable<Canvas>, DisplayListOpFlags {
|
||||
DEFINE_WRAPPERTYPEINFO();
|
||||
FML_FRIEND_MAKE_REF_COUNTED(Canvas);
|
||||
|
||||
@@ -188,8 +188,8 @@ class Canvas : public RefCountedDartWrappable<Canvas> {
|
||||
// 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_;
|
||||
sk_sp<DisplayListBuilder> builder() {
|
||||
return display_list_recorder_->builder();
|
||||
DisplayListBuilder* builder() {
|
||||
return display_list_recorder_->builder().get();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -65,28 +65,31 @@ 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) {
|
||||
is_null_ = Dart_IsNull(paint_data);
|
||||
if (is_null_) {
|
||||
return;
|
||||
}
|
||||
Paint::Paint(Dart_Handle paint_objects, Dart_Handle paint_data)
|
||||
: paint_objects_(paint_objects), paint_data_(paint_data) {}
|
||||
|
||||
tonic::DartByteData byte_data(paint_data);
|
||||
const SkPaint* Paint::paint(SkPaint& paint) const {
|
||||
if (isNull()) {
|
||||
return nullptr;
|
||||
}
|
||||
FML_DCHECK(paint == SkPaint());
|
||||
|
||||
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;
|
||||
Dart_ListGetRange(paint_objects_, 0, kObjectCount, values))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Dart_Handle shader = values[kShaderIndex];
|
||||
@@ -94,75 +97,75 @@ Paint::Paint(Dart_Handle paint_objects, Dart_Handle paint_data) {
|
||||
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]) {
|
||||
@@ -172,9 +175,138 @@ Paint::Paint(Dart_Handle paint_objects, Dart_Handle paint_data) {
|
||||
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
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#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 {
|
||||
@@ -15,13 +17,25 @@ class Paint {
|
||||
Paint() = default;
|
||||
Paint(Dart_Handle paint_objects, Dart_Handle paint_data);
|
||||
|
||||
const SkPaint* paint() const { return is_null_ ? nullptr : &paint_; }
|
||||
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_); }
|
||||
|
||||
private:
|
||||
friend struct tonic::DartConverter<Paint>;
|
||||
|
||||
SkPaint paint_;
|
||||
bool is_null_ = true;
|
||||
Dart_Handle paint_objects_;
|
||||
Dart_Handle paint_data_;
|
||||
};
|
||||
|
||||
// The PaintData argument is a placeholder to receive encoded data for Paint
|
||||
|
||||
@@ -452,17 +452,19 @@ void ParagraphBuilder::pushStyle(tonic::Int32List& encoded,
|
||||
|
||||
if (mask & tsBackgroundMask) {
|
||||
Paint background(background_objects, background_data);
|
||||
if (background.paint()) {
|
||||
if (background.isNotNull()) {
|
||||
SkPaint sk_paint;
|
||||
style.has_background = true;
|
||||
style.background = *background.paint();
|
||||
style.background = *background.paint(sk_paint);
|
||||
}
|
||||
}
|
||||
|
||||
if (mask & tsForegroundMask) {
|
||||
Paint foreground(foreground_objects, foreground_data);
|
||||
if (foreground.paint()) {
|
||||
if (foreground.isNotNull()) {
|
||||
SkPaint sk_paint;
|
||||
style.has_foreground = true;
|
||||
style.foreground = *foreground.paint();
|
||||
style.foreground = *foreground.paint(sk_paint);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user