| /* |
| * Copyright (C) 2018-2021 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #pragma once |
| |
| #include "Color.h" |
| #include "FloatRect.h" |
| #include "SVGAngleValue.h" |
| #include "SVGAnimationAdditiveValueFunction.h" |
| #include "SVGLengthContext.h" |
| #include "SVGLengthValue.h" |
| #include "SVGPathByteStream.h" |
| #include "SVGPropertyTraits.h" |
| |
| namespace WebCore { |
| |
| class SVGAnimationAngleFunction : public SVGAnimationAdditiveValueFunction<SVGAngleValue> { |
| public: |
| using Base = SVGAnimationAdditiveValueFunction<SVGAngleValue>; |
| using Base::Base; |
| |
| void setFromAndToValues(SVGElement&, const String&, const String&) override |
| { |
| // Values will be set by SVGAnimatedAngleOrientAnimator. |
| ASSERT_NOT_REACHED(); |
| } |
| |
| void animate(SVGElement&, float progress, unsigned repeatCount, SVGAngleValue& animated) |
| { |
| float number = animated.value(); |
| number = Base::animate(progress, repeatCount, m_from.value(), m_to.value(), toAtEndOfDuration().value(), number); |
| animated.setValue(number); |
| } |
| |
| private: |
| friend class SVGAnimatedAngleOrientAnimator; |
| |
| void addFromAndToValues(SVGElement&) override |
| { |
| m_to.setValue(m_to.value() + m_from.value()); |
| } |
| }; |
| |
| class SVGAnimationColorFunction : public SVGAnimationAdditiveValueFunction<Color> { |
| public: |
| using Base = SVGAnimationAdditiveValueFunction<Color>; |
| using Base::Base; |
| |
| void setFromAndToValues(SVGElement& targetElement, const String& from, const String& to) override |
| { |
| m_from = colorFromString(targetElement, from); |
| m_to = colorFromString(targetElement, to); |
| } |
| |
| void setToAtEndOfDurationValue(const String& toAtEndOfDuration) override |
| { |
| m_toAtEndOfDuration = SVGPropertyTraits<Color>::fromString(toAtEndOfDuration); |
| } |
| |
| void animate(SVGElement&, float progress, unsigned repeatCount, Color& animated) |
| { |
| auto simpleAnimated = animated.toColorTypeLossy<SRGBA<uint8_t>>().resolved(); |
| auto simpleFrom = m_animationMode == AnimationMode::To ? simpleAnimated : m_from.toColorTypeLossy<SRGBA<uint8_t>>().resolved(); |
| auto simpleTo = m_to.toColorTypeLossy<SRGBA<uint8_t>>().resolved(); |
| auto simpleToAtEndOfDuration = toAtEndOfDuration().toColorTypeLossy<SRGBA<uint8_t>>().resolved(); |
| |
| float red = Base::animate(progress, repeatCount, simpleFrom.red, simpleTo.red, simpleToAtEndOfDuration.red, simpleAnimated.red); |
| float green = Base::animate(progress, repeatCount, simpleFrom.green, simpleTo.green, simpleToAtEndOfDuration.green, simpleAnimated.green); |
| float blue = Base::animate(progress, repeatCount, simpleFrom.blue, simpleTo.blue, simpleToAtEndOfDuration.blue, simpleAnimated.blue); |
| float alpha = Base::animate(progress, repeatCount, simpleFrom.alpha, simpleTo.alpha, simpleToAtEndOfDuration.alpha, simpleAnimated.alpha); |
| |
| animated = makeFromComponentsClamping<SRGBA<uint8_t>>(std::lround(red), std::lround(green), std::lround(blue), std::lround(alpha)); |
| } |
| |
| std::optional<float> calculateDistance(SVGElement&, const String& from, const String& to) const override |
| { |
| Color fromColor = CSSParser::parseColorWithoutContext(from.stripWhiteSpace()); |
| if (!fromColor.isValid()) |
| return { }; |
| Color toColor = CSSParser::parseColorWithoutContext(to.stripWhiteSpace()); |
| if (!toColor.isValid()) |
| return { }; |
| |
| auto simpleFrom = fromColor.toColorTypeLossy<SRGBA<uint8_t>>().resolved(); |
| auto simpleTo = toColor.toColorTypeLossy<SRGBA<uint8_t>>().resolved(); |
| |
| float red = simpleFrom.red - simpleTo.red; |
| float green = simpleFrom.green - simpleTo.green; |
| float blue = simpleFrom.blue - simpleTo.blue; |
| |
| return std::hypot(red, green, blue); |
| } |
| |
| private: |
| void addFromAndToValues(SVGElement&) override |
| { |
| auto simpleFrom = m_from.toColorTypeLossy<SRGBA<uint8_t>>().resolved(); |
| auto simpleTo = m_to.toColorTypeLossy<SRGBA<uint8_t>>().resolved(); |
| |
| // Ignores any alpha and sets alpha on result to 100% opaque. |
| m_to = makeFromComponentsClamping<SRGBA<uint8_t>>(simpleTo.red + simpleFrom.red, simpleTo.green + simpleFrom.green, simpleTo.blue + simpleFrom.blue); |
| } |
| |
| static Color colorFromString(SVGElement&, const String&); |
| }; |
| |
| class SVGAnimationIntegerFunction final : public SVGAnimationAdditiveValueFunction<int> { |
| friend class SVGAnimatedIntegerPairAnimator; |
| |
| public: |
| using Base = SVGAnimationAdditiveValueFunction<int>; |
| using Base::Base; |
| |
| void setFromAndToValues(SVGElement&, const String& from, const String& to) override |
| { |
| m_from = SVGPropertyTraits<int>::fromString(from); |
| m_to = SVGPropertyTraits<int>::fromString(to); |
| } |
| |
| void setToAtEndOfDurationValue(const String& toAtEndOfDuration) final |
| { |
| m_toAtEndOfDuration = SVGPropertyTraits<int>::fromString(toAtEndOfDuration); |
| } |
| |
| void animate(SVGElement&, float progress, unsigned repeatCount, int& animated) |
| { |
| animated = static_cast<int>(roundf(Base::animate(progress, repeatCount, m_from, m_to, toAtEndOfDuration(), animated))); |
| } |
| |
| std::optional<float> calculateDistance(SVGElement&, const String&, const String&) const final; |
| |
| private: |
| void addFromAndToValues(SVGElement&) final |
| { |
| m_to += m_from; |
| } |
| }; |
| |
| class SVGAnimationLengthFunction : public SVGAnimationAdditiveValueFunction<SVGLengthValue> { |
| using Base = SVGAnimationAdditiveValueFunction<SVGLengthValue>; |
| |
| public: |
| SVGAnimationLengthFunction(AnimationMode animationMode, CalcMode calcMode, bool isAccumulated, bool isAdditive, SVGLengthMode lengthMode) |
| : Base(animationMode, calcMode, isAccumulated, isAdditive) |
| , m_lengthMode(lengthMode) |
| { |
| } |
| |
| void setFromAndToValues(SVGElement&, const String& from, const String& to) override |
| { |
| m_from = SVGLengthValue(m_lengthMode, from); |
| m_to = SVGLengthValue(m_lengthMode, to); |
| } |
| |
| void setToAtEndOfDurationValue(const String& toAtEndOfDuration) override |
| { |
| m_toAtEndOfDuration = SVGLengthValue(m_lengthMode, toAtEndOfDuration); |
| } |
| |
| void animate(SVGElement& targetElement, float progress, unsigned repeatCount, SVGLengthValue& animated) |
| { |
| SVGLengthContext lengthContext(&targetElement); |
| SVGLengthType lengthType = progress < 0.5 ? m_from.lengthType() : m_to.lengthType(); |
| |
| float from = (m_animationMode == AnimationMode::To ? animated : m_from).value(lengthContext); |
| float to = m_to.value(lengthContext); |
| float toAtEndOfDuration = this->toAtEndOfDuration().value(lengthContext); |
| float value = animated.value(lengthContext); |
| |
| value = Base::animate(progress, repeatCount, from, to, toAtEndOfDuration, value); |
| animated = { lengthContext, value, lengthType, m_lengthMode }; |
| } |
| |
| std::optional<float> calculateDistance(SVGElement& targetElement, const String& from, const String& to) const override |
| { |
| SVGLengthContext lengthContext(&targetElement); |
| auto fromLength = SVGLengthValue(m_lengthMode, from); |
| auto toLength = SVGLengthValue(m_lengthMode, to); |
| return fabsf(toLength.value(lengthContext) - fromLength.value(lengthContext)); |
| } |
| |
| private: |
| void addFromAndToValues(SVGElement& targetElement) override |
| { |
| SVGLengthContext lengthContext(&targetElement); |
| m_to.setValue(lengthContext, m_to.value(lengthContext) + m_from.value(lengthContext)); |
| } |
| |
| SVGLengthMode m_lengthMode; |
| }; |
| |
| class SVGAnimationNumberFunction : public SVGAnimationAdditiveValueFunction<float> { |
| friend class SVGAnimatedNumberPairAnimator; |
| |
| public: |
| using Base = SVGAnimationAdditiveValueFunction<float>; |
| using Base::Base; |
| |
| void setFromAndToValues(SVGElement&, const String& from, const String& to) override |
| { |
| m_from = SVGPropertyTraits<float>::fromString(from); |
| m_to = SVGPropertyTraits<float>::fromString(to); |
| } |
| |
| void setToAtEndOfDurationValue(const String& toAtEndOfDuration) override |
| { |
| m_toAtEndOfDuration = SVGPropertyTraits<float>::fromString(toAtEndOfDuration); |
| } |
| |
| void animate(SVGElement&, float progress, unsigned repeatCount, float& animated) |
| { |
| float from = m_animationMode == AnimationMode::To ? animated : m_from; |
| animated = Base::animate(progress, repeatCount, from, m_to, toAtEndOfDuration(), animated); |
| } |
| |
| std::optional<float> calculateDistance(SVGElement&, const String& from, const String& to) const override |
| { |
| return std::abs(parseNumber(to).value_or(0) - parseNumber(from).value_or(0)); |
| } |
| |
| private: |
| void addFromAndToValues(SVGElement&) override |
| { |
| m_to += m_from; |
| } |
| }; |
| |
| class SVGAnimationPathSegListFunction : public SVGAnimationAdditiveValueFunction<SVGPathByteStream> { |
| public: |
| using Base = SVGAnimationAdditiveValueFunction<SVGPathByteStream>; |
| using Base::Base; |
| |
| void setFromAndToValues(SVGElement&, const String& from, const String& to) override |
| { |
| m_from = SVGPathByteStream(from); |
| m_to = SVGPathByteStream(to); |
| } |
| |
| void setToAtEndOfDurationValue(const String& toAtEndOfDuration) override |
| { |
| m_toAtEndOfDuration = SVGPathByteStream(toAtEndOfDuration); |
| } |
| |
| void animate(SVGElement&, float progress, unsigned repeatCount, SVGPathByteStream& animated) |
| { |
| SVGPathByteStream underlyingPath; |
| if (m_animationMode == AnimationMode::To) |
| underlyingPath = animated; |
| |
| const SVGPathByteStream& from = m_animationMode == AnimationMode::To ? underlyingPath : m_from; |
| |
| // Cache the current animated value before the buildAnimatedSVGPathByteStream() clears animatedPath. |
| SVGPathByteStream lastAnimated; |
| if (!from.size() || (m_isAdditive && m_animationMode != AnimationMode::To)) |
| lastAnimated = animated; |
| |
| buildAnimatedSVGPathByteStream(from, m_to, animated, progress); |
| |
| // Handle additive='sum'. |
| if (!lastAnimated.isEmpty()) |
| addToSVGPathByteStream(animated, lastAnimated); |
| |
| // Handle accumulate='sum'. |
| if (m_isAccumulated && repeatCount) |
| addToSVGPathByteStream(animated, toAtEndOfDuration(), repeatCount); |
| } |
| |
| private: |
| void addFromAndToValues(SVGElement&) override |
| { |
| if (!m_from.size() || m_from.size() != m_to.size()) |
| return; |
| addToSVGPathByteStream(m_to, m_from); |
| } |
| }; |
| |
| class SVGAnimationRectFunction : public SVGAnimationAdditiveValueFunction<FloatRect> { |
| public: |
| using Base = SVGAnimationAdditiveValueFunction<FloatRect>; |
| using Base::Base; |
| |
| void setFromAndToValues(SVGElement&, const String& from, const String& to) override |
| { |
| m_from = SVGPropertyTraits<FloatRect>::fromString(from); |
| m_to = SVGPropertyTraits<FloatRect>::fromString(to); |
| } |
| |
| void setToAtEndOfDurationValue(const String& toAtEndOfDuration) override |
| { |
| m_toAtEndOfDuration = SVGPropertyTraits<FloatRect>::fromString(toAtEndOfDuration); |
| } |
| |
| void animate(SVGElement&, float progress, unsigned repeatCount, FloatRect& animated) |
| { |
| FloatRect from = m_animationMode == AnimationMode::To ? animated : m_from; |
| |
| float x = Base::animate(progress, repeatCount, from.x(), m_to.x(), toAtEndOfDuration().x(), animated.x()); |
| float y = Base::animate(progress, repeatCount, from.y(), m_to.y(), toAtEndOfDuration().y(), animated.y()); |
| float width = Base::animate(progress, repeatCount, from.width(), m_to.width(), toAtEndOfDuration().width(), animated.width()); |
| float height = Base::animate(progress, repeatCount, from.height(), m_to.height(), toAtEndOfDuration().height(), animated.height()); |
| |
| animated = { x, y, width, height }; |
| } |
| |
| private: |
| void addFromAndToValues(SVGElement&) override |
| { |
| m_to += m_from; |
| } |
| }; |
| |
| } // namespace WebCore |