blob: f3d696942e390cc2ec2e13e1722c41bdbbf0bd05 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/core/animation/path_interpolation_functions.h"
#include <memory>
#include <utility>
#include "base/memory/ptr_util.h"
#include "third_party/blink/renderer/core/animation/interpolated_svg_path_source.h"
#include "third_party/blink/renderer/core/animation/interpolation_environment.h"
#include "third_party/blink/renderer/core/animation/svg_path_seg_interpolation_functions.h"
#include "third_party/blink/renderer/core/css/css_path_value.h"
#include "third_party/blink/renderer/core/svg/svg_path.h"
#include "third_party/blink/renderer/core/svg/svg_path_byte_stream_builder.h"
#include "third_party/blink/renderer/core/svg/svg_path_byte_stream_source.h"
#include "third_party/blink/renderer/core/svg/svg_path_parser.h"
namespace blink {
class SVGPathNonInterpolableValue : public NonInterpolableValue {
public:
~SVGPathNonInterpolableValue() override = default;
static scoped_refptr<SVGPathNonInterpolableValue> Create(
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,
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);
template <>
struct DowncastTraits<SVGPathNonInterpolableValue> {
static bool AllowFrom(const NonInterpolableValue* value) {
return value && AllowFrom(*value);
}
static bool AllowFrom(const NonInterpolableValue& value) {
return value.GetType() == SVGPathNonInterpolableValue::static_type_;
}
};
enum PathComponentIndex : unsigned {
kPathArgsIndex,
kPathNeutralIndex,
kPathComponentIndexCount,
};
InterpolationValue PathInterpolationFunctions::ConvertValue(
const StylePath* style_path,
CoordinateConversion coordinateConversion) {
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;
Vector<SVGPathSegType> path_seg_types;
while (path_source.HasMoreData()) {
const PathSegmentData segment = path_source.ParseSegment();
interpolable_path_segs.push_back(
SVGPathSegInterpolationFunctions::ConsumePathSeg(segment,
current_coordinates));
SVGPathSegType seg_type = segment.command;
if (coordinateConversion == ForceAbsolute)
seg_type = ToAbsolutePathSegType(seg_type);
path_seg_types.push_back(seg_type);
length++;
}
auto path_args = std::make_unique<InterpolableList>(length);
for (wtf_size_t i = 0; i < interpolable_path_segs.size(); i++)
path_args->Set(i, std::move(interpolable_path_segs[i]));
auto result = std::make_unique<InterpolableList>(kPathComponentIndexCount);
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, style_path->GetWindRule()));
}
class UnderlyingPathSegTypesChecker
: public InterpolationType::ConversionChecker {
public:
~UnderlyingPathSegTypesChecker() final = default;
static std::unique_ptr<UnderlyingPathSegTypesChecker> Create(
const InterpolationValue& underlying) {
return base::WrapUnique(new UnderlyingPathSegTypesChecker(
GetPathSegTypes(underlying), GetWindRule(underlying)));
}
private:
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) &&
wind_rule_ == GetWindRule(underlying);
}
Vector<SVGPathSegType> path_seg_types_;
WindRule wind_rule_;
};
InterpolationValue PathInterpolationFunctions::MaybeConvertNeutral(
const InterpolationValue& underlying,
InterpolationType::ConversionCheckers& conversion_checkers) {
conversion_checkers.push_back(
UnderlyingPathSegTypesChecker::Create(underlying));
auto result = std::make_unique<InterpolableList>(kPathComponentIndexCount);
result->Set(kPathArgsIndex,
To<InterpolableList>(*underlying.interpolable_value)
.Get(kPathArgsIndex)
->CloneAndZero());
result->Set(kPathNeutralIndex, std::make_unique<InterpolableNumber>(1));
return InterpolationValue(std::move(result),
underlying.non_interpolable_value.get());
}
static bool PathSegTypesMatch(const Vector<SVGPathSegType>& a,
const Vector<SVGPathSegType>& b) {
if (a.size() != b.size())
return false;
for (wtf_size_t i = 0; i < a.size(); i++) {
if (ToAbsolutePathSegType(a[i]) != ToAbsolutePathSegType(b[i]))
return false;
}
return true;
}
PairwiseInterpolationValue PathInterpolationFunctions::MaybeMergeSingles(
InterpolationValue&& start,
InterpolationValue&& end) {
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;
return PairwiseInterpolationValue(std::move(start.interpolable_value),
std::move(end.interpolable_value),
std::move(end.non_interpolable_value));
}
void PathInterpolationFunctions::Composite(
UnderlyingValueOwner& underlying_value_owner,
double underlying_fraction,
const InterpolationType& type,
const InterpolationValue& value) {
const auto& list = To<InterpolableList>(*value.interpolable_value);
double neutral_component =
To<InterpolableNumber>(list.Get(kPathNeutralIndex))->Value();
if (neutral_component == 0) {
underlying_value_owner.Set(type, value);
return;
}
DCHECK(PathSegTypesMatch(
To<SVGPathNonInterpolableValue>(
*underlying_value_owner.Value().non_interpolable_value)
.PathSegTypes(),
To<SVGPathNonInterpolableValue>(*value.non_interpolable_value)
.PathSegTypes()));
underlying_value_owner.MutableValue().interpolable_value->ScaleAndAdd(
neutral_component, *value.interpolable_value);
underlying_value_owner.MutableValue().non_interpolable_value =
value.non_interpolable_value.get();
}
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)),
non_interpolable_path_value->PathSegTypes());
SVGPathByteStreamBuilder builder(*path_byte_stream);
svg_path_parser::ParsePath(source, builder);
return StylePath::Create(std::move(path_byte_stream),
non_interpolable_path_value->GetWindRule());
}
} // namespace blink