1 /*
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.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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.
14 *
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.
26 */
27
28 #include "config.h"
29 #include "platform/transforms/AffineTransform.h"
30
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"
36
37 namespace WebCore {
38
AffineTransform()39 AffineTransform::AffineTransform()
40 {
41 setMatrix(1, 0, 0, 1, 0, 0);
42 }
43
AffineTransform(double a,double b,double c,double d,double e,double f)44 AffineTransform::AffineTransform(double a, double b, double c, double d, double e, double f)
45 {
46 setMatrix(a, b, c, d, e, f);
47 }
48
makeIdentity()49 void AffineTransform::makeIdentity()
50 {
51 setMatrix(1, 0, 0, 1, 0, 0);
52 }
53
setMatrix(double a,double b,double c,double d,double e,double f)54 void AffineTransform::setMatrix(double a, double b, double c, double d, double e, double f)
55 {
56 m_transform[0] = a;
57 m_transform[1] = b;
58 m_transform[2] = c;
59 m_transform[3] = d;
60 m_transform[4] = e;
61 m_transform[5] = f;
62 }
63
isIdentity() const64 bool AffineTransform::isIdentity() const
65 {
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);
69 }
70
xScale() const71 double AffineTransform::xScale() const
72 {
73 return sqrt(m_transform[0] * m_transform[0] + m_transform[1] * m_transform[1]);
74 }
75
yScale() const76 double AffineTransform::yScale() const
77 {
78 return sqrt(m_transform[2] * m_transform[2] + m_transform[3] * m_transform[3]);
79 }
80
det() const81 double AffineTransform::det() const
82 {
83 return m_transform[0] * m_transform[3] - m_transform[1] * m_transform[2];
84 }
85
isInvertible() const86 bool AffineTransform::isInvertible() const
87 {
88 return det() != 0.0;
89 }
90
inverse() const91 AffineTransform AffineTransform::inverse() const
92 {
93 double determinant = det();
94 if (determinant == 0.0)
95 return AffineTransform();
96
97 AffineTransform result;
98 if (isIdentityOrTranslation()) {
99 result.m_transform[4] = -m_transform[4];
100 result.m_transform[5] = -m_transform[5];
101 return result;
102 }
103
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;
112
113 return result;
114 }
115
116
117 // Multiplies this AffineTransform by the provided AffineTransform - i.e.
118 // this = this * other;
multiply(const AffineTransform & other)119 AffineTransform& AffineTransform::multiply(const AffineTransform& other)
120 {
121 AffineTransform trans;
122
123 trans.m_transform[0] = other.m_transform[0] * m_transform[0] + other.m_transform[1] * m_transform[2];
124 trans.m_transform[1] = other.m_transform[0] * m_transform[1] + other.m_transform[1] * m_transform[3];
125 trans.m_transform[2] = other.m_transform[2] * m_transform[0] + other.m_transform[3] * m_transform[2];
126 trans.m_transform[3] = other.m_transform[2] * m_transform[1] + other.m_transform[3] * m_transform[3];
127 trans.m_transform[4] = other.m_transform[4] * m_transform[0] + other.m_transform[5] * m_transform[2] + m_transform[4];
128 trans.m_transform[5] = other.m_transform[4] * m_transform[1] + other.m_transform[5] * m_transform[3] + m_transform[5];
129
130 setMatrix(trans.m_transform);
131 return *this;
132 }
133
rotate(double a)134 AffineTransform& AffineTransform::rotate(double a)
135 {
136 // angle is in degree. Switch to radian
137 a = deg2rad(a);
138 double cosAngle = cos(a);
139 double sinAngle = sin(a);
140 AffineTransform rot(cosAngle, sinAngle, -sinAngle, cosAngle, 0, 0);
141
142 multiply(rot);
143 return *this;
144 }
145
scale(double s)146 AffineTransform& AffineTransform::scale(double s)
147 {
148 return scale(s, s);
149 }
150
scale(double sx,double sy)151 AffineTransform& AffineTransform::scale(double sx, double sy)
152 {
153 m_transform[0] *= sx;
154 m_transform[1] *= sx;
155 m_transform[2] *= sy;
156 m_transform[3] *= sy;
157 return *this;
158 }
159
160 // *this = *this * translation
translate(double tx,double ty)161 AffineTransform& AffineTransform::translate(double tx, double ty)
162 {
163 if (isIdentityOrTranslation()) {
164 m_transform[4] += tx;
165 m_transform[5] += ty;
166 return *this;
167 }
168
169 m_transform[4] += tx * m_transform[0] + ty * m_transform[2];
170 m_transform[5] += tx * m_transform[1] + ty * m_transform[3];
171 return *this;
172 }
173
scaleNonUniform(double sx,double sy)174 AffineTransform& AffineTransform::scaleNonUniform(double sx, double sy)
175 {
176 return scale(sx, sy);
177 }
178
rotateFromVector(double x,double y)179 AffineTransform& AffineTransform::rotateFromVector(double x, double y)
180 {
181 return rotate(rad2deg(atan2(y, x)));
182 }
183
flipX()184 AffineTransform& AffineTransform::flipX()
185 {
186 return scale(-1, 1);
187 }
188
flipY()189 AffineTransform& AffineTransform::flipY()
190 {
191 return scale(1, -1);
192 }
193
shear(double sx,double sy)194 AffineTransform& AffineTransform::shear(double sx, double sy)
195 {
196 double a = m_transform[0];
197 double b = m_transform[1];
198
199 m_transform[0] += sy * m_transform[2];
200 m_transform[1] += sy * m_transform[3];
201 m_transform[2] += sx * a;
202 m_transform[3] += sx * b;
203
204 return *this;
205 }
206
skew(double angleX,double angleY)207 AffineTransform& AffineTransform::skew(double angleX, double angleY)
208 {
209 return shear(tan(deg2rad(angleX)), tan(deg2rad(angleY)));
210 }
211
skewX(double angle)212 AffineTransform& AffineTransform::skewX(double angle)
213 {
214 return shear(tan(deg2rad(angle)), 0);
215 }
216
skewY(double angle)217 AffineTransform& AffineTransform::skewY(double angle)
218 {
219 return shear(0, tan(deg2rad(angle)));
220 }
221
makeMapBetweenRects(const FloatRect & source,const FloatRect & dest)222 AffineTransform makeMapBetweenRects(const FloatRect& source, const FloatRect& dest)
223 {
224 AffineTransform transform;
225 transform.translate(dest.x() - source.x(), dest.y() - source.y());
226 transform.scale(dest.width() / source.width(), dest.height() / source.height());
227 return transform;
228 }
229
map(double x,double y,double & x2,double & y2) const230 void AffineTransform::map(double x, double y, double& x2, double& y2) const
231 {
232 x2 = (m_transform[0] * x + m_transform[2] * y + m_transform[4]);
233 y2 = (m_transform[1] * x + m_transform[3] * y + m_transform[5]);
234 }
235
mapPoint(const IntPoint & point) const236 IntPoint AffineTransform::mapPoint(const IntPoint& point) const
237 {
238 double x2, y2;
239 map(point.x(), point.y(), x2, y2);
240
241 // Round the point.
242 return IntPoint(lround(x2), lround(y2));
243 }
244
mapPoint(const FloatPoint & point) const245 FloatPoint AffineTransform::mapPoint(const FloatPoint& point) const
246 {
247 double x2, y2;
248 map(point.x(), point.y(), x2, y2);
249
250 return FloatPoint(narrowPrecisionToFloat(x2), narrowPrecisionToFloat(y2));
251 }
252
mapSize(const IntSize & size) const253 IntSize AffineTransform::mapSize(const IntSize& size) const
254 {
255 double width2 = size.width() * xScale();
256 double height2 = size.height() * yScale();
257
258 return IntSize(lround(width2), lround(height2));
259 }
260
mapSize(const FloatSize & size) const261 FloatSize AffineTransform::mapSize(const FloatSize& size) const
262 {
263 double width2 = size.width() * xScale();
264 double height2 = size.height() * yScale();
265
266 return FloatSize(narrowPrecisionToFloat(width2), narrowPrecisionToFloat(height2));
267 }
268
mapRect(const IntRect & rect) const269 IntRect AffineTransform::mapRect(const IntRect &rect) const
270 {
271 return enclosingIntRect(mapRect(FloatRect(rect)));
272 }
273
mapRect(const FloatRect & rect) const274 FloatRect AffineTransform::mapRect(const FloatRect& rect) const
275 {
276 if (isIdentityOrTranslation()) {
277 FloatRect mappedRect(rect);
278 mappedRect.move(narrowPrecisionToFloat(m_transform[4]), narrowPrecisionToFloat(m_transform[5]));
279 return mappedRect;
280 }
281
282 FloatQuad result;
283 result.setP1(mapPoint(rect.location()));
284 result.setP2(mapPoint(FloatPoint(rect.maxX(), rect.y())));
285 result.setP3(mapPoint(FloatPoint(rect.maxX(), rect.maxY())));
286 result.setP4(mapPoint(FloatPoint(rect.x(), rect.maxY())));
287 return result.boundingBox();
288 }
289
mapQuad(const FloatQuad & q) const290 FloatQuad AffineTransform::mapQuad(const FloatQuad& q) const
291 {
292 if (isIdentityOrTranslation()) {
293 FloatQuad mappedQuad(q);
294 mappedQuad.move(narrowPrecisionToFloat(m_transform[4]), narrowPrecisionToFloat(m_transform[5]));
295 return mappedQuad;
296 }
297
298 FloatQuad result;
299 result.setP1(mapPoint(q.p1()));
300 result.setP2(mapPoint(q.p2()));
301 result.setP3(mapPoint(q.p3()));
302 result.setP4(mapPoint(q.p4()));
303 return result;
304 }
305
blend(const AffineTransform & from,double progress)306 void AffineTransform::blend(const AffineTransform& from, double progress)
307 {
308 DecomposedType srA, srB;
309
310 from.decompose(srA);
311 this->decompose(srB);
312
313 // If x-axis of one is flipped, and y-axis of the other, convert to an unflipped rotation.
314 if ((srA.scaleX < 0 && srB.scaleY < 0) || (srA.scaleY < 0 && srB.scaleX < 0)) {
315 srA.scaleX = -srA.scaleX;
316 srA.scaleY = -srA.scaleY;
317 srA.angle += srA.angle < 0 ? piDouble : -piDouble;
318 }
319
320 // Don't rotate the long way around.
321 srA.angle = fmod(srA.angle, 2 * piDouble);
322 srB.angle = fmod(srB.angle, 2 * piDouble);
323
324 if (fabs(srA.angle - srB.angle) > piDouble) {
325 if (srA.angle > srB.angle)
326 srA.angle -= piDouble * 2;
327 else
328 srB.angle -= piDouble * 2;
329 }
330
331 srA.scaleX += progress * (srB.scaleX - srA.scaleX);
332 srA.scaleY += progress * (srB.scaleY - srA.scaleY);
333 srA.angle += progress * (srB.angle - srA.angle);
334 srA.remainderA += progress * (srB.remainderA - srA.remainderA);
335 srA.remainderB += progress * (srB.remainderB - srA.remainderB);
336 srA.remainderC += progress * (srB.remainderC - srA.remainderC);
337 srA.remainderD += progress * (srB.remainderD - srA.remainderD);
338 srA.translateX += progress * (srB.translateX - srA.translateX);
339 srA.translateY += progress * (srB.translateY - srA.translateY);
340
341 this->recompose(srA);
342 }
343
toTransformationMatrix() const344 TransformationMatrix AffineTransform::toTransformationMatrix() const
345 {
346 return TransformationMatrix(m_transform[0], m_transform[1], m_transform[2],
347 m_transform[3], m_transform[4], m_transform[5]);
348 }
349
decompose(DecomposedType & decomp) const350 bool AffineTransform::decompose(DecomposedType& decomp) const
351 {
352 AffineTransform m(*this);
353
354 // Compute scaling factors
355 double sx = xScale();
356 double sy = yScale();
357
358 // Compute cross product of transformed unit vectors. If negative,
359 // one axis was flipped.
360 if (m.a() * m.d() - m.c() * m.b() < 0) {
361 // Flip axis with minimum unit vector dot product
362 if (m.a() < m.d())
363 sx = -sx;
364 else
365 sy = -sy;
366 }
367
368 // Remove scale from matrix
369 m.scale(1 / sx, 1 / sy);
370
371 // Compute rotation
372 double angle = atan2(m.b(), m.a());
373
374 // Remove rotation from matrix
375 m.rotate(rad2deg(-angle));
376
377 // Return results
378 decomp.scaleX = sx;
379 decomp.scaleY = sy;
380 decomp.angle = angle;
381 decomp.remainderA = m.a();
382 decomp.remainderB = m.b();
383 decomp.remainderC = m.c();
384 decomp.remainderD = m.d();
385 decomp.translateX = m.e();
386 decomp.translateY = m.f();
387
388 return true;
389 }
390
recompose(const DecomposedType & decomp)391 void AffineTransform::recompose(const DecomposedType& decomp)
392 {
393 this->setA(decomp.remainderA);
394 this->setB(decomp.remainderB);
395 this->setC(decomp.remainderC);
396 this->setD(decomp.remainderD);
397 this->setE(decomp.translateX);
398 this->setF(decomp.translateY);
399 this->rotate(rad2deg(decomp.angle));
400 this->scale(decomp.scaleX, decomp.scaleY);
401 }
402
403 }
404