2 * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
3 * 2010 Dirk Schulze <krit@webkit.org>
4 * Copyright (C) 2013 Google Inc. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include "platform/transforms/AffineTransform.h"
31 #include "platform/FloatConversion.h"
32 #include "platform/geometry/FloatQuad.h"
33 #include "platform/geometry/FloatRect.h"
34 #include "platform/geometry/IntRect.h"
35 #include "wtf/MathExtras.h"
39 AffineTransform::AffineTransform()
41 setMatrix(1, 0, 0, 1, 0, 0);
44 AffineTransform::AffineTransform(double a
, double b
, double c
, double d
, double e
, double f
)
46 setMatrix(a
, b
, c
, d
, e
, f
);
49 void AffineTransform::makeIdentity()
51 setMatrix(1, 0, 0, 1, 0, 0);
54 void AffineTransform::setMatrix(double a
, double b
, double c
, double d
, double e
, double f
)
64 bool AffineTransform::isIdentity() const
66 return (m_transform
[0] == 1 && m_transform
[1] == 0
67 && m_transform
[2] == 0 && m_transform
[3] == 1
68 && m_transform
[4] == 0 && m_transform
[5] == 0);
71 double AffineTransform::xScale() const
73 return sqrt(m_transform
[0] * m_transform
[0] + m_transform
[1] * m_transform
[1]);
76 double AffineTransform::yScale() const
78 return sqrt(m_transform
[2] * m_transform
[2] + m_transform
[3] * m_transform
[3]);
81 double AffineTransform::det() const
83 return m_transform
[0] * m_transform
[3] - m_transform
[1] * m_transform
[2];
86 bool AffineTransform::isInvertible() const
91 AffineTransform
AffineTransform::inverse() const
93 double determinant
= det();
94 if (determinant
== 0.0)
95 return AffineTransform();
97 AffineTransform result
;
98 if (isIdentityOrTranslation()) {
99 result
.m_transform
[4] = -m_transform
[4];
100 result
.m_transform
[5] = -m_transform
[5];
104 result
.m_transform
[0] = m_transform
[3] / determinant
;
105 result
.m_transform
[1] = -m_transform
[1] / determinant
;
106 result
.m_transform
[2] = -m_transform
[2] / determinant
;
107 result
.m_transform
[3] = m_transform
[0] / determinant
;
108 result
.m_transform
[4] = (m_transform
[2] * m_transform
[5]
109 - m_transform
[3] * m_transform
[4]) / determinant
;
110 result
.m_transform
[5] = (m_transform
[1] * m_transform
[4]
111 - m_transform
[0] * m_transform
[5]) / determinant
;
119 inline void doMultiply(const AffineTransform
& t1
, const AffineTransform
& t2
, AffineTransform
* res
)
121 res
->setA(t1
.a() * t2
.a() + t1
.c() * t2
.b());
122 res
->setB(t1
.b() * t2
.a() + t1
.d() * t2
.b());
123 res
->setC(t1
.a() * t2
.c() + t1
.c() * t2
.d());
124 res
->setD(t1
.b() * t2
.c() + t1
.d() * t2
.d());
125 res
->setE(t1
.a() * t2
.e() + t1
.c() * t2
.f() + t1
.e());
126 res
->setF(t1
.b() * t2
.e() + t1
.d() * t2
.f() + t1
.f());
129 } // anonymous namespace
131 AffineTransform
& AffineTransform::multiply(const AffineTransform
& other
)
133 if (other
.isIdentityOrTranslation()) {
134 if (other
.m_transform
[4] || other
.m_transform
[5])
135 translate(other
.m_transform
[4], other
.m_transform
[5]);
139 AffineTransform trans
;
140 doMultiply(*this, other
, &trans
);
141 setMatrix(trans
.m_transform
);
146 AffineTransform
& AffineTransform::preMultiply(const AffineTransform
& other
)
148 if (other
.isIdentityOrTranslation()) {
149 if (other
.m_transform
[4] || other
.m_transform
[5]) {
150 m_transform
[4] += other
.m_transform
[4];
151 m_transform
[5] += other
.m_transform
[5];
156 AffineTransform trans
;
157 doMultiply(other
, *this, &trans
);
158 setMatrix(trans
.m_transform
);
163 AffineTransform
& AffineTransform::rotate(double a
)
165 // angle is in degree. Switch to radian
166 return rotateRadians(deg2rad(a
));
169 AffineTransform
& AffineTransform::rotateRadians(double a
)
171 double cosAngle
= cos(a
);
172 double sinAngle
= sin(a
);
173 AffineTransform
rot(cosAngle
, sinAngle
, -sinAngle
, cosAngle
, 0, 0);
179 AffineTransform
& AffineTransform::scale(double s
)
184 AffineTransform
& AffineTransform::scale(double sx
, double sy
)
186 m_transform
[0] *= sx
;
187 m_transform
[1] *= sx
;
188 m_transform
[2] *= sy
;
189 m_transform
[3] *= sy
;
193 // *this = *this * translation
194 AffineTransform
& AffineTransform::translate(double tx
, double ty
)
196 if (isIdentityOrTranslation()) {
197 m_transform
[4] += tx
;
198 m_transform
[5] += ty
;
202 m_transform
[4] += tx
* m_transform
[0] + ty
* m_transform
[2];
203 m_transform
[5] += tx
* m_transform
[1] + ty
* m_transform
[3];
207 AffineTransform
& AffineTransform::scaleNonUniform(double sx
, double sy
)
209 return scale(sx
, sy
);
212 AffineTransform
& AffineTransform::rotateFromVector(double x
, double y
)
214 return rotateRadians(atan2(y
, x
));
217 AffineTransform
& AffineTransform::flipX()
222 AffineTransform
& AffineTransform::flipY()
227 AffineTransform
& AffineTransform::shear(double sx
, double sy
)
229 double a
= m_transform
[0];
230 double b
= m_transform
[1];
232 m_transform
[0] += sy
* m_transform
[2];
233 m_transform
[1] += sy
* m_transform
[3];
234 m_transform
[2] += sx
* a
;
235 m_transform
[3] += sx
* b
;
240 AffineTransform
& AffineTransform::skew(double angleX
, double angleY
)
242 return shear(tan(deg2rad(angleX
)), tan(deg2rad(angleY
)));
245 AffineTransform
& AffineTransform::skewX(double angle
)
247 return shear(tan(deg2rad(angle
)), 0);
250 AffineTransform
& AffineTransform::skewY(double angle
)
252 return shear(0, tan(deg2rad(angle
)));
255 void AffineTransform::map(double x
, double y
, double& x2
, double& y2
) const
257 x2
= (m_transform
[0] * x
+ m_transform
[2] * y
+ m_transform
[4]);
258 y2
= (m_transform
[1] * x
+ m_transform
[3] * y
+ m_transform
[5]);
261 IntPoint
AffineTransform::mapPoint(const IntPoint
& point
) const
264 map(point
.x(), point
.y(), x2
, y2
);
267 return IntPoint(lround(x2
), lround(y2
));
270 FloatPoint
AffineTransform::mapPoint(const FloatPoint
& point
) const
273 map(point
.x(), point
.y(), x2
, y2
);
275 return FloatPoint(narrowPrecisionToFloat(x2
), narrowPrecisionToFloat(y2
));
278 IntSize
AffineTransform::mapSize(const IntSize
& size
) const
280 double width2
= size
.width() * xScale();
281 double height2
= size
.height() * yScale();
283 return IntSize(lround(width2
), lround(height2
));
286 FloatSize
AffineTransform::mapSize(const FloatSize
& size
) const
288 double width2
= size
.width() * xScale();
289 double height2
= size
.height() * yScale();
291 return FloatSize(narrowPrecisionToFloat(width2
), narrowPrecisionToFloat(height2
));
294 IntRect
AffineTransform::mapRect(const IntRect
&rect
) const
296 return enclosingIntRect(mapRect(FloatRect(rect
)));
299 FloatRect
AffineTransform::mapRect(const FloatRect
& rect
) const
301 if (isIdentityOrTranslation()) {
302 if (!m_transform
[4] && !m_transform
[5])
305 FloatRect
mappedRect(rect
);
306 mappedRect
.move(narrowPrecisionToFloat(m_transform
[4]), narrowPrecisionToFloat(m_transform
[5]));
311 result
.setP1(mapPoint(rect
.location()));
312 result
.setP2(mapPoint(FloatPoint(rect
.maxX(), rect
.y())));
313 result
.setP3(mapPoint(FloatPoint(rect
.maxX(), rect
.maxY())));
314 result
.setP4(mapPoint(FloatPoint(rect
.x(), rect
.maxY())));
315 return result
.boundingBox();
318 FloatQuad
AffineTransform::mapQuad(const FloatQuad
& q
) const
320 if (isIdentityOrTranslation()) {
321 FloatQuad
mappedQuad(q
);
322 mappedQuad
.move(narrowPrecisionToFloat(m_transform
[4]), narrowPrecisionToFloat(m_transform
[5]));
327 result
.setP1(mapPoint(q
.p1()));
328 result
.setP2(mapPoint(q
.p2()));
329 result
.setP3(mapPoint(q
.p3()));
330 result
.setP4(mapPoint(q
.p4()));
334 TransformationMatrix
AffineTransform::toTransformationMatrix() const
336 return TransformationMatrix(m_transform
[0], m_transform
[1], m_transform
[2],
337 m_transform
[3], m_transform
[4], m_transform
[5]);
340 bool AffineTransform::decompose(DecomposedType
& decomp
) const
342 AffineTransform
m(*this);
344 // Compute scaling factors
345 double sx
= xScale();
346 double sy
= yScale();
348 // Compute cross product of transformed unit vectors. If negative,
349 // one axis was flipped.
350 if (m
.a() * m
.d() - m
.c() * m
.b() < 0) {
351 // Flip axis with minimum unit vector dot product
358 // Remove scale from matrix
359 m
.scale(1 / sx
, 1 / sy
);
362 double angle
= atan2(m
.b(), m
.a());
364 // Remove rotation from matrix
365 m
.rotateRadians(-angle
);
370 decomp
.angle
= angle
;
371 decomp
.remainderA
= m
.a();
372 decomp
.remainderB
= m
.b();
373 decomp
.remainderC
= m
.c();
374 decomp
.remainderD
= m
.d();
375 decomp
.translateX
= m
.e();
376 decomp
.translateY
= m
.f();
381 void AffineTransform::recompose(const DecomposedType
& decomp
)
383 this->setA(decomp
.remainderA
);
384 this->setB(decomp
.remainderB
);
385 this->setC(decomp
.remainderC
);
386 this->setD(decomp
.remainderD
);
387 this->setE(decomp
.translateX
);
388 this->setF(decomp
.translateY
);
389 this->rotateRadians(decomp
.angle
);
390 this->scale(decomp
.scaleX
, decomp
.scaleY
);