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