Skip to content

Commit

Permalink
Implement clip-path: path()
Browse files Browse the repository at this point in the history
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}
  • Loading branch information
noamr authored and Commit Bot committed Oct 15, 2020
1 parent ac07b98 commit c9ee825
Show file tree
Hide file tree
Showing 31 changed files with 314 additions and 115 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,9 @@ InterpolationValue basic_shape_interpolation_functions::MaybeConvertBasicShape(
case BasicShape::kBasicShapePolygonType:
return polygon_functions::ConvertBasicShape(To<BasicShapePolygon>(*shape),
zoom);
// Handled by PathInterpolationFunction.
case BasicShape::kStylePathType:
return nullptr;
default:
NOTREACHED();
return nullptr;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,21 @@ const BasicShape* GetBasicShape(const CSSProperty& property,
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;
auto* shape = clip_path_operation->GetBasicShape();

// Path shape is handled by PathInterpolationType.
if (shape->GetType() == BasicShape::kStylePathType)
return nullptr;
return To<ShapeClipPathOperation>(style.ClipPath())->GetBasicShape();

return shape;
}
default:
NOTREACHED();
return nullptr;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,11 @@ const InterpolationTypes& CSSInterpolationTypesMap::Get(
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));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand All @@ -24,11 +25,13 @@ const StylePath* GetPath(const CSSProperty& property,
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();
Expand All @@ -47,6 +50,9 @@ void SetPath(const CSSProperty& property,
case CSSPropertyID::kOffsetPath:
style.SetOffsetPath(std::move(path));
return;
case CSSPropertyID::kClipPath:
style.SetClipPath(ShapeClipPathOperation::Create(std::move(path)));
return;
default:
NOTREACHED();
return;
Expand All @@ -59,15 +65,9 @@ void CSSPathInterpolationType::ApplyStandardPropertyValue(
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(
Expand Down Expand Up @@ -125,13 +125,13 @@ InterpolationValue CSSPathInterpolationType::MaybeConvertInherit(
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,26 @@ class SVGPathNonInterpolableValue : public NonInterpolableValue {
~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);
Expand All @@ -58,9 +64,12 @@ enum PathComponentIndex : unsigned {
};

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;
Expand All @@ -86,19 +95,9 @@ InterpolationValue PathInterpolationFunctions::ConvertValue(
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
Expand All @@ -108,26 +107,34 @@ class UnderlyingPathSegTypesChecker

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) {
return To<SVGPathNonInterpolableValue>(*underlying.non_interpolable_value)
.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(
Expand Down Expand Up @@ -161,12 +168,15 @@ static bool PathSegTypesMatch(const Vector<SVGPathSegType>& a,
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;

Expand Down Expand Up @@ -201,18 +211,23 @@ void PathInterpolationFunctions::Composite(
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
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,14 @@ class PathInterpolationFunctions {
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);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ InterpolationValue SVGPathInterpolationType::MaybeConvertSVGValue(
return nullptr;

return PathInterpolationFunctions::ConvertValue(
To<SVGPath>(svg_value).ByteStream(),
To<SVGPath>(svg_value).GetStylePath(),
PathInterpolationFunctions::PreserveCoordinates);
}

Expand Down
4 changes: 4 additions & 0 deletions third_party/blink/renderer/core/css/basic_shape_functions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -358,6 +359,9 @@ scoped_refptr<BasicShape> BasicShapeForValue(
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();
}
Expand Down
14 changes: 11 additions & 3 deletions third_party/blink/renderer/core/css/css_path_value.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand All @@ -22,8 +23,9 @@ CSSPathValue::CSSPathValue(scoped_refptr<StylePath> style_path,
}

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 {
Expand All @@ -45,8 +47,14 @@ CSSPathValue& CSSPathValue::EmptyPathValue() {
}

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 {
Expand Down
1 change: 1 addition & 0 deletions third_party/blink/renderer/core/css/css_path_value.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class CSSPathValue : public CSSValue {
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(); }
Expand Down
Loading

0 comments on commit c9ee825

Please sign in to comment.