Make SkRRect work with axis aligned rotation transforms
This patch allows SkRRect::trasform() work with any axis aligned matrix transform meaning it now works with a rotation of 90 or 270 degrees. Adds relevant unit tests. Bug: skia:8944 Change-Id: I63678ec0e3556c181517526de55d84666afeb681 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/205860 Reviewed-by: Robert Phillips <robertphillips@google.com> Reviewed-by: Mike Reed <reed@google.com> Commit-Queue: Robert Phillips <robertphillips@google.com>
This commit is contained in:
parent
e21616804a
commit
e4628b1072
@ -454,7 +454,7 @@ public:
|
||||
|
||||
/** Transforms by SkRRect by matrix, storing result in dst.
|
||||
Returns true if SkRRect transformed can be represented by another SkRRect.
|
||||
Returns false if matrix contains transformations other than scale and translate.
|
||||
Returns false if matrix contains transformations that are not axis aligned.
|
||||
|
||||
Asserts in debug builds if SkRRect equals dst.
|
||||
|
||||
|
@ -389,9 +389,7 @@ bool SkRRect::transform(const SkMatrix& matrix, SkRRect* dst) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If transform supported 90 degree rotations (which it could), we could
|
||||
// use SkMatrix::rectStaysRect() to check for a valid transformation.
|
||||
if (!matrix.isScaleTranslate()) {
|
||||
if (!matrix.preservesAxisAlignment()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -411,7 +409,7 @@ bool SkRRect::transform(const SkMatrix& matrix, SkRRect* dst) const {
|
||||
// At this point, this is guaranteed to succeed, so we can modify dst.
|
||||
dst->fRect = newRect;
|
||||
|
||||
// Since the only transforms that were allowed are scale and translate, the type
|
||||
// Since the only transforms that were allowed are axis aligned, the type
|
||||
// remains unchanged.
|
||||
dst->fType = fType;
|
||||
|
||||
@ -430,11 +428,37 @@ bool SkRRect::transform(const SkMatrix& matrix, SkRRect* dst) const {
|
||||
|
||||
// Now scale each corner
|
||||
SkScalar xScale = matrix.getScaleX();
|
||||
SkScalar yScale = matrix.getScaleY();
|
||||
|
||||
// There is a rotation of 90 (Clockwise 90) or 270 (Counter clockwise 90).
|
||||
// 180 degrees rotations are simply flipX with a flipY and would come under
|
||||
// a scale transform.
|
||||
if (!matrix.isScaleTranslate()) {
|
||||
const bool isClockwise = matrix.getSkewX() < 0;
|
||||
|
||||
// The matrix location for scale changes if there is a rotation.
|
||||
xScale = matrix.getSkewY() * (isClockwise ? 1 : -1);
|
||||
yScale = matrix.getSkewX() * (isClockwise ? -1 : 1);
|
||||
|
||||
const int dir = isClockwise ? 3 : 1;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
const int src = (i + dir) >= 4 ? (i + dir) % 4 : (i + dir);
|
||||
// Swap X and Y axis for the radii.
|
||||
dst->fRadii[i].fX = fRadii[src].fY;
|
||||
dst->fRadii[i].fY = fRadii[src].fX;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
dst->fRadii[i].fX = fRadii[i].fX;
|
||||
dst->fRadii[i].fY = fRadii[i].fY;
|
||||
}
|
||||
}
|
||||
|
||||
const bool flipX = xScale < 0;
|
||||
if (flipX) {
|
||||
xScale = -xScale;
|
||||
}
|
||||
SkScalar yScale = matrix.getScaleY();
|
||||
|
||||
const bool flipY = yScale < 0;
|
||||
if (flipY) {
|
||||
yScale = -yScale;
|
||||
@ -442,8 +466,8 @@ bool SkRRect::transform(const SkMatrix& matrix, SkRRect* dst) const {
|
||||
|
||||
// Scale the radii without respecting the flip.
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
dst->fRadii[i].fX = fRadii[i].fX * xScale;
|
||||
dst->fRadii[i].fY = fRadii[i].fY * yScale;
|
||||
dst->fRadii[i].fX *= xScale;
|
||||
dst->fRadii[i].fY *= yScale;
|
||||
}
|
||||
|
||||
// Now swap as necessary.
|
||||
|
@ -570,8 +570,6 @@ static void test_transform_helper(skiatest::Reporter* reporter, const SkRRect& o
|
||||
|
||||
// Rotation fails.
|
||||
matrix.reset();
|
||||
matrix.setRotate(SkIntToScalar(90));
|
||||
assert_transform_failure(reporter, orig, matrix);
|
||||
matrix.setRotate(SkIntToScalar(37));
|
||||
assert_transform_failure(reporter, orig, matrix);
|
||||
|
||||
@ -689,6 +687,219 @@ static void test_transform_helper(skiatest::Reporter* reporter, const SkRRect& o
|
||||
orig.rect().left() * xScale));
|
||||
REPORTER_ASSERT(reporter, SkScalarNearlyEqual(dst.rect().top(),
|
||||
orig.rect().top() * yScale));
|
||||
|
||||
|
||||
// a-----b d-----a
|
||||
// | | -> | |
|
||||
// | | Rotate 90 | |
|
||||
// d-----c c-----b
|
||||
matrix.reset();
|
||||
matrix.setRotate(SkIntToScalar(90));
|
||||
dst.setEmpty();
|
||||
success = orig.transform(matrix, &dst);
|
||||
REPORTER_ASSERT(reporter, success);
|
||||
{
|
||||
GET_RADII;
|
||||
// Radii have cycled clockwise and swapped their x and y axis.
|
||||
REPORTER_ASSERT(reporter, dstUL.x() == origLL.y());
|
||||
REPORTER_ASSERT(reporter, dstUL.y() == origLL.x());
|
||||
REPORTER_ASSERT(reporter, dstUR.x() == origUL.y());
|
||||
REPORTER_ASSERT(reporter, dstUR.y() == origUL.x());
|
||||
REPORTER_ASSERT(reporter, dstLR.x() == origUR.y());
|
||||
REPORTER_ASSERT(reporter, dstLR.y() == origUR.x());
|
||||
REPORTER_ASSERT(reporter, dstLL.x() == origLR.y());
|
||||
REPORTER_ASSERT(reporter, dstLL.y() == origLR.x());
|
||||
}
|
||||
// Width and height would get swapped.
|
||||
REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().height());
|
||||
REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().width());
|
||||
|
||||
// a-----b b-----a c-----b
|
||||
// | | -> | | -> | |
|
||||
// | | Flip X | | Rotate 90 | |
|
||||
// d-----c c-----d d-----a
|
||||
matrix.reset();
|
||||
matrix.setRotate(SkIntToScalar(90));
|
||||
matrix.postScale(SkIntToScalar(-1), SkIntToScalar(1));
|
||||
dst.setEmpty();
|
||||
success = orig.transform(matrix, &dst);
|
||||
REPORTER_ASSERT(reporter, success);
|
||||
{
|
||||
GET_RADII;
|
||||
REPORTER_ASSERT(reporter, dstUL.x() == origLR.y());
|
||||
REPORTER_ASSERT(reporter, dstUL.y() == origLR.x());
|
||||
REPORTER_ASSERT(reporter, dstUR.x() == origUR.y());
|
||||
REPORTER_ASSERT(reporter, dstUR.y() == origUR.x());
|
||||
REPORTER_ASSERT(reporter, dstLR.x() == origUL.y());
|
||||
REPORTER_ASSERT(reporter, dstLR.y() == origUL.x());
|
||||
REPORTER_ASSERT(reporter, dstLL.x() == origLL.y());
|
||||
REPORTER_ASSERT(reporter, dstLL.y() == origLL.x());
|
||||
}
|
||||
// Width and height would get swapped.
|
||||
REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().height());
|
||||
REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().width());
|
||||
|
||||
// a-----b d-----a c-----b
|
||||
// | | -> | | -> | |
|
||||
// | | Rotate 90 | | Flip Y | |
|
||||
// d-----c c-----b d-----a
|
||||
//
|
||||
// This is the same as Flip X and Rotate 90.
|
||||
matrix.reset();
|
||||
matrix.setScale(SkIntToScalar(1), SkIntToScalar(-1));
|
||||
matrix.postRotate(SkIntToScalar(90));
|
||||
SkRRect dst2;
|
||||
dst2.setEmpty();
|
||||
success = orig.transform(matrix, &dst2);
|
||||
REPORTER_ASSERT(reporter, success);
|
||||
REPORTER_ASSERT(reporter, dst == dst2);
|
||||
|
||||
// a-----b b-----c c-----b
|
||||
// | | -> | | -> | |
|
||||
// | | Rotate 270 | | Flip X | |
|
||||
// d-----c a-----d d-----a
|
||||
matrix.reset();
|
||||
matrix.setScale(SkIntToScalar(-1), SkIntToScalar(1));
|
||||
matrix.postRotate(SkIntToScalar(270));
|
||||
dst2.setEmpty();
|
||||
success = orig.transform(matrix, &dst2);
|
||||
REPORTER_ASSERT(reporter, success);
|
||||
REPORTER_ASSERT(reporter, dst == dst2);
|
||||
|
||||
// a-----b d-----c c-----b
|
||||
// | | -> | | -> | |
|
||||
// | | Flip Y | | Rotate 270 | |
|
||||
// d-----c a-----b d-----a
|
||||
matrix.reset();
|
||||
matrix.setRotate(SkIntToScalar(270));
|
||||
matrix.postScale(SkIntToScalar(1), SkIntToScalar(-1));
|
||||
dst2.setEmpty();
|
||||
success = orig.transform(matrix, &dst2);
|
||||
REPORTER_ASSERT(reporter, success);
|
||||
REPORTER_ASSERT(reporter, dst == dst2);
|
||||
|
||||
// a-----b d-----a a-----d
|
||||
// | | -> | | -> | |
|
||||
// | | Rotate 90 | | Flip X | |
|
||||
// d-----c c-----b b-----c
|
||||
matrix.reset();
|
||||
matrix.setScale(SkIntToScalar(-1), SkIntToScalar(1));
|
||||
matrix.postRotate(SkIntToScalar(90));
|
||||
dst.setEmpty();
|
||||
success = orig.transform(matrix, &dst);
|
||||
REPORTER_ASSERT(reporter, success);
|
||||
{
|
||||
GET_RADII;
|
||||
REPORTER_ASSERT(reporter, dstUL.x() == origUL.y());
|
||||
REPORTER_ASSERT(reporter, dstUL.y() == origUL.x());
|
||||
REPORTER_ASSERT(reporter, dstUR.x() == origLL.y());
|
||||
REPORTER_ASSERT(reporter, dstUR.y() == origLL.x());
|
||||
REPORTER_ASSERT(reporter, dstLR.x() == origLR.y());
|
||||
REPORTER_ASSERT(reporter, dstLR.y() == origLR.x());
|
||||
REPORTER_ASSERT(reporter, dstLL.x() == origUR.y());
|
||||
REPORTER_ASSERT(reporter, dstLL.y() == origUR.x());
|
||||
}
|
||||
// Width and height would get swapped.
|
||||
REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().height());
|
||||
REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().width());
|
||||
|
||||
// a-----b d-----c a-----d
|
||||
// | | -> | | -> | |
|
||||
// | | Flip Y | | Rotate 90 | |
|
||||
// d-----c a-----b b-----c
|
||||
// This is the same as rotate 90 and flip x.
|
||||
matrix.reset();
|
||||
matrix.setRotate(SkIntToScalar(90));
|
||||
matrix.postScale(SkIntToScalar(1), SkIntToScalar(-1));
|
||||
dst2.setEmpty();
|
||||
success = orig.transform(matrix, &dst2);
|
||||
REPORTER_ASSERT(reporter, success);
|
||||
REPORTER_ASSERT(reporter, dst == dst2);
|
||||
|
||||
// a-----b b-----a a-----d
|
||||
// | | -> | | -> | |
|
||||
// | | Flip X | | Rotate 270 | |
|
||||
// d-----c c-----d b-----c
|
||||
matrix.reset();
|
||||
matrix.setRotate(SkIntToScalar(270));
|
||||
matrix.postScale(SkIntToScalar(-1), SkIntToScalar(1));
|
||||
dst2.setEmpty();
|
||||
success = orig.transform(matrix, &dst2);
|
||||
REPORTER_ASSERT(reporter, success);
|
||||
REPORTER_ASSERT(reporter, dst == dst2);
|
||||
|
||||
// a-----b b-----c a-----d
|
||||
// | | -> | | -> | |
|
||||
// | | Rotate 270 | | Flip Y | |
|
||||
// d-----c a-----d b-----c
|
||||
matrix.reset();
|
||||
matrix.setScale(SkIntToScalar(1), SkIntToScalar(-1));
|
||||
matrix.postRotate(SkIntToScalar(270));
|
||||
dst2.setEmpty();
|
||||
success = orig.transform(matrix, &dst2);
|
||||
REPORTER_ASSERT(reporter, success);
|
||||
REPORTER_ASSERT(reporter, dst == dst2);
|
||||
|
||||
|
||||
// a-----b b-----a c-----d b-----c
|
||||
// | | -> | | -> | | -> | |
|
||||
// | | Flip X | | Flip Y | | Rotate 90 | |
|
||||
// d-----c c-----d b-----a a-----d
|
||||
//
|
||||
// This is the same as rotation by 270.
|
||||
matrix.reset();
|
||||
matrix.setRotate(SkIntToScalar(90));
|
||||
matrix.postScale(SkIntToScalar(-1), SkIntToScalar(-1));
|
||||
dst.setEmpty();
|
||||
success = orig.transform(matrix, &dst);
|
||||
REPORTER_ASSERT(reporter, success);
|
||||
{
|
||||
GET_RADII;
|
||||
// Radii have cycled clockwise and swapped their x and y axis.
|
||||
REPORTER_ASSERT(reporter, dstUL.x() == origUR.y());
|
||||
REPORTER_ASSERT(reporter, dstUL.y() == origUR.x());
|
||||
REPORTER_ASSERT(reporter, dstUR.x() == origLR.y());
|
||||
REPORTER_ASSERT(reporter, dstUR.y() == origLR.x());
|
||||
REPORTER_ASSERT(reporter, dstLR.x() == origLL.y());
|
||||
REPORTER_ASSERT(reporter, dstLR.y() == origLL.x());
|
||||
REPORTER_ASSERT(reporter, dstLL.x() == origUL.y());
|
||||
REPORTER_ASSERT(reporter, dstLL.y() == origUL.x());
|
||||
}
|
||||
// Width and height would get swapped.
|
||||
REPORTER_ASSERT(reporter, orig.rect().width() == dst.rect().height());
|
||||
REPORTER_ASSERT(reporter, orig.rect().height() == dst.rect().width());
|
||||
|
||||
// a-----b b-----c
|
||||
// | | -> | |
|
||||
// | | Rotate 270 | |
|
||||
// d-----c a-----d
|
||||
//
|
||||
dst2.setEmpty();
|
||||
matrix.reset();
|
||||
matrix.setRotate(SkIntToScalar(270));
|
||||
success = orig.transform(matrix, &dst2);
|
||||
REPORTER_ASSERT(reporter, success);
|
||||
REPORTER_ASSERT(reporter, dst == dst2);
|
||||
|
||||
// a-----b b-----a c-----d d-----a
|
||||
// | | -> | | -> | | -> | |
|
||||
// | | Flip X | | Flip Y | | Rotate 270 | |
|
||||
// d-----c c-----d b-----a c-----b
|
||||
//
|
||||
// This is the same as rotation by 90 degrees.
|
||||
matrix.reset();
|
||||
matrix.setRotate(SkIntToScalar(270));
|
||||
matrix.postScale(SkIntToScalar(-1), SkIntToScalar(-1));
|
||||
dst.setEmpty();
|
||||
success = orig.transform(matrix, &dst);
|
||||
REPORTER_ASSERT(reporter, success);
|
||||
|
||||
matrix.reset();
|
||||
matrix.setRotate(SkIntToScalar(90));
|
||||
dst2.setEmpty();
|
||||
success = orig.transform(matrix, &dst2);
|
||||
REPORTER_ASSERT(reporter, dst == dst2);
|
||||
|
||||
}
|
||||
|
||||
static void test_round_rect_transform(skiatest::Reporter* reporter) {
|
||||
|
Loading…
Reference in New Issue
Block a user