Fix RRect tranform bug

When a RRect is an oval transforming the rectangle and the radii separately can result in a non-oval result (i.e., due to numerical issues some tiny straight edges may creep in). This CL remedies the situation by computing the new radii directly from the transformed rect.

BUG=skia:2696
R=caryclark@google.com

Author: robertphillips@google.com

Review URL: https://codereview.chromium.org/354913004
This commit is contained in:
robertphillips 2014-06-27 08:59:26 -07:00 committed by Commit bot
parent a8377402ee
commit e5c1e3cd63
2 changed files with 43 additions and 4 deletions

View File

@ -342,6 +342,19 @@ 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
// remains unchanged.
dst->fType = fType;
if (kOval_Type == fType) {
for (int i = 0; i < 4; ++i) {
dst->fRadii[i].fX = SkScalarHalf(newRect.width());
dst->fRadii[i].fY = SkScalarHalf(newRect.height());
}
SkDEBUGCODE(dst->validate();)
return true;
}
// Now scale each corner
SkScalar xScale = matrix.getScaleX();
const bool flipX = xScale < 0;
@ -377,10 +390,6 @@ bool SkRRect::transform(const SkMatrix& matrix, SkRRect* dst) const {
SkTSwap(dst->fRadii[kUpperRight_Corner], dst->fRadii[kLowerRight_Corner]);
}
// Since the only transforms that were allowed are scale and translate, the type
// remains unchanged.
dst->fType = fType;
SkDEBUGCODE(dst->validate();)
return true;

View File

@ -582,6 +582,35 @@ static void test_round_rect_transform(skiatest::Reporter* reporter) {
}
}
// Test out the case where an oval already off in space is translated/scaled
// further off into space - yielding numerical issues when the rect & radii
// are transformed separatly
// BUG=skia:2696
static void test_issue_2696(skiatest::Reporter* reporter) {
SkRRect rrect;
SkRect r = { 28443.8594f, 53.1428604f, 28446.7148f, 56.0000038f };
rrect.setOval(r);
SkMatrix xform;
xform.setAll(2.44f, 0.0f, 485411.7f,
0.0f, 2.44f, -438.7f,
0.0f, 0.0f, 1.0f);
SkRRect dst;
bool success = rrect.transform(xform, &dst);
REPORTER_ASSERT(reporter, success);
SkScalar halfWidth = SkScalarHalf(dst.width());
SkScalar halfHeight = SkScalarHalf(dst.height());
for (int i = 0; i < 4; ++i) {
REPORTER_ASSERT(reporter,
SkScalarNearlyEqual(dst.radii((SkRRect::Corner)i).fX, halfWidth));
REPORTER_ASSERT(reporter,
SkScalarNearlyEqual(dst.radii((SkRRect::Corner)i).fY, halfHeight));
}
}
DEF_TEST(RoundRect, reporter) {
test_round_rect_basic(reporter);
test_round_rect_rects(reporter);
@ -591,4 +620,5 @@ DEF_TEST(RoundRect, reporter) {
test_inset(reporter);
test_round_rect_contains_rect(reporter);
test_round_rect_transform(reporter);
test_issue_2696(reporter);
}