| 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 | |