Commit 44ea54e8 authored by Fredrik Söderquist's avatar Fredrik Söderquist Committed by Commit Bot

Fix hit-testing of nested clip-paths with objectBoundingBox units

A nested clip-path should resolve against the original elements
reference box, but it would instead resolve against the referencing
<clipPath>.
Pass the appropriate reference box to SVGLayoutSupport::IntersectsClipPath.

Took the opportunity to export some related tests to WPT.

Bug: 938913
Change-Id: I6d6ad88f0a97028b21b1f1a488afbdd42a96264b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1505949Reviewed-by: default avatarStephen Chenney <schenney@chromium.org>
Commit-Queue: Fredrik Söderquist <fs@opera.com>
Cr-Commit-Position: refs/heads/master@{#638293}
parent b36fdbaf
......@@ -184,7 +184,8 @@ bool LayoutSVGContainer::NodeAtPoint(
LocalToSVGParentTransform());
if (!local_location)
return false;
if (!SVGLayoutSupport::IntersectsClipPath(*this, *local_location))
if (!SVGLayoutSupport::IntersectsClipPath(*this, object_bounding_box_,
*local_location))
return false;
if (SVGLayoutSupport::HitTestChildren(LastChild(), result, *local_location,
......
......@@ -195,7 +195,8 @@ bool LayoutSVGImage::NodeAtPoint(HitTestResult& result,
LocalToSVGParentTransform());
if (!local_location)
return false;
if (!SVGLayoutSupport::IntersectsClipPath(*this, *local_location))
if (!SVGLayoutSupport::IntersectsClipPath(*this, object_bounding_box_,
*local_location))
return false;
if (hit_rules.can_hit_fill || hit_rules.can_hit_bounding_box) {
......
......@@ -238,7 +238,8 @@ AffineTransform LayoutSVGResourceClipper::CalculateClipTransform(
bool LayoutSVGResourceClipper::HitTestClipContent(
const FloatRect& object_bounding_box,
const HitTestLocation& location) const {
if (!SVGLayoutSupport::IntersectsClipPath(*this, location))
if (!SVGLayoutSupport::IntersectsClipPath(*this, object_bounding_box,
location))
return false;
TransformedHitTestLocation local_location(
......
......@@ -369,7 +369,8 @@ bool LayoutSVGShape::NodeAtPoint(HitTestResult& result,
LocalToSVGParentTransform());
if (!local_location)
return false;
if (!SVGLayoutSupport::IntersectsClipPath(*this, *local_location))
if (!SVGLayoutSupport::IntersectsClipPath(*this, fill_bounding_box_,
*local_location))
return false;
if (HitTestShape(result.GetHitTestRequest(), *local_location, hit_rules)) {
......
......@@ -326,7 +326,8 @@ bool LayoutSVGText::NodeAtPoint(HitTestResult& result,
LocalToSVGParentTransform());
if (!local_location)
return false;
if (!SVGLayoutSupport::IntersectsClipPath(*this, *local_location))
if (!SVGLayoutSupport::IntersectsClipPath(*this, ObjectBoundingBox(),
*local_location))
return false;
if (LayoutBlock::NodeAtPoint(result, *local_location, accumulated_offset,
......
......@@ -418,11 +418,11 @@ bool SVGLayoutSupport::HasFilterResource(const LayoutObject& object) {
}
bool SVGLayoutSupport::IntersectsClipPath(const LayoutObject& object,
const FloatRect& reference_box,
const HitTestLocation& location) {
ClipPathOperation* clip_path_operation = object.StyleRef().ClipPath();
if (!clip_path_operation)
return true;
const FloatRect& reference_box = object.ObjectBoundingBox();
if (clip_path_operation->GetType() == ClipPathOperation::SHAPE) {
ShapeClipPathOperation& clip_path =
ToShapeClipPathOperation(*clip_path_operation);
......
......@@ -72,8 +72,13 @@ class CORE_EXPORT SVGLayoutSupport {
// Determine if the LayoutObject references a filter resource object.
static bool HasFilterResource(const LayoutObject&);
// Determine whether the passed location intersects the clip path of |object|.
static bool IntersectsClipPath(const LayoutObject&, const HitTestLocation&);
// Determine whether the passed location intersects a clip path referenced by
// the passed LayoutObject.
// |reference_box| is used to resolve 'objectBoundingBox' units/percentages,
// and can differ from the reference box of the passed LayoutObject.
static bool IntersectsClipPath(const LayoutObject&,
const FloatRect& reference_box,
const HitTestLocation&);
// Shared child hit-testing code between LayoutSVGRoot/LayoutSVGContainer.
static bool HitTestChildren(LayoutObject* last_child,
......
<!DOCTYPE html>
<title>Hit-test of clip-path objectBoundingBox &lt;clipPath> with additional transform</title>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<link rel="help" href="https://drafts.fxtf.org/css-masking/#the-clip-path">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
body {
margin: 0;
......@@ -22,14 +23,14 @@ body {
</svg>
<script>
function assert_element_at(element, pointlist) {
for (var point of pointlist) {
var result = document.elementFromPoint(point[0], point[1]);
for (let point of pointlist) {
let result = document.elementFromPoint(point[0], point[1]);
assert_equals(result, element, point.join(','));
}
}
test(function() {
var div = document.querySelector('.box');
let div = document.querySelector('.box');
// Points inside clip-path.
assert_element_at(div, [[150, 150], [150, 125], [150, 175], [125, 150], [175, 150]]);
......
<!DOCTYPE html>
<title>Hit-test of clip-path nested objectBoundingBox &lt;clipPath></title>
<link rel="help" href="https://drafts.fxtf.org/css-masking/#the-clip-path">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
body {
margin: 0;
}
.box {
width: 200px;
height: 200px;
background-color: blue;
margin: 100px;
clip-path: url(#clip);
}
</style>
<div class="box"></div>
<svg height="0">
<clipPath id="nested" clipPathUnits="objectBoundingBox">
<circle cx="0.25" cy="0.25" r="0.25"/>
</clipPath>
<clipPath id="clip" clipPathUnits="objectBoundingBox" clip-path="url(#nested)">
<rect width="0.5" height="0.5"/>
</clipPath>
</svg>
<script>
function assert_element_at(element, pointlist) {
for (let point of pointlist) {
let result = document.elementFromPoint(point[0], point[1]);
assert_equals(result, element, point.join(','));
}
}
test(function() {
let div = document.querySelector('.box');
// Points inside clip-path.
assert_element_at(div, [[150, 150], [150, 125], [150, 175], [125, 150], [175, 150]]);
// Points outside clip-path.
assert_element_at(document.body, [[110, 110], [190, 110], [110, 190], [190, 190]]);
});
</script>
<!DOCTYPE html>
<title>Hit-test of clip-path userSpaceOnUse &lt;clipPath> on &lt;div></title>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<title>Hit-test of clip-path userSpaceOnUse &lt;clipPath></title>
<link rel="help" href="https://drafts.fxtf.org/css-masking/#the-clip-path">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
body {
margin: 0;
......@@ -11,11 +12,10 @@ body {
height: 100px;
background-color: blue;
margin: 100px;
-webkit-clip-path: url(#clip);
clip-path: url(#clip);
}
</style>
<div class=box></div>
<div class="box"></div>
<svg height="0">
<clipPath id="clip" clipPathUnits="userSpaceOnUse">
<polygon points="50,0 100,50 50,100 0,50"/>
......@@ -23,14 +23,14 @@ body {
</svg>
<script>
function assert_element_at(element, pointlist) {
for (var point of pointlist) {
var result = document.elementFromPoint(point[0], point[1]);
for (let point of pointlist) {
let result = document.elementFromPoint(point[0], point[1]);
assert_equals(result, element, point.join(','));
}
}
test(function() {
var div = document.querySelector('.box');
let div = document.querySelector('.box');
// Points inside clip-path.
assert_element_at(div, [[150, 150], [150, 125], [150, 175], [125, 150], [175, 150]]);
......
<!DOCTYPE html>
<title>Hit-test of clip-path polygon on &lt;div> with box-shadow</title>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<title>Hit-test of clip-path polygon combined with box-shadow</title>
<link rel="help" href="https://drafts.fxtf.org/css-masking/#the-clip-path">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<style>
body {
margin: 0;
......@@ -11,21 +12,20 @@ body {
height: 100px;
background-color: blue;
box-shadow: -100px 0px red;
-webkit-clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
}
</style>
<div class=box></div>
<div class="box"></div>
<script>
function assert_element_at(element, pointlist) {
for (var point of pointlist) {
var result = document.elementFromPoint(point[0], point[1]);
for (let point of pointlist) {
let result = document.elementFromPoint(point[0], point[1]);
assert_equals(result, element, point.join(','));
}
}
test(function() {
var div = document.querySelector('.box');
let div = document.querySelector('.box');
// Points inside clip-path.
assert_element_at(div, [[50, 50], [50, 25], [50, 75], [25, 50], [75, 50]]);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment