mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
359 lines
11 KiB
C++
359 lines
11 KiB
C++
/*
|
|
* Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
|
|
* 2010 Dirk Schulze <krit@webkit.org>
|
|
* Copyright (C) 2013 Google Inc. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "flutter/sky/engine/platform/transforms/AffineTransform.h"
|
|
|
|
#include "flutter/sky/engine/platform/FloatConversion.h"
|
|
#include "flutter/sky/engine/platform/geometry/FloatQuad.h"
|
|
#include "flutter/sky/engine/platform/geometry/FloatRect.h"
|
|
#include "flutter/sky/engine/platform/geometry/IntRect.h"
|
|
#include "flutter/sky/engine/wtf/MathExtras.h"
|
|
|
|
namespace blink {
|
|
|
|
AffineTransform::AffineTransform() {
|
|
setMatrix(1, 0, 0, 1, 0, 0);
|
|
}
|
|
|
|
AffineTransform::AffineTransform(double a,
|
|
double b,
|
|
double c,
|
|
double d,
|
|
double e,
|
|
double f) {
|
|
setMatrix(a, b, c, d, e, f);
|
|
}
|
|
|
|
void AffineTransform::makeIdentity() {
|
|
setMatrix(1, 0, 0, 1, 0, 0);
|
|
}
|
|
|
|
void AffineTransform::setMatrix(double a,
|
|
double b,
|
|
double c,
|
|
double d,
|
|
double e,
|
|
double f) {
|
|
m_transform[0] = a;
|
|
m_transform[1] = b;
|
|
m_transform[2] = c;
|
|
m_transform[3] = d;
|
|
m_transform[4] = e;
|
|
m_transform[5] = f;
|
|
}
|
|
|
|
bool AffineTransform::isIdentity() const {
|
|
return (m_transform[0] == 1 && m_transform[1] == 0 && m_transform[2] == 0 &&
|
|
m_transform[3] == 1 && m_transform[4] == 0 && m_transform[5] == 0);
|
|
}
|
|
|
|
double AffineTransform::xScale() const {
|
|
return sqrt(m_transform[0] * m_transform[0] +
|
|
m_transform[1] * m_transform[1]);
|
|
}
|
|
|
|
double AffineTransform::yScale() const {
|
|
return sqrt(m_transform[2] * m_transform[2] +
|
|
m_transform[3] * m_transform[3]);
|
|
}
|
|
|
|
double AffineTransform::det() const {
|
|
return m_transform[0] * m_transform[3] - m_transform[1] * m_transform[2];
|
|
}
|
|
|
|
bool AffineTransform::isInvertible() const {
|
|
return det() != 0.0;
|
|
}
|
|
|
|
AffineTransform AffineTransform::inverse() const {
|
|
double determinant = det();
|
|
if (determinant == 0.0)
|
|
return AffineTransform();
|
|
|
|
AffineTransform result;
|
|
if (isIdentityOrTranslation()) {
|
|
result.m_transform[4] = -m_transform[4];
|
|
result.m_transform[5] = -m_transform[5];
|
|
return result;
|
|
}
|
|
|
|
result.m_transform[0] = m_transform[3] / determinant;
|
|
result.m_transform[1] = -m_transform[1] / determinant;
|
|
result.m_transform[2] = -m_transform[2] / determinant;
|
|
result.m_transform[3] = m_transform[0] / determinant;
|
|
result.m_transform[4] =
|
|
(m_transform[2] * m_transform[5] - m_transform[3] * m_transform[4]) /
|
|
determinant;
|
|
result.m_transform[5] =
|
|
(m_transform[1] * m_transform[4] - m_transform[0] * m_transform[5]) /
|
|
determinant;
|
|
|
|
return result;
|
|
}
|
|
|
|
// Multiplies this AffineTransform by the provided AffineTransform - i.e.
|
|
// this = this * other;
|
|
AffineTransform& AffineTransform::multiply(const AffineTransform& other) {
|
|
AffineTransform trans;
|
|
|
|
trans.m_transform[0] = other.m_transform[0] * m_transform[0] +
|
|
other.m_transform[1] * m_transform[2];
|
|
trans.m_transform[1] = other.m_transform[0] * m_transform[1] +
|
|
other.m_transform[1] * m_transform[3];
|
|
trans.m_transform[2] = other.m_transform[2] * m_transform[0] +
|
|
other.m_transform[3] * m_transform[2];
|
|
trans.m_transform[3] = other.m_transform[2] * m_transform[1] +
|
|
other.m_transform[3] * m_transform[3];
|
|
trans.m_transform[4] = other.m_transform[4] * m_transform[0] +
|
|
other.m_transform[5] * m_transform[2] + m_transform[4];
|
|
trans.m_transform[5] = other.m_transform[4] * m_transform[1] +
|
|
other.m_transform[5] * m_transform[3] + m_transform[5];
|
|
|
|
setMatrix(trans.m_transform);
|
|
return *this;
|
|
}
|
|
|
|
AffineTransform& AffineTransform::rotate(double a) {
|
|
// angle is in degree. Switch to radian
|
|
return rotateRadians(deg2rad(a));
|
|
}
|
|
|
|
AffineTransform& AffineTransform::rotateRadians(double a) {
|
|
double cosAngle = cos(a);
|
|
double sinAngle = sin(a);
|
|
AffineTransform rot(cosAngle, sinAngle, -sinAngle, cosAngle, 0, 0);
|
|
|
|
multiply(rot);
|
|
return *this;
|
|
}
|
|
|
|
AffineTransform& AffineTransform::scale(double s) {
|
|
return scale(s, s);
|
|
}
|
|
|
|
AffineTransform& AffineTransform::scale(double sx, double sy) {
|
|
m_transform[0] *= sx;
|
|
m_transform[1] *= sx;
|
|
m_transform[2] *= sy;
|
|
m_transform[3] *= sy;
|
|
return *this;
|
|
}
|
|
|
|
// *this = *this * translation
|
|
AffineTransform& AffineTransform::translate(double tx, double ty) {
|
|
if (isIdentityOrTranslation()) {
|
|
m_transform[4] += tx;
|
|
m_transform[5] += ty;
|
|
return *this;
|
|
}
|
|
|
|
m_transform[4] += tx * m_transform[0] + ty * m_transform[2];
|
|
m_transform[5] += tx * m_transform[1] + ty * m_transform[3];
|
|
return *this;
|
|
}
|
|
|
|
AffineTransform& AffineTransform::scaleNonUniform(double sx, double sy) {
|
|
return scale(sx, sy);
|
|
}
|
|
|
|
AffineTransform& AffineTransform::rotateFromVector(double x, double y) {
|
|
return rotateRadians(atan2(y, x));
|
|
}
|
|
|
|
AffineTransform& AffineTransform::flipX() {
|
|
return scale(-1, 1);
|
|
}
|
|
|
|
AffineTransform& AffineTransform::flipY() {
|
|
return scale(1, -1);
|
|
}
|
|
|
|
AffineTransform& AffineTransform::shear(double sx, double sy) {
|
|
double a = m_transform[0];
|
|
double b = m_transform[1];
|
|
|
|
m_transform[0] += sy * m_transform[2];
|
|
m_transform[1] += sy * m_transform[3];
|
|
m_transform[2] += sx * a;
|
|
m_transform[3] += sx * b;
|
|
|
|
return *this;
|
|
}
|
|
|
|
AffineTransform& AffineTransform::skew(double angleX, double angleY) {
|
|
return shear(tan(deg2rad(angleX)), tan(deg2rad(angleY)));
|
|
}
|
|
|
|
AffineTransform& AffineTransform::skewX(double angle) {
|
|
return shear(tan(deg2rad(angle)), 0);
|
|
}
|
|
|
|
AffineTransform& AffineTransform::skewY(double angle) {
|
|
return shear(0, tan(deg2rad(angle)));
|
|
}
|
|
|
|
AffineTransform makeMapBetweenRects(const FloatRect& source,
|
|
const FloatRect& dest) {
|
|
AffineTransform transform;
|
|
transform.translate(dest.x() - source.x(), dest.y() - source.y());
|
|
transform.scale(dest.width() / source.width(),
|
|
dest.height() / source.height());
|
|
return transform;
|
|
}
|
|
|
|
void AffineTransform::map(double x, double y, double& x2, double& y2) const {
|
|
x2 = (m_transform[0] * x + m_transform[2] * y + m_transform[4]);
|
|
y2 = (m_transform[1] * x + m_transform[3] * y + m_transform[5]);
|
|
}
|
|
|
|
IntPoint AffineTransform::mapPoint(const IntPoint& point) const {
|
|
double x2, y2;
|
|
map(point.x(), point.y(), x2, y2);
|
|
|
|
// Round the point.
|
|
return IntPoint(lround(x2), lround(y2));
|
|
}
|
|
|
|
FloatPoint AffineTransform::mapPoint(const FloatPoint& point) const {
|
|
double x2, y2;
|
|
map(point.x(), point.y(), x2, y2);
|
|
|
|
return FloatPoint(narrowPrecisionToFloat(x2), narrowPrecisionToFloat(y2));
|
|
}
|
|
|
|
IntSize AffineTransform::mapSize(const IntSize& size) const {
|
|
double width2 = size.width() * xScale();
|
|
double height2 = size.height() * yScale();
|
|
|
|
return IntSize(lround(width2), lround(height2));
|
|
}
|
|
|
|
FloatSize AffineTransform::mapSize(const FloatSize& size) const {
|
|
double width2 = size.width() * xScale();
|
|
double height2 = size.height() * yScale();
|
|
|
|
return FloatSize(narrowPrecisionToFloat(width2),
|
|
narrowPrecisionToFloat(height2));
|
|
}
|
|
|
|
IntRect AffineTransform::mapRect(const IntRect& rect) const {
|
|
return enclosingIntRect(mapRect(FloatRect(rect)));
|
|
}
|
|
|
|
FloatRect AffineTransform::mapRect(const FloatRect& rect) const {
|
|
if (isIdentityOrTranslation()) {
|
|
if (!m_transform[4] && !m_transform[5])
|
|
return rect;
|
|
|
|
FloatRect mappedRect(rect);
|
|
mappedRect.move(narrowPrecisionToFloat(m_transform[4]),
|
|
narrowPrecisionToFloat(m_transform[5]));
|
|
return mappedRect;
|
|
}
|
|
|
|
FloatQuad result;
|
|
result.setP1(mapPoint(rect.location()));
|
|
result.setP2(mapPoint(FloatPoint(rect.maxX(), rect.y())));
|
|
result.setP3(mapPoint(FloatPoint(rect.maxX(), rect.maxY())));
|
|
result.setP4(mapPoint(FloatPoint(rect.x(), rect.maxY())));
|
|
return result.boundingBox();
|
|
}
|
|
|
|
FloatQuad AffineTransform::mapQuad(const FloatQuad& q) const {
|
|
if (isIdentityOrTranslation()) {
|
|
FloatQuad mappedQuad(q);
|
|
mappedQuad.move(narrowPrecisionToFloat(m_transform[4]),
|
|
narrowPrecisionToFloat(m_transform[5]));
|
|
return mappedQuad;
|
|
}
|
|
|
|
FloatQuad result;
|
|
result.setP1(mapPoint(q.p1()));
|
|
result.setP2(mapPoint(q.p2()));
|
|
result.setP3(mapPoint(q.p3()));
|
|
result.setP4(mapPoint(q.p4()));
|
|
return result;
|
|
}
|
|
|
|
TransformationMatrix AffineTransform::toTransformationMatrix() const {
|
|
return TransformationMatrix(m_transform[0], m_transform[1], m_transform[2],
|
|
m_transform[3], m_transform[4], m_transform[5]);
|
|
}
|
|
|
|
bool AffineTransform::decompose(DecomposedType& decomp) const {
|
|
AffineTransform m(*this);
|
|
|
|
// Compute scaling factors
|
|
double sx = xScale();
|
|
double sy = yScale();
|
|
|
|
// Compute cross product of transformed unit vectors. If negative,
|
|
// one axis was flipped.
|
|
if (m.a() * m.d() - m.c() * m.b() < 0) {
|
|
// Flip axis with minimum unit vector dot product
|
|
if (m.a() < m.d())
|
|
sx = -sx;
|
|
else
|
|
sy = -sy;
|
|
}
|
|
|
|
// Remove scale from matrix
|
|
m.scale(1 / sx, 1 / sy);
|
|
|
|
// Compute rotation
|
|
double angle = atan2(m.b(), m.a());
|
|
|
|
// Remove rotation from matrix
|
|
m.rotateRadians(-angle);
|
|
|
|
// Return results
|
|
decomp.scaleX = sx;
|
|
decomp.scaleY = sy;
|
|
decomp.angle = angle;
|
|
decomp.remainderA = m.a();
|
|
decomp.remainderB = m.b();
|
|
decomp.remainderC = m.c();
|
|
decomp.remainderD = m.d();
|
|
decomp.translateX = m.e();
|
|
decomp.translateY = m.f();
|
|
|
|
return true;
|
|
}
|
|
|
|
void AffineTransform::recompose(const DecomposedType& decomp) {
|
|
this->setA(decomp.remainderA);
|
|
this->setB(decomp.remainderB);
|
|
this->setC(decomp.remainderC);
|
|
this->setD(decomp.remainderD);
|
|
this->setE(decomp.translateX);
|
|
this->setF(decomp.translateY);
|
|
this->rotateRadians(decomp.angle);
|
|
this->scale(decomp.scaleX, decomp.scaleY);
|
|
}
|
|
|
|
} // namespace blink
|