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