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