• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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