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