diff options
author | Steve Block <steveblock@google.com> | 2011-05-06 11:45:16 +0100 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2011-05-12 13:44:10 +0100 |
commit | cad810f21b803229eb11403f9209855525a25d57 (patch) | |
tree | 29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /Source/WebCore/platform/graphics/transforms | |
parent | 121b0cf4517156d0ac5111caf9830c51b69bae8f (diff) | |
download | external_webkit-cad810f21b803229eb11403f9209855525a25d57.zip external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.gz external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.bz2 |
Merge WebKit at r75315: Initial merge by git.
Change-Id: I570314b346ce101c935ed22a626b48c2af266b84
Diffstat (limited to 'Source/WebCore/platform/graphics/transforms')
22 files changed, 3339 insertions, 0 deletions
diff --git a/Source/WebCore/platform/graphics/transforms/AffineTransform.cpp b/Source/WebCore/platform/graphics/transforms/AffineTransform.cpp new file mode 100644 index 0000000..f275526 --- /dev/null +++ b/Source/WebCore/platform/graphics/transforms/AffineTransform.cpp @@ -0,0 +1,388 @@ +/* + * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved. + * 2010 Dirk Schulze <krit@webkit.org> + * + * 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 COMPUTER, 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 COMPUTER, 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. + */ + +#include "config.h" +#include "AffineTransform.h" + +#include "FloatConversion.h" +#include "FloatQuad.h" +#include "FloatRect.h" +#include "IntRect.h" + +#include <wtf/MathExtras.h> + +namespace WebCore { + +static void affineTransformDecompose(const AffineTransform& matrix, double sr[9]) +{ + AffineTransform m(matrix); + + // Compute scaling factors + double sx = matrix.xScale(); + double sy = matrix.yScale(); + + // Compute cross product of transformed unit vectors. If negative, + // one axis was flipped. + if (m.a() * m.d() - m.c() * m.b() < 0.0) { + // Flip axis with minimum unit vector dot product + if (m.a() < m.d()) + sx = -sx; + else + sy = -sy; + } + + // Remove scale from matrix + m.scale(1.0 / sx, 1.0 / sy); + + // Compute rotation + double angle = atan2(m.b(), m.a()); + + // Remove rotation from matrix + m.rotate(rad2deg(-angle)); + + // Return results + sr[0] = sx; + sr[1] = sy; + sr[2] = angle; + sr[3] = m.a(); + sr[4] = m.b(); + sr[5] = m.c(); + sr[6] = m.d(); + sr[7] = m.e(); + sr[8] = m.f(); +} + +static void affineTransformCompose(AffineTransform& m, const double sr[9]) +{ + m.setA(sr[3]); + m.setB(sr[4]); + m.setC(sr[5]); + m.setD(sr[6]); + m.setE(sr[7]); + m.setF(sr[8]); + m.rotate(rad2deg(sr[2])); + m.scale(sr[0], sr[1]); +} + +AffineTransform::AffineTransform() +{ + setMatrix(1, 0, 0, 1, 0, 0); +} + +AffineTransform::AffineTransform(double a, double b, double c, double d, double e, double f) +{ + setMatrix(a, b, c, d, e, f); +} + +void AffineTransform::makeIdentity() +{ + setMatrix(1, 0, 0, 1, 0, 0); +} + +void AffineTransform::setMatrix(double a, double b, double c, double d, double e, double f) +{ + m_transform[0] = a; + m_transform[1] = b; + m_transform[2] = c; + m_transform[3] = d; + m_transform[4] = e; + m_transform[5] = f; +} + +bool AffineTransform::isIdentity() const +{ + return (m_transform[0] == 1 && m_transform[1] == 0 + && m_transform[2] == 0 && m_transform[3] == 1 + && m_transform[4] == 0 && m_transform[5] == 0); +} + +double AffineTransform::xScale() const +{ + return sqrt(m_transform[0] * m_transform[0] + m_transform[1] * m_transform[1]); +} + +double AffineTransform::yScale() const +{ + return sqrt(m_transform[2] * m_transform[2] + m_transform[3] * m_transform[3]); +} + +double AffineTransform::det() const +{ + return m_transform[0] * m_transform[3] - m_transform[1] * m_transform[2]; +} + +bool AffineTransform::isInvertible() const +{ + return det() != 0.0; +} + +AffineTransform AffineTransform::inverse() const +{ + double determinant = det(); + if (determinant == 0.0) + return AffineTransform(); + + AffineTransform result; + if (isIdentityOrTranslation()) { + result.m_transform[4] = -m_transform[4]; + result.m_transform[5] = -m_transform[5]; + return result; + } + + result.m_transform[0] = m_transform[3] / determinant; + result.m_transform[1] = -m_transform[1] / determinant; + result.m_transform[2] = -m_transform[2] / determinant; + result.m_transform[3] = m_transform[0] / determinant; + result.m_transform[4] = (m_transform[2] * m_transform[5] + - m_transform[3] * m_transform[4]) / determinant; + result.m_transform[5] = (m_transform[1] * m_transform[4] + - m_transform[0] * m_transform[5]) / determinant; + + return result; +} + +AffineTransform& AffineTransform::multiply(const AffineTransform& other) +{ + return (*this) *= other; +} + +AffineTransform& AffineTransform::multLeft(const AffineTransform& other) +{ + AffineTransform trans; + + trans.m_transform[0] = other.m_transform[0] * m_transform[0] + other.m_transform[1] * m_transform[2]; + trans.m_transform[1] = other.m_transform[0] * m_transform[1] + other.m_transform[1] * m_transform[3]; + trans.m_transform[2] = other.m_transform[2] * m_transform[0] + other.m_transform[3] * m_transform[2]; + trans.m_transform[3] = other.m_transform[2] * m_transform[1] + other.m_transform[3] * m_transform[3]; + trans.m_transform[4] = other.m_transform[4] * m_transform[0] + other.m_transform[5] * m_transform[2] + m_transform[4]; + trans.m_transform[5] = other.m_transform[4] * m_transform[1] + other.m_transform[5] * m_transform[3] + m_transform[5]; + + setMatrix(trans.m_transform); + return *this; +} + +AffineTransform& AffineTransform::rotate(double a) +{ + // angle is in degree. Switch to radian + a = deg2rad(a); + double cosAngle = cos(a); + double sinAngle = sin(a); + AffineTransform rot(cosAngle, sinAngle, -sinAngle, cosAngle, 0, 0); + + multLeft(rot); + return *this; +} + +AffineTransform& AffineTransform::scale(double s) +{ + return scale(s, s); +} + +AffineTransform& AffineTransform::scale(double sx, double sy) +{ + m_transform[0] *= sx; + m_transform[1] *= sx; + m_transform[2] *= sy; + m_transform[3] *= sy; + return *this; +} + +// *this = *this * translation +AffineTransform& AffineTransform::translate(double tx, double ty) +{ + if (isIdentityOrTranslation()) { + m_transform[4] += tx; + m_transform[5] += ty; + return *this; + } + + m_transform[4] += tx * m_transform[0] + ty * m_transform[2]; + m_transform[5] += tx * m_transform[1] + ty * m_transform[3]; + return *this; +} + +// *this = translation * *this +AffineTransform& AffineTransform::translateRight(double tx, double ty) +{ + m_transform[4] += tx; + m_transform[5] += ty; + return *this; +} + +AffineTransform& AffineTransform::scaleNonUniform(double sx, double sy) +{ + return scale(sx, sy); +} + +AffineTransform& AffineTransform::rotateFromVector(double x, double y) +{ + return rotate(rad2deg(atan2(y, x))); +} + +AffineTransform& AffineTransform::flipX() +{ + return scale(-1, 1); +} + +AffineTransform& AffineTransform::flipY() +{ + return scale(1, -1); +} + +AffineTransform& AffineTransform::shear(double sx, double sy) +{ + double a = m_transform[0]; + double b = m_transform[1]; + + m_transform[0] += sy * m_transform[2]; + m_transform[1] += sy * m_transform[3]; + m_transform[2] += sx * a; + m_transform[3] += sx * b; + + return *this; +} + +AffineTransform& AffineTransform::skew(double angleX, double angleY) +{ + return shear(tan(deg2rad(angleX)), tan(deg2rad(angleY))); +} + +AffineTransform& AffineTransform::skewX(double angle) +{ + return shear(tan(deg2rad(angle)), 0); +} + +AffineTransform& AffineTransform::skewY(double angle) +{ + return shear(0, tan(deg2rad(angle))); +} + +AffineTransform makeMapBetweenRects(const FloatRect& source, const FloatRect& dest) +{ + AffineTransform transform; + transform.translate(dest.x() - source.x(), dest.y() - source.y()); + transform.scale(dest.width() / source.width(), dest.height() / source.height()); + return transform; +} + +void AffineTransform::map(double x, double y, double& x2, double& y2) const +{ + x2 = (m_transform[0] * x + m_transform[2] * y + m_transform[4]); + y2 = (m_transform[1] * x + m_transform[3] * y + m_transform[5]); +} + +IntPoint AffineTransform::mapPoint(const IntPoint& point) const +{ + double x2, y2; + map(point.x(), point.y(), x2, y2); + + // Round the point. + return IntPoint(lround(x2), lround(y2)); +} + +FloatPoint AffineTransform::mapPoint(const FloatPoint& point) const +{ + double x2, y2; + map(point.x(), point.y(), x2, y2); + + return FloatPoint(narrowPrecisionToFloat(x2), narrowPrecisionToFloat(y2)); +} + +IntRect AffineTransform::mapRect(const IntRect &rect) const +{ + return enclosingIntRect(mapRect(FloatRect(rect))); +} + +FloatRect AffineTransform::mapRect(const FloatRect& rect) const +{ + if (isIdentityOrTranslation()) { + FloatRect mappedRect(rect); + mappedRect.move(narrowPrecisionToFloat(m_transform[4]), narrowPrecisionToFloat(m_transform[5])); + return mappedRect; + } + + FloatQuad result; + result.setP1(mapPoint(rect.location())); + result.setP2(mapPoint(FloatPoint(rect.right(), rect.y()))); + result.setP3(mapPoint(FloatPoint(rect.right(), rect.bottom()))); + result.setP4(mapPoint(FloatPoint(rect.x(), rect.bottom()))); + return result.boundingBox(); +} + +FloatQuad AffineTransform::mapQuad(const FloatQuad& q) const +{ + if (isIdentityOrTranslation()) { + FloatQuad mappedQuad(q); + mappedQuad.move(narrowPrecisionToFloat(m_transform[4]), narrowPrecisionToFloat(m_transform[5])); + return mappedQuad; + } + + FloatQuad result; + result.setP1(mapPoint(q.p1())); + result.setP2(mapPoint(q.p2())); + result.setP3(mapPoint(q.p3())); + result.setP4(mapPoint(q.p4())); + return result; +} + +void AffineTransform::blend(const AffineTransform& from, double progress) +{ + double srA[9], srB[9]; + + affineTransformDecompose(from, srA); + affineTransformDecompose(*this, srB); + + // If x-axis of one is flipped, and y-axis of the other, convert to an unflipped rotation. + if ((srA[0] < 0 && srB[1] < 0) || (srA[1] < 0 && srB[0] < 0)) { + srA[0] = -srA[0]; + srA[1] = -srA[1]; + srA[2] += srA[2] < 0 ? piDouble : -piDouble; + } + + // Don't rotate the long way around. + srA[2] = fmod(srA[2], 2.0 * piDouble); + srB[2] = fmod(srB[2], 2.0 * piDouble); + + if (fabs(srA[2] - srB[2]) > piDouble) { + if (srA[2] > srB[2]) + srA[2] -= piDouble * 2.0; + else + srB[2] -= piDouble * 2.0; + } + + for (int i = 0; i < 9; i++) + srA[i] = srA[i] + progress * (srB[i] - srA[i]); + + affineTransformCompose(*this, srA); +} + +TransformationMatrix AffineTransform::toTransformationMatrix() const +{ + return TransformationMatrix(m_transform[0], m_transform[1], m_transform[2], + m_transform[3], m_transform[4], m_transform[5]); +} + +} diff --git a/Source/WebCore/platform/graphics/transforms/AffineTransform.h b/Source/WebCore/platform/graphics/transforms/AffineTransform.h new file mode 100644 index 0000000..baee102 --- /dev/null +++ b/Source/WebCore/platform/graphics/transforms/AffineTransform.h @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved. + * 2010 Dirk Schulze <krit@webkit.org> + * + * 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 COMPUTER, 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 COMPUTER, 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. + */ + +#ifndef AffineTransform_h +#define AffineTransform_h + +#include "TransformationMatrix.h" + +#include <string.h> // for memcpy +#include <wtf/FastAllocBase.h> + +#if PLATFORM(CG) +#include <CoreGraphics/CGAffineTransform.h> +#elif PLATFORM(CAIRO) +#include <cairo.h> +#elif PLATFORM(OPENVG) +#include "VGUtils.h" +#elif PLATFORM(QT) +#include <QTransform> +#elif PLATFORM(SKIA) +#include <SkMatrix.h> +#elif PLATFORM(WX) && USE(WXGC) +#include <wx/graphics.h> +#endif + +namespace WebCore { + +class FloatPoint; +class FloatQuad; +class FloatRect; +class IntPoint; +class IntRect; +class TransformationMatrix; + +class AffineTransform : public FastAllocBase { +public: + typedef double Transform[6]; + + AffineTransform(); + AffineTransform(double a, double b, double c, double d, double e, double f); + + void setMatrix(double a, double b, double c, double d, double e, double f); + + void map(double x, double y, double& x2, double& y2) const; + + // Rounds the mapped point to the nearest integer value. + IntPoint mapPoint(const IntPoint&) const; + + FloatPoint mapPoint(const FloatPoint&) const; + + // Rounds the resulting mapped rectangle out. This is helpful for bounding + // box computations but may not be what is wanted in other contexts. + IntRect mapRect(const IntRect&) const; + + FloatRect mapRect(const FloatRect&) const; + FloatQuad mapQuad(const FloatQuad&) const; + + bool isIdentity() const; + + double a() const { return m_transform[0]; } + void setA(double a) { m_transform[0] = a; } + double b() const { return m_transform[1]; } + void setB(double b) { m_transform[1] = b; } + double c() const { return m_transform[2]; } + void setC(double c) { m_transform[2] = c; } + double d() const { return m_transform[3]; } + void setD(double d) { m_transform[3] = d; } + double e() const { return m_transform[4]; } + void setE(double e) { m_transform[4] = e; } + double f() const { return m_transform[5]; } + void setF(double f) { m_transform[5] = f; } + + void makeIdentity(); + + AffineTransform& multiply(const AffineTransform&); + AffineTransform& multLeft(const AffineTransform&); + AffineTransform& scale(double); + AffineTransform& scale(double sx, double sy); + AffineTransform& scaleNonUniform(double sx, double sy); + AffineTransform& rotate(double d); + AffineTransform& rotateFromVector(double x, double y); + AffineTransform& translate(double tx, double ty); + AffineTransform& translateRight(double tx, double ty); + AffineTransform& shear(double sx, double sy); + AffineTransform& flipX(); + AffineTransform& flipY(); + AffineTransform& skew(double angleX, double angleY); + AffineTransform& skewX(double angle); + AffineTransform& skewY(double angle); + + double xScale() const; + double yScale() const; + + double det() const; + bool isInvertible() const; + AffineTransform inverse() const; + + void blend(const AffineTransform& from, double progress); + + TransformationMatrix toTransformationMatrix() const; + + bool isIdentityOrTranslation() const + { + return m_transform[0] == 1 && m_transform[1] == 0 && m_transform[2] == 0 && m_transform[3] == 1; + } + + bool isIdentityOrTranslationOrFlipped() const + { + return m_transform[0] == 1 && m_transform[1] == 0 && m_transform[2] == 0 && (m_transform[3] == 1 || m_transform[3] == -1); + } + + bool operator== (const AffineTransform& m2) const + { + return (m_transform[0] == m2.m_transform[0] + && m_transform[1] == m2.m_transform[1] + && m_transform[2] == m2.m_transform[2] + && m_transform[3] == m2.m_transform[3] + && m_transform[4] == m2.m_transform[4] + && m_transform[5] == m2.m_transform[5]); + } + + bool operator!=(const AffineTransform& other) const { return !(*this == other); } + + // *this = *this * t (i.e., a multRight) + AffineTransform& operator*=(const AffineTransform& t) + { + *this = *this * t; + return *this; + } + + // result = *this * t (i.e., a multRight) + AffineTransform operator*(const AffineTransform& t) const + { + AffineTransform result = t; + result.multLeft(*this); + return result; + } + +#if PLATFORM(CG) + operator CGAffineTransform() const; +#elif PLATFORM(CAIRO) + operator cairo_matrix_t() const; +#elif PLATFORM(OPENVG) + operator VGMatrix() const; +#elif PLATFORM(QT) + operator QTransform() const; +#elif PLATFORM(SKIA) + operator SkMatrix() const; +#elif PLATFORM(WX) && USE(WXGC) + operator wxGraphicsMatrix() const; +#endif + +private: + void setMatrix(const Transform m) + { + if (m && m != m_transform) + memcpy(m_transform, m, sizeof(Transform)); + } + + Transform m_transform; +}; + +AffineTransform makeMapBetweenRects(const FloatRect& source, const FloatRect& dest); + +} + +#endif diff --git a/Source/WebCore/platform/graphics/transforms/IdentityTransformOperation.h b/Source/WebCore/platform/graphics/transforms/IdentityTransformOperation.h new file mode 100644 index 0000000..347737c --- /dev/null +++ b/Source/WebCore/platform/graphics/transforms/IdentityTransformOperation.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2000 Lars Knoll (knoll@kde.org) + * (C) 2000 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com) + * + * 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., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef IdentityTransformOperation_h +#define IdentityTransformOperation_h + +#include "TransformOperation.h" + +namespace WebCore { + +class IdentityTransformOperation : public TransformOperation { +public: + static PassRefPtr<IdentityTransformOperation> create() + { + return adoptRef(new IdentityTransformOperation()); + } + +private: + virtual bool isIdentity() const { return true; } + virtual OperationType getOperationType() const { return IDENTITY; } + virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == IDENTITY; } + + virtual bool operator==(const TransformOperation& o) const + { + return isSameType(o); + } + + virtual bool apply(TransformationMatrix&, const IntSize&) const + { + return false; + } + + virtual PassRefPtr<TransformOperation> blend(const TransformOperation*, double, bool = false) + { + return this; + } + + IdentityTransformOperation() + { + } + +}; + +} // namespace WebCore + +#endif // IdentityTransformOperation_h diff --git a/Source/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.cpp b/Source/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.cpp new file mode 100644 index 0000000..230be3c --- /dev/null +++ b/Source/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2009 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 COMPUTER, 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. + */ + +#include "config.h" +#include "Matrix3DTransformOperation.h" + +#include <algorithm> + +using namespace std; + +namespace WebCore { + +PassRefPtr<TransformOperation> Matrix3DTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity) +{ + if (from && !from->isSameType(*this)) + return this; + + // Convert the TransformOperations into matrices + IntSize size; + TransformationMatrix fromT; + TransformationMatrix toT; + if (from) + from->apply(fromT, size); + + apply(toT, size); + + if (blendToIdentity) + std::swap(fromT, toT); + + toT.blend(fromT, progress); + return Matrix3DTransformOperation::create(toT); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.h b/Source/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.h new file mode 100644 index 0000000..0a0aaf0 --- /dev/null +++ b/Source/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2009 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 COMPUTER, 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. + */ + +#ifndef Matrix3DTransformOperation_h +#define Matrix3DTransformOperation_h + +#include "TransformOperation.h" + +namespace WebCore { + +class Matrix3DTransformOperation : public TransformOperation { +public: + static PassRefPtr<Matrix3DTransformOperation> create(const TransformationMatrix& matrix) + { + return adoptRef(new Matrix3DTransformOperation(matrix)); + } + + TransformationMatrix matrix() const {return m_matrix; } + +private: + virtual bool isIdentity() const { return m_matrix.isIdentity(); } + + virtual OperationType getOperationType() const { return MATRIX_3D; } + virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == MATRIX_3D; } + + virtual bool operator==(const TransformOperation& o) const + { + if (!isSameType(o)) + return false; + const Matrix3DTransformOperation* m = static_cast<const Matrix3DTransformOperation*>(&o); + return m_matrix == m->m_matrix; + } + + virtual bool apply(TransformationMatrix& transform, const IntSize&) const + { + transform.multLeft(TransformationMatrix(m_matrix)); + return false; + } + + virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false); + + Matrix3DTransformOperation(const TransformationMatrix& mat) + { + m_matrix = mat; + } + + TransformationMatrix m_matrix; +}; + +} // namespace WebCore + +#endif // Matrix3DTransformOperation_h diff --git a/Source/WebCore/platform/graphics/transforms/MatrixTransformOperation.cpp b/Source/WebCore/platform/graphics/transforms/MatrixTransformOperation.cpp new file mode 100644 index 0000000..0eaccea --- /dev/null +++ b/Source/WebCore/platform/graphics/transforms/MatrixTransformOperation.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * 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., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "MatrixTransformOperation.h" + +#include <algorithm> + +using namespace std; + +namespace WebCore { + +PassRefPtr<TransformOperation> MatrixTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity) +{ + if (from && !from->isSameType(*this)) + return this; + + // convert the TransformOperations into matrices + IntSize size; + TransformationMatrix fromT; + TransformationMatrix toT(m_a, m_b, m_c, m_d, m_e, m_f); + if (from) { + const MatrixTransformOperation* m = static_cast<const MatrixTransformOperation*>(from); + fromT.setMatrix(m->m_a, m->m_b, m->m_c, m->m_d, m->m_e, m->m_f); + } + + if (blendToIdentity) + std::swap(fromT, toT); + + toT.blend(fromT, progress); + return MatrixTransformOperation::create(toT.a(), toT.b(), toT.c(), toT.d(), toT.e(), toT.f()); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/transforms/MatrixTransformOperation.h b/Source/WebCore/platform/graphics/transforms/MatrixTransformOperation.h new file mode 100644 index 0000000..fd9b27e --- /dev/null +++ b/Source/WebCore/platform/graphics/transforms/MatrixTransformOperation.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2000 Lars Knoll (knoll@kde.org) + * (C) 2000 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com) + * + * 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., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef MatrixTransformOperation_h +#define MatrixTransformOperation_h + +#include "TransformOperation.h" +#include "TransformationMatrix.h" + +namespace WebCore { + +class MatrixTransformOperation : public TransformOperation { +public: + static PassRefPtr<MatrixTransformOperation> create(double a, double b, double c, double d, double e, double f) + { + return adoptRef(new MatrixTransformOperation(a, b, c, d, e, f)); + } + + static PassRefPtr<MatrixTransformOperation> create(const TransformationMatrix& t) + { + return adoptRef(new MatrixTransformOperation(t)); + } + + TransformationMatrix matrix() const { return TransformationMatrix(m_a, m_b, m_c, m_d, m_e, m_f); } + +private: + virtual bool isIdentity() const { return m_a == 1 && m_b == 0 && m_c == 0 && m_d == 1 && m_e == 0 && m_f == 0; } + + virtual OperationType getOperationType() const { return MATRIX; } + virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == MATRIX; } + + virtual bool operator==(const TransformOperation& o) const + { + if (!isSameType(o)) + return false; + + const MatrixTransformOperation* m = static_cast<const MatrixTransformOperation*>(&o); + return m_a == m->m_a && m_b == m->m_b && m_c == m->m_c && m_d == m->m_d && m_e == m->m_e && m_f == m->m_f; + } + + virtual bool apply(TransformationMatrix& transform, const IntSize&) const + { + TransformationMatrix matrix(m_a, m_b, m_c, m_d, m_e, m_f); + transform.multLeft(TransformationMatrix(matrix)); + return false; + } + + virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false); + + MatrixTransformOperation(double a, double b, double c, double d, double e, double f) + : m_a(a) + , m_b(b) + , m_c(c) + , m_d(d) + , m_e(e) + , m_f(f) + { + } + + MatrixTransformOperation(const TransformationMatrix& t) + : m_a(t.a()) + , m_b(t.b()) + , m_c(t.c()) + , m_d(t.d()) + , m_e(t.e()) + , m_f(t.f()) + { + } + + double m_a; + double m_b; + double m_c; + double m_d; + double m_e; + double m_f; +}; + +} // namespace WebCore + +#endif // MatrixTransformOperation_h diff --git a/Source/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.cpp b/Source/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.cpp new file mode 100644 index 0000000..9fd03a1 --- /dev/null +++ b/Source/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2009 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 COMPUTER, 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. + */ + +#include "config.h" +#include "PerspectiveTransformOperation.h" + +#include <algorithm> + +using namespace std; + +namespace WebCore { + +PassRefPtr<TransformOperation> PerspectiveTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity) +{ + if (from && !from->isSameType(*this)) + return this; + + if (blendToIdentity) + return PerspectiveTransformOperation::create(m_p + (1. - m_p) * progress); + + const PerspectiveTransformOperation* fromOp = static_cast<const PerspectiveTransformOperation*>(from); + double fromP = fromOp ? fromOp->m_p : 0; + double toP = m_p; + + TransformationMatrix fromT; + TransformationMatrix toT; + fromT.applyPerspective(fromP); + toT.applyPerspective(toP); + toT.blend(fromT, progress); + TransformationMatrix::DecomposedType decomp; + toT.decompose(decomp); + + return PerspectiveTransformOperation::create(decomp.perspectiveZ ? -1.0 / decomp.perspectiveZ : 0.0); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.h b/Source/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.h new file mode 100644 index 0000000..834cc83 --- /dev/null +++ b/Source/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2009 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 COMPUTER, 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. + */ + +#ifndef PerspectiveTransformOperation_h +#define PerspectiveTransformOperation_h + +#include "TransformOperation.h" + +namespace WebCore { + +class PerspectiveTransformOperation : public TransformOperation { +public: + static PassRefPtr<PerspectiveTransformOperation> create(double p) + { + return adoptRef(new PerspectiveTransformOperation(p)); + } + + double perspective() const { return m_p; } + +private: + virtual bool isIdentity() const { return m_p == 0; } + virtual OperationType getOperationType() const { return PERSPECTIVE; } + virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == PERSPECTIVE; } + + virtual bool operator==(const TransformOperation& o) const + { + if (!isSameType(o)) + return false; + const PerspectiveTransformOperation* p = static_cast<const PerspectiveTransformOperation*>(&o); + return m_p == p->m_p; + } + + virtual bool apply(TransformationMatrix& transform, const IntSize&) const + { + transform.applyPerspective(m_p); + return false; + } + + virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false); + + PerspectiveTransformOperation(double p) + : m_p(p) + { + } + + double m_p; +}; + +} // namespace WebCore + +#endif // PerspectiveTransformOperation_h diff --git a/Source/WebCore/platform/graphics/transforms/RotateTransformOperation.cpp b/Source/WebCore/platform/graphics/transforms/RotateTransformOperation.cpp new file mode 100644 index 0000000..919d174 --- /dev/null +++ b/Source/WebCore/platform/graphics/transforms/RotateTransformOperation.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * 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., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "RotateTransformOperation.h" + +#include <algorithm> +#include <wtf/MathExtras.h> + +using namespace std; + +namespace WebCore { + +PassRefPtr<TransformOperation> RotateTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity) +{ + if (from && !from->isSameType(*this)) + return this; + + if (blendToIdentity) + return RotateTransformOperation::create(m_x, m_y, m_z, m_angle - m_angle * progress, m_type); + + const RotateTransformOperation* fromOp = static_cast<const RotateTransformOperation*>(from); + + // Optimize for single axis rotation + if (!fromOp || (fromOp->m_x == 0 && fromOp->m_y == 0 && fromOp->m_z == 1) || + (fromOp->m_x == 0 && fromOp->m_y == 1 && fromOp->m_z == 0) || + (fromOp->m_x == 1 && fromOp->m_y == 0 && fromOp->m_z == 0)) { + double fromAngle = fromOp ? fromOp->m_angle : 0; + return RotateTransformOperation::create(fromOp ? fromOp->m_x : m_x, + fromOp ? fromOp->m_y : m_y, + fromOp ? fromOp->m_z : m_z, + fromAngle + (m_angle - fromAngle) * progress, m_type); + } + + const RotateTransformOperation* toOp = this; + + // Create the 2 rotation matrices + TransformationMatrix fromT; + TransformationMatrix toT; + fromT.rotate3d((float)(fromOp ? fromOp->m_x : 0), + (float)(fromOp ? fromOp->m_y : 0), + (float)(fromOp ? fromOp->m_z : 1), + (float)(fromOp ? fromOp->m_angle : 0)); + + toT.rotate3d((float)(toOp ? toOp->m_x : 0), + (float)(toOp ? toOp->m_y : 0), + (float)(toOp ? toOp->m_z : 1), + (float)(toOp ? toOp->m_angle : 0)); + + // Blend them + toT.blend(fromT, progress); + + // Extract the result as a quaternion + TransformationMatrix::DecomposedType decomp; + toT.decompose(decomp); + + // Convert that to Axis/Angle form + double x = -decomp.quaternionX; + double y = -decomp.quaternionY; + double z = -decomp.quaternionZ; + double length = sqrt(x * x + y * y + z * z); + double angle = 0; + + if (length > 0.00001) { + x /= length; + y /= length; + z /= length; + angle = rad2deg(acos(decomp.quaternionW) * 2); + } else { + x = 0; + y = 0; + z = 1; + } + return RotateTransformOperation::create(x, y, z, angle, ROTATE_3D); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/transforms/RotateTransformOperation.h b/Source/WebCore/platform/graphics/transforms/RotateTransformOperation.h new file mode 100644 index 0000000..2acb002 --- /dev/null +++ b/Source/WebCore/platform/graphics/transforms/RotateTransformOperation.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2000 Lars Knoll (knoll@kde.org) + * (C) 2000 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com) + * + * 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., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef RotateTransformOperation_h +#define RotateTransformOperation_h + +#include "TransformOperation.h" + +namespace WebCore { + +class RotateTransformOperation : public TransformOperation { +public: + static PassRefPtr<RotateTransformOperation> create(double angle, OperationType type) + { + return adoptRef(new RotateTransformOperation(0, 0, 1, angle, type)); + } + + static PassRefPtr<RotateTransformOperation> create(double x, double y, double z, double angle, OperationType type) + { + return adoptRef(new RotateTransformOperation(x, y, z, angle, type)); + } + + double x() const { return m_x; } + double y() const { return m_y; } + double z() const { return m_z; } + double angle() const { return m_angle; } + +private: + virtual bool isIdentity() const { return m_angle == 0; } + + virtual OperationType getOperationType() const { return m_type; } + virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == m_type; } + + virtual bool operator==(const TransformOperation& o) const + { + if (!isSameType(o)) + return false; + const RotateTransformOperation* r = static_cast<const RotateTransformOperation*>(&o); + return m_x == r->m_x && m_y == r->m_y && m_z == r->m_z && m_angle == r->m_angle; + } + + virtual bool apply(TransformationMatrix& transform, const IntSize& /*borderBoxSize*/) const + { + transform.rotate3d(m_x, m_y, m_z, m_angle); + return false; + } + + virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false); + + RotateTransformOperation(double x, double y, double z, double angle, OperationType type) + : m_x(x) + , m_y(y) + , m_z(z) + , m_angle(angle) + , m_type(type) + { + ASSERT(type == ROTATE_X || type == ROTATE_Y || type == ROTATE_Z || type == ROTATE_3D); + } + + double m_x; + double m_y; + double m_z; + double m_angle; + OperationType m_type; +}; + +} // namespace WebCore + +#endif // RotateTransformOperation_h diff --git a/Source/WebCore/platform/graphics/transforms/ScaleTransformOperation.cpp b/Source/WebCore/platform/graphics/transforms/ScaleTransformOperation.cpp new file mode 100644 index 0000000..45d119c --- /dev/null +++ b/Source/WebCore/platform/graphics/transforms/ScaleTransformOperation.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * 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., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "ScaleTransformOperation.h" + +namespace WebCore { + +PassRefPtr<TransformOperation> ScaleTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity) +{ + if (from && !from->isSameType(*this)) + return this; + + if (blendToIdentity) + return ScaleTransformOperation::create(m_x + (1. - m_x) * progress, + m_y + (1. - m_y) * progress, + m_z + (1. - m_z) * progress, m_type); + + const ScaleTransformOperation* fromOp = static_cast<const ScaleTransformOperation*>(from); + double fromX = fromOp ? fromOp->m_x : 1.; + double fromY = fromOp ? fromOp->m_y : 1.; + double fromZ = fromOp ? fromOp->m_z : 1.; + return ScaleTransformOperation::create(fromX + (m_x - fromX) * progress, + fromY + (m_y - fromY) * progress, + fromZ + (m_z - fromZ) * progress, m_type); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/transforms/ScaleTransformOperation.h b/Source/WebCore/platform/graphics/transforms/ScaleTransformOperation.h new file mode 100644 index 0000000..a87bb3b --- /dev/null +++ b/Source/WebCore/platform/graphics/transforms/ScaleTransformOperation.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2000 Lars Knoll (knoll@kde.org) + * (C) 2000 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com) + * + * 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., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef ScaleTransformOperation_h +#define ScaleTransformOperation_h + +#include "TransformOperation.h" + +namespace WebCore { + +class ScaleTransformOperation : public TransformOperation { +public: + static PassRefPtr<ScaleTransformOperation> create(double sx, double sy, OperationType type) + { + return adoptRef(new ScaleTransformOperation(sx, sy, 1, type)); + } + + static PassRefPtr<ScaleTransformOperation> create(double sx, double sy, double sz, OperationType type) + { + return adoptRef(new ScaleTransformOperation(sx, sy, sz, type)); + } + + double x() const { return m_x; } + double y() const { return m_y; } + double z() const { return m_z; } + +private: + virtual bool isIdentity() const { return m_x == 1 && m_y == 1 && m_z == 1; } + + virtual OperationType getOperationType() const { return m_type; } + virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == m_type; } + + virtual bool operator==(const TransformOperation& o) const + { + if (!isSameType(o)) + return false; + const ScaleTransformOperation* s = static_cast<const ScaleTransformOperation*>(&o); + return m_x == s->m_x && m_y == s->m_y && m_z == s->m_z; + } + + virtual bool apply(TransformationMatrix& transform, const IntSize&) const + { + transform.scale3d(m_x, m_y, m_z); + return false; + } + + virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false); + + ScaleTransformOperation(double sx, double sy, double sz, OperationType type) + : m_x(sx) + , m_y(sy) + , m_z(sz) + , m_type(type) + { + ASSERT(type == SCALE_X || type == SCALE_Y || type == SCALE_Z || type == SCALE || type == SCALE_3D); + } + + double m_x; + double m_y; + double m_z; + OperationType m_type; +}; + +} // namespace WebCore + +#endif // ScaleTransformOperation_h diff --git a/Source/WebCore/platform/graphics/transforms/SkewTransformOperation.cpp b/Source/WebCore/platform/graphics/transforms/SkewTransformOperation.cpp new file mode 100644 index 0000000..2a430e9 --- /dev/null +++ b/Source/WebCore/platform/graphics/transforms/SkewTransformOperation.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * 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., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "SkewTransformOperation.h" + +namespace WebCore { + +PassRefPtr<TransformOperation> SkewTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity) +{ + if (from && !from->isSameType(*this)) + return this; + + if (blendToIdentity) + return SkewTransformOperation::create(m_angleX - m_angleX * progress, m_angleY - m_angleY * progress, m_type); + + const SkewTransformOperation* fromOp = static_cast<const SkewTransformOperation*>(from); + double fromAngleX = fromOp ? fromOp->m_angleX : 0; + double fromAngleY = fromOp ? fromOp->m_angleY : 0; + return SkewTransformOperation::create(fromAngleX + (m_angleX - fromAngleX) * progress, fromAngleY + (m_angleY - fromAngleY) * progress, m_type); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/transforms/SkewTransformOperation.h b/Source/WebCore/platform/graphics/transforms/SkewTransformOperation.h new file mode 100644 index 0000000..afe9a7b --- /dev/null +++ b/Source/WebCore/platform/graphics/transforms/SkewTransformOperation.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2000 Lars Knoll (knoll@kde.org) + * (C) 2000 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com) + * + * 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., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef SkewTransformOperation_h +#define SkewTransformOperation_h + +#include "TransformOperation.h" + +namespace WebCore { + +class SkewTransformOperation : public TransformOperation { +public: + static PassRefPtr<SkewTransformOperation> create(double angleX, double angleY, OperationType type) + { + return adoptRef(new SkewTransformOperation(angleX, angleY, type)); + } + + double angleX() const { return m_angleX; } + double angleY() const { return m_angleY; } + +private: + virtual bool isIdentity() const { return m_angleX == 0 && m_angleY == 0; } + virtual OperationType getOperationType() const { return m_type; } + virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == m_type; } + + virtual bool operator==(const TransformOperation& o) const + { + if (!isSameType(o)) + return false; + const SkewTransformOperation* s = static_cast<const SkewTransformOperation*>(&o); + return m_angleX == s->m_angleX && m_angleY == s->m_angleY; + } + + virtual bool apply(TransformationMatrix& transform, const IntSize&) const + { + transform.skew(m_angleX, m_angleY); + return false; + } + + virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false); + + SkewTransformOperation(double angleX, double angleY, OperationType type) + : m_angleX(angleX) + , m_angleY(angleY) + , m_type(type) + { + } + + double m_angleX; + double m_angleY; + OperationType m_type; +}; + +} // namespace WebCore + +#endif // SkewTransformOperation_h diff --git a/Source/WebCore/platform/graphics/transforms/TransformOperation.h b/Source/WebCore/platform/graphics/transforms/TransformOperation.h new file mode 100644 index 0000000..c610c4b --- /dev/null +++ b/Source/WebCore/platform/graphics/transforms/TransformOperation.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2000 Lars Knoll (knoll@kde.org) + * (C) 2000 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com) + * + * 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., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef TransformOperation_h +#define TransformOperation_h + +#include "TransformationMatrix.h" +#include "IntSize.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + +// CSS Transforms (may become part of CSS3) + +class TransformOperation : public RefCounted<TransformOperation> { +public: + enum OperationType { + SCALE_X, SCALE_Y, SCALE, + TRANSLATE_X, TRANSLATE_Y, TRANSLATE, + ROTATE, + ROTATE_Z = ROTATE, + SKEW_X, SKEW_Y, SKEW, + MATRIX, + SCALE_Z, SCALE_3D, + TRANSLATE_Z, TRANSLATE_3D, + ROTATE_X, ROTATE_Y, ROTATE_3D, + MATRIX_3D, + PERSPECTIVE, + IDENTITY, NONE + }; + + virtual ~TransformOperation() { } + + virtual bool operator==(const TransformOperation&) const = 0; + bool operator!=(const TransformOperation& o) const { return !(*this == o); } + + virtual bool isIdentity() const = 0; + + // Return true if the borderBoxSize was used in the computation, false otherwise. + virtual bool apply(TransformationMatrix&, const IntSize& borderBoxSize) const = 0; + + virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false) = 0; + + virtual OperationType getOperationType() const = 0; + virtual bool isSameType(const TransformOperation&) const { return false; } + + bool is3DOperation() const + { + OperationType opType = getOperationType(); + return opType == SCALE_Z || + opType == SCALE_3D || + opType == TRANSLATE_Z || + opType == TRANSLATE_3D || + opType == ROTATE_X || + opType == ROTATE_Y || + opType == ROTATE_3D || + opType == MATRIX_3D || + opType == PERSPECTIVE; + } +}; + +} // namespace WebCore + +#endif // TransformOperation_h diff --git a/Source/WebCore/platform/graphics/transforms/TransformOperations.cpp b/Source/WebCore/platform/graphics/transforms/TransformOperations.cpp new file mode 100644 index 0000000..3d71480 --- /dev/null +++ b/Source/WebCore/platform/graphics/transforms/TransformOperations.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * 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., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "TransformOperations.h" + +#include "IdentityTransformOperation.h" + +namespace WebCore { + +TransformOperations::TransformOperations(bool makeIdentity) +{ + if (makeIdentity) + m_operations.append(IdentityTransformOperation::create()); +} + +bool TransformOperations::operator==(const TransformOperations& o) const +{ + if (m_operations.size() != o.m_operations.size()) + return false; + + unsigned s = m_operations.size(); + for (unsigned i = 0; i < s; i++) { + if (*m_operations[i] != *o.m_operations[i]) + return false; + } + + return true; +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/transforms/TransformOperations.h b/Source/WebCore/platform/graphics/transforms/TransformOperations.h new file mode 100644 index 0000000..c0da377 --- /dev/null +++ b/Source/WebCore/platform/graphics/transforms/TransformOperations.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2000 Lars Knoll (knoll@kde.org) + * (C) 2000 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com) + * + * 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., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef TransformOperations_h +#define TransformOperations_h + +#include "TransformOperation.h" +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class TransformOperations : public FastAllocBase { +public: + TransformOperations(bool makeIdentity = false); + + bool operator==(const TransformOperations& o) const; + bool operator!=(const TransformOperations& o) const + { + return !(*this == o); + } + + void apply(const IntSize& sz, TransformationMatrix& t) const + { + for (unsigned i = 0; i < m_operations.size(); ++i) + m_operations[i]->apply(t, sz); + } + + // Return true if any of the operation types are 3D operation types (even if the + // values describe affine transforms) + bool has3DOperation() const + { + for (unsigned i = 0; i < m_operations.size(); ++i) + if (m_operations[i]->is3DOperation()) + return true; + return false; + } + + void clear() + { + m_operations.clear(); + } + + Vector<RefPtr<TransformOperation> >& operations() { return m_operations; } + const Vector<RefPtr<TransformOperation> >& operations() const { return m_operations; } + + size_t size() const { return m_operations.size(); } + const TransformOperation* at(size_t index) const { return index < m_operations.size() ? m_operations.at(index).get() : 0; } + +private: + Vector<RefPtr<TransformOperation> > m_operations; +}; + +} // namespace WebCore + +#endif // TransformOperations_h diff --git a/Source/WebCore/platform/graphics/transforms/TransformationMatrix.cpp b/Source/WebCore/platform/graphics/transforms/TransformationMatrix.cpp new file mode 100644 index 0000000..10c7f70 --- /dev/null +++ b/Source/WebCore/platform/graphics/transforms/TransformationMatrix.cpp @@ -0,0 +1,1132 @@ +/* + * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (C) 2009 Torch Mobile, Inc. + * + * 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 COMPUTER, 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 COMPUTER, 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. + */ + +#include "config.h" +#include "TransformationMatrix.h" + +#include "FloatPoint3D.h" +#include "FloatRect.h" +#include "FloatQuad.h" +#include "IntRect.h" + +#include <wtf/Assertions.h> +#include <wtf/MathExtras.h> + +namespace WebCore { + +// +// Supporting Math Functions +// +// This is a set of function from various places (attributed inline) to do things like +// inversion and decomposition of a 4x4 matrix. They are used throughout the code +// + +// +// Adapted from Matrix Inversion by Richard Carling, Graphics Gems <http://tog.acm.org/GraphicsGems/index.html>. + +// EULA: The Graphics Gems code is copyright-protected. In other words, you cannot claim the text of the code +// as your own and resell it. Using the code is permitted in any program, product, or library, non-commercial +// or commercial. Giving credit is not required, though is a nice gesture. The code comes as-is, and if there +// are any flaws or problems with any Gems code, nobody involved with Gems - authors, editors, publishers, or +// webmasters - are to be held responsible. Basically, don't be a jerk, and remember that anything free comes +// with no guarantee. + +// A Note About row-major vs. column major matrixes +// +// The clients of this class (CSSMatrix and SVGMatrix) assume a column-major ordering. +// That means that when the matrix is initialized with 16 values, the first 4 values +// go in the 4 rows of the first column, etc. And in the dereferencing calls, the first +// digit is the column (e.g., m23() is column 2 row 3). Because C++ uses row-major arrays +// the internal matrix is stored in row-major order, so m[2][0] means row 2, column 0. This +// has no bearing on how the matrix is viewed on the outside, since all access is done +// with function calls. But it does help make the code more clear if you know that. +// +// FIXME: Multiply calls are named for what they do in the internal, row-major world. +// multLeft is actually a multRight in a column-major world, and multiply is a multLeft +// in a column-major world. For now I've left it that way to avoid too many confusing +// changes to the code. In particular AffineTransform uses these same terms for the +// opposite operations. So we have to be VERY careful when we change them. + +typedef double Vector4[4]; +typedef double Vector3[3]; + +const double SMALL_NUMBER = 1.e-8; + +// inverse(original_matrix, inverse_matrix) +// +// calculate the inverse of a 4x4 matrix +// +// -1 +// A = ___1__ adjoint A +// det A + +// double = determinant2x2(double a, double b, double c, double d) +// +// calculate the determinant of a 2x2 matrix. + +static double determinant2x2(double a, double b, double c, double d) +{ + return a * d - b * c; +} + +// double = determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3) +// +// Calculate the determinant of a 3x3 matrix +// in the form +// +// | a1, b1, c1 | +// | a2, b2, c2 | +// | a3, b3, c3 | + +static double determinant3x3(double a1, double a2, double a3, double b1, double b2, double b3, double c1, double c2, double c3) +{ + return a1 * determinant2x2(b2, b3, c2, c3) + - b1 * determinant2x2(a2, a3, c2, c3) + + c1 * determinant2x2(a2, a3, b2, b3); +} + +// double = determinant4x4(matrix) +// +// calculate the determinant of a 4x4 matrix. + +static double determinant4x4(const TransformationMatrix::Matrix4& m) +{ + // Assign to individual variable names to aid selecting + // correct elements + + double a1 = m[0][0]; + double b1 = m[0][1]; + double c1 = m[0][2]; + double d1 = m[0][3]; + + double a2 = m[1][0]; + double b2 = m[1][1]; + double c2 = m[1][2]; + double d2 = m[1][3]; + + double a3 = m[2][0]; + double b3 = m[2][1]; + double c3 = m[2][2]; + double d3 = m[2][3]; + + double a4 = m[3][0]; + double b4 = m[3][1]; + double c4 = m[3][2]; + double d4 = m[3][3]; + + return a1 * determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4) + - b1 * determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4) + + c1 * determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4) + - d1 * determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4); +} + +// adjoint( original_matrix, inverse_matrix ) +// +// calculate the adjoint of a 4x4 matrix +// +// Let a denote the minor determinant of matrix A obtained by +// ij +// +// deleting the ith row and jth column from A. +// +// i+j +// Let b = (-1) a +// ij ji +// +// The matrix B = (b ) is the adjoint of A +// ij + +static void adjoint(const TransformationMatrix::Matrix4& matrix, TransformationMatrix::Matrix4& result) +{ + // Assign to individual variable names to aid + // selecting correct values + double a1 = matrix[0][0]; + double b1 = matrix[0][1]; + double c1 = matrix[0][2]; + double d1 = matrix[0][3]; + + double a2 = matrix[1][0]; + double b2 = matrix[1][1]; + double c2 = matrix[1][2]; + double d2 = matrix[1][3]; + + double a3 = matrix[2][0]; + double b3 = matrix[2][1]; + double c3 = matrix[2][2]; + double d3 = matrix[2][3]; + + double a4 = matrix[3][0]; + double b4 = matrix[3][1]; + double c4 = matrix[3][2]; + double d4 = matrix[3][3]; + + // Row column labeling reversed since we transpose rows & columns + result[0][0] = determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4); + result[1][0] = - determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4); + result[2][0] = determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4); + result[3][0] = - determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4); + + result[0][1] = - determinant3x3(b1, b3, b4, c1, c3, c4, d1, d3, d4); + result[1][1] = determinant3x3(a1, a3, a4, c1, c3, c4, d1, d3, d4); + result[2][1] = - determinant3x3(a1, a3, a4, b1, b3, b4, d1, d3, d4); + result[3][1] = determinant3x3(a1, a3, a4, b1, b3, b4, c1, c3, c4); + + result[0][2] = determinant3x3(b1, b2, b4, c1, c2, c4, d1, d2, d4); + result[1][2] = - determinant3x3(a1, a2, a4, c1, c2, c4, d1, d2, d4); + result[2][2] = determinant3x3(a1, a2, a4, b1, b2, b4, d1, d2, d4); + result[3][2] = - determinant3x3(a1, a2, a4, b1, b2, b4, c1, c2, c4); + + result[0][3] = - determinant3x3(b1, b2, b3, c1, c2, c3, d1, d2, d3); + result[1][3] = determinant3x3(a1, a2, a3, c1, c2, c3, d1, d2, d3); + result[2][3] = - determinant3x3(a1, a2, a3, b1, b2, b3, d1, d2, d3); + result[3][3] = determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3); +} + +// Returns false if the matrix is not invertible +static bool inverse(const TransformationMatrix::Matrix4& matrix, TransformationMatrix::Matrix4& result) +{ + // Calculate the adjoint matrix + adjoint(matrix, result); + + // Calculate the 4x4 determinant + // If the determinant is zero, + // then the inverse matrix is not unique. + double det = determinant4x4(matrix); + + if (fabs(det) < SMALL_NUMBER) + return false; + + // Scale the adjoint matrix to get the inverse + + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) + result[i][j] = result[i][j] / det; + + return true; +} + +// End of code adapted from Matrix Inversion by Richard Carling + +// Perform a decomposition on the passed matrix, return false if unsuccessful +// From Graphics Gems: unmatrix.c + +// Transpose rotation portion of matrix a, return b +static void transposeMatrix4(const TransformationMatrix::Matrix4& a, TransformationMatrix::Matrix4& b) +{ + for (int i = 0; i < 4; i++) + for (int j = 0; j < 4; j++) + b[i][j] = a[j][i]; +} + +// Multiply a homogeneous point by a matrix and return the transformed point +static void v4MulPointByMatrix(const Vector4 p, const TransformationMatrix::Matrix4& m, Vector4 result) +{ + result[0] = (p[0] * m[0][0]) + (p[1] * m[1][0]) + + (p[2] * m[2][0]) + (p[3] * m[3][0]); + result[1] = (p[0] * m[0][1]) + (p[1] * m[1][1]) + + (p[2] * m[2][1]) + (p[3] * m[3][1]); + result[2] = (p[0] * m[0][2]) + (p[1] * m[1][2]) + + (p[2] * m[2][2]) + (p[3] * m[3][2]); + result[3] = (p[0] * m[0][3]) + (p[1] * m[1][3]) + + (p[2] * m[2][3]) + (p[3] * m[3][3]); +} + +static double v3Length(Vector3 a) +{ + return sqrt((a[0] * a[0]) + (a[1] * a[1]) + (a[2] * a[2])); +} + +static void v3Scale(Vector3 v, double desiredLength) +{ + double len = v3Length(v); + if (len != 0) { + double l = desiredLength / len; + v[0] *= l; + v[1] *= l; + v[2] *= l; + } +} + +static double v3Dot(const Vector3 a, const Vector3 b) +{ + return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]); +} + +// Make a linear combination of two vectors and return the result. +// result = (a * ascl) + (b * bscl) +static void v3Combine(const Vector3 a, const Vector3 b, Vector3 result, double ascl, double bscl) +{ + result[0] = (ascl * a[0]) + (bscl * b[0]); + result[1] = (ascl * a[1]) + (bscl * b[1]); + result[2] = (ascl * a[2]) + (bscl * b[2]); +} + +// Return the cross product result = a cross b */ +static void v3Cross(const Vector3 a, const Vector3 b, Vector3 result) +{ + result[0] = (a[1] * b[2]) - (a[2] * b[1]); + result[1] = (a[2] * b[0]) - (a[0] * b[2]); + result[2] = (a[0] * b[1]) - (a[1] * b[0]); +} + +static bool decompose(const TransformationMatrix::Matrix4& mat, TransformationMatrix::DecomposedType& result) +{ + TransformationMatrix::Matrix4 localMatrix; + memcpy(localMatrix, mat, sizeof(TransformationMatrix::Matrix4)); + + // Normalize the matrix. + if (localMatrix[3][3] == 0) + return false; + + int i, j; + for (i = 0; i < 4; i++) + for (j = 0; j < 4; j++) + localMatrix[i][j] /= localMatrix[3][3]; + + // perspectiveMatrix is used to solve for perspective, but it also provides + // an easy way to test for singularity of the upper 3x3 component. + TransformationMatrix::Matrix4 perspectiveMatrix; + memcpy(perspectiveMatrix, localMatrix, sizeof(TransformationMatrix::Matrix4)); + for (i = 0; i < 3; i++) + perspectiveMatrix[i][3] = 0; + perspectiveMatrix[3][3] = 1; + + if (determinant4x4(perspectiveMatrix) == 0) + return false; + + // First, isolate perspective. This is the messiest. + if (localMatrix[0][3] != 0 || localMatrix[1][3] != 0 || localMatrix[2][3] != 0) { + // rightHandSide is the right hand side of the equation. + Vector4 rightHandSide; + rightHandSide[0] = localMatrix[0][3]; + rightHandSide[1] = localMatrix[1][3]; + rightHandSide[2] = localMatrix[2][3]; + rightHandSide[3] = localMatrix[3][3]; + + // Solve the equation by inverting perspectiveMatrix and multiplying + // rightHandSide by the inverse. (This is the easiest way, not + // necessarily the best.) + TransformationMatrix::Matrix4 inversePerspectiveMatrix, transposedInversePerspectiveMatrix; + inverse(perspectiveMatrix, inversePerspectiveMatrix); + transposeMatrix4(inversePerspectiveMatrix, transposedInversePerspectiveMatrix); + + Vector4 perspectivePoint; + v4MulPointByMatrix(rightHandSide, transposedInversePerspectiveMatrix, perspectivePoint); + + result.perspectiveX = perspectivePoint[0]; + result.perspectiveY = perspectivePoint[1]; + result.perspectiveZ = perspectivePoint[2]; + result.perspectiveW = perspectivePoint[3]; + + // Clear the perspective partition + localMatrix[0][3] = localMatrix[1][3] = localMatrix[2][3] = 0; + localMatrix[3][3] = 1; + } else { + // No perspective. + result.perspectiveX = result.perspectiveY = result.perspectiveZ = 0; + result.perspectiveW = 1; + } + + // Next take care of translation (easy). + result.translateX = localMatrix[3][0]; + localMatrix[3][0] = 0; + result.translateY = localMatrix[3][1]; + localMatrix[3][1] = 0; + result.translateZ = localMatrix[3][2]; + localMatrix[3][2] = 0; + + // Vector4 type and functions need to be added to the common set. + Vector3 row[3], pdum3; + + // Now get scale and shear. + for (i = 0; i < 3; i++) { + row[i][0] = localMatrix[i][0]; + row[i][1] = localMatrix[i][1]; + row[i][2] = localMatrix[i][2]; + } + + // Compute X scale factor and normalize first row. + result.scaleX = v3Length(row[0]); + v3Scale(row[0], 1.0); + + // Compute XY shear factor and make 2nd row orthogonal to 1st. + result.skewXY = v3Dot(row[0], row[1]); + v3Combine(row[1], row[0], row[1], 1.0, -result.skewXY); + + // Now, compute Y scale and normalize 2nd row. + result.scaleY = v3Length(row[1]); + v3Scale(row[1], 1.0); + result.skewXY /= result.scaleY; + + // Compute XZ and YZ shears, orthogonalize 3rd row. + result.skewXZ = v3Dot(row[0], row[2]); + v3Combine(row[2], row[0], row[2], 1.0, -result.skewXZ); + result.skewYZ = v3Dot(row[1], row[2]); + v3Combine(row[2], row[1], row[2], 1.0, -result.skewYZ); + + // Next, get Z scale and normalize 3rd row. + result.scaleZ = v3Length(row[2]); + v3Scale(row[2], 1.0); + result.skewXZ /= result.scaleZ; + result.skewYZ /= result.scaleZ; + + // At this point, the matrix (in rows[]) is orthonormal. + // Check for a coordinate system flip. If the determinant + // is -1, then negate the matrix and the scaling factors. + v3Cross(row[1], row[2], pdum3); + if (v3Dot(row[0], pdum3) < 0) { + for (i = 0; i < 3; i++) { + result.scaleX *= -1; + row[i][0] *= -1; + row[i][1] *= -1; + row[i][2] *= -1; + } + } + + // Now, get the rotations out, as described in the gem. + + // FIXME - Add the ability to return either quaternions (which are + // easier to recompose with) or Euler angles (rx, ry, rz), which + // are easier for authors to deal with. The latter will only be useful + // when we fix https://bugs.webkit.org/show_bug.cgi?id=23799, so I + // will leave the Euler angle code here for now. + + // ret.rotateY = asin(-row[0][2]); + // if (cos(ret.rotateY) != 0) { + // ret.rotateX = atan2(row[1][2], row[2][2]); + // ret.rotateZ = atan2(row[0][1], row[0][0]); + // } else { + // ret.rotateX = atan2(-row[2][0], row[1][1]); + // ret.rotateZ = 0; + // } + + double s, t, x, y, z, w; + + t = row[0][0] + row[1][1] + row[2][2] + 1.0; + + if (t > 1e-4) { + s = 0.5 / sqrt(t); + w = 0.25 / s; + x = (row[2][1] - row[1][2]) * s; + y = (row[0][2] - row[2][0]) * s; + z = (row[1][0] - row[0][1]) * s; + } else if (row[0][0] > row[1][1] && row[0][0] > row[2][2]) { + s = sqrt (1.0 + row[0][0] - row[1][1] - row[2][2]) * 2.0; // S=4*qx + x = 0.25 * s; + y = (row[0][1] + row[1][0]) / s; + z = (row[0][2] + row[2][0]) / s; + w = (row[2][1] - row[1][2]) / s; + } else if (row[1][1] > row[2][2]) { + s = sqrt (1.0 + row[1][1] - row[0][0] - row[2][2]) * 2.0; // S=4*qy + x = (row[0][1] + row[1][0]) / s; + y = 0.25 * s; + z = (row[1][2] + row[2][1]) / s; + w = (row[0][2] - row[2][0]) / s; + } else { + s = sqrt(1.0 + row[2][2] - row[0][0] - row[1][1]) * 2.0; // S=4*qz + x = (row[0][2] + row[2][0]) / s; + y = (row[1][2] + row[2][1]) / s; + z = 0.25 * s; + w = (row[1][0] - row[0][1]) / s; + } + + result.quaternionX = x; + result.quaternionY = y; + result.quaternionZ = z; + result.quaternionW = w; + + return true; +} + +// Perform a spherical linear interpolation between the two +// passed quaternions with 0 <= t <= 1 +static void slerp(double qa[4], const double qb[4], double t) +{ + double ax, ay, az, aw; + double bx, by, bz, bw; + double cx, cy, cz, cw; + double angle; + double th, invth, scale, invscale; + + ax = qa[0]; ay = qa[1]; az = qa[2]; aw = qa[3]; + bx = qb[0]; by = qb[1]; bz = qb[2]; bw = qb[3]; + + angle = ax * bx + ay * by + az * bz + aw * bw; + + if (angle < 0.0) { + ax = -ax; ay = -ay; + az = -az; aw = -aw; + angle = -angle; + } + + if (angle + 1.0 > .05) { + if (1.0 - angle >= .05) { + th = acos (angle); + invth = 1.0 / sin (th); + scale = sin (th * (1.0 - t)) * invth; + invscale = sin (th * t) * invth; + } else { + scale = 1.0 - t; + invscale = t; + } + } else { + bx = -ay; + by = ax; + bz = -aw; + bw = az; + scale = sin(piDouble * (.5 - t)); + invscale = sin (piDouble * t); + } + + cx = ax * scale + bx * invscale; + cy = ay * scale + by * invscale; + cz = az * scale + bz * invscale; + cw = aw * scale + bw * invscale; + + qa[0] = cx; qa[1] = cy; qa[2] = cz; qa[3] = cw; +} + +// End of Supporting Math Functions + +TransformationMatrix& TransformationMatrix::scale(double s) +{ + return scaleNonUniform(s, s); +} + +TransformationMatrix& TransformationMatrix::rotateFromVector(double x, double y) +{ + return rotate(rad2deg(atan2(y, x))); +} + +TransformationMatrix& TransformationMatrix::flipX() +{ + return scaleNonUniform(-1.0f, 1.0f); +} + +TransformationMatrix& TransformationMatrix::flipY() +{ + return scaleNonUniform(1.0f, -1.0f); +} + +FloatPoint TransformationMatrix::projectPoint(const FloatPoint& p) const +{ + // This is basically raytracing. We have a point in the destination + // plane with z=0, and we cast a ray parallel to the z-axis from that + // point to find the z-position at which it intersects the z=0 plane + // with the transform applied. Once we have that point we apply the + // inverse transform to find the corresponding point in the source + // space. + // + // Given a plane with normal Pn, and a ray starting at point R0 and + // with direction defined by the vector Rd, we can find the + // intersection point as a distance d from R0 in units of Rd by: + // + // d = -dot (Pn', R0) / dot (Pn', Rd) + + double x = p.x(); + double y = p.y(); + double z = -(m13() * x + m23() * y + m43()) / m33(); + + double outX = x * m11() + y * m21() + z * m31() + m41(); + double outY = x * m12() + y * m22() + z * m32() + m42(); + + double w = x * m14() + y * m24() + z * m34() + m44(); + if (w != 1 && w != 0) { + outX /= w; + outY /= w; + } + + return FloatPoint(static_cast<float>(outX), static_cast<float>(outY)); +} + +FloatQuad TransformationMatrix::projectQuad(const FloatQuad& q) const +{ + FloatQuad projectedQuad; + projectedQuad.setP1(projectPoint(q.p1())); + projectedQuad.setP2(projectPoint(q.p2())); + projectedQuad.setP3(projectPoint(q.p3())); + projectedQuad.setP4(projectPoint(q.p4())); + return projectedQuad; +} + +FloatPoint TransformationMatrix::mapPoint(const FloatPoint& p) const +{ + if (isIdentityOrTranslation()) + return FloatPoint(p.x() + static_cast<float>(m_matrix[3][0]), p.y() + static_cast<float>(m_matrix[3][1])); + + double x, y; + multVecMatrix(p.x(), p.y(), x, y); + return FloatPoint(static_cast<float>(x), static_cast<float>(y)); +} + +FloatPoint3D TransformationMatrix::mapPoint(const FloatPoint3D& p) const +{ + if (isIdentityOrTranslation()) + return FloatPoint3D(p.x() + static_cast<float>(m_matrix[3][0]), + p.y() + static_cast<float>(m_matrix[3][1]), + p.z() + static_cast<float>(m_matrix[3][2])); + + double x, y, z; + multVecMatrix(p.x(), p.y(), p.z(), x, y, z); + return FloatPoint3D(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z)); +} + +IntRect TransformationMatrix::mapRect(const IntRect &rect) const +{ + return enclosingIntRect(mapRect(FloatRect(rect))); +} + +FloatRect TransformationMatrix::mapRect(const FloatRect& r) const +{ + if (isIdentityOrTranslation()) { + FloatRect mappedRect(r); + mappedRect.move(static_cast<float>(m_matrix[3][0]), static_cast<float>(m_matrix[3][1])); + return mappedRect; + } + + FloatQuad resultQuad = mapQuad(FloatQuad(r)); + return resultQuad.boundingBox(); +} + +FloatQuad TransformationMatrix::mapQuad(const FloatQuad& q) const +{ + if (isIdentityOrTranslation()) { + FloatQuad mappedQuad(q); + mappedQuad.move(static_cast<float>(m_matrix[3][0]), static_cast<float>(m_matrix[3][1])); + return mappedQuad; + } + + FloatQuad result; + result.setP1(mapPoint(q.p1())); + result.setP2(mapPoint(q.p2())); + result.setP3(mapPoint(q.p3())); + result.setP4(mapPoint(q.p4())); + return result; +} + +TransformationMatrix& TransformationMatrix::scaleNonUniform(double sx, double sy) +{ + TransformationMatrix mat; + mat.m_matrix[0][0] = sx; + mat.m_matrix[1][1] = sy; + + multLeft(mat); + return *this; +} + +TransformationMatrix& TransformationMatrix::scale3d(double sx, double sy, double sz) +{ + TransformationMatrix mat; + mat.m_matrix[0][0] = sx; + mat.m_matrix[1][1] = sy; + mat.m_matrix[2][2] = sz; + + multLeft(mat); + return *this; +} + +TransformationMatrix& TransformationMatrix::rotate3d(double x, double y, double z, double angle) +{ + // angles are in degrees. Switch to radians + angle = deg2rad(angle); + + angle /= 2.0f; + double sinA = sin(angle); + double cosA = cos(angle); + double sinA2 = sinA * sinA; + + // normalize + double length = sqrt(x * x + y * y + z * z); + if (length == 0) { + // bad vector, just use something reasonable + x = 0; + y = 0; + z = 1; + } else if (length != 1) { + x /= length; + y /= length; + z /= length; + } + + TransformationMatrix mat; + + // optimize case where axis is along major axis + if (x == 1.0f && y == 0.0f && z == 0.0f) { + mat.m_matrix[0][0] = 1.0f; + mat.m_matrix[0][1] = 0.0f; + mat.m_matrix[0][2] = 0.0f; + mat.m_matrix[1][0] = 0.0f; + mat.m_matrix[1][1] = 1.0f - 2.0f * sinA2; + mat.m_matrix[1][2] = 2.0f * sinA * cosA; + mat.m_matrix[2][0] = 0.0f; + mat.m_matrix[2][1] = -2.0f * sinA * cosA; + mat.m_matrix[2][2] = 1.0f - 2.0f * sinA2; + mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f; + mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f; + mat.m_matrix[3][3] = 1.0f; + } else if (x == 0.0f && y == 1.0f && z == 0.0f) { + mat.m_matrix[0][0] = 1.0f - 2.0f * sinA2; + mat.m_matrix[0][1] = 0.0f; + mat.m_matrix[0][2] = -2.0f * sinA * cosA; + mat.m_matrix[1][0] = 0.0f; + mat.m_matrix[1][1] = 1.0f; + mat.m_matrix[1][2] = 0.0f; + mat.m_matrix[2][0] = 2.0f * sinA * cosA; + mat.m_matrix[2][1] = 0.0f; + mat.m_matrix[2][2] = 1.0f - 2.0f * sinA2; + mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f; + mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f; + mat.m_matrix[3][3] = 1.0f; + } else if (x == 0.0f && y == 0.0f && z == 1.0f) { + mat.m_matrix[0][0] = 1.0f - 2.0f * sinA2; + mat.m_matrix[0][1] = 2.0f * sinA * cosA; + mat.m_matrix[0][2] = 0.0f; + mat.m_matrix[1][0] = -2.0f * sinA * cosA; + mat.m_matrix[1][1] = 1.0f - 2.0f * sinA2; + mat.m_matrix[1][2] = 0.0f; + mat.m_matrix[2][0] = 0.0f; + mat.m_matrix[2][1] = 0.0f; + mat.m_matrix[2][2] = 1.0f; + mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f; + mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f; + mat.m_matrix[3][3] = 1.0f; + } else { + double x2 = x*x; + double y2 = y*y; + double z2 = z*z; + + mat.m_matrix[0][0] = 1.0f - 2.0f * (y2 + z2) * sinA2; + mat.m_matrix[0][1] = 2.0f * (x * y * sinA2 + z * sinA * cosA); + mat.m_matrix[0][2] = 2.0f * (x * z * sinA2 - y * sinA * cosA); + mat.m_matrix[1][0] = 2.0f * (y * x * sinA2 - z * sinA * cosA); + mat.m_matrix[1][1] = 1.0f - 2.0f * (z2 + x2) * sinA2; + mat.m_matrix[1][2] = 2.0f * (y * z * sinA2 + x * sinA * cosA); + mat.m_matrix[2][0] = 2.0f * (z * x * sinA2 + y * sinA * cosA); + mat.m_matrix[2][1] = 2.0f * (z * y * sinA2 - x * sinA * cosA); + mat.m_matrix[2][2] = 1.0f - 2.0f * (x2 + y2) * sinA2; + mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f; + mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f; + mat.m_matrix[3][3] = 1.0f; + } + multLeft(mat); + return *this; +} + +TransformationMatrix& TransformationMatrix::rotate3d(double rx, double ry, double rz) +{ + // angles are in degrees. Switch to radians + rx = deg2rad(rx); + ry = deg2rad(ry); + rz = deg2rad(rz); + + TransformationMatrix mat; + + rz /= 2.0f; + double sinA = sin(rz); + double cosA = cos(rz); + double sinA2 = sinA * sinA; + + mat.m_matrix[0][0] = 1.0f - 2.0f * sinA2; + mat.m_matrix[0][1] = 2.0f * sinA * cosA; + mat.m_matrix[0][2] = 0.0f; + mat.m_matrix[1][0] = -2.0f * sinA * cosA; + mat.m_matrix[1][1] = 1.0f - 2.0f * sinA2; + mat.m_matrix[1][2] = 0.0f; + mat.m_matrix[2][0] = 0.0f; + mat.m_matrix[2][1] = 0.0f; + mat.m_matrix[2][2] = 1.0f; + mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f; + mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f; + mat.m_matrix[3][3] = 1.0f; + + TransformationMatrix rmat(mat); + + ry /= 2.0f; + sinA = sin(ry); + cosA = cos(ry); + sinA2 = sinA * sinA; + + mat.m_matrix[0][0] = 1.0f - 2.0f * sinA2; + mat.m_matrix[0][1] = 0.0f; + mat.m_matrix[0][2] = -2.0f * sinA * cosA; + mat.m_matrix[1][0] = 0.0f; + mat.m_matrix[1][1] = 1.0f; + mat.m_matrix[1][2] = 0.0f; + mat.m_matrix[2][0] = 2.0f * sinA * cosA; + mat.m_matrix[2][1] = 0.0f; + mat.m_matrix[2][2] = 1.0f - 2.0f * sinA2; + mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f; + mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f; + mat.m_matrix[3][3] = 1.0f; + + rmat.multLeft(mat); + + rx /= 2.0f; + sinA = sin(rx); + cosA = cos(rx); + sinA2 = sinA * sinA; + + mat.m_matrix[0][0] = 1.0f; + mat.m_matrix[0][1] = 0.0f; + mat.m_matrix[0][2] = 0.0f; + mat.m_matrix[1][0] = 0.0f; + mat.m_matrix[1][1] = 1.0f - 2.0f * sinA2; + mat.m_matrix[1][2] = 2.0f * sinA * cosA; + mat.m_matrix[2][0] = 0.0f; + mat.m_matrix[2][1] = -2.0f * sinA * cosA; + mat.m_matrix[2][2] = 1.0f - 2.0f * sinA2; + mat.m_matrix[0][3] = mat.m_matrix[1][3] = mat.m_matrix[2][3] = 0.0f; + mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0f; + mat.m_matrix[3][3] = 1.0f; + + rmat.multLeft(mat); + + multLeft(rmat); + return *this; +} + +TransformationMatrix& TransformationMatrix::translate(double tx, double ty) +{ + m_matrix[3][0] += tx * m_matrix[0][0] + ty * m_matrix[1][0]; + m_matrix[3][1] += tx * m_matrix[0][1] + ty * m_matrix[1][1]; + m_matrix[3][2] += tx * m_matrix[0][2] + ty * m_matrix[1][2]; + m_matrix[3][3] += tx * m_matrix[0][3] + ty * m_matrix[1][3]; + return *this; +} + +TransformationMatrix& TransformationMatrix::translate3d(double tx, double ty, double tz) +{ + m_matrix[3][0] += tx * m_matrix[0][0] + ty * m_matrix[1][0] + tz * m_matrix[2][0]; + m_matrix[3][1] += tx * m_matrix[0][1] + ty * m_matrix[1][1] + tz * m_matrix[2][1]; + m_matrix[3][2] += tx * m_matrix[0][2] + ty * m_matrix[1][2] + tz * m_matrix[2][2]; + m_matrix[3][3] += tx * m_matrix[0][3] + ty * m_matrix[1][3] + tz * m_matrix[2][3]; + return *this; +} + +TransformationMatrix& TransformationMatrix::translateRight(double tx, double ty) +{ + if (tx != 0) { + m_matrix[0][0] += m_matrix[0][3] * tx; + m_matrix[1][0] += m_matrix[1][3] * tx; + m_matrix[2][0] += m_matrix[2][3] * tx; + m_matrix[3][0] += m_matrix[3][3] * tx; + } + + if (ty != 0) { + m_matrix[0][1] += m_matrix[0][3] * ty; + m_matrix[1][1] += m_matrix[1][3] * ty; + m_matrix[2][1] += m_matrix[2][3] * ty; + m_matrix[3][1] += m_matrix[3][3] * ty; + } + + return *this; +} + +TransformationMatrix& TransformationMatrix::translateRight3d(double tx, double ty, double tz) +{ + translateRight(tx, ty); + if (tz != 0) { + m_matrix[0][2] += m_matrix[0][3] * tz; + m_matrix[1][2] += m_matrix[1][3] * tz; + m_matrix[2][2] += m_matrix[2][3] * tz; + m_matrix[3][2] += m_matrix[3][3] * tz; + } + + return *this; +} + +TransformationMatrix& TransformationMatrix::skew(double sx, double sy) +{ + // angles are in degrees. Switch to radians + sx = deg2rad(sx); + sy = deg2rad(sy); + + TransformationMatrix mat; + mat.m_matrix[0][1] = tan(sy); // note that the y shear goes in the first row + mat.m_matrix[1][0] = tan(sx); // and the x shear in the second row + + multLeft(mat); + return *this; +} + +TransformationMatrix& TransformationMatrix::applyPerspective(double p) +{ + TransformationMatrix mat; + if (p != 0) + mat.m_matrix[2][3] = -1/p; + + multLeft(mat); + return *this; +} + +TransformationMatrix TransformationMatrix::rectToRect(const FloatRect& from, const FloatRect& to) +{ + ASSERT(!from.isEmpty()); + return TransformationMatrix(to.width() / from.width(), + 0, 0, + to.height() / from.height(), + to.x() - from.x(), + to.y() - from.y()); +} + +// +// *this = mat * *this +// +TransformationMatrix& TransformationMatrix::multLeft(const TransformationMatrix& mat) +{ + Matrix4 tmp; + + tmp[0][0] = (mat.m_matrix[0][0] * m_matrix[0][0] + mat.m_matrix[0][1] * m_matrix[1][0] + + mat.m_matrix[0][2] * m_matrix[2][0] + mat.m_matrix[0][3] * m_matrix[3][0]); + tmp[0][1] = (mat.m_matrix[0][0] * m_matrix[0][1] + mat.m_matrix[0][1] * m_matrix[1][1] + + mat.m_matrix[0][2] * m_matrix[2][1] + mat.m_matrix[0][3] * m_matrix[3][1]); + tmp[0][2] = (mat.m_matrix[0][0] * m_matrix[0][2] + mat.m_matrix[0][1] * m_matrix[1][2] + + mat.m_matrix[0][2] * m_matrix[2][2] + mat.m_matrix[0][3] * m_matrix[3][2]); + tmp[0][3] = (mat.m_matrix[0][0] * m_matrix[0][3] + mat.m_matrix[0][1] * m_matrix[1][3] + + mat.m_matrix[0][2] * m_matrix[2][3] + mat.m_matrix[0][3] * m_matrix[3][3]); + + tmp[1][0] = (mat.m_matrix[1][0] * m_matrix[0][0] + mat.m_matrix[1][1] * m_matrix[1][0] + + mat.m_matrix[1][2] * m_matrix[2][0] + mat.m_matrix[1][3] * m_matrix[3][0]); + tmp[1][1] = (mat.m_matrix[1][0] * m_matrix[0][1] + mat.m_matrix[1][1] * m_matrix[1][1] + + mat.m_matrix[1][2] * m_matrix[2][1] + mat.m_matrix[1][3] * m_matrix[3][1]); + tmp[1][2] = (mat.m_matrix[1][0] * m_matrix[0][2] + mat.m_matrix[1][1] * m_matrix[1][2] + + mat.m_matrix[1][2] * m_matrix[2][2] + mat.m_matrix[1][3] * m_matrix[3][2]); + tmp[1][3] = (mat.m_matrix[1][0] * m_matrix[0][3] + mat.m_matrix[1][1] * m_matrix[1][3] + + mat.m_matrix[1][2] * m_matrix[2][3] + mat.m_matrix[1][3] * m_matrix[3][3]); + + tmp[2][0] = (mat.m_matrix[2][0] * m_matrix[0][0] + mat.m_matrix[2][1] * m_matrix[1][0] + + mat.m_matrix[2][2] * m_matrix[2][0] + mat.m_matrix[2][3] * m_matrix[3][0]); + tmp[2][1] = (mat.m_matrix[2][0] * m_matrix[0][1] + mat.m_matrix[2][1] * m_matrix[1][1] + + mat.m_matrix[2][2] * m_matrix[2][1] + mat.m_matrix[2][3] * m_matrix[3][1]); + tmp[2][2] = (mat.m_matrix[2][0] * m_matrix[0][2] + mat.m_matrix[2][1] * m_matrix[1][2] + + mat.m_matrix[2][2] * m_matrix[2][2] + mat.m_matrix[2][3] * m_matrix[3][2]); + tmp[2][3] = (mat.m_matrix[2][0] * m_matrix[0][3] + mat.m_matrix[2][1] * m_matrix[1][3] + + mat.m_matrix[2][2] * m_matrix[2][3] + mat.m_matrix[2][3] * m_matrix[3][3]); + + tmp[3][0] = (mat.m_matrix[3][0] * m_matrix[0][0] + mat.m_matrix[3][1] * m_matrix[1][0] + + mat.m_matrix[3][2] * m_matrix[2][0] + mat.m_matrix[3][3] * m_matrix[3][0]); + tmp[3][1] = (mat.m_matrix[3][0] * m_matrix[0][1] + mat.m_matrix[3][1] * m_matrix[1][1] + + mat.m_matrix[3][2] * m_matrix[2][1] + mat.m_matrix[3][3] * m_matrix[3][1]); + tmp[3][2] = (mat.m_matrix[3][0] * m_matrix[0][2] + mat.m_matrix[3][1] * m_matrix[1][2] + + mat.m_matrix[3][2] * m_matrix[2][2] + mat.m_matrix[3][3] * m_matrix[3][2]); + tmp[3][3] = (mat.m_matrix[3][0] * m_matrix[0][3] + mat.m_matrix[3][1] * m_matrix[1][3] + + mat.m_matrix[3][2] * m_matrix[2][3] + mat.m_matrix[3][3] * m_matrix[3][3]); + + setMatrix(tmp); + return *this; +} + +void TransformationMatrix::multVecMatrix(double x, double y, double& resultX, double& resultY) const +{ + resultX = m_matrix[3][0] + x * m_matrix[0][0] + y * m_matrix[1][0]; + resultY = m_matrix[3][1] + x * m_matrix[0][1] + y * m_matrix[1][1]; + double w = m_matrix[3][3] + x * m_matrix[0][3] + y * m_matrix[1][3]; + if (w != 1 && w != 0) { + resultX /= w; + resultY /= w; + } +} + +void TransformationMatrix::multVecMatrix(double x, double y, double z, double& resultX, double& resultY, double& resultZ) const +{ + resultX = m_matrix[3][0] + x * m_matrix[0][0] + y * m_matrix[1][0] + z * m_matrix[2][0]; + resultY = m_matrix[3][1] + x * m_matrix[0][1] + y * m_matrix[1][1] + z * m_matrix[2][1]; + resultZ = m_matrix[3][2] + x * m_matrix[0][2] + y * m_matrix[1][2] + z * m_matrix[2][2]; + double w = m_matrix[3][3] + x * m_matrix[0][3] + y * m_matrix[1][3] + z * m_matrix[2][3]; + if (w != 1 && w != 0) { + resultX /= w; + resultY /= w; + resultZ /= w; + } +} + +bool TransformationMatrix::isInvertible() const +{ + if (isIdentityOrTranslation()) + return true; + + double det = WebCore::determinant4x4(m_matrix); + + if (fabs(det) < SMALL_NUMBER) + return false; + + return true; +} + +TransformationMatrix TransformationMatrix::inverse() const +{ + if (isIdentityOrTranslation()) { + // identity matrix + if (m_matrix[3][0] == 0 && m_matrix[3][1] == 0 && m_matrix[3][2] == 0) + return TransformationMatrix(); + + // translation + return TransformationMatrix(1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + -m_matrix[3][0], -m_matrix[3][1], -m_matrix[3][2], 1); + } + + TransformationMatrix invMat; + bool inverted = WebCore::inverse(m_matrix, invMat.m_matrix); + if (!inverted) + return TransformationMatrix(); + + return invMat; +} + +void TransformationMatrix::makeAffine() +{ + m_matrix[0][2] = 0; + m_matrix[0][3] = 0; + + m_matrix[1][2] = 0; + m_matrix[1][3] = 0; + + m_matrix[2][0] = 0; + m_matrix[2][1] = 0; + m_matrix[2][2] = 1; + m_matrix[2][3] = 0; + + m_matrix[3][2] = 0; + m_matrix[3][3] = 1; +} + +AffineTransform TransformationMatrix::toAffineTransform() const +{ + return AffineTransform(m_matrix[0][0], m_matrix[0][1], m_matrix[1][0], + m_matrix[1][1], m_matrix[3][0], m_matrix[3][1]); +} + +static inline void blendFloat(double& from, double to, double progress) +{ + if (from != to) + from = from + (to - from) * progress; +} + +void TransformationMatrix::blend(const TransformationMatrix& from, double progress) +{ + if (from.isIdentity() && isIdentity()) + return; + + // decompose + DecomposedType fromDecomp; + DecomposedType toDecomp; + from.decompose(fromDecomp); + decompose(toDecomp); + + // interpolate + blendFloat(fromDecomp.scaleX, toDecomp.scaleX, progress); + blendFloat(fromDecomp.scaleY, toDecomp.scaleY, progress); + blendFloat(fromDecomp.scaleZ, toDecomp.scaleZ, progress); + blendFloat(fromDecomp.skewXY, toDecomp.skewXY, progress); + blendFloat(fromDecomp.skewXZ, toDecomp.skewXZ, progress); + blendFloat(fromDecomp.skewYZ, toDecomp.skewYZ, progress); + blendFloat(fromDecomp.translateX, toDecomp.translateX, progress); + blendFloat(fromDecomp.translateY, toDecomp.translateY, progress); + blendFloat(fromDecomp.translateZ, toDecomp.translateZ, progress); + blendFloat(fromDecomp.perspectiveX, toDecomp.perspectiveX, progress); + blendFloat(fromDecomp.perspectiveY, toDecomp.perspectiveY, progress); + blendFloat(fromDecomp.perspectiveZ, toDecomp.perspectiveZ, progress); + blendFloat(fromDecomp.perspectiveW, toDecomp.perspectiveW, progress); + + slerp(&fromDecomp.quaternionX, &toDecomp.quaternionX, progress); + + // recompose + recompose(fromDecomp); +} + +bool TransformationMatrix::decompose(DecomposedType& decomp) const +{ + if (isIdentity()) { + memset(&decomp, 0, sizeof(decomp)); + decomp.perspectiveW = 1; + decomp.scaleX = 1; + decomp.scaleY = 1; + decomp.scaleZ = 1; + } + + if (!WebCore::decompose(m_matrix, decomp)) + return false; + return true; +} + +void TransformationMatrix::recompose(const DecomposedType& decomp) +{ + makeIdentity(); + + // first apply perspective + m_matrix[0][3] = (float) decomp.perspectiveX; + m_matrix[1][3] = (float) decomp.perspectiveY; + m_matrix[2][3] = (float) decomp.perspectiveZ; + m_matrix[3][3] = (float) decomp.perspectiveW; + + // now translate + translate3d((float) decomp.translateX, (float) decomp.translateY, (float) decomp.translateZ); + + // apply rotation + double xx = decomp.quaternionX * decomp.quaternionX; + double xy = decomp.quaternionX * decomp.quaternionY; + double xz = decomp.quaternionX * decomp.quaternionZ; + double xw = decomp.quaternionX * decomp.quaternionW; + double yy = decomp.quaternionY * decomp.quaternionY; + double yz = decomp.quaternionY * decomp.quaternionZ; + double yw = decomp.quaternionY * decomp.quaternionW; + double zz = decomp.quaternionZ * decomp.quaternionZ; + double zw = decomp.quaternionZ * decomp.quaternionW; + + // Construct a composite rotation matrix from the quaternion values + TransformationMatrix rotationMatrix(1 - 2 * (yy + zz), 2 * (xy - zw), 2 * (xz + yw), 0, + 2 * (xy + zw), 1 - 2 * (xx + zz), 2 * (yz - xw), 0, + 2 * (xz - yw), 2 * (yz + xw), 1 - 2 * (xx + yy), 0, + 0, 0, 0, 1); + + multLeft(rotationMatrix); + + // now apply skew + if (decomp.skewYZ) { + TransformationMatrix tmp; + tmp.setM32((float) decomp.skewYZ); + multLeft(tmp); + } + + if (decomp.skewXZ) { + TransformationMatrix tmp; + tmp.setM31((float) decomp.skewXZ); + multLeft(tmp); + } + + if (decomp.skewXY) { + TransformationMatrix tmp; + tmp.setM21((float) decomp.skewXY); + multLeft(tmp); + } + + // finally, apply scale + scale3d((float) decomp.scaleX, (float) decomp.scaleY, (float) decomp.scaleZ); +} + +} diff --git a/Source/WebCore/platform/graphics/transforms/TransformationMatrix.h b/Source/WebCore/platform/graphics/transforms/TransformationMatrix.h new file mode 100644 index 0000000..f13bcc1 --- /dev/null +++ b/Source/WebCore/platform/graphics/transforms/TransformationMatrix.h @@ -0,0 +1,364 @@ +/* + * Copyright (C) 2005, 2006 Apple Computer, 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 COMPUTER, 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 COMPUTER, 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. + */ + +#ifndef TransformationMatrix_h +#define TransformationMatrix_h + +#include "AffineTransform.h" +#include "FloatPoint.h" +#include "IntPoint.h" +#include <string.h> //for memcpy +#include <wtf/FastAllocBase.h> + +#if PLATFORM(CA) +#include <QuartzCore/CATransform3D.h> +#endif +#if PLATFORM(CG) +#include <CoreGraphics/CGAffineTransform.h> +#elif PLATFORM(CAIRO) +#include <cairo.h> +#elif PLATFORM(OPENVG) +#include "VGUtils.h" +#elif PLATFORM(QT) +#include <QTransform> +#elif PLATFORM(SKIA) +#include <SkMatrix.h> +#elif PLATFORM(WX) && USE(WXGC) +#include <wx/graphics.h> +#endif + +#if PLATFORM(WIN) || (PLATFORM(QT) && OS(WINDOWS)) || (PLATFORM(WX) && OS(WINDOWS)) +#if COMPILER(MINGW) && !COMPILER(MINGW64) +typedef struct _XFORM XFORM; +#else +typedef struct tagXFORM XFORM; +#endif +#endif + +namespace WebCore { + +class AffineTransform; +class IntRect; +class FloatPoint3D; +class FloatRect; +class FloatQuad; + +class TransformationMatrix : public FastAllocBase { +public: + typedef double Matrix4[4][4]; + + TransformationMatrix() { makeIdentity(); } + TransformationMatrix(const TransformationMatrix& t) { *this = t; } + TransformationMatrix(double a, double b, double c, double d, double e, double f) { setMatrix(a, b, c, d, e, f); } + TransformationMatrix(double m11, double m12, double m13, double m14, + double m21, double m22, double m23, double m24, + double m31, double m32, double m33, double m34, + double m41, double m42, double m43, double m44) + { + setMatrix(m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44); + } + + void setMatrix(double a, double b, double c, double d, double e, double f) + { + m_matrix[0][0] = a; m_matrix[0][1] = b; m_matrix[0][2] = 0; m_matrix[0][3] = 0; + m_matrix[1][0] = c; m_matrix[1][1] = d; m_matrix[1][2] = 0; m_matrix[1][3] = 0; + m_matrix[2][0] = 0; m_matrix[2][1] = 0; m_matrix[2][2] = 1; m_matrix[2][3] = 0; + m_matrix[3][0] = e; m_matrix[3][1] = f; m_matrix[3][2] = 0; m_matrix[3][3] = 1; + } + + void setMatrix(double m11, double m12, double m13, double m14, + double m21, double m22, double m23, double m24, + double m31, double m32, double m33, double m34, + double m41, double m42, double m43, double m44) + { + m_matrix[0][0] = m11; m_matrix[0][1] = m12; m_matrix[0][2] = m13; m_matrix[0][3] = m14; + m_matrix[1][0] = m21; m_matrix[1][1] = m22; m_matrix[1][2] = m23; m_matrix[1][3] = m24; + m_matrix[2][0] = m31; m_matrix[2][1] = m32; m_matrix[2][2] = m33; m_matrix[2][3] = m34; + m_matrix[3][0] = m41; m_matrix[3][1] = m42; m_matrix[3][2] = m43; m_matrix[3][3] = m44; + } + + TransformationMatrix& operator =(const TransformationMatrix &t) + { + setMatrix(t.m_matrix); + return *this; + } + + TransformationMatrix& makeIdentity() + { + setMatrix(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); + return *this; + } + + bool isIdentity() const + { + return m_matrix[0][0] == 1 && m_matrix[0][1] == 0 && m_matrix[0][2] == 0 && m_matrix[0][3] == 0 && + m_matrix[1][0] == 0 && m_matrix[1][1] == 1 && m_matrix[1][2] == 0 && m_matrix[1][3] == 0 && + m_matrix[2][0] == 0 && m_matrix[2][1] == 0 && m_matrix[2][2] == 1 && m_matrix[2][3] == 0 && + m_matrix[3][0] == 0 && m_matrix[3][1] == 0 && m_matrix[3][2] == 0 && m_matrix[3][3] == 1; + } + + // This form preserves the double math from input to output + void map(double x, double y, double& x2, double& y2) const { multVecMatrix(x, y, x2, y2); } + + // Map a 3D point through the transform, returning a 3D point. + FloatPoint3D mapPoint(const FloatPoint3D&) const; + + // Map a 2D point through the transform, returning a 2D point. + // Note that this ignores the z component, effectively projecting the point into the z=0 plane. + FloatPoint mapPoint(const FloatPoint&) const; + + // Like the version above, except that it rounds the mapped point to the nearest integer value. + IntPoint mapPoint(const IntPoint& p) const + { + return roundedIntPoint(mapPoint(FloatPoint(p))); + } + + // If the matrix has 3D components, the z component of the result is + // dropped, effectively projecting the rect into the z=0 plane + FloatRect mapRect(const FloatRect&) const; + + // Rounds the resulting mapped rectangle out. This is helpful for bounding + // box computations but may not be what is wanted in other contexts. + IntRect mapRect(const IntRect&) const; + + // If the matrix has 3D components, the z component of the result is + // dropped, effectively projecting the quad into the z=0 plane + FloatQuad mapQuad(const FloatQuad&) const; + + // Map a point on the z=0 plane into a point on + // the plane with with the transform applied, by extending + // a ray perpendicular to the source plane and computing + // the local x,y position of the point where that ray intersects + // with the destination plane. + FloatPoint projectPoint(const FloatPoint&) const; + // Projects the four corners of the quad + FloatQuad projectQuad(const FloatQuad&) const; + + double m11() const { return m_matrix[0][0]; } + void setM11(double f) { m_matrix[0][0] = f; } + double m12() const { return m_matrix[0][1]; } + void setM12(double f) { m_matrix[0][1] = f; } + double m13() const { return m_matrix[0][2]; } + void setM13(double f) { m_matrix[0][2] = f; } + double m14() const { return m_matrix[0][3]; } + void setM14(double f) { m_matrix[0][3] = f; } + double m21() const { return m_matrix[1][0]; } + void setM21(double f) { m_matrix[1][0] = f; } + double m22() const { return m_matrix[1][1]; } + void setM22(double f) { m_matrix[1][1] = f; } + double m23() const { return m_matrix[1][2]; } + void setM23(double f) { m_matrix[1][2] = f; } + double m24() const { return m_matrix[1][3]; } + void setM24(double f) { m_matrix[1][3] = f; } + double m31() const { return m_matrix[2][0]; } + void setM31(double f) { m_matrix[2][0] = f; } + double m32() const { return m_matrix[2][1]; } + void setM32(double f) { m_matrix[2][1] = f; } + double m33() const { return m_matrix[2][2]; } + void setM33(double f) { m_matrix[2][2] = f; } + double m34() const { return m_matrix[2][3]; } + void setM34(double f) { m_matrix[2][3] = f; } + double m41() const { return m_matrix[3][0]; } + void setM41(double f) { m_matrix[3][0] = f; } + double m42() const { return m_matrix[3][1]; } + void setM42(double f) { m_matrix[3][1] = f; } + double m43() const { return m_matrix[3][2]; } + void setM43(double f) { m_matrix[3][2] = f; } + double m44() const { return m_matrix[3][3]; } + void setM44(double f) { m_matrix[3][3] = f; } + + double a() const { return m_matrix[0][0]; } + void setA(double a) { m_matrix[0][0] = a; } + + double b() const { return m_matrix[0][1]; } + void setB(double b) { m_matrix[0][1] = b; } + + double c() const { return m_matrix[1][0]; } + void setC(double c) { m_matrix[1][0] = c; } + + double d() const { return m_matrix[1][1]; } + void setD(double d) { m_matrix[1][1] = d; } + + double e() const { return m_matrix[3][0]; } + void setE(double e) { m_matrix[3][0] = e; } + + double f() const { return m_matrix[3][1]; } + void setF(double f) { m_matrix[3][1] = f; } + + // this = this * mat + TransformationMatrix& multiply(const TransformationMatrix& t) { return *this *= t; } + + // this = mat * this + TransformationMatrix& multLeft(const TransformationMatrix& mat); + + TransformationMatrix& scale(double); + TransformationMatrix& scaleNonUniform(double sx, double sy); + TransformationMatrix& scale3d(double sx, double sy, double sz); + + TransformationMatrix& rotate(double d) { return rotate3d(0, 0, d); } + TransformationMatrix& rotateFromVector(double x, double y); + TransformationMatrix& rotate3d(double rx, double ry, double rz); + + // The vector (x,y,z) is normalized if it's not already. A vector of + // (0,0,0) uses a vector of (0,0,1). + TransformationMatrix& rotate3d(double x, double y, double z, double angle); + + TransformationMatrix& translate(double tx, double ty); + TransformationMatrix& translate3d(double tx, double ty, double tz); + + // translation added with a post-multiply + TransformationMatrix& translateRight(double tx, double ty); + TransformationMatrix& translateRight3d(double tx, double ty, double tz); + + TransformationMatrix& flipX(); + TransformationMatrix& flipY(); + TransformationMatrix& skew(double angleX, double angleY); + TransformationMatrix& skewX(double angle) { return skew(angle, 0); } + TransformationMatrix& skewY(double angle) { return skew(0, angle); } + + TransformationMatrix& applyPerspective(double p); + bool hasPerspective() const { return m_matrix[2][3] != 0.0f; } + + // returns a transformation that maps a rect to a rect + static TransformationMatrix rectToRect(const FloatRect&, const FloatRect&); + + bool isInvertible() const; + + // This method returns the identity matrix if it is not invertible. + // Use isInvertible() before calling this if you need to know. + TransformationMatrix inverse() const; + + // decompose the matrix into its component parts + typedef struct { + double scaleX, scaleY, scaleZ; + double skewXY, skewXZ, skewYZ; + double quaternionX, quaternionY, quaternionZ, quaternionW; + double translateX, translateY, translateZ; + double perspectiveX, perspectiveY, perspectiveZ, perspectiveW; + } DecomposedType; + + bool decompose(DecomposedType& decomp) const; + void recompose(const DecomposedType& decomp); + + void blend(const TransformationMatrix& from, double progress); + + bool isAffine() const + { + return (m13() == 0 && m14() == 0 && m23() == 0 && m24() == 0 && + m31() == 0 && m32() == 0 && m33() == 1 && m34() == 0 && m43() == 0 && m44() == 1); + } + + // Throw away the non-affine parts of the matrix (lossy!) + void makeAffine(); + + AffineTransform toAffineTransform() const; + + bool operator==(const TransformationMatrix& m2) const + { + return (m_matrix[0][0] == m2.m_matrix[0][0] && + m_matrix[0][1] == m2.m_matrix[0][1] && + m_matrix[0][2] == m2.m_matrix[0][2] && + m_matrix[0][3] == m2.m_matrix[0][3] && + m_matrix[1][0] == m2.m_matrix[1][0] && + m_matrix[1][1] == m2.m_matrix[1][1] && + m_matrix[1][2] == m2.m_matrix[1][2] && + m_matrix[1][3] == m2.m_matrix[1][3] && + m_matrix[2][0] == m2.m_matrix[2][0] && + m_matrix[2][1] == m2.m_matrix[2][1] && + m_matrix[2][2] == m2.m_matrix[2][2] && + m_matrix[2][3] == m2.m_matrix[2][3] && + m_matrix[3][0] == m2.m_matrix[3][0] && + m_matrix[3][1] == m2.m_matrix[3][1] && + m_matrix[3][2] == m2.m_matrix[3][2] && + m_matrix[3][3] == m2.m_matrix[3][3]); + } + + bool operator!=(const TransformationMatrix& other) const { return !(*this == other); } + + // *this = *this * t (i.e., a multRight) + TransformationMatrix& operator*=(const TransformationMatrix& t) + { + *this = *this * t; + return *this; + } + + // result = *this * t (i.e., a multRight) + TransformationMatrix operator*(const TransformationMatrix& t) const + { + TransformationMatrix result = t; + result.multLeft(*this); + return result; + } + +#if PLATFORM(CA) + TransformationMatrix(const CATransform3D&); + operator CATransform3D() const; +#endif +#if PLATFORM(CG) + TransformationMatrix(const CGAffineTransform&); + operator CGAffineTransform() const; +#elif PLATFORM(CAIRO) + operator cairo_matrix_t() const; +#elif PLATFORM(OPENVG) + operator VGMatrix() const; +#elif PLATFORM(QT) + operator QTransform() const; +#elif PLATFORM(SKIA) + operator SkMatrix() const; +#elif PLATFORM(WX) && USE(WXGC) + operator wxGraphicsMatrix() const; +#endif + +#if PLATFORM(WIN) || (PLATFORM(QT) && OS(WINDOWS)) || (PLATFORM(WX) && OS(WINDOWS)) + operator XFORM() const; +#endif + + bool isIdentityOrTranslation() const + { + return m_matrix[0][0] == 1 && m_matrix[0][1] == 0 && m_matrix[0][2] == 0 && m_matrix[0][3] == 0 + && m_matrix[1][0] == 0 && m_matrix[1][1] == 1 && m_matrix[1][2] == 0 && m_matrix[1][3] == 0 + && m_matrix[2][0] == 0 && m_matrix[2][1] == 0 && m_matrix[2][2] == 1 && m_matrix[2][3] == 0 + && m_matrix[3][3] == 1; + } + +private: + // multiply passed 2D point by matrix (assume z=0) + void multVecMatrix(double x, double y, double& dstX, double& dstY) const; + + // multiply passed 3D point by matrix + void multVecMatrix(double x, double y, double z, double& dstX, double& dstY, double& dstZ) const; + + void setMatrix(const Matrix4 m) + { + if (m && m != m_matrix) + memcpy(m_matrix, m, sizeof(Matrix4)); + } + + Matrix4 m_matrix; +}; + +} // namespace WebCore + +#endif // TransformationMatrix_h diff --git a/Source/WebCore/platform/graphics/transforms/TranslateTransformOperation.cpp b/Source/WebCore/platform/graphics/transforms/TranslateTransformOperation.cpp new file mode 100644 index 0000000..a8ad131 --- /dev/null +++ b/Source/WebCore/platform/graphics/transforms/TranslateTransformOperation.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * 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., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "TranslateTransformOperation.h" + +namespace WebCore { + +PassRefPtr<TransformOperation> TranslateTransformOperation::blend(const TransformOperation* from, double progress, bool blendToIdentity) +{ + if (from && !from->isSameType(*this)) + return this; + + if (blendToIdentity) + return TranslateTransformOperation::create(Length(m_x.type()).blend(m_x, progress), + Length(m_y.type()).blend(m_y, progress), + Length(m_z.type()).blend(m_z, progress), m_type); + + const TranslateTransformOperation* fromOp = static_cast<const TranslateTransformOperation*>(from); + Length fromX = fromOp ? fromOp->m_x : Length(m_x.type()); + Length fromY = fromOp ? fromOp->m_y : Length(m_y.type()); + Length fromZ = fromOp ? fromOp->m_z : Length(m_z.type()); + return TranslateTransformOperation::create(m_x.blend(fromX, progress), m_y.blend(fromY, progress), m_z.blend(fromZ, progress), m_type); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/graphics/transforms/TranslateTransformOperation.h b/Source/WebCore/platform/graphics/transforms/TranslateTransformOperation.h new file mode 100644 index 0000000..ea48d49 --- /dev/null +++ b/Source/WebCore/platform/graphics/transforms/TranslateTransformOperation.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2000 Lars Knoll (knoll@kde.org) + * (C) 2000 Antti Koivisto (koivisto@kde.org) + * (C) 2000 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2003, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com) + * + * 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., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef TranslateTransformOperation_h +#define TranslateTransformOperation_h + +#include "Length.h" +#include "TransformOperation.h" + +namespace WebCore { + +class TranslateTransformOperation : public TransformOperation { +public: + static PassRefPtr<TranslateTransformOperation> create(const Length& tx, const Length& ty, OperationType type) + { + return adoptRef(new TranslateTransformOperation(tx, ty, Length(0, Fixed), type)); + } + + static PassRefPtr<TranslateTransformOperation> create(const Length& tx, const Length& ty, const Length& tz, OperationType type) + { + return adoptRef(new TranslateTransformOperation(tx, ty, tz, type)); + } + + double x(const IntSize& borderBoxSize) const { return m_x.calcFloatValue(borderBoxSize.width()); } + double y(const IntSize& borderBoxSize) const { return m_y.calcFloatValue(borderBoxSize.height()); } + double z(const IntSize&) const { return m_z.calcFloatValue(1); } + + Length x() const { return m_x; } + Length y() const { return m_y; } + Length z() const { return m_z; } + +private: + virtual bool isIdentity() const { return m_x.calcFloatValue(1) == 0 && m_y.calcFloatValue(1) == 0 && m_z.calcFloatValue(1) == 0; } + + virtual OperationType getOperationType() const { return m_type; } + virtual bool isSameType(const TransformOperation& o) const { return o.getOperationType() == m_type; } + + virtual bool operator==(const TransformOperation& o) const + { + if (!isSameType(o)) + return false; + const TranslateTransformOperation* t = static_cast<const TranslateTransformOperation*>(&o); + return m_x == t->m_x && m_y == t->m_y && m_z == t->m_z; + } + + virtual bool apply(TransformationMatrix& transform, const IntSize& borderBoxSize) const + { + transform.translate3d(x(borderBoxSize), y(borderBoxSize), z(borderBoxSize)); + return m_x.type() == Percent || m_y.type() == Percent; + } + + virtual PassRefPtr<TransformOperation> blend(const TransformOperation* from, double progress, bool blendToIdentity = false); + + TranslateTransformOperation(const Length& tx, const Length& ty, const Length& tz, OperationType type) + : m_x(tx) + , m_y(ty) + , m_z(tz) + , m_type(type) + { + ASSERT(type == TRANSLATE_X || type == TRANSLATE_Y || type == TRANSLATE_Z || type == TRANSLATE || type == TRANSLATE_3D); + } + + Length m_x; + Length m_y; + Length m_z; + OperationType m_type; +}; + +} // namespace WebCore + +#endif // TranslateTransformOperation_h |