| /* |
| Copyright (C) 2007 Eric Seidel <eric@webkit.org> |
| |
| This file is part of the WebKit project |
| |
| This library is free software; you can redistribute it and/or |
| modify it under the terms of the GNU Library General Public |
| License as published by the Free Software Foundation; either |
| version 2 of the License, or (at your option) any later version. |
| |
| This library is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| Library General Public License for more details. |
| |
| You should have received a copy of the GNU Library General Public License |
| along with this library; see the file COPYING.LIB. If not, write to |
| the Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
| Boston, MA 02111-1307, USA. |
| */ |
| |
| #include "config.h" |
| #if ENABLE(SVG) |
| #include "SVGTransformDistance.h" |
| |
| #include "FloatConversion.h" |
| #include "FloatPoint.h" |
| #include "FloatSize.h" |
| #include "SVGTransform.h" |
| |
| #include <math.h> |
| |
| namespace WebCore { |
| |
| SVGTransformDistance::SVGTransformDistance() |
| : m_type(SVGTransform::SVG_TRANSFORM_UNKNOWN) |
| , m_angle(0) |
| { |
| } |
| |
| SVGTransformDistance::SVGTransformDistance(SVGTransform::SVGTransformType type, double angle, double cx, double cy, const AffineTransform& transform) |
| : m_type(type) |
| , m_angle(angle) |
| , m_cx(cx) |
| , m_cy(cy) |
| , m_transform(transform) |
| { |
| } |
| |
| SVGTransformDistance::SVGTransformDistance(const SVGTransform& fromSVGTransform, const SVGTransform& toSVGTransform) |
| : m_type(fromSVGTransform.type()) |
| , m_angle(0) |
| , m_cx(0) |
| , m_cy(0) |
| { |
| ASSERT(m_type == toSVGTransform.type()); |
| |
| switch (m_type) { |
| case SVGTransform::SVG_TRANSFORM_UNKNOWN: |
| return; |
| case SVGTransform::SVG_TRANSFORM_MATRIX: |
| // FIXME: need to be able to subtract to matrices |
| return; |
| case SVGTransform::SVG_TRANSFORM_ROTATE: |
| { |
| FloatSize centerDistance = toSVGTransform.rotationCenter() - fromSVGTransform.rotationCenter(); |
| m_angle = toSVGTransform.angle() - fromSVGTransform.angle(); |
| m_cx = centerDistance.width(); |
| m_cy = centerDistance.height(); |
| return; |
| } |
| case SVGTransform::SVG_TRANSFORM_TRANSLATE: |
| { |
| FloatSize translationDistance = toSVGTransform.translate() - fromSVGTransform.translate(); |
| m_transform.translate(translationDistance.width(), translationDistance.height()); |
| return; |
| } |
| case SVGTransform::SVG_TRANSFORM_SCALE: |
| { |
| float scaleX = fromSVGTransform.scale().width() != 0 ? toSVGTransform.scale().width() / fromSVGTransform.scale().width() : toSVGTransform.scale().width() / 0.00001f; |
| float scaleY = fromSVGTransform.scale().height() != 0 ? toSVGTransform.scale().height() / fromSVGTransform.scale().height() : toSVGTransform.scale().height() / 0.00001f; |
| m_transform.scale(scaleX, scaleY); |
| return; |
| } |
| case SVGTransform::SVG_TRANSFORM_SKEWX: |
| case SVGTransform::SVG_TRANSFORM_SKEWY: |
| m_angle = toSVGTransform.angle() - fromSVGTransform.angle(); |
| return; |
| } |
| } |
| |
| SVGTransformDistance SVGTransformDistance::scaledDistance(float scaleFactor) const |
| { |
| switch (m_type) { |
| case SVGTransform::SVG_TRANSFORM_UNKNOWN: |
| return SVGTransformDistance(); |
| case SVGTransform::SVG_TRANSFORM_ROTATE: |
| return SVGTransformDistance(m_type, m_angle * scaleFactor, m_cx * scaleFactor, m_cy * scaleFactor, AffineTransform()); |
| case SVGTransform::SVG_TRANSFORM_SCALE: |
| case SVGTransform::SVG_TRANSFORM_MATRIX: |
| return SVGTransformDistance(m_type, m_angle * scaleFactor, m_cx * scaleFactor, m_cy * scaleFactor, AffineTransform(m_transform).scale(scaleFactor)); |
| case SVGTransform::SVG_TRANSFORM_TRANSLATE: |
| { |
| AffineTransform newTransform(m_transform); |
| newTransform.setE(m_transform.e() * scaleFactor); |
| newTransform.setF(m_transform.f() * scaleFactor); |
| return SVGTransformDistance(m_type, 0, 0, 0, newTransform); |
| } |
| case SVGTransform::SVG_TRANSFORM_SKEWX: |
| case SVGTransform::SVG_TRANSFORM_SKEWY: |
| return SVGTransformDistance(m_type, m_angle * scaleFactor, m_cx * scaleFactor, m_cy * scaleFactor, AffineTransform()); |
| } |
| |
| ASSERT_NOT_REACHED(); |
| return SVGTransformDistance(); |
| } |
| |
| 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(); |
| } |
| |
| void SVGTransformDistance::addSVGTransform(const SVGTransform& transform, bool absoluteValue) |
| { |
| // If this is the first add, set the type for this SVGTransformDistance |
| if (m_type == SVGTransform::SVG_TRANSFORM_UNKNOWN) |
| m_type = transform.type(); |
| |
| ASSERT(m_type == transform.type()); |
| |
| switch (m_type) { |
| case SVGTransform::SVG_TRANSFORM_UNKNOWN: |
| return; |
| case SVGTransform::SVG_TRANSFORM_MATRIX: |
| m_transform *= transform.matrix(); // FIXME: what does 'distance' between two transforms mean? how should we respect 'absoluteValue' here? |
| return; |
| case SVGTransform::SVG_TRANSFORM_ROTATE: |
| m_angle += absoluteValue ? fabsf(transform.angle()) : transform.angle(); |
| m_cx += absoluteValue ? fabsf(transform.rotationCenter().x()) : transform.rotationCenter().x(); |
| m_cy += absoluteValue ? fabsf(transform.rotationCenter().y()) : transform.rotationCenter().y(); |
| // fall through |
| case SVGTransform::SVG_TRANSFORM_TRANSLATE: |
| { |
| float dx = absoluteValue ? fabsf(transform.translate().x()) : transform.translate().x(); |
| float dy = absoluteValue ? fabsf(transform.translate().y()) : transform.translate().y(); |
| m_transform.translate(dx, dy); |
| return; |
| } |
| case SVGTransform::SVG_TRANSFORM_SCALE: |
| { |
| float scaleX = absoluteValue ? fabsf(transform.scale().width()) : transform.scale().width(); |
| float scaleY = absoluteValue ? fabsf(transform.scale().height()) : transform.scale().height(); |
| m_transform.scale(scaleX, scaleY); |
| return; |
| } |
| case SVGTransform::SVG_TRANSFORM_SKEWX: |
| case SVGTransform::SVG_TRANSFORM_SKEWY: |
| m_angle += absoluteValue ? fabsf(transform.angle()) : transform.angle(); |
| return; |
| } |
| |
| ASSERT_NOT_REACHED(); |
| return; |
| } |
| |
| 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(narrowPrecisionToFloat(transform.angle() + m_angle), |
| narrowPrecisionToFloat(center.x() + m_cx), |
| narrowPrecisionToFloat(center.y() + m_cy)); |
| return newTransform; |
| } |
| case SVGTransform::SVG_TRANSFORM_SKEWX: |
| newTransform.setSkewX(narrowPrecisionToFloat(transform.angle() + m_angle)); |
| return newTransform; |
| case SVGTransform::SVG_TRANSFORM_SKEWY: |
| newTransform.setSkewY(narrowPrecisionToFloat(transform.angle() + m_angle)); |
| return newTransform; |
| } |
| |
| ASSERT_NOT_REACHED(); |
| return SVGTransform(); |
| } |
| |
| bool SVGTransformDistance::isZero() const |
| { |
| return (m_transform == AffineTransform() && m_angle == 0); |
| } |
| |
| float SVGTransformDistance::distance() const |
| { |
| switch (m_type) { |
| case SVGTransform::SVG_TRANSFORM_UNKNOWN: |
| return 0.0f; |
| case SVGTransform::SVG_TRANSFORM_ROTATE: |
| return narrowPrecisionToFloat(sqrt(m_angle * m_angle + m_cx * m_cx + m_cy * m_cy)); |
| case SVGTransform::SVG_TRANSFORM_MATRIX: |
| return 0.0f; // I'm not quite sure yet what distance between two matrices means. |
| case SVGTransform::SVG_TRANSFORM_SCALE: |
| return narrowPrecisionToFloat(sqrt(m_transform.a() * m_transform.a() + m_transform.d() * m_transform.d())); |
| case SVGTransform::SVG_TRANSFORM_TRANSLATE: |
| return narrowPrecisionToFloat(sqrt(m_transform.e() * m_transform.e() + m_transform.f() * m_transform.f())); |
| case SVGTransform::SVG_TRANSFORM_SKEWX: |
| case SVGTransform::SVG_TRANSFORM_SKEWY: |
| return narrowPrecisionToFloat(m_angle); |
| } |
| ASSERT_NOT_REACHED(); |
| return 0.0f; |
| } |
| |
| } |
| |
| #endif |