Make Transform::TransformRRectF tolerate values within kEpsilon of 0.
This changes Transform::TransformRRectF so that it doesn't fail due to
lack of axis-alignment in cases where
Transform::Preserves2dAxisAlignment is true, by adjusting relevant
values that are within kEpsilon of 0.
This change prevents us from (a) deciding that we can take the
border-radius fast path, and then (b) having that fast path fail.
Fixed: 1207151
Change-Id: I2ae31ec86f4f4a32ae02fc1bc6b4815b253cda2f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3353877
Reviewed-by: danakj chromium <danakj@chromium.org>
Commit-Queue: David Baron <dbaron@chromium.org>
Cr-Commit-Position: refs/heads/main@{#953613}
diff --git a/cc/trees/draw_property_utils.cc b/cc/trees/draw_property_utils.cc
index 2b8ad609..e8a6155a 100644
--- a/cc/trees/draw_property_utils.cc
+++ b/cc/trees/draw_property_utils.cc
@@ -769,8 +769,10 @@
auto result =
std::make_pair(node->mask_filter_info, node->is_fast_rounded_corner);
- if (!result.first.Transform(to_target))
+ if (!result.first.Transform(to_target)) {
+ DCHECK(result.first.IsEmpty());
return kEmptyMaskFilterInfoPair;
+ }
return result;
}
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/border-radius-clipping-with-transform-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/border-radius-clipping-with-transform-001-ref.html
new file mode 100644
index 0000000..db3ae40
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/border-radius-clipping-with-transform-001-ref.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<title>CSS Test (Backgrounds): border-radius clipping on overflow:hidden with transforms</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<style>
+
+#outer {
+ border: 10px solid #000;
+ border-radius: 60px;
+ width: 200px;
+ height: 200px;
+ background: blue;
+ position: absolute;
+ top: 10px;
+ left: 10px;
+}
+
+#coverinner, #coverouter {
+ position: absolute;
+ border: 4px solid fuchsia;
+ filter: grayscale(30%);
+}
+
+#coverinner {
+ width: 196px;
+ height: 196px;
+ top: 18px;
+ left: 18px;
+ border-radius: 52px;
+}
+
+#coverouter {
+ width: 216px;
+ height: 216px;
+ top: 8px;
+ left: 8px;
+ border-radius: 62px;
+}
+
+</style>
+
+<div id="outer">
+</div>
+<div id="coverinner">
+</div>
+<div id="coverouter">
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/border-radius-clipping-with-transform-001.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/border-radius-clipping-with-transform-001.html
new file mode 100644
index 0000000..e7d173b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/border-radius-clipping-with-transform-001.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<title>CSS Test (Backgrounds): border-radius clipping on overflow:hidden with transforms</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1207151">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#corner-clipping">
+<link rel="match" href="border-radius-clipping-with-transform-001-ref.html">
+<meta name="assert" content="The content should be clipped correctly, despite the interesting transforms.">
+<style>
+
+#outer {
+ border: 10px solid #000;
+ border-radius: 60px;
+ width: 200px;
+ height: 200px;
+ overflow: hidden;
+ transform: rotate(90deg);
+ position: absolute;
+ top: 10px;
+ left: 10px;
+}
+#inner {
+ width: 100%;
+ height: 100%;
+ background: blue;
+ transform: translateZ(0);
+}
+
+#coverinner, #coverouter {
+ position: absolute;
+ border: 4px solid fuchsia;
+ filter: grayscale(30%);
+}
+
+#coverinner {
+ width: 196px;
+ height: 196px;
+ top: 18px;
+ left: 18px;
+ border-radius: 52px;
+}
+
+#coverouter {
+ width: 216px;
+ height: 216px;
+ top: 8px;
+ left: 8px;
+ border-radius: 62px;
+}
+
+</style>
+
+<div id="outer">
+ <div id="inner">
+ </div>
+</div>
+<div id="coverinner">
+</div>
+<div id="coverouter">
+</div>
diff --git a/ui/gfx/geometry/transform.cc b/ui/gfx/geometry/transform.cc
index eee5af7..ef9e268 100644
--- a/ui/gfx/geometry/transform.cc
+++ b/ui/gfx/geometry/transform.cc
@@ -485,8 +485,23 @@
}
bool Transform::TransformRRectF(RRectF* rrect) const {
+ // We want this to fail only in cases where our
+ // Transform::Preserves2dAxisAlignment returns false. However,
+ // SkMatrix::preservesAxisAlignment is stricter (it lacks the kEpsilon
+ // test). So after converting our skia::Matrix44 to SkMatrix, round
+ // relevant values less than kEpsilon to zero.
+ SkMatrix rounded_matrix(matrix_);
+ if (std::abs(rounded_matrix.get(SkMatrix::kMScaleX)) < kEpsilon)
+ rounded_matrix.set(SkMatrix::kMScaleX, 0.0f);
+ if (std::abs(rounded_matrix.get(SkMatrix::kMSkewX)) < kEpsilon)
+ rounded_matrix.set(SkMatrix::kMSkewX, 0.0f);
+ if (std::abs(rounded_matrix.get(SkMatrix::kMSkewY)) < kEpsilon)
+ rounded_matrix.set(SkMatrix::kMSkewY, 0.0f);
+ if (std::abs(rounded_matrix.get(SkMatrix::kMScaleY)) < kEpsilon)
+ rounded_matrix.set(SkMatrix::kMScaleY, 0.0f);
+
SkRRect result;
- if (!SkRRect(*rrect).transform(SkMatrix(matrix_), &result))
+ if (!SkRRect(*rrect).transform(rounded_matrix, &result))
return false;
*rrect = gfx::RRectF(result);
return true;
diff --git a/ui/gfx/geometry/transform_unittest.cc b/ui/gfx/geometry/transform_unittest.cc
index 127c203..fb57d8a 100644
--- a/ui/gfx/geometry/transform_unittest.cc
+++ b/ui/gfx/geometry/transform_unittest.cc
@@ -2645,6 +2645,14 @@
EXPECT_TRUE(rotation_90_Clock.TransformRRectF(&rrect));
EXPECT_EQ(expected.ToString(), rrect.ToString());
+ Transform rotation_90_unrounded;
+ rotation_90_unrounded.Rotate(90.0);
+ rrect = RRectF(gfx::RectF(0, 0, 20.f, 25.f),
+ gfx::RoundedCornersF(1.f, 2.f, 3.f, 4.f));
+ EXPECT_TRUE(rotation_90_unrounded.Preserves2dAxisAlignment());
+ EXPECT_TRUE(rotation_90_unrounded.TransformRRectF(&rrect));
+ EXPECT_EQ(expected.ToString(), rrect.ToString());
+
Transform scale;
scale.Scale(2.f, 2.f);
rrect = RRectF(gfx::RectF(0, 0, 20.f, 25.f),