Use DisplayListMatrixClipTracker in DisplayListBuilder (#38349)
* Use DisplayListMatrixClipTracker in DisplayListBuilder
* Ignore is_aa
* Revert "Ignore is_aa"
This reverts commit b201dadc773f8e726ec68ed88114df9be7b5a9b0.
* Tweak code
* Use content_culled
* getLocalClipBounds without device clip bounds roundsOut
* Tweak code and add more tests
* remove virtual
diff --git a/display_list/display_list_builder.cc b/display_list/display_list_builder.cc
index 14289a3..6cb5d6c 100644
--- a/display_list/display_list_builder.cc
+++ b/display_list/display_list_builder.cc
@@ -67,16 +67,15 @@
}
DisplayListBuilder::DisplayListBuilder(const SkRect& cull_rect,
- bool prepare_rtree) {
+ bool prepare_rtree)
+ : tracker_(cull_rect, SkMatrix::I()) {
if (prepare_rtree) {
accumulator_ = std::make_unique<RTreeBoundsAccumulator>();
} else {
accumulator_ = std::make_unique<RectBoundsAccumulator>();
}
- // isEmpty protects us against NaN as we normalize any empty cull rects
- SkRect cull = cull_rect.isEmpty() ? SkRect::MakeEmpty() : cull_rect;
- layer_stack_.emplace_back(SkM44(), SkMatrix::I(), cull);
+ layer_stack_.emplace_back();
current_layer_ = &layer_stack_.back();
}
@@ -440,9 +439,10 @@
}
void DisplayListBuilder::save() {
- layer_stack_.emplace_back(current_layer_);
+ layer_stack_.emplace_back();
current_layer_ = &layer_stack_.back();
current_layer_->has_deferred_save_op_ = true;
+ tracker_.save();
accumulator()->save();
}
@@ -455,6 +455,7 @@
// on the stack.
LayerInfo layer_info = layer_stack_.back();
+ tracker_.restore();
layer_stack_.pop_back();
current_layer_ = &layer_stack_.back();
bool is_unbounded = layer_info.is_unbounded();
@@ -463,7 +464,7 @@
// current accumulator and adjust it as required based on the filter.
std::shared_ptr<const DlImageFilter> filter = layer_info.filter();
if (filter) {
- const SkRect* clip = ¤t_layer_->clip_bounds();
+ const SkRect clip = tracker_.device_cull_rect();
if (!accumulator()->restore(
[filter = filter, matrix = getTransform()](const SkRect& input,
SkRect& output) {
@@ -473,7 +474,7 @@
output.set(output_bounds);
return ret;
},
- clip)) {
+ &clip)) {
is_unbounded = true;
}
} else {
@@ -544,11 +545,12 @@
// We will fill the clip of the outer layer when we restore
AccumulateUnbounded();
}
- layer_stack_.emplace_back(current_layer_, save_layer_offset, true,
+ layer_stack_.emplace_back(save_layer_offset, true,
current_.getImageFilter());
} else {
- layer_stack_.emplace_back(current_layer_, save_layer_offset, true, nullptr);
+ layer_stack_.emplace_back(save_layer_offset, true, nullptr);
}
+ tracker_.save();
accumulator()->save();
current_layer_ = &layer_stack_.back();
if (options.renders_with_attributes()) {
@@ -566,7 +568,7 @@
// use them as the temporary layer bounds during rendering the layer, so
// we set them as if a clip operation were performed.
if (bounds) {
- intersect(*bounds);
+ tracker_.clipRect(*bounds, SkClipOp::kIntersect, false);
}
if (backdrop) {
// A backdrop will affect up to the entire surface, bounded by the clip
@@ -590,8 +592,7 @@
(tx != 0.0 || ty != 0.0)) {
checkForDeferredSave();
Push<TranslateOp>(0, 1, tx, ty);
- current_layer_->matrix().preTranslate(tx, ty);
- current_layer_->update_matrix33();
+ tracker_.translate(tx, ty);
}
}
void DisplayListBuilder::scale(SkScalar sx, SkScalar sy) {
@@ -599,16 +600,14 @@
(sx != 1.0 || sy != 1.0)) {
checkForDeferredSave();
Push<ScaleOp>(0, 1, sx, sy);
- current_layer_->matrix().preScale(sx, sy);
- current_layer_->update_matrix33();
+ tracker_.scale(sx, sy);
}
}
void DisplayListBuilder::rotate(SkScalar degrees) {
if (SkScalarMod(degrees, 360.0) != 0.0) {
checkForDeferredSave();
Push<RotateOp>(0, 1, degrees);
- current_layer_->matrix().preConcat(SkMatrix::RotateDeg(degrees));
- current_layer_->update_matrix33();
+ tracker_.rotate(degrees);
}
}
void DisplayListBuilder::skew(SkScalar sx, SkScalar sy) {
@@ -616,8 +615,7 @@
(sx != 0.0 || sy != 0.0)) {
checkForDeferredSave();
Push<SkewOp>(0, 1, sx, sy);
- current_layer_->matrix().preConcat(SkMatrix::Skew(sx, sy));
- current_layer_->update_matrix33();
+ tracker_.skew(sx, sy);
}
}
@@ -636,11 +634,8 @@
Push<Transform2DAffineOp>(0, 1,
mxx, mxy, mxt,
myx, myy, myt);
- current_layer_->matrix().preConcat(SkM44(mxx, mxy, 0, mxt,
- myx, myy, 0, myt,
- 0, 0, 1, 0,
- 0, 0, 0, 1));
- current_layer_->update_matrix33();
+ tracker_.transform2DAffine(mxx, mxy, mxt,
+ myx, myy, myt);
}
}
// full 4x4 transform in row major order
@@ -665,19 +660,17 @@
myx, myy, myz, myt,
mzx, mzy, mzz, mzt,
mwx, mwy, mwz, mwt);
- current_layer_->matrix().preConcat(SkM44(mxx, mxy, mxz, mxt,
- myx, myy, myz, myt,
- mzx, mzy, mzz, mzt,
- mwx, mwy, mwz, mwt));
- current_layer_->update_matrix33();
+ tracker_.transformFullPerspective(mxx, mxy, mxz, mxt,
+ myx, myy, myz, myt,
+ mzx, mzy, mzz, mzt,
+ mwx, mwy, mwz, mwt);
}
}
// clang-format on
void DisplayListBuilder::transformReset() {
checkForDeferredSave();
Push<TransformResetOp>(0, 0);
- current_layer_->matrix().setIdentity();
- current_layer_->update_matrix33();
+ tracker_.setIdentity();
}
void DisplayListBuilder::transform(const SkMatrix* matrix) {
if (matrix != nullptr) {
@@ -704,12 +697,12 @@
switch (clip_op) {
case SkClipOp::kIntersect:
Push<ClipIntersectRectOp>(0, 1, rect, is_aa);
- intersect(rect);
break;
case SkClipOp::kDifference:
Push<ClipDifferenceRectOp>(0, 1, rect, is_aa);
break;
}
+ tracker_.clipRect(rect, clip_op, is_aa);
}
void DisplayListBuilder::clipRRect(const SkRRect& rrect,
SkClipOp clip_op,
@@ -721,12 +714,12 @@
switch (clip_op) {
case SkClipOp::kIntersect:
Push<ClipIntersectRRectOp>(0, 1, rrect, is_aa);
- intersect(rrect.getBounds());
break;
case SkClipOp::kDifference:
Push<ClipDifferenceRRectOp>(0, 1, rrect, is_aa);
break;
}
+ tracker_.clipRRect(rrect, clip_op, is_aa);
}
}
void DisplayListBuilder::clipPath(const SkPath& path,
@@ -753,48 +746,16 @@
switch (clip_op) {
case SkClipOp::kIntersect:
Push<ClipIntersectPathOp>(0, 1, path, is_aa);
- if (!path.isInverseFillType()) {
- intersect(path.getBounds());
- }
break;
case SkClipOp::kDifference:
Push<ClipDifferencePathOp>(0, 1, path, is_aa);
- // Map "kDifference of inverse path" to "kIntersect of the original path".
- if (path.isInverseFillType()) {
- intersect(path.getBounds());
- }
break;
}
-}
-void DisplayListBuilder::intersect(const SkRect& rect) {
- SkRect dev_clip_bounds = getTransform().mapRect(rect);
- if (!current_layer_->clip_bounds().intersect(dev_clip_bounds)) {
- current_layer_->clip_bounds().setEmpty();
- }
-}
-SkRect DisplayListBuilder::getLocalClipBounds() {
- SkM44 inverse;
- if (current_layer_->matrix().invert(&inverse)) {
- SkRect dev_bounds;
- current_layer_->clip_bounds().roundOut(&dev_bounds);
- return inverse.asM33().mapRect(dev_bounds);
- }
- return kMaxCullRect;
+ tracker_.clipPath(path, clip_op, is_aa);
}
bool DisplayListBuilder::quickReject(const SkRect& bounds) const {
- if (bounds.isEmpty()) {
- return true;
- }
- SkMatrix matrix = getTransform();
- // We don't need the inverse, but this method tells us if the matrix
- // is singular in which case we can reject all rendering.
- if (!matrix.invert(nullptr)) {
- return true;
- }
- SkRect dev_bounds;
- matrix.mapRect(bounds).roundOut(&dev_bounds);
- return !current_layer_->clip_bounds().intersects(dev_bounds);
+ return tracker_.content_culled(bounds);
}
void DisplayListBuilder::drawPaint() {
@@ -1357,7 +1318,7 @@
}
void DisplayListBuilder::AccumulateUnbounded() {
- accumulator()->accumulate(current_layer_->clip_bounds());
+ accumulator()->accumulate(tracker_.device_cull_rect());
}
void DisplayListBuilder::AccumulateOpBounds(SkRect& bounds,
@@ -1369,8 +1330,8 @@
}
}
void DisplayListBuilder::AccumulateBounds(SkRect& bounds) {
- getTransform().mapRect(&bounds);
- if (bounds.intersect(current_layer_->clip_bounds())) {
+ tracker_.mapRect(&bounds);
+ if (bounds.intersect(tracker_.device_cull_rect())) {
accumulator()->accumulate(bounds);
}
}
diff --git a/display_list/display_list_builder.h b/display_list/display_list_builder.h
index 94a784f..b1caf37 100644
--- a/display_list/display_list_builder.h
+++ b/display_list/display_list_builder.h
@@ -11,6 +11,7 @@
#include "flutter/display_list/display_list_dispatcher.h"
#include "flutter/display_list/display_list_flags.h"
#include "flutter/display_list/display_list_image.h"
+#include "flutter/display_list/display_list_matrix_clip_tracker.h"
#include "flutter/display_list/display_list_paint.h"
#include "flutter/display_list/display_list_path_effect.h"
#include "flutter/display_list/display_list_sampling_options.h"
@@ -210,11 +211,11 @@
/// Returns the 4x4 full perspective transform representing all transform
/// operations executed so far in this DisplayList within the enclosing
/// save stack.
- SkM44 getTransformFullPerspective() const { return current_layer_->matrix(); }
+ SkM44 getTransformFullPerspective() const { return tracker_.matrix_4x4(); }
/// Returns the 3x3 partial perspective transform representing all transform
/// operations executed so far in this DisplayList within the enclosing
/// save stack.
- SkMatrix getTransform() const { return current_layer_->matrix33(); }
+ SkMatrix getTransform() const { return tracker_.matrix_3x3(); }
void clipRect(const SkRect& rect, SkClipOp clip_op, bool is_aa) override;
void clipRRect(const SkRRect& rrect, SkClipOp clip_op, bool is_aa) override;
@@ -223,11 +224,11 @@
/// Conservative estimate of the bounds of all outstanding clip operations
/// measured in the coordinate space within which this DisplayList will
/// be rendered.
- SkRect getDestinationClipBounds() { return current_layer_->clip_bounds(); }
+ SkRect getDestinationClipBounds() { return tracker_.device_cull_rect(); }
/// Conservative estimate of the bounds of all outstanding clip operations
/// transformed into the local coordinate space in which currently
/// recorded rendering operations are interpreted.
- SkRect getLocalClipBounds();
+ SkRect getLocalClipBounds() { return tracker_.local_cull_rect(); }
/// Return true iff the supplied bounds are easily shown to be outside
/// of the current clip bounds. This method may conservatively return
@@ -386,33 +387,16 @@
class LayerInfo {
public:
- explicit LayerInfo(const SkM44& matrix,
- const SkMatrix& matrix33,
- const SkRect& clip_bounds,
- size_t save_layer_offset = 0,
+ explicit LayerInfo(size_t save_layer_offset = 0,
bool has_layer = false,
std::shared_ptr<const DlImageFilter> filter = nullptr)
: save_layer_offset_(save_layer_offset),
has_layer_(has_layer),
cannot_inherit_opacity_(false),
has_compatible_op_(false),
- matrix_(matrix),
- matrix33_(matrix33),
- clip_bounds_(clip_bounds),
filter_(filter),
is_unbounded_(false) {}
- explicit LayerInfo(const LayerInfo* current_layer,
- size_t save_layer_offset = 0,
- bool has_layer = false,
- std::shared_ptr<const DlImageFilter> filter = nullptr)
- : LayerInfo(current_layer->matrix_,
- current_layer->matrix33_,
- current_layer->clip_bounds_,
- save_layer_offset,
- has_layer,
- filter) {}
-
// The offset into the memory buffer where the saveLayer DLOp record
// for this saveLayer() call is placed. This may be needed if the
// eventual restore() call has discovered important information about
@@ -424,11 +408,6 @@
bool has_layer() const { return has_layer_; }
bool cannot_inherit_opacity() const { return cannot_inherit_opacity_; }
bool has_compatible_op() const { return cannot_inherit_opacity_; }
- SkM44& matrix() { return matrix_; }
- SkMatrix& matrix33() { return matrix33_; }
- SkRect& clip_bounds() { return clip_bounds_; }
-
- void update_matrix33() { matrix33_ = matrix_.asM33(); }
bool is_group_opacity_compatible() const {
return !cannot_inherit_opacity_;
@@ -486,9 +465,6 @@
bool has_layer_;
bool cannot_inherit_opacity_;
bool has_compatible_op_;
- SkM44 matrix_;
- SkMatrix matrix33_;
- SkRect clip_bounds_;
std::shared_ptr<const DlImageFilter> filter_;
bool is_unbounded_;
bool has_deferred_save_op_ = false;
@@ -498,6 +474,7 @@
std::vector<LayerInfo> layer_stack_;
LayerInfo* current_layer_;
+ DisplayListMatrixClipTracker tracker_;
std::unique_ptr<BoundsAccumulator> accumulator_;
BoundsAccumulator* accumulator() { return accumulator_.get(); }
diff --git a/display_list/display_list_matrix_clip_tracker.cc b/display_list/display_list_matrix_clip_tracker.cc
index 49f653f..d79f693 100644
--- a/display_list/display_list_matrix_clip_tracker.cc
+++ b/display_list/display_list_matrix_clip_tracker.cc
@@ -39,12 +39,13 @@
void setTransform(const SkMatrix& matrix) override { m44_ = SkM44(matrix); }
void setTransform(const SkM44& m44) override { m44_ = m44; }
void setIdentity() override { m44_.setIdentity(); }
+ bool mapRect(const SkRect& rect, SkRect* mapped) const override {
+ return m44_.asM33().mapRect(mapped, rect);
+ }
+ bool canBeInverted() const override { return m44_.asM33().invert(nullptr); }
protected:
bool has_perspective() const override;
- bool map_rect(const SkRect& rect, SkRect* mapped) const override {
- return m44_.asM33().mapRect(mapped, rect);
- }
private:
SkM44 m44_;
@@ -80,12 +81,13 @@
FML_CHECK(false) << "SkM44 was set without upgrading Data";
}
void setIdentity() override { matrix_.setIdentity(); }
+ bool mapRect(const SkRect& rect, SkRect* mapped) const override {
+ return matrix_.mapRect(mapped, rect);
+ }
+ bool canBeInverted() const override { return matrix_.invert(nullptr); }
protected:
bool has_perspective() const override { return matrix_.hasPerspective(); }
- bool map_rect(const SkRect& rect, SkRect* mapped) const override {
- return matrix_.mapRect(mapped, rect);
- }
private:
SkMatrix matrix_;
@@ -103,21 +105,64 @@
DisplayListMatrixClipTracker::DisplayListMatrixClipTracker(
const SkRect& cull_rect,
const SkMatrix& matrix) {
- saved_.emplace_back(std::make_unique<Data3x3>(matrix, cull_rect));
+ // isEmpty protects us against NaN as we normalize any empty cull rects
+ SkRect cull = cull_rect.isEmpty() ? SkRect::MakeEmpty() : cull_rect;
+ saved_.emplace_back(std::make_unique<Data3x3>(matrix, cull));
current_ = saved_.back().get();
}
DisplayListMatrixClipTracker::DisplayListMatrixClipTracker(
const SkRect& cull_rect,
const SkM44& m44) {
+ // isEmpty protects us against NaN as we normalize any empty cull rects
+ SkRect cull = cull_rect.isEmpty() ? SkRect::MakeEmpty() : cull_rect;
if (is_3x3(m44)) {
- saved_.emplace_back(std::make_unique<Data3x3>(m44.asM33(), cull_rect));
+ saved_.emplace_back(std::make_unique<Data3x3>(m44.asM33(), cull));
} else {
- saved_.emplace_back(std::make_unique<Data4x4>(m44, cull_rect));
+ saved_.emplace_back(std::make_unique<Data4x4>(m44, cull));
}
current_ = saved_.back().get();
}
+// clang-format off
+void DisplayListMatrixClipTracker::transform2DAffine(
+ SkScalar mxx, SkScalar mxy, SkScalar mxt,
+ SkScalar myx, SkScalar myy, SkScalar myt) {
+ if (!current_->is_4x4()) {
+ transform(SkMatrix::MakeAll(mxx, mxy, mxt,
+ myx, myy, myt,
+ 0, 0, 1));
+ } else {
+ transform(SkM44(mxx, mxy, 0, mxt,
+ myx, myy, 0, myt,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1));
+ }
+}
+void DisplayListMatrixClipTracker::transformFullPerspective(
+ SkScalar mxx, SkScalar mxy, SkScalar mxz, SkScalar mxt,
+ SkScalar myx, SkScalar myy, SkScalar myz, SkScalar myt,
+ SkScalar mzx, SkScalar mzy, SkScalar mzz, SkScalar mzt,
+ SkScalar mwx, SkScalar mwy, SkScalar mwz, SkScalar mwt) {
+ if (!current_->is_4x4()) {
+ if ( mxz == 0 &&
+ myz == 0 &&
+ mzx == 0 && mzy == 0 && mzz == 1 && mzt == 0 &&
+ mwz == 0) {
+ transform(SkMatrix::MakeAll(mxx, mxy, mxt,
+ myx, myy, myt,
+ mwx, mwy, mwt));
+ return;
+ }
+ }
+
+ transform(SkM44(mxx, mxy, mxz, mxt,
+ myx, myy, myz, myt,
+ mzx, mzy, mzz, mzt,
+ mwx, mwy, mwz, mwt));
+}
+// clang-format on
+
void DisplayListMatrixClipTracker::save() {
if (current_->is_4x4()) {
saved_.emplace_back(std::make_unique<Data4x4>(current_));
@@ -183,6 +228,19 @@
void DisplayListMatrixClipTracker::clipPath(const SkPath& path,
SkClipOp op,
bool is_aa) {
+ // Map "kDifference of inverse path" to "kIntersect of the original path" and
+ // map "kIntersect of inverse path" to "kDifference of the original path"
+ if (path.isInverseFillType()) {
+ switch (op) {
+ case SkClipOp::kIntersect:
+ op = SkClipOp::kDifference;
+ break;
+ case SkClipOp::kDifference:
+ op = SkClipOp::kIntersect;
+ break;
+ }
+ }
+
SkRect bounds;
switch (op) {
case SkClipOp::kIntersect:
@@ -202,11 +260,14 @@
if (cull_rect_.isEmpty() || content_bounds.isEmpty()) {
return true;
}
+ if (!canBeInverted()) {
+ return true;
+ }
if (has_perspective()) {
return false;
}
SkRect mapped;
- map_rect(content_bounds, &mapped);
+ mapRect(content_bounds, &mapped);
return !mapped.intersects(cull_rect_);
}
@@ -228,7 +289,7 @@
break;
}
SkRect rect;
- map_rect(clip, &rect);
+ mapRect(clip, &rect);
if (is_aa) {
rect.roundOut(&rect);
}
@@ -242,7 +303,7 @@
break;
}
SkRect rect;
- if (map_rect(clip, &rect)) {
+ if (mapRect(clip, &rect)) {
// This technique only works if it is rect -> rect
if (is_aa) {
SkIRect rounded;
diff --git a/display_list/display_list_matrix_clip_tracker.h b/display_list/display_list_matrix_clip_tracker.h
index 52c9d99..1bde44a 100644
--- a/display_list/display_list_matrix_clip_tracker.h
+++ b/display_list/display_list_matrix_clip_tracker.h
@@ -44,9 +44,20 @@
void rotate(SkScalar degrees) { current_->rotate(degrees); }
void transform(const SkM44& m44);
void transform(const SkMatrix& matrix) { current_->transform(matrix); }
+ // clang-format off
+ void transform2DAffine(
+ SkScalar mxx, SkScalar mxy, SkScalar mxt,
+ SkScalar myx, SkScalar myy, SkScalar myt);
+ void transformFullPerspective(
+ SkScalar mxx, SkScalar mxy, SkScalar mxz, SkScalar mxt,
+ SkScalar myx, SkScalar myy, SkScalar myz, SkScalar myt,
+ SkScalar mzx, SkScalar mzy, SkScalar mzz, SkScalar mzt,
+ SkScalar mwx, SkScalar mwy, SkScalar mwz, SkScalar mwt);
+ // clang-format on
void setTransform(const SkMatrix& matrix) { current_->setTransform(matrix); }
void setTransform(const SkM44& m44);
void setIdentity() { current_->setIdentity(); }
+ bool mapRect(SkRect* rect) const { return current_->mapRect(*rect, rect); }
void clipRect(const SkRect& rect, SkClipOp op, bool is_aa) {
current_->clipBounds(rect, op, is_aa);
@@ -77,6 +88,8 @@
virtual void setTransform(const SkMatrix& matrix) = 0;
virtual void setTransform(const SkM44& m44) = 0;
virtual void setIdentity() = 0;
+ virtual bool mapRect(const SkRect& rect, SkRect* mapped) const = 0;
+ virtual bool canBeInverted() const = 0;
virtual void clipBounds(const SkRect& clip, SkClipOp op, bool is_aa);
@@ -84,7 +97,6 @@
Data(const SkRect& rect) : cull_rect_(rect) {}
virtual bool has_perspective() const = 0;
- virtual bool map_rect(const SkRect& rect, SkRect* mapped) const = 0;
SkRect cull_rect_;
};
diff --git a/display_list/display_list_matrix_clip_tracker_unittests.cc b/display_list/display_list_matrix_clip_tracker_unittests.cc
index c4ffb18..eff7e90 100644
--- a/display_list/display_list_matrix_clip_tracker_unittests.cc
+++ b/display_list/display_list_matrix_clip_tracker_unittests.cc
@@ -4,6 +4,7 @@
#include "flutter/display_list/display_list_matrix_clip_tracker.h"
#include "gtest/gtest.h"
+#include "third_party/skia/include/core/SkPath.h"
namespace flutter {
namespace testing {
@@ -225,5 +226,127 @@
ASSERT_EQ(tracker2.matrix_4x4(), rotated_m44);
}
+TEST(DisplayListMatrixClipTracker, Transform2DAffine) {
+ const SkRect cull_rect = SkRect::MakeLTRB(20, 20, 60, 60);
+ const SkMatrix matrix = SkMatrix::Scale(4, 4);
+ const SkM44 m44 = SkM44::Scale(4, 4);
+
+ const SkMatrix transformed_matrix =
+ SkMatrix::Concat(matrix, SkMatrix::MakeAll(2, 0, 5, //
+ 0, 2, 6, //
+ 0, 0, 1));
+ const SkM44 transformed_m44 = SkM44(transformed_matrix);
+ const SkRect local_cull_rect = SkRect::MakeLTRB(0, -0.5, 5, 4.5);
+
+ DisplayListMatrixClipTracker tracker1(cull_rect, matrix);
+ DisplayListMatrixClipTracker tracker2(cull_rect, m44);
+ tracker1.transform2DAffine(2, 0, 5, //
+ 0, 2, 6);
+ tracker2.transform2DAffine(2, 0, 5, //
+ 0, 2, 6);
+ ASSERT_FALSE(tracker1.using_4x4_matrix());
+ ASSERT_EQ(tracker1.device_cull_rect(), cull_rect);
+ ASSERT_EQ(tracker1.local_cull_rect(), local_cull_rect);
+ ASSERT_EQ(tracker1.matrix_3x3(), transformed_matrix);
+ ASSERT_EQ(tracker1.matrix_4x4(), transformed_m44);
+
+ ASSERT_FALSE(tracker2.using_4x4_matrix());
+ ASSERT_EQ(tracker2.device_cull_rect(), cull_rect);
+ ASSERT_EQ(tracker2.local_cull_rect(), local_cull_rect);
+ ASSERT_EQ(tracker2.matrix_3x3(), transformed_matrix);
+ ASSERT_EQ(tracker2.matrix_4x4(), transformed_m44);
+}
+
+TEST(DisplayListMatrixClipTracker, TransformFullPerspectiveUsing3x3Matrix) {
+ const SkRect cull_rect = SkRect::MakeLTRB(20, 20, 60, 60);
+ const SkMatrix matrix = SkMatrix::Scale(4, 4);
+ const SkM44 m44 = SkM44::Scale(4, 4);
+
+ const SkMatrix transformed_matrix =
+ SkMatrix::Concat(matrix, SkMatrix::MakeAll(2, 0, 5, //
+ 0, 2, 6, //
+ 0, 0, 1));
+ const SkM44 transformed_m44 = SkM44(transformed_matrix);
+ const SkRect local_cull_rect = SkRect::MakeLTRB(0, -0.5, 5, 4.5);
+
+ DisplayListMatrixClipTracker tracker1(cull_rect, matrix);
+ DisplayListMatrixClipTracker tracker2(cull_rect, m44);
+ tracker1.transformFullPerspective(2, 0, 0, 5, //
+ 0, 2, 0, 6, //
+ 0, 0, 1, 0, //
+ 0, 0, 0, 1);
+ tracker2.transformFullPerspective(2, 0, 0, 5, //
+ 0, 2, 0, 6, //
+ 0, 0, 1, 0, //
+ 0, 0, 0, 1);
+ ASSERT_FALSE(tracker1.using_4x4_matrix());
+ ASSERT_EQ(tracker1.device_cull_rect(), cull_rect);
+ ASSERT_EQ(tracker1.local_cull_rect(), local_cull_rect);
+ ASSERT_EQ(tracker1.matrix_3x3(), transformed_matrix);
+ ASSERT_EQ(tracker1.matrix_4x4(), transformed_m44);
+
+ ASSERT_FALSE(tracker2.using_4x4_matrix());
+ ASSERT_EQ(tracker2.device_cull_rect(), cull_rect);
+ ASSERT_EQ(tracker2.local_cull_rect(), local_cull_rect);
+ ASSERT_EQ(tracker2.matrix_3x3(), transformed_matrix);
+ ASSERT_EQ(tracker2.matrix_4x4(), transformed_m44);
+}
+
+TEST(DisplayListMatrixClipTracker, TransformFullPerspectiveUsing4x4Matrix) {
+ const SkRect cull_rect = SkRect::MakeLTRB(20, 20, 60, 60);
+ const SkMatrix matrix = SkMatrix::Scale(4, 4);
+ const SkM44 m44 = SkM44::Scale(4, 4);
+
+ const SkM44 transformed_m44 = SkM44(m44, SkM44(2, 0, 0, 5, //
+ 0, 2, 0, 6, //
+ 0, 0, 1, 7, //
+ 0, 0, 0, 1));
+ const SkRect local_cull_rect = SkRect::MakeLTRB(0, -0.5, 5, 4.5);
+
+ DisplayListMatrixClipTracker tracker1(cull_rect, matrix);
+ DisplayListMatrixClipTracker tracker2(cull_rect, m44);
+ tracker1.transformFullPerspective(2, 0, 0, 5, //
+ 0, 2, 0, 6, //
+ 0, 0, 1, 7, //
+ 0, 0, 0, 1);
+ tracker2.transformFullPerspective(2, 0, 0, 5, //
+ 0, 2, 0, 6, //
+ 0, 0, 1, 7, //
+ 0, 0, 0, 1);
+ ASSERT_TRUE(tracker1.using_4x4_matrix());
+ ASSERT_EQ(tracker1.device_cull_rect(), cull_rect);
+ ASSERT_EQ(tracker1.local_cull_rect(), local_cull_rect);
+ ASSERT_EQ(tracker1.matrix_4x4(), transformed_m44);
+
+ ASSERT_TRUE(tracker2.using_4x4_matrix());
+ ASSERT_EQ(tracker2.device_cull_rect(), cull_rect);
+ ASSERT_EQ(tracker2.local_cull_rect(), local_cull_rect);
+ ASSERT_EQ(tracker2.matrix_4x4(), transformed_m44);
+}
+
+TEST(DisplayListMatrixClipTracker, ClipPathWithInvertFillType) {
+ SkRect cull_rect = SkRect::MakeLTRB(0, 0, 100.0, 100.0);
+ DisplayListMatrixClipTracker builder(cull_rect, SkMatrix::I());
+ SkPath clip = SkPath().addCircle(10.2, 11.3, 2).addCircle(20.4, 25.7, 2);
+ clip.setFillType(SkPathFillType::kInverseWinding);
+ builder.clipPath(clip, SkClipOp::kIntersect, false);
+
+ ASSERT_EQ(builder.local_cull_rect(), cull_rect);
+ ASSERT_EQ(builder.device_cull_rect(), cull_rect);
+}
+
+TEST(DisplayListMatrixClipTracker, DiffClipPathWithInvertFillType) {
+ SkRect cull_rect = SkRect::MakeLTRB(0, 0, 100.0, 100.0);
+ DisplayListMatrixClipTracker tracker(cull_rect, SkMatrix::I());
+
+ SkPath clip = SkPath().addCircle(10.2, 11.3, 2).addCircle(20.4, 25.7, 2);
+ clip.setFillType(SkPathFillType::kInverseWinding);
+ SkRect clip_bounds = SkRect::MakeLTRB(8.2, 9.3, 22.4, 27.7);
+ tracker.clipPath(clip, SkClipOp::kDifference, false);
+
+ ASSERT_EQ(tracker.local_cull_rect(), clip_bounds);
+ ASSERT_EQ(tracker.device_cull_rect(), clip_bounds);
+}
+
} // namespace testing
} // namespace flutter
diff --git a/display_list/display_list_unittests.cc b/display_list/display_list_unittests.cc
index 4c5359d..d0cd15d 100644
--- a/display_list/display_list_unittests.cc
+++ b/display_list/display_list_unittests.cc
@@ -1361,22 +1361,21 @@
TEST(DisplayList, ClipRectAffectsClipBounds) {
DisplayListBuilder builder;
SkRect clip_bounds = SkRect::MakeLTRB(10.2, 11.3, 20.4, 25.7);
- SkRect clip_expanded_bounds = SkRect::MakeLTRB(10, 11, 21, 26);
builder.clipRect(clip_bounds, SkClipOp::kIntersect, false);
// Save initial return values for testing restored values
SkRect initial_local_bounds = builder.getLocalClipBounds();
SkRect initial_destination_bounds = builder.getDestinationClipBounds();
- ASSERT_EQ(initial_local_bounds, clip_expanded_bounds);
+ ASSERT_EQ(initial_local_bounds, clip_bounds);
ASSERT_EQ(initial_destination_bounds, clip_bounds);
builder.save();
builder.clipRect({0, 0, 15, 15}, SkClipOp::kIntersect, false);
// Both clip bounds have changed
- ASSERT_NE(builder.getLocalClipBounds(), clip_expanded_bounds);
+ ASSERT_NE(builder.getLocalClipBounds(), clip_bounds);
ASSERT_NE(builder.getDestinationClipBounds(), clip_bounds);
// Previous return values have not changed
- ASSERT_EQ(initial_local_bounds, clip_expanded_bounds);
+ ASSERT_EQ(initial_local_bounds, clip_bounds);
ASSERT_EQ(initial_destination_bounds, clip_bounds);
builder.restore();
@@ -1386,10 +1385,49 @@
builder.save();
builder.scale(2, 2);
+ SkRect scaled_clip_bounds = SkRect::MakeLTRB(5.1, 5.65, 10.2, 12.85);
+ ASSERT_EQ(builder.getLocalClipBounds(), scaled_clip_bounds);
+ // Destination bounds are unaffected by transform
+ ASSERT_EQ(builder.getDestinationClipBounds(), clip_bounds);
+ builder.restore();
+
+ // save/restore returned the values to their original values
+ ASSERT_EQ(builder.getLocalClipBounds(), initial_local_bounds);
+ ASSERT_EQ(builder.getDestinationClipBounds(), initial_destination_bounds);
+}
+
+TEST(DisplayList, ClipRectDoAAAffectsClipBounds) {
+ DisplayListBuilder builder;
+ SkRect clip_bounds = SkRect::MakeLTRB(10.2, 11.3, 20.4, 25.7);
+ SkRect clip_expanded_bounds = SkRect::MakeLTRB(10, 11, 21, 26);
+ builder.clipRect(clip_bounds, SkClipOp::kIntersect, true);
+
+ // Save initial return values for testing restored values
+ SkRect initial_local_bounds = builder.getLocalClipBounds();
+ SkRect initial_destination_bounds = builder.getDestinationClipBounds();
+ ASSERT_EQ(initial_local_bounds, clip_expanded_bounds);
+ ASSERT_EQ(initial_destination_bounds, clip_expanded_bounds);
+
+ builder.save();
+ builder.clipRect({0, 0, 15, 15}, SkClipOp::kIntersect, true);
+ // Both clip bounds have changed
+ ASSERT_NE(builder.getLocalClipBounds(), clip_expanded_bounds);
+ ASSERT_NE(builder.getDestinationClipBounds(), clip_expanded_bounds);
+ // Previous return values have not changed
+ ASSERT_EQ(initial_local_bounds, clip_expanded_bounds);
+ ASSERT_EQ(initial_destination_bounds, clip_expanded_bounds);
+ builder.restore();
+
+ // save/restore returned the values to their original values
+ ASSERT_EQ(builder.getLocalClipBounds(), initial_local_bounds);
+ ASSERT_EQ(builder.getDestinationClipBounds(), initial_destination_bounds);
+
+ builder.save();
+ builder.scale(2, 2);
SkRect scaled_expanded_bounds = SkRect::MakeLTRB(5, 5.5, 10.5, 13);
ASSERT_EQ(builder.getLocalClipBounds(), scaled_expanded_bounds);
// Destination bounds are unaffected by transform
- ASSERT_EQ(builder.getDestinationClipBounds(), clip_bounds);
+ ASSERT_EQ(builder.getDestinationClipBounds(), clip_expanded_bounds);
builder.restore();
// save/restore returned the values to their original values
@@ -1419,23 +1457,22 @@
TEST(DisplayList, ClipRRectAffectsClipBounds) {
DisplayListBuilder builder;
SkRect clip_bounds = SkRect::MakeLTRB(10.2, 11.3, 20.4, 25.7);
- SkRect clip_expanded_bounds = SkRect::MakeLTRB(10, 11, 21, 26);
SkRRect clip = SkRRect::MakeRectXY(clip_bounds, 3, 2);
builder.clipRRect(clip, SkClipOp::kIntersect, false);
// Save initial return values for testing restored values
SkRect initial_local_bounds = builder.getLocalClipBounds();
SkRect initial_destination_bounds = builder.getDestinationClipBounds();
- ASSERT_EQ(initial_local_bounds, clip_expanded_bounds);
+ ASSERT_EQ(initial_local_bounds, clip_bounds);
ASSERT_EQ(initial_destination_bounds, clip_bounds);
builder.save();
builder.clipRect({0, 0, 15, 15}, SkClipOp::kIntersect, false);
// Both clip bounds have changed
- ASSERT_NE(builder.getLocalClipBounds(), clip_expanded_bounds);
+ ASSERT_NE(builder.getLocalClipBounds(), clip_bounds);
ASSERT_NE(builder.getDestinationClipBounds(), clip_bounds);
// Previous return values have not changed
- ASSERT_EQ(initial_local_bounds, clip_expanded_bounds);
+ ASSERT_EQ(initial_local_bounds, clip_bounds);
ASSERT_EQ(initial_destination_bounds, clip_bounds);
builder.restore();
@@ -1445,10 +1482,50 @@
builder.save();
builder.scale(2, 2);
+ SkRect scaled_clip_bounds = SkRect::MakeLTRB(5.1, 5.65, 10.2, 12.85);
+ ASSERT_EQ(builder.getLocalClipBounds(), scaled_clip_bounds);
+ // Destination bounds are unaffected by transform
+ ASSERT_EQ(builder.getDestinationClipBounds(), clip_bounds);
+ builder.restore();
+
+ // save/restore returned the values to their original values
+ ASSERT_EQ(builder.getLocalClipBounds(), initial_local_bounds);
+ ASSERT_EQ(builder.getDestinationClipBounds(), initial_destination_bounds);
+}
+
+TEST(DisplayList, ClipRRectDoAAAffectsClipBounds) {
+ DisplayListBuilder builder;
+ SkRect clip_bounds = SkRect::MakeLTRB(10.2, 11.3, 20.4, 25.7);
+ SkRect clip_expanded_bounds = SkRect::MakeLTRB(10, 11, 21, 26);
+ SkRRect clip = SkRRect::MakeRectXY(clip_bounds, 3, 2);
+ builder.clipRRect(clip, SkClipOp::kIntersect, true);
+
+ // Save initial return values for testing restored values
+ SkRect initial_local_bounds = builder.getLocalClipBounds();
+ SkRect initial_destination_bounds = builder.getDestinationClipBounds();
+ ASSERT_EQ(initial_local_bounds, clip_expanded_bounds);
+ ASSERT_EQ(initial_destination_bounds, clip_expanded_bounds);
+
+ builder.save();
+ builder.clipRect({0, 0, 15, 15}, SkClipOp::kIntersect, true);
+ // Both clip bounds have changed
+ ASSERT_NE(builder.getLocalClipBounds(), clip_expanded_bounds);
+ ASSERT_NE(builder.getDestinationClipBounds(), clip_expanded_bounds);
+ // Previous return values have not changed
+ ASSERT_EQ(initial_local_bounds, clip_expanded_bounds);
+ ASSERT_EQ(initial_destination_bounds, clip_expanded_bounds);
+ builder.restore();
+
+ // save/restore returned the values to their original values
+ ASSERT_EQ(builder.getLocalClipBounds(), initial_local_bounds);
+ ASSERT_EQ(builder.getDestinationClipBounds(), initial_destination_bounds);
+
+ builder.save();
+ builder.scale(2, 2);
SkRect scaled_expanded_bounds = SkRect::MakeLTRB(5, 5.5, 10.5, 13);
ASSERT_EQ(builder.getLocalClipBounds(), scaled_expanded_bounds);
// Destination bounds are unaffected by transform
- ASSERT_EQ(builder.getDestinationClipBounds(), clip_bounds);
+ ASSERT_EQ(builder.getDestinationClipBounds(), clip_expanded_bounds);
builder.restore();
// save/restore returned the values to their original values
@@ -1482,22 +1559,21 @@
DisplayListBuilder builder;
SkPath clip = SkPath().addCircle(10.2, 11.3, 2).addCircle(20.4, 25.7, 2);
SkRect clip_bounds = SkRect::MakeLTRB(8.2, 9.3, 22.4, 27.7);
- SkRect clip_expanded_bounds = SkRect::MakeLTRB(8, 9, 23, 28);
builder.clipPath(clip, SkClipOp::kIntersect, false);
// Save initial return values for testing restored values
SkRect initial_local_bounds = builder.getLocalClipBounds();
SkRect initial_destination_bounds = builder.getDestinationClipBounds();
- ASSERT_EQ(initial_local_bounds, clip_expanded_bounds);
+ ASSERT_EQ(initial_local_bounds, clip_bounds);
ASSERT_EQ(initial_destination_bounds, clip_bounds);
builder.save();
builder.clipRect({0, 0, 15, 15}, SkClipOp::kIntersect, false);
// Both clip bounds have changed
- ASSERT_NE(builder.getLocalClipBounds(), clip_expanded_bounds);
+ ASSERT_NE(builder.getLocalClipBounds(), clip_bounds);
ASSERT_NE(builder.getDestinationClipBounds(), clip_bounds);
// Previous return values have not changed
- ASSERT_EQ(initial_local_bounds, clip_expanded_bounds);
+ ASSERT_EQ(initial_local_bounds, clip_bounds);
ASSERT_EQ(initial_destination_bounds, clip_bounds);
builder.restore();
@@ -1507,10 +1583,49 @@
builder.save();
builder.scale(2, 2);
+ SkRect scaled_clip_bounds = SkRect::MakeLTRB(4.1, 4.65, 11.2, 13.85);
+ ASSERT_EQ(builder.getLocalClipBounds(), scaled_clip_bounds);
+ // Destination bounds are unaffected by transform
+ ASSERT_EQ(builder.getDestinationClipBounds(), clip_bounds);
+ builder.restore();
+
+ // save/restore returned the values to their original values
+ ASSERT_EQ(builder.getLocalClipBounds(), initial_local_bounds);
+ ASSERT_EQ(builder.getDestinationClipBounds(), initial_destination_bounds);
+}
+
+TEST(DisplayList, ClipPathDoAAAffectsClipBounds) {
+ DisplayListBuilder builder;
+ SkPath clip = SkPath().addCircle(10.2, 11.3, 2).addCircle(20.4, 25.7, 2);
+ SkRect clip_expanded_bounds = SkRect::MakeLTRB(8, 9, 23, 28);
+ builder.clipPath(clip, SkClipOp::kIntersect, true);
+
+ // Save initial return values for testing restored values
+ SkRect initial_local_bounds = builder.getLocalClipBounds();
+ SkRect initial_destination_bounds = builder.getDestinationClipBounds();
+ ASSERT_EQ(initial_local_bounds, clip_expanded_bounds);
+ ASSERT_EQ(initial_destination_bounds, clip_expanded_bounds);
+
+ builder.save();
+ builder.clipRect({0, 0, 15, 15}, SkClipOp::kIntersect, true);
+ // Both clip bounds have changed
+ ASSERT_NE(builder.getLocalClipBounds(), clip_expanded_bounds);
+ ASSERT_NE(builder.getDestinationClipBounds(), clip_expanded_bounds);
+ // Previous return values have not changed
+ ASSERT_EQ(initial_local_bounds, clip_expanded_bounds);
+ ASSERT_EQ(initial_destination_bounds, clip_expanded_bounds);
+ builder.restore();
+
+ // save/restore returned the values to their original values
+ ASSERT_EQ(builder.getLocalClipBounds(), initial_local_bounds);
+ ASSERT_EQ(builder.getDestinationClipBounds(), initial_destination_bounds);
+
+ builder.save();
+ builder.scale(2, 2);
SkRect scaled_expanded_bounds = SkRect::MakeLTRB(4, 4.5, 11.5, 14);
ASSERT_EQ(builder.getLocalClipBounds(), scaled_expanded_bounds);
// Destination bounds are unaffected by transform
- ASSERT_EQ(builder.getDestinationClipBounds(), clip_bounds);
+ ASSERT_EQ(builder.getDestinationClipBounds(), clip_expanded_bounds);
builder.restore();
// save/restore returned the values to their original values
@@ -1543,13 +1658,12 @@
DisplayListBuilder builder;
SkRect diff_clip = SkRect::MakeLTRB(0, 0, 15, 15);
SkRect clip_bounds = SkRect::MakeLTRB(10.2, 11.3, 20.4, 25.7);
- SkRect clip_expanded_bounds = SkRect::MakeLTRB(10, 11, 21, 26);
builder.clipRect(clip_bounds, SkClipOp::kIntersect, false);
// Save initial return values for testing after kDifference clip
SkRect initial_local_bounds = builder.getLocalClipBounds();
SkRect initial_destination_bounds = builder.getDestinationClipBounds();
- ASSERT_EQ(initial_local_bounds, clip_expanded_bounds);
+ ASSERT_EQ(initial_local_bounds, clip_bounds);
ASSERT_EQ(initial_destination_bounds, clip_bounds);
builder.clipRect(diff_clip, SkClipOp::kDifference, false);
@@ -1561,14 +1675,13 @@
DisplayListBuilder builder;
SkRRect diff_clip = SkRRect::MakeRectXY({0, 0, 15, 15}, 1, 1);
SkRect clip_bounds = SkRect::MakeLTRB(10.2, 11.3, 20.4, 25.7);
- SkRect clip_expanded_bounds = SkRect::MakeLTRB(10, 11, 21, 26);
SkRRect clip = SkRRect::MakeRectXY({10.2, 11.3, 20.4, 25.7}, 3, 2);
builder.clipRRect(clip, SkClipOp::kIntersect, false);
// Save initial return values for testing after kDifference clip
SkRect initial_local_bounds = builder.getLocalClipBounds();
SkRect initial_destination_bounds = builder.getDestinationClipBounds();
- ASSERT_EQ(initial_local_bounds, clip_expanded_bounds);
+ ASSERT_EQ(initial_local_bounds, clip_bounds);
ASSERT_EQ(initial_destination_bounds, clip_bounds);
builder.clipRRect(diff_clip, SkClipOp::kDifference, false);
@@ -1581,13 +1694,12 @@
SkPath diff_clip = SkPath().addRect({0, 0, 15, 15});
SkPath clip = SkPath().addCircle(10.2, 11.3, 2).addCircle(20.4, 25.7, 2);
SkRect clip_bounds = SkRect::MakeLTRB(8.2, 9.3, 22.4, 27.7);
- SkRect clip_expanded_bounds = SkRect::MakeLTRB(8, 9, 23, 28);
builder.clipPath(clip, SkClipOp::kIntersect, false);
// Save initial return values for testing after kDifference clip
SkRect initial_local_bounds = builder.getLocalClipBounds();
SkRect initial_destination_bounds = builder.getDestinationClipBounds();
- ASSERT_EQ(initial_local_bounds, clip_expanded_bounds);
+ ASSERT_EQ(initial_local_bounds, clip_bounds);
ASSERT_EQ(initial_destination_bounds, clip_bounds);
builder.clipPath(diff_clip, SkClipOp::kDifference, false);
@@ -1612,10 +1724,9 @@
SkPath clip = SkPath().addCircle(10.2, 11.3, 2).addCircle(20.4, 25.7, 2);
clip.setFillType(SkPathFillType::kInverseWinding);
SkRect clip_bounds = SkRect::MakeLTRB(8.2, 9.3, 22.4, 27.7);
- SkRect clip_expanded_bounds = SkRect::MakeLTRB(8, 9, 23, 28);
builder.clipPath(clip, SkClipOp::kDifference, false);
- ASSERT_EQ(builder.getLocalClipBounds(), clip_expanded_bounds);
+ ASSERT_EQ(builder.getLocalClipBounds(), clip_bounds);
ASSERT_EQ(builder.getDestinationClipBounds(), clip_bounds);
}
diff --git a/testing/dart/canvas_test.dart b/testing/dart/canvas_test.dart
index 5870692..69bcbc7 100644
--- a/testing/dart/canvas_test.dart
+++ b/testing/dart/canvas_test.dart
@@ -726,7 +726,7 @@
Expect.fail('$value is too close to $expected');
};
- test('Canvas.clipRect affects canvas.getClipBounds', () async {
+ test('Canvas.clipRect(doAA=true) affects canvas.getClipBounds', () async {
final PictureRecorder recorder = PictureRecorder();
final Canvas canvas = Canvas(recorder);
const Rect clipBounds = Rect.fromLTRB(10.2, 11.3, 20.4, 25.7);
@@ -737,16 +737,16 @@
final Rect initialLocalBounds = canvas.getLocalClipBounds();
final Rect initialDestinationBounds = canvas.getDestinationClipBounds();
expect(initialLocalBounds, closeToRect(clipExpandedBounds));
- expect(initialDestinationBounds, closeToRect(clipBounds));
+ expect(initialDestinationBounds, closeToRect(clipExpandedBounds));
canvas.save();
canvas.clipRect(const Rect.fromLTRB(0, 0, 15, 15));
// Both clip bounds have changed
expect(canvas.getLocalClipBounds(), notCloseToRect(clipExpandedBounds));
- expect(canvas.getDestinationClipBounds(), notCloseToRect(clipBounds));
+ expect(canvas.getDestinationClipBounds(), notCloseToRect(clipExpandedBounds));
// Previous return values have not changed
expect(initialLocalBounds, closeToRect(clipExpandedBounds));
- expect(initialDestinationBounds, closeToRect(clipBounds));
+ expect(initialDestinationBounds, closeToRect(clipExpandedBounds));
canvas.restore();
// save/restore returned the values to their original values
@@ -758,6 +758,45 @@
const Rect scaledExpandedBounds = Rect.fromLTRB(5, 5.5, 10.5, 13);
expect(canvas.getLocalClipBounds(), closeToRect(scaledExpandedBounds));
// Destination bounds are unaffected by transform
+ expect(canvas.getDestinationClipBounds(), closeToRect(clipExpandedBounds));
+ canvas.restore();
+
+ // save/restore returned the values to their original values
+ expect(canvas.getLocalClipBounds(), initialLocalBounds);
+ expect(canvas.getDestinationClipBounds(), initialDestinationBounds);
+ });
+
+ test('Canvas.clipRect(doAA=false) affects canvas.getClipBounds', () async {
+ final PictureRecorder recorder = PictureRecorder();
+ final Canvas canvas = Canvas(recorder);
+ const Rect clipBounds = Rect.fromLTRB(10.2, 11.3, 20.4, 25.7);
+ canvas.clipRect(clipBounds, doAntiAlias: false);
+
+ // Save initial return values for testing restored values
+ final Rect initialLocalBounds = canvas.getLocalClipBounds();
+ final Rect initialDestinationBounds = canvas.getDestinationClipBounds();
+ expect(initialLocalBounds, closeToRect(clipBounds));
+ expect(initialDestinationBounds, closeToRect(clipBounds));
+
+ canvas.save();
+ canvas.clipRect(const Rect.fromLTRB(0, 0, 15, 15));
+ // Both clip bounds have changed
+ expect(canvas.getLocalClipBounds(), notCloseToRect(clipBounds));
+ expect(canvas.getDestinationClipBounds(), notCloseToRect(clipBounds));
+ // Previous return values have not changed
+ expect(initialLocalBounds, closeToRect(clipBounds));
+ expect(initialDestinationBounds, closeToRect(clipBounds));
+ canvas.restore();
+
+ // save/restore returned the values to their original values
+ expect(canvas.getLocalClipBounds(), initialLocalBounds);
+ expect(canvas.getDestinationClipBounds(), initialDestinationBounds);
+
+ canvas.save();
+ canvas.scale(2, 2);
+ const Rect scaledClipBounds = Rect.fromLTRB(5.1, 5.65, 10.2, 12.85);
+ expect(canvas.getLocalClipBounds(), closeToRect(scaledClipBounds));
+ // Destination bounds are unaffected by transform
expect(canvas.getDestinationClipBounds(), closeToRect(clipBounds));
canvas.restore();
@@ -773,21 +812,21 @@
const Rect clipBounds2 = Rect.fromLTRB(10.0, 10.0, 20.0, 20.0);
canvas.save();
- canvas.clipRect(clipBounds1);
+ canvas.clipRect(clipBounds1, doAntiAlias: false);
canvas.translate(0, 10.0);
- canvas.clipRect(clipBounds1);
+ canvas.clipRect(clipBounds1, doAntiAlias: false);
expect(canvas.getDestinationClipBounds().isEmpty, isTrue);
canvas.restore();
canvas.save();
- canvas.clipRect(clipBounds1);
+ canvas.clipRect(clipBounds1, doAntiAlias: false);
canvas.translate(-10.0, -10.0);
- canvas.clipRect(clipBounds2);
+ canvas.clipRect(clipBounds2, doAntiAlias: false);
expect(canvas.getDestinationClipBounds(), clipBounds1);
canvas.restore();
});
- test('Canvas.clipRRect affects canvas.getClipBounds', () async {
+ test('Canvas.clipRRect(doAA=true) affects canvas.getClipBounds', () async {
final PictureRecorder recorder = PictureRecorder();
final Canvas canvas = Canvas(recorder);
const Rect clipBounds = Rect.fromLTRB(10.2, 11.3, 20.4, 25.7);
@@ -799,16 +838,16 @@
final Rect initialLocalBounds = canvas.getLocalClipBounds();
final Rect initialDestinationBounds = canvas.getDestinationClipBounds();
expect(initialLocalBounds, closeToRect(clipExpandedBounds));
- expect(initialDestinationBounds, closeToRect(clipBounds));
+ expect(initialDestinationBounds, closeToRect(clipExpandedBounds));
canvas.save();
canvas.clipRect(const Rect.fromLTRB(0, 0, 15, 15));
// Both clip bounds have changed
expect(canvas.getLocalClipBounds(), notCloseToRect(clipExpandedBounds));
- expect(canvas.getDestinationClipBounds(), notCloseToRect(clipBounds));
+ expect(canvas.getDestinationClipBounds(), notCloseToRect(clipExpandedBounds));
// Previous return values have not changed
expect(initialLocalBounds, closeToRect(clipExpandedBounds));
- expect(initialDestinationBounds, closeToRect(clipBounds));
+ expect(initialDestinationBounds, closeToRect(clipExpandedBounds));
canvas.restore();
// save/restore returned the values to their original values
@@ -820,6 +859,46 @@
const Rect scaledExpandedBounds = Rect.fromLTRB(5, 5.5, 10.5, 13);
expect(canvas.getLocalClipBounds(), closeToRect(scaledExpandedBounds));
// Destination bounds are unaffected by transform
+ expect(canvas.getDestinationClipBounds(), closeToRect(clipExpandedBounds));
+ canvas.restore();
+
+ // save/restore returned the values to their original values
+ expect(canvas.getLocalClipBounds(), initialLocalBounds);
+ expect(canvas.getDestinationClipBounds(), initialDestinationBounds);
+ });
+
+ test('Canvas.clipRRect(doAA=false) affects canvas.getClipBounds', () async {
+ final PictureRecorder recorder = PictureRecorder();
+ final Canvas canvas = Canvas(recorder);
+ const Rect clipBounds = Rect.fromLTRB(10.2, 11.3, 20.4, 25.7);
+ final RRect clip = RRect.fromRectAndRadius(clipBounds, const Radius.circular(3));
+ canvas.clipRRect(clip, doAntiAlias: false);
+
+ // Save initial return values for testing restored values
+ final Rect initialLocalBounds = canvas.getLocalClipBounds();
+ final Rect initialDestinationBounds = canvas.getDestinationClipBounds();
+ expect(initialLocalBounds, closeToRect(clipBounds));
+ expect(initialDestinationBounds, closeToRect(clipBounds));
+
+ canvas.save();
+ canvas.clipRect(const Rect.fromLTRB(0, 0, 15, 15), doAntiAlias: false);
+ // Both clip bounds have changed
+ expect(canvas.getLocalClipBounds(), notCloseToRect(clipBounds));
+ expect(canvas.getDestinationClipBounds(), notCloseToRect(clipBounds));
+ // Previous return values have not changed
+ expect(initialLocalBounds, closeToRect(clipBounds));
+ expect(initialDestinationBounds, closeToRect(clipBounds));
+ canvas.restore();
+
+ // save/restore returned the values to their original values
+ expect(canvas.getLocalClipBounds(), initialLocalBounds);
+ expect(canvas.getDestinationClipBounds(), initialDestinationBounds);
+
+ canvas.save();
+ canvas.scale(2, 2);
+ const Rect scaledClipBounds = Rect.fromLTRB(5.1, 5.65, 10.2, 12.85);
+ expect(canvas.getLocalClipBounds(), closeToRect(scaledClipBounds));
+ // Destination bounds are unaffected by transform
expect(canvas.getDestinationClipBounds(), closeToRect(clipBounds));
canvas.restore();
@@ -837,21 +916,21 @@
final RRect clip2 = RRect.fromRectAndRadius(clipBounds2, const Radius.circular(3));
canvas.save();
- canvas.clipRRect(clip1);
+ canvas.clipRRect(clip1, doAntiAlias: false);
canvas.translate(0, 10.0);
- canvas.clipRRect(clip1);
+ canvas.clipRRect(clip1, doAntiAlias: false);
expect(canvas.getDestinationClipBounds().isEmpty, isTrue);
canvas.restore();
canvas.save();
- canvas.clipRRect(clip1);
+ canvas.clipRRect(clip1, doAntiAlias: false);
canvas.translate(-10.0, -10.0);
- canvas.clipRRect(clip2);
+ canvas.clipRRect(clip2, doAntiAlias: false);
expect(canvas.getDestinationClipBounds(), clipBounds1);
canvas.restore();
});
- test('Canvas.clipPath affects canvas.getClipBounds', () async {
+ test('Canvas.clipPath(doAA=true) affects canvas.getClipBounds', () async {
final PictureRecorder recorder = PictureRecorder();
final Canvas canvas = Canvas(recorder);
const Rect clipBounds = Rect.fromLTRB(10.2, 11.3, 20.4, 25.7);
@@ -863,16 +942,16 @@
final Rect initialLocalBounds = canvas.getLocalClipBounds();
final Rect initialDestinationBounds = canvas.getDestinationClipBounds();
expect(initialLocalBounds, closeToRect(clipExpandedBounds));
- expect(initialDestinationBounds, closeToRect(clipBounds));
+ expect(initialDestinationBounds, closeToRect(clipExpandedBounds));
canvas.save();
canvas.clipRect(const Rect.fromLTRB(0, 0, 15, 15));
// Both clip bounds have changed
expect(canvas.getLocalClipBounds(), notCloseToRect(clipExpandedBounds));
- expect(canvas.getDestinationClipBounds(), notCloseToRect(clipBounds));
+ expect(canvas.getDestinationClipBounds(), notCloseToRect(clipExpandedBounds));
// Previous return values have not changed
expect(initialLocalBounds, closeToRect(clipExpandedBounds));
- expect(initialDestinationBounds, closeToRect(clipBounds));
+ expect(initialDestinationBounds, closeToRect(clipExpandedBounds));
canvas.restore();
// save/restore returned the values to their original values
@@ -884,6 +963,46 @@
const Rect scaledExpandedBounds = Rect.fromLTRB(5, 5.5, 10.5, 13);
expect(canvas.getLocalClipBounds(), closeToRect(scaledExpandedBounds));
// Destination bounds are unaffected by transform
+ expect(canvas.getDestinationClipBounds(), closeToRect(clipExpandedBounds));
+ canvas.restore();
+
+ // save/restore returned the values to their original values
+ expect(canvas.getLocalClipBounds(), initialLocalBounds);
+ expect(canvas.getDestinationClipBounds(), initialDestinationBounds);
+ });
+
+ test('Canvas.clipPath(doAA=false) affects canvas.getClipBounds', () async {
+ final PictureRecorder recorder = PictureRecorder();
+ final Canvas canvas = Canvas(recorder);
+ const Rect clipBounds = Rect.fromLTRB(10.2, 11.3, 20.4, 25.7);
+ final Path clip = Path()..addRect(clipBounds)..addOval(clipBounds);
+ canvas.clipPath(clip, doAntiAlias: false);
+
+ // Save initial return values for testing restored values
+ final Rect initialLocalBounds = canvas.getLocalClipBounds();
+ final Rect initialDestinationBounds = canvas.getDestinationClipBounds();
+ expect(initialLocalBounds, closeToRect(clipBounds));
+ expect(initialDestinationBounds, closeToRect(clipBounds));
+
+ canvas.save();
+ canvas.clipRect(const Rect.fromLTRB(0, 0, 15, 15), doAntiAlias: false);
+ // Both clip bounds have changed
+ expect(canvas.getLocalClipBounds(), notCloseToRect(clipBounds));
+ expect(canvas.getDestinationClipBounds(), notCloseToRect(clipBounds));
+ // Previous return values have not changed
+ expect(initialLocalBounds, closeToRect(clipBounds));
+ expect(initialDestinationBounds, closeToRect(clipBounds));
+ canvas.restore();
+
+ // save/restore returned the values to their original values
+ expect(canvas.getLocalClipBounds(), initialLocalBounds);
+ expect(canvas.getDestinationClipBounds(), initialDestinationBounds);
+
+ canvas.save();
+ canvas.scale(2, 2);
+ const Rect scaledClipBounds = Rect.fromLTRB(5.1, 5.65, 10.2, 12.85);
+ expect(canvas.getLocalClipBounds(), closeToRect(scaledClipBounds));
+ // Destination bounds are unaffected by transform
expect(canvas.getDestinationClipBounds(), closeToRect(clipBounds));
canvas.restore();
@@ -901,16 +1020,16 @@
final Path clip2 = Path()..addRect(clipBounds2)..addOval(clipBounds2);
canvas.save();
- canvas.clipPath(clip1);
+ canvas.clipPath(clip1, doAntiAlias: false);
canvas.translate(0, 10.0);
- canvas.clipPath(clip1);
+ canvas.clipPath(clip1, doAntiAlias: false);
expect(canvas.getDestinationClipBounds().isEmpty, isTrue);
canvas.restore();
canvas.save();
- canvas.clipPath(clip1);
+ canvas.clipPath(clip1, doAntiAlias: false);
canvas.translate(-10.0, -10.0);
- canvas.clipPath(clip2);
+ canvas.clipPath(clip2, doAntiAlias: false);
expect(canvas.getDestinationClipBounds(), clipBounds1);
canvas.restore();
});
@@ -919,16 +1038,15 @@
final PictureRecorder recorder = PictureRecorder();
final Canvas canvas = Canvas(recorder);
const Rect clipBounds = Rect.fromLTRB(10.2, 11.3, 20.4, 25.7);
- const Rect clipExpandedBounds = Rect.fromLTRB(10, 11, 21, 26);
- canvas.clipRect(clipBounds);
+ canvas.clipRect(clipBounds, doAntiAlias: false);
// Save initial return values for testing restored values
final Rect initialLocalBounds = canvas.getLocalClipBounds();
final Rect initialDestinationBounds = canvas.getDestinationClipBounds();
- expect(initialLocalBounds, closeToRect(clipExpandedBounds));
+ expect(initialLocalBounds, closeToRect(clipBounds));
expect(initialDestinationBounds, closeToRect(clipBounds));
- canvas.clipRect(const Rect.fromLTRB(0, 0, 15, 15), clipOp: ClipOp.difference);
+ canvas.clipRect(const Rect.fromLTRB(0, 0, 15, 15), clipOp: ClipOp.difference, doAntiAlias: false);
expect(canvas.getLocalClipBounds(), initialLocalBounds);
expect(canvas.getDestinationClipBounds(), initialDestinationBounds);
});