diff options
author | robertphillips <robertphillips@google.com> | 2014-06-27 08:59:26 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-06-27 08:59:26 -0700 |
commit | e5c1e3cd63e22bb06c24dd051f4d814f24786c08 (patch) | |
tree | 993b1d4b6479905fb4a745a0b1680e0a658de873 | |
parent | a8377402ee626bd0a6c61ef9f0c256f06eca5759 (diff) |
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
-rw-r--r-- | src/core/SkRRect.cpp | 17 | ||||
-rw-r--r-- | tests/RoundRectTest.cpp | 30 |
2 files changed, 43 insertions, 4 deletions
diff --git a/src/core/SkRRect.cpp b/src/core/SkRRect.cpp index 9bb6725dea..10d3d7676b 100644 --- a/src/core/SkRRect.cpp +++ b/src/core/SkRRect.cpp @@ -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; diff --git a/tests/RoundRectTest.cpp b/tests/RoundRectTest.cpp index 0a528a6535..261ec67ca0 100644 --- a/tests/RoundRectTest.cpp +++ b/tests/RoundRectTest.cpp @@ -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); } |