void SVGAnimatedTransformListAnimator::calculateAnimatedValue(float percentage, unsigned repeatCount, OwnPtr<SVGAnimatedType>& from, OwnPtr<SVGAnimatedType>& to, OwnPtr<SVGAnimatedType>& animated) { ASSERT(m_animationElement); // Spec: To animations provide specific functionality to get a smooth change from the underlying value to the // ‘to’ attribute value, which conflicts mathematically with the requirement for additive transform animations // to be post-multiplied. As a consequence, in SVG 1.1 the behavior of to animations for ‘animateTransform’ is undefined. // FIXME: This is not taken into account yet. SVGTransformList& fromTransformList = from->transformList(); SVGTransformList& toTransformList = to->transformList(); SVGTransformList& animatedTransformList = animated->transformList(); // Pass false to 'resizeAnimatedListIfNeeded' here, as the special post-multiplication behavior of <animateTransform> needs to be respected below. if (!m_animationElement->adjustFromToListValues<SVGTransformList>(0, fromTransformList, toTransformList, animatedTransformList, percentage, m_contextElement, false)) return; // Never resize the animatedTransformList to the toTransformList size, instead either clear the list or append to it. if (!animatedTransformList.isEmpty() && !m_animationElement->isAdditive()) animatedTransformList.clear(); unsigned fromTransformListSize = fromTransformList.size(); SVGTransform& toTransform = toTransformList[0]; SVGTransform effectiveFrom = fromTransformListSize ? fromTransformList[0] : SVGTransform(toTransform.type()); SVGTransform currentTransform = SVGTransformDistance(effectiveFrom, toTransform).scaledDistance(percentage).addToSVGTransform(effectiveFrom); if (m_animationElement->isAccumulated() && repeatCount) animatedTransformList.append(SVGTransformDistance::addSVGTransforms(currentTransform, toTransform, repeatCount)); else animatedTransformList.append(currentTransform); }
SVGTransform SVGTransformDistance::addToSVGTransform(const SVGTransform& transform) const { ASSERT(m_type == transform.type() || transform == SVGTransform()); SVGTransform newTransform(transform); switch (m_type) { case SVGTransform::SVG_TRANSFORM_UNKNOWN: return SVGTransform(); case SVGTransform::SVG_TRANSFORM_MATRIX: return SVGTransform(transform.matrix() * m_transform); case SVGTransform::SVG_TRANSFORM_TRANSLATE: { FloatPoint translation = transform.translate(); translation += FloatSize::narrowPrecision(m_transform.e(), m_transform.f()); newTransform.setTranslate(translation.x(), translation.y()); return newTransform; } case SVGTransform::SVG_TRANSFORM_SCALE: { FloatSize scale = transform.scale(); scale += FloatSize::narrowPrecision(m_transform.a(), m_transform.d()); newTransform.setScale(scale.width(), scale.height()); return newTransform; } case SVGTransform::SVG_TRANSFORM_ROTATE: { // FIXME: I'm not certain the translation is calculated correctly here FloatPoint center = transform.rotationCenter(); newTransform.setRotate(transform.angle() + m_angle, center.x() + m_cx, center.y() + m_cy); return newTransform; } case SVGTransform::SVG_TRANSFORM_SKEWX: newTransform.setSkewX(transform.angle() + m_angle); return newTransform; case SVGTransform::SVG_TRANSFORM_SKEWY: newTransform.setSkewY(transform.angle() + m_angle); return newTransform; } ASSERT_NOT_REACHED(); return SVGTransform(); }
SVGTransform SVGTransformDistance::addSVGTransforms(const SVGTransform& first, const SVGTransform& second) { ASSERT(first.type() == second.type()); SVGTransform transform; switch (first.type()) { case SVGTransform::SVG_TRANSFORM_UNKNOWN: return SVGTransform(); case SVGTransform::SVG_TRANSFORM_ROTATE: { transform.setRotate(first.angle() + second.angle(), first.rotationCenter().x() + second.rotationCenter().x(), first.rotationCenter().y() + second.rotationCenter().y()); return transform; } case SVGTransform::SVG_TRANSFORM_MATRIX: transform.setMatrix(first.matrix() * second.matrix()); return transform; case SVGTransform::SVG_TRANSFORM_TRANSLATE: { float dx = first.translate().x() + second.translate().x(); float dy = first.translate().y() + second.translate().y(); transform.setTranslate(dx, dy); return transform; } case SVGTransform::SVG_TRANSFORM_SCALE: { FloatSize scale = first.scale() + second.scale(); transform.setScale(scale.width(), scale.height()); return transform; } case SVGTransform::SVG_TRANSFORM_SKEWX: transform.setSkewX(first.angle() + second.angle()); return transform; case SVGTransform::SVG_TRANSFORM_SKEWY: transform.setSkewY(first.angle() + second.angle()); return transform; } ASSERT_NOT_REACHED(); return SVGTransform(); }
SVGTransform SVGTransformList::consolidate() { AffineTransform matrix; if (!concatenate(matrix)) return SVGTransform(); SVGTransform transform(matrix); clear(); append(transform); return transform; }
SVGTransform SVGAnimateTransformElement::parseTransformValue(const String& value) const { if (value.isEmpty()) return SVGTransform(m_type); SVGTransform result; // FIXME: This is pretty dumb but parseTransformValue() wants those parenthesis. String parseString("(" + value + ")"); const UChar* ptr = parseString.characters(); SVGTransformable::parseTransformValue(m_type, ptr, ptr + parseString.length(), result); // ignoring return value return result; }
SVGTransform SVGSVGElement::createSVGTransformFromMatrix(const AffineTransform& matrix) { return SVGTransform(matrix); }
SVGTransform SVGSVGElement::createSVGTransform() { return SVGTransform(); }
SVGTransform SVGSVGElement::createSVGTransform() { return SVGTransform(SVGTransform::SVG_TRANSFORM_MATRIX); }
SVGTransform SVGSVGElement::createSVGTransformFromMatrix(const SVGMatrix& matrix) { return SVGTransform(static_cast<const AffineTransform&>(matrix)); }
SVGTransform SVGSVGElement::createSVGTransformFromMatrix(const TransformationMatrix& matrix) { return SVGTransform(matrix); }
void SVGAnimateTransformElement::calculateAnimatedValue(float percentage, unsigned repeat, SVGSMILElement* resultElement) { if (!hasValidTarget()) return; SVGElement* targetElement = resultElement->targetElement(); RefPtr<SVGTransformList> transformList = transformListFor(targetElement); ASSERT(transformList); ExceptionCode ec; if (!isAdditive()) transformList->clear(ec); if (isAccumulated() && repeat) { SVGTransform accumulatedTransform = SVGTransformDistance(m_fromTransform, m_toTransform).scaledDistance(repeat).addToSVGTransform(SVGTransform()); transformList->appendItem(accumulatedTransform, ec); } SVGTransform transform = SVGTransformDistance(m_fromTransform, m_toTransform).scaledDistance(percentage).addToSVGTransform(m_fromTransform); transformList->appendItem(transform, ec); }
void SVGAnimatedTransformListAnimator::calculateAnimatedValue(float percentage, unsigned repeatCount, SVGAnimatedType* from, SVGAnimatedType* to, SVGAnimatedType* toAtEndOfDuration, SVGAnimatedType* animated) { ASSERT(m_animationElement); // Spec: To animations provide specific functionality to get a smooth change from the underlying value to the // ‘to’ attribute value, which conflicts mathematically with the requirement for additive transform animations // to be post-multiplied. As a consequence, in SVG 1.1 the behavior of to animations for ‘animateTransform’ is undefined. const SVGTransformList& fromTransformList = from->transformList(); const SVGTransformList& toTransformList = to->transformList(); const SVGTransformList& toAtEndOfDurationTransformList = toAtEndOfDuration->transformList(); SVGTransformList& animatedTransformList = animated->transformList(); // Pass false to 'resizeAnimatedListIfNeeded' here, as the special post-multiplication behavior of <animateTransform> needs to be respected below. if (!m_animationElement->adjustFromToListValues<SVGTransformList>(fromTransformList, toTransformList, animatedTransformList, percentage, false)) return; // Never resize the animatedTransformList to the toTransformList size, instead either clear the list or append to it. if (!animatedTransformList.isEmpty() && (!m_animationElement->isAdditive() || m_animationElement->animationMode() == ToAnimation)) animatedTransformList.clear(); unsigned fromTransformListSize = fromTransformList.size(); const SVGTransform& toTransform = toTransformList[0]; const SVGTransform effectiveFrom = fromTransformListSize ? fromTransformList[0] : SVGTransform(toTransform.type(), SVGTransform::ConstructZeroTransform); SVGTransform currentTransform = SVGTransformDistance(effectiveFrom, toTransform).scaledDistance(percentage).addToSVGTransform(effectiveFrom); if (m_animationElement->isAccumulated() && repeatCount) { const SVGTransform effectiveToAtEnd = toAtEndOfDurationTransformList.size() ? toAtEndOfDurationTransformList[0] : SVGTransform(toTransform.type(), SVGTransform::ConstructZeroTransform); animatedTransformList.append(SVGTransformDistance::addSVGTransforms(currentTransform, effectiveToAtEnd, repeatCount)); } else animatedTransformList.append(currentTransform); }