Implement clip-path: path()
Extended StylePath to contain windRule.
Extended path CSS property parser to account for wind-rule, e.g.
path(oddeven, '...').
Pass through a zoom parameter when requesting a path for a ShapeClipPath.
Allow PathInterpolationFunction to try to handle clip-path animations,
when the shape is a path.
Patched the necessary bits to allow CSSPathValue in clip-path.
Unskipped relevant WPT tests, and added 3 new ones to handle page zoom.
Those tests use zoom css property, in lieu of page-zoom support in WPT
Bug: 880983
Change-Id: I0bf8d7a4ec746f656c33c0f99c37e0af1e3ff7e9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2442797
Commit-Queue: Fredrik Söderquist <fs@opera.com>
Reviewed-by: Fredrik Söderquist <fs@opera.com>
Cr-Commit-Position: refs/heads/master@{#817421}
diff --git a/third_party/blink/renderer/core/animation/basic_shape_interpolation_functions.cc b/third_party/blink/renderer/core/animation/basic_shape_interpolation_functions.cc
index ed8acf1..d549899 100644
--- a/third_party/blink/renderer/core/animation/basic_shape_interpolation_functions.cc
+++ b/third_party/blink/renderer/core/animation/basic_shape_interpolation_functions.cc
@@ -537,6 +537,9 @@
case BasicShape::kBasicShapePolygonType:
return polygon_functions::ConvertBasicShape(To<BasicShapePolygon>(*shape),
zoom);
+ // Handled by PathInterpolationFunction.
+ case BasicShape::kStylePathType:
+ return nullptr;
default:
NOTREACHED();
return nullptr;
diff --git a/third_party/blink/renderer/core/animation/css_basic_shape_interpolation_type.cc b/third_party/blink/renderer/core/animation/css_basic_shape_interpolation_type.cc
index f6e7f98..1bb38aa 100644
--- a/third_party/blink/renderer/core/animation/css_basic_shape_interpolation_type.cc
+++ b/third_party/blink/renderer/core/animation/css_basic_shape_interpolation_type.cc
@@ -33,12 +33,21 @@
if (style.ShapeOutside()->CssBox() != CSSBoxType::kMissing)
return nullptr;
return style.ShapeOutside()->Shape();
- case CSSPropertyID::kClipPath:
+ case CSSPropertyID::kClipPath: {
if (!style.ClipPath())
return nullptr;
- if (style.ClipPath()->GetType() != ClipPathOperation::SHAPE)
+ auto* clip_path_operation =
+ DynamicTo<ShapeClipPathOperation>(style.ClipPath());
+ if (!clip_path_operation)
return nullptr;
- return To<ShapeClipPathOperation>(style.ClipPath())->GetBasicShape();
+ auto* shape = clip_path_operation->GetBasicShape();
+
+ // Path shape is handled by PathInterpolationType.
+ if (shape->GetType() == BasicShape::kStylePathType)
+ return nullptr;
+
+ return shape;
+ }
default:
NOTREACHED();
return nullptr;
diff --git a/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc b/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc
index 0dbbc62..71ea57ec 100644
--- a/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc
+++ b/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc
@@ -343,6 +343,11 @@
std::make_unique<CSSImageSliceInterpolationType>(used_property));
break;
case CSSPropertyID::kClipPath:
+ applicable_types->push_back(
+ std::make_unique<CSSBasicShapeInterpolationType>(used_property));
+ applicable_types->push_back(
+ std::make_unique<CSSPathInterpolationType>(used_property));
+ break;
case CSSPropertyID::kShapeOutside:
applicable_types->push_back(
std::make_unique<CSSBasicShapeInterpolationType>(used_property));
diff --git a/third_party/blink/renderer/core/animation/css_path_interpolation_type.cc b/third_party/blink/renderer/core/animation/css_path_interpolation_type.cc
index 37c5b4d2..d60b395 100644
--- a/third_party/blink/renderer/core/animation/css_path_interpolation_type.cc
+++ b/third_party/blink/renderer/core/animation/css_path_interpolation_type.cc
@@ -12,6 +12,7 @@
#include "third_party/blink/renderer/core/css/css_path_value.h"
#include "third_party/blink/renderer/core/css/resolver/style_resolver_state.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
+#include "third_party/blink/renderer/core/style/shape_clip_path_operation.h"
namespace blink {
@@ -24,11 +25,13 @@
switch (property.PropertyID()) {
case CSSPropertyID::kD:
return style.SvgStyle().D();
- case CSSPropertyID::kOffsetPath: {
- BasicShape* offset_path = style.OffsetPath();
- if (!offset_path || offset_path->GetType() != BasicShape::kStylePathType)
+ case CSSPropertyID::kOffsetPath:
+ return DynamicTo<StylePath>(style.OffsetPath());
+ case CSSPropertyID::kClipPath: {
+ auto* shape = DynamicTo<ShapeClipPathOperation>(style.ClipPath());
+ if (!shape)
return nullptr;
- return To<StylePath>(style.OffsetPath());
+ return DynamicTo<StylePath>(shape->GetBasicShape());
}
default:
NOTREACHED();
@@ -47,6 +50,9 @@
case CSSPropertyID::kOffsetPath:
style.SetOffsetPath(std::move(path));
return;
+ case CSSPropertyID::kClipPath:
+ style.SetClipPath(ShapeClipPathOperation::Create(std::move(path)));
+ return;
default:
NOTREACHED();
return;
@@ -59,15 +65,9 @@
const InterpolableValue& interpolable_value,
const NonInterpolableValue* non_interpolable_value,
StyleResolverState& state) const {
- std::unique_ptr<SVGPathByteStream> path_byte_stream =
- PathInterpolationFunctions::AppliedValue(interpolable_value,
- non_interpolable_value);
- if (path_byte_stream->IsEmpty()) {
- SetPath(CssProperty(), *state.Style(), nullptr);
- return;
- }
SetPath(CssProperty(), *state.Style(),
- StylePath::Create(std::move(path_byte_stream)));
+ PathInterpolationFunctions::AppliedValue(interpolable_value,
+ non_interpolable_value));
}
void CSSPathInterpolationType::Composite(
@@ -125,13 +125,13 @@
InterpolationValue CSSPathInterpolationType::MaybeConvertValue(
const CSSValue& value,
const StyleResolverState*,
- ConversionCheckers& conversion_checkers) const {
+ ConversionCheckers&) const {
auto* path_value = DynamicTo<cssvalue::CSSPathValue>(value);
- if (!path_value) {
+ if (!path_value)
return nullptr;
- }
+
return PathInterpolationFunctions::ConvertValue(
- path_value->ByteStream(), PathInterpolationFunctions::ForceAbsolute);
+ path_value->GetStylePath(), PathInterpolationFunctions::ForceAbsolute);
}
InterpolationValue
diff --git a/third_party/blink/renderer/core/animation/path_interpolation_functions.cc b/third_party/blink/renderer/core/animation/path_interpolation_functions.cc
index 4331bcc..f3d696942e 100644
--- a/third_party/blink/renderer/core/animation/path_interpolation_functions.cc
+++ b/third_party/blink/renderer/core/animation/path_interpolation_functions.cc
@@ -24,20 +24,26 @@
~SVGPathNonInterpolableValue() override = default;
static scoped_refptr<SVGPathNonInterpolableValue> Create(
- Vector<SVGPathSegType>& path_seg_types) {
- return base::AdoptRef(new SVGPathNonInterpolableValue(path_seg_types));
+ Vector<SVGPathSegType>& path_seg_types,
+ WindRule wind_rule = RULE_NONZERO) {
+ return base::AdoptRef(
+ new SVGPathNonInterpolableValue(path_seg_types, wind_rule));
}
const Vector<SVGPathSegType>& PathSegTypes() const { return path_seg_types_; }
+ WindRule GetWindRule() const { return wind_rule_; }
DECLARE_NON_INTERPOLABLE_VALUE_TYPE();
private:
- SVGPathNonInterpolableValue(Vector<SVGPathSegType>& path_seg_types) {
+ SVGPathNonInterpolableValue(Vector<SVGPathSegType>& path_seg_types,
+ WindRule wind_rule)
+ : wind_rule_(wind_rule) {
path_seg_types_.swap(path_seg_types);
}
Vector<SVGPathSegType> path_seg_types_;
+ WindRule wind_rule_;
};
DEFINE_NON_INTERPOLABLE_VALUE_TYPE(SVGPathNonInterpolableValue);
@@ -58,9 +64,12 @@
};
InterpolationValue PathInterpolationFunctions::ConvertValue(
- const SVGPathByteStream& byte_stream,
+ const StylePath* style_path,
CoordinateConversion coordinateConversion) {
- SVGPathByteStreamSource path_source(byte_stream);
+ if (!style_path)
+ return nullptr;
+
+ SVGPathByteStreamSource path_source(style_path->ByteStream());
wtf_size_t length = 0;
PathCoordinates current_coordinates;
Vector<std::unique_ptr<InterpolableValue>> interpolable_path_segs;
@@ -86,19 +95,9 @@
result->Set(kPathArgsIndex, std::move(path_args));
result->Set(kPathNeutralIndex, std::make_unique<InterpolableNumber>(0));
- return InterpolationValue(
- std::move(result), SVGPathNonInterpolableValue::Create(path_seg_types));
-}
-
-InterpolationValue PathInterpolationFunctions::ConvertValue(
- const StylePath* style_path,
- CoordinateConversion coordinateConversion) {
- if (style_path)
- return ConvertValue(style_path->ByteStream(), coordinateConversion);
-
- std::unique_ptr<SVGPathByteStream> empty_path =
- std::make_unique<SVGPathByteStream>();
- return ConvertValue(*empty_path, ForceAbsolute);
+ return InterpolationValue(std::move(result),
+ SVGPathNonInterpolableValue::Create(
+ path_seg_types, style_path->GetWindRule()));
}
class UnderlyingPathSegTypesChecker
@@ -108,13 +107,14 @@
static std::unique_ptr<UnderlyingPathSegTypesChecker> Create(
const InterpolationValue& underlying) {
- return base::WrapUnique(
- new UnderlyingPathSegTypesChecker(GetPathSegTypes(underlying)));
+ return base::WrapUnique(new UnderlyingPathSegTypesChecker(
+ GetPathSegTypes(underlying), GetWindRule(underlying)));
}
private:
- UnderlyingPathSegTypesChecker(const Vector<SVGPathSegType>& path_seg_types)
- : path_seg_types_(path_seg_types) {}
+ UnderlyingPathSegTypesChecker(const Vector<SVGPathSegType>& path_seg_types,
+ WindRule wind_rule)
+ : path_seg_types_(path_seg_types), wind_rule_(wind_rule) {}
static const Vector<SVGPathSegType>& GetPathSegTypes(
const InterpolationValue& underlying) {
@@ -122,12 +122,19 @@
.PathSegTypes();
}
+ static WindRule GetWindRule(const InterpolationValue& underlying) {
+ return To<SVGPathNonInterpolableValue>(*underlying.non_interpolable_value)
+ .GetWindRule();
+ }
+
bool IsValid(const InterpolationEnvironment&,
const InterpolationValue& underlying) const final {
- return path_seg_types_ == GetPathSegTypes(underlying);
+ return path_seg_types_ == GetPathSegTypes(underlying) &&
+ wind_rule_ == GetWindRule(underlying);
}
Vector<SVGPathSegType> path_seg_types_;
+ WindRule wind_rule_;
};
InterpolationValue PathInterpolationFunctions::MaybeConvertNeutral(
@@ -161,12 +168,15 @@
PairwiseInterpolationValue PathInterpolationFunctions::MaybeMergeSingles(
InterpolationValue&& start,
InterpolationValue&& end) {
- const Vector<SVGPathSegType>& start_types =
- To<SVGPathNonInterpolableValue>(*start.non_interpolable_value)
- .PathSegTypes();
- const Vector<SVGPathSegType>& end_types =
- To<SVGPathNonInterpolableValue>(*end.non_interpolable_value)
- .PathSegTypes();
+ auto& start_path =
+ To<SVGPathNonInterpolableValue>(*start.non_interpolable_value);
+ auto& end_path = To<SVGPathNonInterpolableValue>(*end.non_interpolable_value);
+
+ if (start_path.GetWindRule() != end_path.GetWindRule())
+ return nullptr;
+
+ const Vector<SVGPathSegType>& start_types = start_path.PathSegTypes();
+ const Vector<SVGPathSegType>& end_types = end_path.PathSegTypes();
if (start_types.size() == 0 || !PathSegTypesMatch(start_types, end_types))
return nullptr;
@@ -201,18 +211,23 @@
value.non_interpolable_value.get();
}
-std::unique_ptr<SVGPathByteStream> PathInterpolationFunctions::AppliedValue(
+scoped_refptr<StylePath> PathInterpolationFunctions::AppliedValue(
const InterpolableValue& interpolable_value,
const NonInterpolableValue* non_interpolable_value) {
std::unique_ptr<SVGPathByteStream> path_byte_stream =
std::make_unique<SVGPathByteStream>();
+
+ auto* non_interpolable_path_value =
+ To<SVGPathNonInterpolableValue>(non_interpolable_value);
InterpolatedSVGPathSource source(
To<InterpolableList>(
*To<InterpolableList>(interpolable_value).Get(kPathArgsIndex)),
- To<SVGPathNonInterpolableValue>(non_interpolable_value)->PathSegTypes());
+ non_interpolable_path_value->PathSegTypes());
SVGPathByteStreamBuilder builder(*path_byte_stream);
svg_path_parser::ParsePath(source, builder);
- return path_byte_stream;
+
+ return StylePath::Create(std::move(path_byte_stream),
+ non_interpolable_path_value->GetWindRule());
}
} // namespace blink
diff --git a/third_party/blink/renderer/core/animation/path_interpolation_functions.h b/third_party/blink/renderer/core/animation/path_interpolation_functions.h
index a545f023..dddce78 100644
--- a/third_party/blink/renderer/core/animation/path_interpolation_functions.h
+++ b/third_party/blink/renderer/core/animation/path_interpolation_functions.h
@@ -20,18 +20,14 @@
public:
enum CoordinateConversion { PreserveCoordinates, ForceAbsolute };
- static std::unique_ptr<SVGPathByteStream> AppliedValue(
- const InterpolableValue&,
- const NonInterpolableValue*);
+ static scoped_refptr<StylePath> AppliedValue(const InterpolableValue&,
+ const NonInterpolableValue*);
static void Composite(UnderlyingValueOwner&,
double underlying_fraction,
const InterpolationType&,
const InterpolationValue&);
- static InterpolationValue ConvertValue(const SVGPathByteStream&,
- CoordinateConversion);
-
static InterpolationValue ConvertValue(const StylePath*,
CoordinateConversion);
diff --git a/third_party/blink/renderer/core/animation/svg_path_interpolation_type.cc b/third_party/blink/renderer/core/animation/svg_path_interpolation_type.cc
index 7fa8e96..9c256e7 100644
--- a/third_party/blink/renderer/core/animation/svg_path_interpolation_type.cc
+++ b/third_party/blink/renderer/core/animation/svg_path_interpolation_type.cc
@@ -16,7 +16,7 @@
return nullptr;
return PathInterpolationFunctions::ConvertValue(
- To<SVGPath>(svg_value).ByteStream(),
+ To<SVGPath>(svg_value).GetStylePath(),
PathInterpolationFunctions::PreserveCoordinates);
}
diff --git a/third_party/blink/renderer/core/css/basic_shape_functions.cc b/third_party/blink/renderer/core/css/basic_shape_functions.cc
index f6418d3..0ab751f 100644
--- a/third_party/blink/renderer/core/css/basic_shape_functions.cc
+++ b/third_party/blink/renderer/core/css/basic_shape_functions.cc
@@ -32,6 +32,7 @@
#include "third_party/blink/renderer/core/css/css_basic_shape_values.h"
#include "third_party/blink/renderer/core/css/css_identifier_value.h"
#include "third_party/blink/renderer/core/css/css_numeric_literal_value.h"
+#include "third_party/blink/renderer/core/css/css_path_value.h"
#include "third_party/blink/renderer/core/css/css_primitive_value_mappings.h"
#include "third_party/blink/renderer/core/css/css_ray_value.h"
#include "third_party/blink/renderer/core/css/css_value_pair.h"
@@ -358,6 +359,9 @@
StyleRay::RaySize size = KeywordToRaySize(ray_value->Size().GetValueID());
bool contain = !!ray_value->Contain();
basic_shape = StyleRay::Create(angle, size, contain);
+ } else if (const auto* path_value =
+ DynamicTo<cssvalue::CSSPathValue>(basic_shape_value)) {
+ basic_shape = path_value->GetStylePath();
} else {
NOTREACHED();
}
diff --git a/third_party/blink/renderer/core/css/css_path_value.cc b/third_party/blink/renderer/core/css/css_path_value.cc
index 3c1ae0b..d4f7425 100644
--- a/third_party/blink/renderer/core/css/css_path_value.cc
+++ b/third_party/blink/renderer/core/css/css_path_value.cc
@@ -8,6 +8,7 @@
#include "third_party/blink/renderer/core/style/style_path.h"
#include "third_party/blink/renderer/core/svg/svg_path_utilities.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
+#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
namespace blink {
@@ -22,8 +23,9 @@
}
CSSPathValue::CSSPathValue(std::unique_ptr<SVGPathByteStream> path_byte_stream,
+ WindRule wind_rule,
PathSerializationFormat serialization_format)
- : CSSPathValue(StylePath::Create(std::move(path_byte_stream)),
+ : CSSPathValue(StylePath::Create(std::move(path_byte_stream), wind_rule),
serialization_format) {}
namespace {
@@ -45,8 +47,14 @@
}
String CSSPathValue::CustomCSSText() const {
- return "path(\"" +
- BuildStringFromByteStream(ByteStream(), serialization_format_) + "\")";
+ StringBuilder result;
+ result.Append("path(");
+ if (style_path_->GetWindRule() == RULE_EVENODD)
+ result.Append("evenodd, ");
+ result.Append("\"");
+ result.Append(BuildStringFromByteStream(ByteStream(), serialization_format_));
+ result.Append("\")");
+ return result.ToString();
}
bool CSSPathValue::Equals(const CSSPathValue& other) const {
diff --git a/third_party/blink/renderer/core/css/css_path_value.h b/third_party/blink/renderer/core/css/css_path_value.h
index ee3d8128..2642b31 100644
--- a/third_party/blink/renderer/core/css/css_path_value.h
+++ b/third_party/blink/renderer/core/css/css_path_value.h
@@ -26,6 +26,7 @@
explicit CSSPathValue(scoped_refptr<StylePath>,
PathSerializationFormat = kNoTransformation);
explicit CSSPathValue(std::unique_ptr<SVGPathByteStream>,
+ WindRule wind_rule = RULE_NONZERO,
PathSerializationFormat = kNoTransformation);
StylePath* GetStylePath() const { return style_path_.get(); }
diff --git a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
index c9dd2a0..a72cce67 100644
--- a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
+++ b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
@@ -4386,7 +4386,43 @@
return false;
}
-CSSValue* ConsumePath(CSSParserTokenRange& range) {
+std::unique_ptr<SVGPathByteStream> ConsumePathStringArg(
+ CSSParserTokenRange& args) {
+ if (args.Peek().GetType() != kStringToken)
+ return nullptr;
+
+ StringView path_string = args.ConsumeIncludingWhitespace().Value();
+ std::unique_ptr<SVGPathByteStream> byte_stream =
+ std::make_unique<SVGPathByteStream>();
+ if (BuildByteStreamFromString(path_string, *byte_stream) !=
+ SVGParseStatus::kNoError) {
+ return nullptr;
+ }
+
+ return byte_stream;
+}
+
+cssvalue::CSSPathValue* ConsumeBasicShapePath(CSSParserTokenRange& args) {
+ auto wind_rule = RULE_NONZERO;
+
+ if (IdentMatches<CSSValueID::kEvenodd, CSSValueID::kNonzero>(
+ args.Peek().Id())) {
+ wind_rule = args.ConsumeIncludingWhitespace().Id() == CSSValueID::kEvenodd
+ ? RULE_EVENODD
+ : RULE_NONZERO;
+ if (!ConsumeCommaIncludingWhitespace(args))
+ return nullptr;
+ }
+
+ auto byte_stream = ConsumePathStringArg(args);
+ if (!byte_stream || !args.AtEnd())
+ return nullptr;
+
+ return MakeGarbageCollected<cssvalue::CSSPathValue>(std::move(byte_stream),
+ wind_rule);
+}
+
+CSSValue* ConsumePathFunction(CSSParserTokenRange& range) {
// FIXME: Add support for <url>, <basic-shape>, <geometry-box>.
if (range.Peek().FunctionId() != CSSValueID::kPath)
return nullptr;
@@ -4394,16 +4430,9 @@
CSSParserTokenRange function_range = range;
CSSParserTokenRange function_args = ConsumeFunction(function_range);
- if (function_args.Peek().GetType() != kStringToken)
+ auto byte_stream = ConsumePathStringArg(function_args);
+ if (!byte_stream || !function_args.AtEnd())
return nullptr;
- StringView path_string = function_args.ConsumeIncludingWhitespace().Value();
- std::unique_ptr<SVGPathByteStream> byte_stream =
- std::make_unique<SVGPathByteStream>();
- if (BuildByteStreamFromString(path_string, *byte_stream) !=
- SVGParseStatus::kNoError ||
- !function_args.AtEnd()) {
- return nullptr;
- }
range = function_range;
if (byte_stream->IsEmpty())
@@ -4505,7 +4534,7 @@
if (id == CSSValueID::kNone)
return ConsumeIdent(range);
- return ConsumePath(range);
+ return ConsumePathFunction(range);
}
CSSValue* ConsumeOffsetRotate(CSSParserTokenRange& range,
@@ -4574,7 +4603,8 @@
}
CSSValue* ConsumeBasicShape(CSSParserTokenRange& range,
- const CSSParserContext& context) {
+ const CSSParserContext& context,
+ AllowPathValue allow_path) {
CSSValue* shape = nullptr;
if (range.Peek().GetType() != kFunctionToken)
return nullptr;
@@ -4589,6 +4619,8 @@
shape = ConsumeBasicShapePolygon(args, context);
else if (id == CSSValueID::kInset)
shape = ConsumeBasicShapeInset(args, context);
+ else if (id == CSSValueID::kPath && allow_path == AllowPathValue::kAllow)
+ shape = ConsumeBasicShapePath(args);
if (!shape || !args.AtEnd())
return nullptr;
diff --git a/third_party/blink/renderer/core/css/properties/css_parsing_utils.h b/third_party/blink/renderer/core/css/properties/css_parsing_utils.h
index b051a17..543a8615 100644
--- a/third_party/blink/renderer/core/css/properties/css_parsing_utils.h
+++ b/third_party/blink/renderer/core/css/properties/css_parsing_utils.h
@@ -45,6 +45,7 @@
enum class AllowInsetAndSpread { kAllow, kForbid };
enum class AllowTextValue { kAllow, kForbid };
+enum class AllowPathValue { kAllow, kForbid };
enum class DefaultFill { kFill, kNoFill };
enum class ParsingStyle { kLegacy, kNotLegacy };
enum class TrackListType { kGridTemplate, kGridTemplateNoRepeat, kGridAuto };
@@ -416,7 +417,9 @@
CSSValue* ConsumePathOrNone(CSSParserTokenRange&);
CSSValue* ConsumeOffsetRotate(CSSParserTokenRange&, const CSSParserContext&);
-CSSValue* ConsumeBasicShape(CSSParserTokenRange&, const CSSParserContext&);
+CSSValue* ConsumeBasicShape(CSSParserTokenRange&,
+ const CSSParserContext&,
+ AllowPathValue);
bool ConsumeRadii(CSSValue* horizontal_radii[4],
CSSValue* vertical_radii[4],
CSSParserTokenRange&,
diff --git a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
index f7cdcad..41e88676 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
@@ -1455,7 +1455,8 @@
if (cssvalue::CSSURIValue* url =
css_parsing_utils::ConsumeUrl(range, context))
return url;
- return css_parsing_utils::ConsumeBasicShape(range, context);
+ return css_parsing_utils::ConsumeBasicShape(
+ range, context, css_parsing_utils::AllowPathValue::kAllow);
}
const CSSValue* ClipPath::CSSValueFromComputedStyleInternal(
@@ -5791,8 +5792,8 @@
return image_value;
CSSValueList* list = CSSValueList::CreateSpaceSeparated();
CSSValue* box_value = css_parsing_utils::ConsumeShapeBox(range);
- if (CSSValue* shape_value =
- css_parsing_utils::ConsumeBasicShape(range, context)) {
+ if (CSSValue* shape_value = css_parsing_utils::ConsumeBasicShape(
+ range, context, css_parsing_utils::AllowPathValue::kForbid)) {
list->Append(*shape_value);
if (!box_value) {
box_value = css_parsing_utils::ConsumeShapeBox(range);
diff --git a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
index df82a83a..35eb45c 100644
--- a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
@@ -147,8 +147,9 @@
scoped_refptr<ClipPathOperation> StyleBuilderConverter::ConvertClipPath(
StyleResolverState& state,
const CSSValue& value) {
- if (value.IsBasicShapeValue())
+ if (value.IsBasicShapeValue() || value.IsPathValue())
return ShapeClipPathOperation::Create(BasicShapeForValue(state, value));
+
if (const auto* url_value = DynamicTo<cssvalue::CSSURIValue>(value)) {
SVGResource* resource =
state.GetElementStyleResources().GetSVGResourceFromValue(
diff --git a/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc b/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc
index f002404..27e3f04 100644
--- a/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc
+++ b/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc
@@ -453,7 +453,7 @@
if (clip_path_operation->GetType() == ClipPathOperation::SHAPE) {
ShapeClipPathOperation& clip_path =
To<ShapeClipPathOperation>(*clip_path_operation);
- return clip_path.GetPath(reference_box)
+ return clip_path.GetPath(reference_box, 1)
.Contains(location.TransformedPoint());
}
DCHECK_EQ(clip_path_operation->GetType(), ClipPathOperation::REFERENCE);
diff --git a/third_party/blink/renderer/core/paint/clip_path_clipper.cc b/third_party/blink/renderer/core/paint/clip_path_clipper.cc
index cd34316..efe54d6 100644
--- a/third_party/blink/renderer/core/paint/clip_path_clipper.cc
+++ b/third_party/blink/renderer/core/paint/clip_path_clipper.cc
@@ -75,7 +75,9 @@
ShapeClipPathOperation& shape = To<ShapeClipPathOperation>(clip_path);
if (!shape.IsValid())
return base::nullopt;
- FloatRect bounding_box = shape.GetPath(reference_box).BoundingRect();
+ auto zoom =
+ UsesZoomedReferenceBox(object) ? object.StyleRef().EffectiveZoom() : 1;
+ FloatRect bounding_box = shape.GetPath(reference_box, zoom).BoundingRect();
bounding_box.Intersect(LayoutRect::InfiniteIntRect());
return bounding_box;
}
@@ -160,7 +162,10 @@
DCHECK_EQ(clip_path.GetType(), ClipPathOperation::SHAPE);
auto& shape = To<ShapeClipPathOperation>(clip_path);
- return shape.GetPath(reference_box);
+ float zoom = uses_zoomed_reference_box
+ ? clip_path_owner.StyleRef().EffectiveZoom()
+ : 1;
+ return shape.GetPath(reference_box, zoom);
}
void ClipPathClipper::PaintClipPathAsMaskImage(
diff --git a/third_party/blink/renderer/core/paint/paint_layer.cc b/third_party/blink/renderer/core/paint/paint_layer.cc
index 32f79ae..d99f1d0d 100644
--- a/third_party/blink/renderer/core/paint/paint_layer.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -2544,7 +2544,10 @@
if (clip_path_operation->GetType() == ClipPathOperation::SHAPE) {
ShapeClipPathOperation* clip_path =
To<ShapeClipPathOperation>(clip_path_operation);
- return !clip_path->GetPath(reference_box).Contains(point);
+ return !clip_path
+ ->GetPath(reference_box,
+ GetLayoutObject().StyleRef().EffectiveZoom())
+ .Contains(point);
}
DCHECK_EQ(clip_path_operation->GetType(), ClipPathOperation::REFERENCE);
LayoutSVGResourceClipper* clipper = GetSVGResourceAsType(clip_path_operation);
diff --git a/third_party/blink/renderer/core/style/basic_shapes.cc b/third_party/blink/renderer/core/style/basic_shapes.cc
index a2abd9c..a847bfc 100644
--- a/third_party/blink/renderer/core/style/basic_shapes.cc
+++ b/third_party/blink/renderer/core/style/basic_shapes.cc
@@ -64,7 +64,9 @@
std::max(center.Y(), height_delta));
}
-void BasicShapeCircle::GetPath(Path& path, const FloatRect& bounding_box) {
+void BasicShapeCircle::GetPath(Path& path,
+ const FloatRect& bounding_box,
+ float) {
DCHECK(path.IsEmpty());
FloatPoint center =
FloatPointForCenterCoordinate(center_x_, center_y_, bounding_box.Size());
@@ -97,7 +99,9 @@
return std::max(center, width_or_height_delta);
}
-void BasicShapeEllipse::GetPath(Path& path, const FloatRect& bounding_box) {
+void BasicShapeEllipse::GetPath(Path& path,
+ const FloatRect& bounding_box,
+ float) {
DCHECK(path.IsEmpty());
FloatPoint center =
FloatPointForCenterCoordinate(center_x_, center_y_, bounding_box.Size());
@@ -110,7 +114,9 @@
radius_x * 2, radius_y * 2));
}
-void BasicShapePolygon::GetPath(Path& path, const FloatRect& bounding_box) {
+void BasicShapePolygon::GetPath(Path& path,
+ const FloatRect& bounding_box,
+ float) {
DCHECK(path.IsEmpty());
DCHECK(!(values_.size() % 2));
wtf_size_t length = values_.size();
@@ -140,7 +146,9 @@
return wind_rule_ == other.wind_rule_ && values_ == other.values_;
}
-void BasicShapeInset::GetPath(Path& path, const FloatRect& bounding_box) {
+void BasicShapeInset::GetPath(Path& path,
+ const FloatRect& bounding_box,
+ float) {
DCHECK(path.IsEmpty());
float left = FloatValueForLength(left_, bounding_box.Width());
float top = FloatValueForLength(top_, bounding_box.Height());
diff --git a/third_party/blink/renderer/core/style/basic_shapes.h b/third_party/blink/renderer/core/style/basic_shapes.h
index d73aa6e..c7ec083 100644
--- a/third_party/blink/renderer/core/style/basic_shapes.h
+++ b/third_party/blink/renderer/core/style/basic_shapes.h
@@ -65,7 +65,7 @@
return GetType() == other.GetType();
}
- virtual void GetPath(Path&, const FloatRect&) = 0;
+ virtual void GetPath(Path&, const FloatRect&, float zoom) = 0;
virtual WindRule GetWindRule() const { return RULE_NONZERO; }
virtual bool operator==(const BasicShape&) const = 0;
@@ -146,7 +146,7 @@
void SetCenterY(BasicShapeCenterCoordinate center_y) { center_y_ = center_y; }
void SetRadius(BasicShapeRadius radius) { radius_ = radius; }
- void GetPath(Path&, const FloatRect&) override;
+ void GetPath(Path&, const FloatRect&, float) override;
bool operator==(const BasicShape&) const override;
ShapeType GetType() const override { return kBasicShapeCircleType; }
@@ -185,7 +185,7 @@
void SetRadiusX(BasicShapeRadius radius_x) { radius_x_ = radius_x; }
void SetRadiusY(BasicShapeRadius radius_y) { radius_y_ = radius_y; }
- void GetPath(Path&, const FloatRect&) override;
+ void GetPath(Path&, const FloatRect&, float) override;
bool operator==(const BasicShape&) const override;
ShapeType GetType() const override { return kBasicShapeEllipseType; }
@@ -220,7 +220,7 @@
values_.push_back(y);
}
- void GetPath(Path&, const FloatRect&) override;
+ void GetPath(Path&, const FloatRect&, float) override;
bool operator==(const BasicShape&) const override;
WindRule GetWindRule() const override { return wind_rule_; }
@@ -273,7 +273,7 @@
bottom_left_radius_ = radius;
}
- void GetPath(Path&, const FloatRect&) override;
+ void GetPath(Path&, const FloatRect&, float) override;
bool operator==(const BasicShape&) const override;
ShapeType GetType() const override { return kBasicShapeInsetType; }
diff --git a/third_party/blink/renderer/core/style/shape_clip_path_operation.h b/third_party/blink/renderer/core/style/shape_clip_path_operation.h
index 03d4c447..ae51942 100644
--- a/third_party/blink/renderer/core/style/shape_clip_path_operation.h
+++ b/third_party/blink/renderer/core/style/shape_clip_path_operation.h
@@ -45,10 +45,10 @@
const BasicShape* GetBasicShape() const { return shape_.get(); }
bool IsValid() const { return shape_.get(); }
- Path GetPath(const FloatRect& bounding_rect) const {
+ Path GetPath(const FloatRect& bounding_rect, float zoom) const {
DCHECK(shape_);
Path path;
- shape_->GetPath(path, bounding_rect);
+ shape_->GetPath(path, bounding_rect, zoom);
path.SetWindRule(shape_->GetWindRule());
return path;
}
diff --git a/third_party/blink/renderer/core/style/style_path.cc b/third_party/blink/renderer/core/style/style_path.cc
index 41ccc527..4bcf5b2a 100644
--- a/third_party/blink/renderer/core/style/style_path.cc
+++ b/third_party/blink/renderer/core/style/style_path.cc
@@ -13,20 +13,24 @@
#include "third_party/blink/renderer/core/svg/svg_path_utilities.h"
#include "third_party/blink/renderer/platform/graphics/path.h"
#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/transforms/affine_transform.h"
namespace blink {
-StylePath::StylePath(std::unique_ptr<SVGPathByteStream> path_byte_stream)
+StylePath::StylePath(std::unique_ptr<SVGPathByteStream> path_byte_stream,
+ WindRule wind_rule)
: byte_stream_(std::move(path_byte_stream)),
- path_length_(std::numeric_limits<float>::quiet_NaN()) {
+ path_length_(std::numeric_limits<float>::quiet_NaN()),
+ wind_rule_(wind_rule) {
DCHECK(byte_stream_);
}
StylePath::~StylePath() = default;
scoped_refptr<StylePath> StylePath::Create(
- std::unique_ptr<SVGPathByteStream> path_byte_stream) {
- return base::AdoptRef(new StylePath(std::move(path_byte_stream)));
+ std::unique_ptr<SVGPathByteStream> path_byte_stream,
+ WindRule wind_rule) {
+ return base::AdoptRef(new StylePath(std::move(path_byte_stream), wind_rule));
}
const StylePath* StylePath::EmptyPath() {
@@ -62,12 +66,13 @@
if (!IsSameType(o))
return false;
const StylePath& other = To<StylePath>(o);
- return *byte_stream_ == *other.byte_stream_;
+ return wind_rule_ == other.wind_rule_ && *byte_stream_ == *other.byte_stream_;
}
-void StylePath::GetPath(Path&, const FloatRect&) {
- // Callers should use GetPath() overload, which avoids making a copy.
- NOTREACHED();
+void StylePath::GetPath(Path& path, const FloatRect& offset_rect, float zoom) {
+ path = GetPath();
+ path.Transform(AffineTransform::Translation(offset_rect.X(), offset_rect.Y())
+ .Scale(zoom));
}
} // namespace blink
diff --git a/third_party/blink/renderer/core/style/style_path.h b/third_party/blink/renderer/core/style/style_path.h
index b25f308..52d7b300 100644
--- a/third_party/blink/renderer/core/style/style_path.h
+++ b/third_party/blink/renderer/core/style/style_path.h
@@ -18,7 +18,8 @@
class StylePath final : public BasicShape {
public:
- static scoped_refptr<StylePath> Create(std::unique_ptr<SVGPathByteStream>);
+ static scoped_refptr<StylePath> Create(std::unique_ptr<SVGPathByteStream>,
+ WindRule wind_rule = RULE_NONZERO);
~StylePath() override;
static const StylePath* EmptyPath();
@@ -31,17 +32,20 @@
CSSValue* ComputedCSSValue() const;
- void GetPath(Path&, const FloatRect&) override;
+ void GetPath(Path&, const FloatRect&, float zoom) override;
+ WindRule GetWindRule() const override { return wind_rule_; }
+
bool operator==(const BasicShape&) const override;
ShapeType GetType() const override { return kStylePathType; }
private:
- explicit StylePath(std::unique_ptr<SVGPathByteStream>);
+ explicit StylePath(std::unique_ptr<SVGPathByteStream>, WindRule wind_rule);
std::unique_ptr<SVGPathByteStream> byte_stream_;
mutable std::unique_ptr<Path> path_;
mutable float path_length_;
+ WindRule wind_rule_;
};
template <>
diff --git a/third_party/blink/renderer/core/style/style_ray.cc b/third_party/blink/renderer/core/style/style_ray.cc
index 3d6b5d6a..b8dc0fa 100644
--- a/third_party/blink/renderer/core/style/style_ray.cc
+++ b/third_party/blink/renderer/core/style/style_ray.cc
@@ -25,7 +25,7 @@
contain_ == other.contain_;
}
-void StyleRay::GetPath(Path&, const FloatRect&) {
+void StyleRay::GetPath(Path&, const FloatRect&, float) {
// ComputedStyle::ApplyMotionPathTransform cannot call GetPath
// for rays as they may have infinite length.
NOTREACHED();
diff --git a/third_party/blink/renderer/core/style/style_ray.h b/third_party/blink/renderer/core/style/style_ray.h
index 636b4d6..7e3dd53 100644
--- a/third_party/blink/renderer/core/style/style_ray.h
+++ b/third_party/blink/renderer/core/style/style_ray.h
@@ -27,7 +27,7 @@
RaySize Size() const { return size_; }
bool Contain() const { return contain_; }
- void GetPath(Path&, const FloatRect&) override;
+ void GetPath(Path&, const FloatRect&, float) override;
bool operator==(const BasicShape&) const override;
ShapeType GetType() const override { return kStyleRayType; }
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 2f6d8d5..e30501f 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -2960,11 +2960,7 @@
crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-display-rendering.html [ Failure ]
crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-tall.html [ Failure ]
crbug.com/626703 external/wpt/speech-api/SpeechSynthesis-pause-resume.tentative.html [ Timeout ]
-crbug.com/880983 external/wpt/css/css-masking/clip-path/clip-path-path-interpolation-001.html [ Failure ]
-crbug.com/880983 external/wpt/css/css-masking/clip-path/clip-path-path-interpolation-002.html [ Failure ]
crbug.com/891944 external/wpt/css/css-scrollbars/textarea-scrollbar-width-none.html [ Failure ]
-crbug.com/880983 external/wpt/css/css-masking/clip-path/clip-path-path-002.html [ Failure ]
-crbug.com/880983 external/wpt/css/css-masking/clip-path/clip-path-path-001.html [ Failure ]
crbug.com/432153 external/wpt/css/css-masking/mask-image/mask-image-url-local-mask.html [ Failure ]
crbug.com/432153 external/wpt/css/css-masking/mask-image/mask-image-url-image.html [ Failure ]
crbug.com/432153 external/wpt/css/css-masking/mask-image/mask-image-url-remote-mask.html [ Failure ]
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-path-interpolation-with-zoom.html b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-path-interpolation-with-zoom.html
new file mode 100644
index 0000000..4d54708
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-path-interpolation-with-zoom.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+ <title>CSS Masking: Test clip-path nonzero path interpolation with zoom</title>
+ <link rel="help" href="https://drafts.csswg.org/css-shapes-2/#funcdef-path">
+ <link rel="match" href="reference/clip-path-path-interpolation-with-zoom-ref.html">
+ <meta name="assert" content="The clip-path property takes the basic shape
+ 'path()' for clipping. Test the interpolation of nonzero
+ path function.">
+ <style>
+ @keyframes anim {
+ from {
+ clip-path: path(nonzero, 'M20,20h60 v60 h-60z M30,30 h40 v40 h-40z');
+ }
+ to {
+ clip-path: path(nonzero, 'M50,50h50 v50 h-50z M20,20 h50 v50 h-50z');
+ }
+ }
+ #rect {
+ width: 100px;
+ zoom: 3;
+ height: 100px;
+ background-color: green;
+ animation: anim 10s -5s paused linear;
+ }
+ </style>
+ <div id="rect"></div>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-path-with-zoom-hittest.html b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-path-with-zoom-hittest.html
new file mode 100644
index 0000000..30ceefcb
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-path-with-zoom-hittest.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<title>CSS Masking: Test clip-path property hit-testing when the page is zoomed</title>
+<link rel="author" title="Noam Rosenthal" href="mailto:noam@webkit.org">
+<link rel="help" href="https://drafts.csswg.org/css-shapes-2/#funcdef-path">
+<meta name="assert" content="The zoomed path is hit-tested correctly">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+ #triangle {
+ width: 100px;
+ height: 100px;
+ background-color: green;
+ clip-path: path(nonzero, 'M0 0, L100 0, L0 100, L 0 0');
+ zoom: 2;
+ }
+</style>
+<div id="triangle"></div>
+<script>
+ test(() => {
+ assert_equals(document.elementFromPoint(20, 20).id, 'triangle')
+ assert_equals(document.elementFromPoint(150, 20).id, 'triangle')
+ assert_equals(document.elementFromPoint(180, 180).tagName, 'BODY')
+ }, 'clip-path: path() hit-test takes zoom into account');
+
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-path-with-zoom.html b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-path-with-zoom.html
new file mode 100644
index 0000000..5879917f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-path-with-zoom.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<title>CSS Masking: Test clip-path property when the page is zoomed</title>
+<link rel="author" title="Noam Rosenthal" href="mailto:noam@webkit.org">
+<link rel="help" href="https://drafts.csswg.org/css-shapes-2/#funcdef-path">
+<link rel="match" href="reference/clip-path-path-with-zoom-ref.html">
+<meta name="assert" content="The path gets zoomed together with the content">
+<style>
+ #red {
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ background: red;
+ }
+ #rect {
+ width: 100px;
+ height: 100px;
+ background-color: green;
+ clip-path: path(nonzero, 'M0 0, L100 0, L0 100, L 0 0');
+ zoom: 2;
+ }
+</style>
+<div id="red"></div>
+<div id="rect"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/reference/clip-path-path-interpolation-with-zoom-ref.html b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/reference/clip-path-path-interpolation-with-zoom-ref.html
new file mode 100644
index 0000000..7e0d2a54
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/reference/clip-path-path-interpolation-with-zoom-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<title>CSS Masking: Test clip-path nonzero path interpolation with zoom</title>
+<style type="text/css">
+ #rect {
+ width: 300px;
+ height: 300px;
+ background-color: green;
+ clip-path: path('M105,105 H270 V270 H105Z M75,75 H210 V210 H75Z');
+ }
+
+</style>
+<div id="rect"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/reference/clip-path-path-with-zoom-ref.html b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/reference/clip-path-path-with-zoom-ref.html
new file mode 100644
index 0000000..ef91c619
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/reference/clip-path-path-with-zoom-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+ <title>CSS Masking: Test clip-path property when the page is zoomed</title>
+ <style>
+ #rect {
+ width: 200px;
+ height: 200px;
+ background: green;
+ clip-path: path(nonzero, 'M0 0, L200 0, L0 200');
+ }
+ </style>
+ <div id="rect"></div>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/parsing/clip-path-valid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-masking/parsing/clip-path-valid-expected.txt
index 1646361..60c4fb0 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-masking/parsing/clip-path-valid-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/parsing/clip-path-valid-expected.txt
@@ -23,11 +23,11 @@
PASS e.style['clip-path'] = "polygon(1% 2%)" should set the property value
PASS e.style['clip-path'] = "polygon(nonzero, 1px 2px, 3em 4em)" should set the property value
PASS e.style['clip-path'] = "polygon(evenodd, 1px 2px, 3em 4em, 5pt 6%)" should set the property value
-FAIL e.style['clip-path'] = "path(\"m 20 0 h -100\")" should set the property value assert_not_equals: property should be set got disallowed value ""
-FAIL e.style['clip-path'] = "path(evenodd, \"M 20 20 h 60 v 60 h -60 Z M 30 30 h 40 v 40 h -40 Z\")" should set the property value assert_not_equals: property should be set got disallowed value ""
-FAIL e.style['clip-path'] = "path(nonzero, \"M20,20h60 v60 h-60z M30,30 h40 v40 h-40z\")" should set the property value assert_not_equals: property should be set got disallowed value ""
-FAIL e.style['clip-path'] = "path(\" \")" should set the property value assert_not_equals: property should be set got disallowed value ""
-FAIL e.style['clip-path'] = "path(evenodd, \"\")" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['clip-path'] = "path(\"m 20 0 h -100\")" should set the property value
+PASS e.style['clip-path'] = "path(evenodd, \"M 20 20 h 60 v 60 h -60 Z M 30 30 h 40 v 40 h -40 Z\")" should set the property value
+PASS e.style['clip-path'] = "path(nonzero, \"M20,20h60 v60 h-60z M30,30 h40 v40 h-40z\")" should set the property value
+PASS e.style['clip-path'] = "path(\" \")" should set the property value
+PASS e.style['clip-path'] = "path(evenodd, \"\")" should set the property value
FAIL e.style['clip-path'] = "border-box" should set the property value assert_not_equals: property should be set got disallowed value ""
FAIL e.style['clip-path'] = "padding-box" should set the property value assert_not_equals: property should be set got disallowed value ""
FAIL e.style['clip-path'] = "content-box" should set the property value assert_not_equals: property should be set got disallowed value ""