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