2 * Copyright (C) 2005, 2006 Apple Inc. All rights reserved.
3 * 2010 Dirk Schulze <krit@webkit.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include "AffineTransform.h"
30 #include "FloatConversion.h"
31 #include "FloatQuad.h"
32 #include "FloatRect.h"
34 #include "TransformationMatrix.h"
36 #include <wtf/MathExtras.h>
41 AffineTransform::AffineTransform()
43 m_transform = { 1, 0, 0, 1, 0, 0 };
46 AffineTransform::AffineTransform(double a, double b, double c, double d, double e, double f)
48 m_transform = { a, b, c, d, e, f };
51 AffineTransform::AffineTransform()
52 : m_transform { { 1, 0, 0, 1, 0, 0 } }
56 AffineTransform::AffineTransform(double a, double b, double c, double d, double e, double f)
57 : m_transform{ { a, b, c, d, e, f } }
62 void AffineTransform::makeIdentity()
64 setMatrix(1, 0, 0, 1, 0, 0);
67 void AffineTransform::setMatrix(double a, double b, double c, double d, double e, double f)
77 bool AffineTransform::isIdentity() const
79 return (m_transform[0] == 1 && m_transform[1] == 0
80 && m_transform[2] == 0 && m_transform[3] == 1
81 && m_transform[4] == 0 && m_transform[5] == 0);
84 double AffineTransform::xScale() const
86 return sqrt(m_transform[0] * m_transform[0] + m_transform[1] * m_transform[1]);
89 double AffineTransform::yScale() const
91 return sqrt(m_transform[2] * m_transform[2] + m_transform[3] * m_transform[3]);
94 double AffineTransform::det() const
96 return m_transform[0] * m_transform[3] - m_transform[1] * m_transform[2];
99 bool AffineTransform::isInvertible() const
101 double determinant = det();
103 return std::isfinite(determinant) && determinant != 0;
106 AffineTransform AffineTransform::inverse() const
108 double determinant = det();
109 if (!std::isfinite(determinant) || determinant == 0)
110 return AffineTransform();
112 AffineTransform result;
113 if (isIdentityOrTranslation()) {
114 result.m_transform[4] = -m_transform[4];
115 result.m_transform[5] = -m_transform[5];
119 result.m_transform[0] = m_transform[3] / determinant;
120 result.m_transform[1] = -m_transform[1] / determinant;
121 result.m_transform[2] = -m_transform[2] / determinant;
122 result.m_transform[3] = m_transform[0] / determinant;
123 result.m_transform[4] = (m_transform[2] * m_transform[5]
124 - m_transform[3] * m_transform[4]) / determinant;
125 result.m_transform[5] = (m_transform[1] * m_transform[4]
126 - m_transform[0] * m_transform[5]) / determinant;
132 // Multiplies this AffineTransform by the provided AffineTransform - i.e.
133 // this = this * other;
134 AffineTransform& AffineTransform::multiply(const AffineTransform& other)
136 AffineTransform trans;
138 trans.m_transform[0] = other.m_transform[0] * m_transform[0] + other.m_transform[1] * m_transform[2];
139 trans.m_transform[1] = other.m_transform[0] * m_transform[1] + other.m_transform[1] * m_transform[3];
140 trans.m_transform[2] = other.m_transform[2] * m_transform[0] + other.m_transform[3] * m_transform[2];
141 trans.m_transform[3] = other.m_transform[2] * m_transform[1] + other.m_transform[3] * m_transform[3];
142 trans.m_transform[4] = other.m_transform[4] * m_transform[0] + other.m_transform[5] * m_transform[2] + m_transform[4];
143 trans.m_transform[5] = other.m_transform[4] * m_transform[1] + other.m_transform[5] * m_transform[3] + m_transform[5];
149 AffineTransform& AffineTransform::rotate(double a)
151 // angle is in degree. Switch to radian
153 double cosAngle = cos(a);
154 double sinAngle = sin(a);
155 AffineTransform rot(cosAngle, sinAngle, -sinAngle, cosAngle, 0, 0);
161 AffineTransform& AffineTransform::scale(double s)
166 AffineTransform& AffineTransform::scale(double sx, double sy)
168 m_transform[0] *= sx;
169 m_transform[1] *= sx;
170 m_transform[2] *= sy;
171 m_transform[3] *= sy;
175 // *this = *this * translation
176 AffineTransform& AffineTransform::translate(double tx, double ty)
178 if (isIdentityOrTranslation()) {
179 m_transform[4] += tx;
180 m_transform[5] += ty;
184 m_transform[4] += tx * m_transform[0] + ty * m_transform[2];
185 m_transform[5] += tx * m_transform[1] + ty * m_transform[3];
189 AffineTransform& AffineTransform::scaleNonUniform(double sx, double sy)
191 return scale(sx, sy);
194 AffineTransform& AffineTransform::rotateFromVector(double x, double y)
196 return rotate(rad2deg(atan2(y, x)));
199 AffineTransform& AffineTransform::flipX()
204 AffineTransform& AffineTransform::flipY()
209 AffineTransform& AffineTransform::shear(double sx, double sy)
211 double a = m_transform[0];
212 double b = m_transform[1];
214 m_transform[0] += sy * m_transform[2];
215 m_transform[1] += sy * m_transform[3];
216 m_transform[2] += sx * a;
217 m_transform[3] += sx * b;
222 AffineTransform& AffineTransform::skew(double angleX, double angleY)
224 return shear(tan(deg2rad(angleX)), tan(deg2rad(angleY)));
227 AffineTransform& AffineTransform::skewX(double angle)
229 return shear(tan(deg2rad(angle)), 0);
232 AffineTransform& AffineTransform::skewY(double angle)
234 return shear(0, tan(deg2rad(angle)));
237 AffineTransform makeMapBetweenRects(const FloatRect& source, const FloatRect& dest)
239 AffineTransform transform;
240 transform.translate(dest.x() - source.x(), dest.y() - source.y());
241 transform.scale(dest.width() / source.width(), dest.height() / source.height());
245 void AffineTransform::map(double x, double y, double& x2, double& y2) const
247 x2 = (m_transform[0] * x + m_transform[2] * y + m_transform[4]);
248 y2 = (m_transform[1] * x + m_transform[3] * y + m_transform[5]);
251 IntPoint AffineTransform::mapPoint(const IntPoint& point) const
254 map(point.x(), point.y(), x2, y2);
257 return IntPoint(lround(x2), lround(y2));
260 FloatPoint AffineTransform::mapPoint(const FloatPoint& point) const
263 map(point.x(), point.y(), x2, y2);
265 return FloatPoint(narrowPrecisionToFloat(x2), narrowPrecisionToFloat(y2));
268 IntSize AffineTransform::mapSize(const IntSize& size) const
270 double width2 = size.width() * xScale();
271 double height2 = size.height() * yScale();
273 return IntSize(lround(width2), lround(height2));
276 FloatSize AffineTransform::mapSize(const FloatSize& size) const
278 double width2 = size.width() * xScale();
279 double height2 = size.height() * yScale();
281 return FloatSize(narrowPrecisionToFloat(width2), narrowPrecisionToFloat(height2));
284 IntRect AffineTransform::mapRect(const IntRect &rect) const
286 return enclosingIntRect(mapRect(FloatRect(rect)));
289 FloatRect AffineTransform::mapRect(const FloatRect& rect) const
291 if (isIdentityOrTranslation()) {
292 FloatRect mappedRect(rect);
293 mappedRect.move(narrowPrecisionToFloat(m_transform[4]), narrowPrecisionToFloat(m_transform[5]));
298 result.setP1(mapPoint(rect.location()));
299 result.setP2(mapPoint(FloatPoint(rect.maxX(), rect.y())));
300 result.setP3(mapPoint(FloatPoint(rect.maxX(), rect.maxY())));
301 result.setP4(mapPoint(FloatPoint(rect.x(), rect.maxY())));
302 return result.boundingBox();
305 FloatQuad AffineTransform::mapQuad(const FloatQuad& q) const
307 if (isIdentityOrTranslation()) {
308 FloatQuad mappedQuad(q);
309 mappedQuad.move(narrowPrecisionToFloat(m_transform[4]), narrowPrecisionToFloat(m_transform[5]));
314 result.setP1(mapPoint(q.p1()));
315 result.setP2(mapPoint(q.p2()));
316 result.setP3(mapPoint(q.p3()));
317 result.setP4(mapPoint(q.p4()));
321 void AffineTransform::blend(const AffineTransform& from, double progress)
323 DecomposedType srA, srB;
326 this->decompose(srB);
328 // If x-axis of one is flipped, and y-axis of the other, convert to an unflipped rotation.
329 if ((srA.scaleX < 0 && srB.scaleY < 0) || (srA.scaleY < 0 && srB.scaleX < 0)) {
330 srA.scaleX = -srA.scaleX;
331 srA.scaleY = -srA.scaleY;
332 srA.angle += srA.angle < 0 ? piDouble : -piDouble;
335 // Don't rotate the long way around.
336 srA.angle = fmod(srA.angle, 2 * piDouble);
337 srB.angle = fmod(srB.angle, 2 * piDouble);
339 if (fabs(srA.angle - srB.angle) > piDouble) {
340 if (srA.angle > srB.angle)
341 srA.angle -= piDouble * 2;
343 srB.angle -= piDouble * 2;
346 srA.scaleX += progress * (srB.scaleX - srA.scaleX);
347 srA.scaleY += progress * (srB.scaleY - srA.scaleY);
348 srA.angle += progress * (srB.angle - srA.angle);
349 srA.remainderA += progress * (srB.remainderA - srA.remainderA);
350 srA.remainderB += progress * (srB.remainderB - srA.remainderB);
351 srA.remainderC += progress * (srB.remainderC - srA.remainderC);
352 srA.remainderD += progress * (srB.remainderD - srA.remainderD);
353 srA.translateX += progress * (srB.translateX - srA.translateX);
354 srA.translateY += progress * (srB.translateY - srA.translateY);
356 this->recompose(srA);
359 TransformationMatrix AffineTransform::toTransformationMatrix() const
361 return TransformationMatrix(m_transform[0], m_transform[1], m_transform[2],
362 m_transform[3], m_transform[4], m_transform[5]);
365 bool AffineTransform::decompose(DecomposedType& decomp) const
367 AffineTransform m(*this);
369 // Compute scaling factors
370 double sx = xScale();
371 double sy = yScale();
373 // Compute cross product of transformed unit vectors. If negative,
374 // one axis was flipped.
375 if (m.a() * m.d() - m.c() * m.b() < 0) {
376 // Flip axis with minimum unit vector dot product
383 // Remove scale from matrix
384 m.scale(1 / sx, 1 / sy);
387 double angle = atan2(m.b(), m.a());
389 // Remove rotation from matrix
390 m.rotate(rad2deg(-angle));
395 decomp.angle = angle;
396 decomp.remainderA = m.a();
397 decomp.remainderB = m.b();
398 decomp.remainderC = m.c();
399 decomp.remainderD = m.d();
400 decomp.translateX = m.e();
401 decomp.translateY = m.f();
406 void AffineTransform::recompose(const DecomposedType& decomp)
408 this->setA(decomp.remainderA);
409 this->setB(decomp.remainderB);
410 this->setC(decomp.remainderC);
411 this->setD(decomp.remainderD);
412 this->setE(decomp.translateX);
413 this->setF(decomp.translateY);
414 this->rotate(rad2deg(decomp.angle));
415 this->scale(decomp.scaleX, decomp.scaleY);