// 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 #include #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 Create( Vector& path_seg_types) { return base::AdoptRef(new SVGPathNonInterpolableValue(path_seg_types)); } const Vector& PathSegTypes() const { return path_seg_types_; } DECLARE_NON_INTERPOLABLE_VALUE_TYPE(); private: SVGPathNonInterpolableValue(Vector& path_seg_types) { path_seg_types_.swap(path_seg_types); } Vector path_seg_types_; }; DEFINE_NON_INTERPOLABLE_VALUE_TYPE(SVGPathNonInterpolableValue); template <> struct DowncastTraits { 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 SVGPathByteStream& byte_stream, CoordinateConversion coordinateConversion) { SVGPathByteStreamSource path_source(byte_stream); wtf_size_t length = 0; PathCoordinates current_coordinates; Vector> interpolable_path_segs; Vector 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(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(kPathComponentIndexCount); result->Set(kPathArgsIndex, std::move(path_args)); result->Set(kPathNeutralIndex, std::make_unique(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 empty_path = std::make_unique(); return ConvertValue(*empty_path, ForceAbsolute); } class UnderlyingPathSegTypesChecker : public InterpolationType::ConversionChecker { public: ~UnderlyingPathSegTypesChecker() final = default; static std::unique_ptr Create( const InterpolationValue& underlying) { return base::WrapUnique( new UnderlyingPathSegTypesChecker(GetPathSegTypes(underlying))); } private: UnderlyingPathSegTypesChecker(const Vector& path_seg_types) : path_seg_types_(path_seg_types) {} static const Vector& GetPathSegTypes( const InterpolationValue& underlying) { return To(*underlying.non_interpolable_value) .PathSegTypes(); } bool IsValid(const InterpolationEnvironment&, const InterpolationValue& underlying) const final { return path_seg_types_ == GetPathSegTypes(underlying); } Vector path_seg_types_; }; InterpolationValue PathInterpolationFunctions::MaybeConvertNeutral( const InterpolationValue& underlying, InterpolationType::ConversionCheckers& conversion_checkers) { conversion_checkers.push_back( UnderlyingPathSegTypesChecker::Create(underlying)); auto result = std::make_unique(kPathComponentIndexCount); result->Set(kPathArgsIndex, To(*underlying.interpolable_value) .Get(kPathArgsIndex) ->CloneAndZero()); result->Set(kPathNeutralIndex, std::make_unique(1)); return InterpolationValue(std::move(result), underlying.non_interpolable_value.get()); } static bool PathSegTypesMatch(const Vector& a, const Vector& 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) { const Vector& start_types = To(*start.non_interpolable_value) .PathSegTypes(); const Vector& end_types = To(*end.non_interpolable_value) .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(*value.interpolable_value); double neutral_component = To(list.Get(kPathNeutralIndex))->Value(); if (neutral_component == 0) { underlying_value_owner.Set(type, value); return; } DCHECK(PathSegTypesMatch( To( *underlying_value_owner.Value().non_interpolable_value) .PathSegTypes(), To(*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(); } std::unique_ptr PathInterpolationFunctions::AppliedValue( const InterpolableValue& interpolable_value, const NonInterpolableValue* non_interpolable_value) { std::unique_ptr path_byte_stream = std::make_unique(); InterpolatedSVGPathSource source( To( *To(interpolable_value).Get(kPathArgsIndex)), To(non_interpolable_value)->PathSegTypes()); SVGPathByteStreamBuilder builder(*path_byte_stream); svg_path_parser::ParsePath(source, builder); return path_byte_stream; } } // namespace blink