diff options
author | 2013-10-20 13:11:16 +0000 | |
---|---|---|
committer | 2013-10-20 13:11:16 +0000 | |
commit | 123671901abfa595d09ca789b487c4bc7c1f7cbc (patch) | |
tree | dd1ba8fb90718e0d8dbf1d82375619b718eeed68 /src | |
parent | b3c2da312f26b4852726a431a7de6effe045c3c4 (diff) |
Fix cubic->quad RR corner regression
https://codereview.chromium.org/29673002/
git-svn-id: http://skia.googlecode.com/svn/trunk@11870 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src')
-rw-r--r-- | src/core/SkCanvas.cpp | 4 | ||||
-rw-r--r-- | src/core/SkPath.cpp | 86 |
2 files changed, 57 insertions, 33 deletions
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index 7add524260..6036186fc2 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -1124,7 +1124,7 @@ bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { doAA &= fAllowSoftClip; if (fMCRec->fMatrix->rectStaysRect()) { - // for these simpler matrices, we can stay a rect ever after applying + // for these simpler matrices, we can stay a rect even after applying // the matrix. This means we don't have to a) make a path, and b) tell // the region code to scan-convert the path, only to discover that it // is really just a rect. @@ -1134,7 +1134,7 @@ bool SkCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { fClipStack.clipDevRect(r, op, doAA); return fMCRec->fRasterClip->op(r, op, doAA); } else { - // since we're rotate or some such thing, we convert the rect to a path + // since we're rotated or some such thing, we convert the rect to a path // and clip against that, since it can handle any matrix. However, to // avoid recursion in the case where we are subclassed (e.g. Pictures) // we explicitly call "our" version of clipPath. diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp index 3b3a125d0e..9df62850fd 100644 --- a/src/core/SkPath.cpp +++ b/src/core/SkPath.cpp @@ -17,8 +17,6 @@ SK_DEFINE_INST_COUNT(SkPath); -#define SK_IGNORE_QUAD_RR_CORNERS_OPT 1 - // This value is just made-up for now. When count is 4, calling memset was much // slower than just writing the loop. This seems odd, and hopefully in the // future this we appear to have been a fluke... @@ -966,8 +964,7 @@ static int build_arc_points(const SkRect& oval, SkScalar startAngle, static void add_corner_arc(SkPath* path, const SkRect& rect, SkScalar rx, SkScalar ry, int startAngle, - SkPath::Direction dir, bool addArcTo, - bool forceMoveTo = false) { + SkPath::Direction dir, bool forceMoveTo) { // These two asserts are not sufficient, since really we want to know // that the pair of radii (e.g. left and right, or top and bottom) sum // to <= dimension, but we don't have that data here, so we just have @@ -997,15 +994,7 @@ static void add_corner_arc(SkPath* path, const SkRect& rect, sweep = -sweep; } - if (addArcTo) { - path->arcTo(r, start, sweep, forceMoveTo); - } else { - SkPoint pts[kSkBuildQuadArcStorage]; - int count = build_arc_points(r, start, sweep, pts); - for (int i = 1; i < count; i += 2) { - path->quadTo(pts[i], pts[i+1]); - } - } + path->arcTo(r, start, sweep, forceMoveTo); } void SkPath::addRoundRect(const SkRect& rect, const SkScalar radii[], @@ -1035,15 +1024,15 @@ void SkPath::addRRect(const SkRRect& rrect, Direction dir) { SkAutoPathBoundsUpdate apbu(this, bounds); if (kCW_Direction == dir) { - add_corner_arc(this, bounds, rrect.fRadii[0].fX, rrect.fRadii[0].fY, 180, dir, true, true); - add_corner_arc(this, bounds, rrect.fRadii[1].fX, rrect.fRadii[1].fY, 270, dir, true); - add_corner_arc(this, bounds, rrect.fRadii[2].fX, rrect.fRadii[2].fY, 0, dir, true); - add_corner_arc(this, bounds, rrect.fRadii[3].fX, rrect.fRadii[3].fY, 90, dir, true); + add_corner_arc(this, bounds, rrect.fRadii[0].fX, rrect.fRadii[0].fY, 180, dir, true); + add_corner_arc(this, bounds, rrect.fRadii[1].fX, rrect.fRadii[1].fY, 270, dir, false); + add_corner_arc(this, bounds, rrect.fRadii[2].fX, rrect.fRadii[2].fY, 0, dir, false); + add_corner_arc(this, bounds, rrect.fRadii[3].fX, rrect.fRadii[3].fY, 90, dir, false); } else { - add_corner_arc(this, bounds, rrect.fRadii[0].fX, rrect.fRadii[0].fY, 180, dir, true, true); - add_corner_arc(this, bounds, rrect.fRadii[3].fX, rrect.fRadii[3].fY, 90, dir, true); - add_corner_arc(this, bounds, rrect.fRadii[2].fX, rrect.fRadii[2].fY, 0, dir, true); - add_corner_arc(this, bounds, rrect.fRadii[1].fX, rrect.fRadii[1].fY, 270, dir, true); + add_corner_arc(this, bounds, rrect.fRadii[0].fX, rrect.fRadii[0].fY, 180, dir, true); + add_corner_arc(this, bounds, rrect.fRadii[3].fX, rrect.fRadii[3].fY, 90, dir, false); + add_corner_arc(this, bounds, rrect.fRadii[2].fX, rrect.fRadii[2].fY, 0, dir, false); + add_corner_arc(this, bounds, rrect.fRadii[1].fX, rrect.fRadii[1].fY, 270, dir, false); } this->close(); } @@ -1113,9 +1102,20 @@ void SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, this->incReserve(17); #else - this->incReserve(13); + // Please see SkBuildQuadArc for more information but, we need to pull + // the off-curve quadratic points in a little bit to make the round + // rects convex. + static const SkScalar kOffCurveEpsilon = 0.0001f; + + SkScalar midPtX = rx * SK_ScalarRoot2Over2; + SkScalar midPtY = ry * SK_ScalarRoot2Over2; + + SkScalar offPtX = rx * SK_ScalarTanPIOver8 - kOffCurveEpsilon; + SkScalar offPtY = ry * SK_ScalarTanPIOver8 - kOffCurveEpsilon; + + this->incReserve(21); #endif - this->moveTo(rect.fRight - rx, rect.fTop); + this->moveTo(rect.fRight - rx, rect.fTop); // top-right if (dir == kCCW_Direction) { if (!skip_hori) { this->lineTo(rect.fLeft + rx, rect.fTop); // top @@ -1125,7 +1125,10 @@ void SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, rect.fLeft, rect.fTop + ry - sy, rect.fLeft, rect.fTop + ry); // top-left #else - add_corner_arc(this, rect, rx, ry, 180, dir, false); // top-left + this->quadTo(rect.fLeft + rx - offPtX, rect.fTop + kOffCurveEpsilon, + rect.fLeft + rx - midPtX, rect.fTop + ry - midPtY); + this->quadTo(rect.fLeft + kOffCurveEpsilon, rect.fTop + ry - offPtY, + rect.fLeft, rect.fTop + ry); #endif if (!skip_vert) { this->lineTo(rect.fLeft, rect.fBottom - ry); // left @@ -1135,7 +1138,10 @@ void SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, rect.fLeft + rx - sx, rect.fBottom, rect.fLeft + rx, rect.fBottom); // bot-left #else - add_corner_arc(this, rect, rx, ry, 90, dir, false); // bot-left + this->quadTo(rect.fLeft + kOffCurveEpsilon, rect.fBottom - ry + offPtY, + rect.fLeft + rx - midPtX, rect.fBottom - ry + midPtY); + this->quadTo(rect.fLeft + rx - offPtX, rect.fBottom - kOffCurveEpsilon, + rect.fLeft + rx, rect.fBottom); #endif if (!skip_hori) { this->lineTo(rect.fRight - rx, rect.fBottom); // bottom @@ -1145,7 +1151,10 @@ void SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, rect.fRight, rect.fBottom - ry + sy, rect.fRight, rect.fBottom - ry); // bot-right #else - add_corner_arc(this, rect, rx, ry, 0, dir, false); // bot-right + this->quadTo(rect.fRight - rx + offPtX, rect.fBottom - kOffCurveEpsilon, + rect.fRight - rx + midPtX, rect.fBottom - ry + midPtY); + this->quadTo(rect.fRight - kOffCurveEpsilon, rect.fBottom - ry + offPtY, + rect.fRight, rect.fBottom - ry); #endif if (!skip_vert) { this->lineTo(rect.fRight, rect.fTop + ry); // right @@ -1155,7 +1164,10 @@ void SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, rect.fRight - rx + sx, rect.fTop, rect.fRight - rx, rect.fTop); // top-right #else - add_corner_arc(this, rect, rx, ry, 270, dir, false); // top-right + this->quadTo(rect.fRight - kOffCurveEpsilon, rect.fTop + ry - offPtY, + rect.fRight - rx + midPtX, rect.fTop + ry - midPtY); + this->quadTo(rect.fRight - rx + offPtX, rect.fTop + kOffCurveEpsilon, + rect.fRight - rx, rect.fTop); #endif } else { #ifdef SK_IGNORE_QUAD_RR_CORNERS_OPT @@ -1163,7 +1175,10 @@ void SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, rect.fRight, rect.fTop + ry - sy, rect.fRight, rect.fTop + ry); // top-right #else - add_corner_arc(this, rect, rx, ry, 270, dir, false); // top-right + this->quadTo(rect.fRight - rx + offPtX, rect.fTop + kOffCurveEpsilon, + rect.fRight - rx + midPtX, rect.fTop + ry - midPtY); + this->quadTo(rect.fRight - kOffCurveEpsilon, rect.fTop + ry - offPtY, + rect.fRight, rect.fTop + ry); #endif if (!skip_vert) { this->lineTo(rect.fRight, rect.fBottom - ry); // right @@ -1173,7 +1188,10 @@ void SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, rect.fRight - rx + sx, rect.fBottom, rect.fRight - rx, rect.fBottom); // bot-right #else - add_corner_arc(this, rect, rx, ry, 0, dir, false); // bot-right + this->quadTo(rect.fRight - kOffCurveEpsilon, rect.fBottom - ry + offPtY, + rect.fRight - rx + midPtX, rect.fBottom - ry + midPtY); + this->quadTo(rect.fRight - rx + offPtX, rect.fBottom - kOffCurveEpsilon, + rect.fRight - rx, rect.fBottom); #endif if (!skip_hori) { this->lineTo(rect.fLeft + rx, rect.fBottom); // bottom @@ -1183,7 +1201,10 @@ void SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, rect.fLeft, rect.fBottom - ry + sy, rect.fLeft, rect.fBottom - ry); // bot-left #else - add_corner_arc(this, rect, rx, ry, 90, dir, false); // bot-left + this->quadTo(rect.fLeft + rx - offPtX, rect.fBottom - kOffCurveEpsilon, + rect.fLeft + rx - midPtX, rect.fBottom - ry + midPtY); + this->quadTo(rect.fLeft + kOffCurveEpsilon, rect.fBottom - ry + offPtY, + rect.fLeft, rect.fBottom - ry); #endif if (!skip_vert) { this->lineTo(rect.fLeft, rect.fTop + ry); // left @@ -1193,7 +1214,10 @@ void SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, rect.fLeft + rx - sx, rect.fTop, rect.fLeft + rx, rect.fTop); // top-left #else - add_corner_arc(this, rect, rx, ry, 180, dir, false); // top-left + this->quadTo(rect.fLeft + kOffCurveEpsilon, rect.fTop + ry - offPtY, + rect.fLeft + rx - midPtX, rect.fTop + ry - midPtY); + this->quadTo(rect.fLeft + rx - offPtX, rect.fTop + kOffCurveEpsilon, + rect.fLeft + rx, rect.fTop); #endif if (!skip_hori) { this->lineTo(rect.fRight - rx, rect.fTop); // top |