Index: src/core/SkScan_Antihair.cpp |
diff --git a/src/core/SkScan_Antihair.cpp b/src/core/SkScan_Antihair.cpp |
index 67c8917f0afc9900e08892cbd7949b7f9c65e95a..e31f66cc568653fdfdb067226d562a155876de56 100644 |
--- a/src/core/SkScan_Antihair.cpp |
+++ b/src/core/SkScan_Antihair.cpp |
@@ -974,6 +974,15 @@ static void innerstrokedot8(FDot8 L, FDot8 T, FDot8 R, FDot8 B, |
} |
} |
+static inline void align_thin_stroke(FDot8& edge1, FDot8& edge2) { |
+ SkASSERT(edge1 <= edge2); |
+ |
+ if (FDot8Floor(edge1) == FDot8Floor(edge2)) { |
+ edge2 -= (edge1 & 0xFF); |
+ edge1 &= ~0xFF; |
+ } |
+} |
+ |
void SkScan::AntiFrameRect(const SkRect& r, const SkPoint& strokeSize, |
const SkRegion* clip, SkBlitter* blitter) { |
SkASSERT(strokeSize.fX >= 0 && strokeSize.fY >= 0); |
@@ -982,14 +991,14 @@ void SkScan::AntiFrameRect(const SkRect& r, const SkPoint& strokeSize, |
SkScalar ry = SkScalarHalf(strokeSize.fY); |
// outset by the radius |
- FDot8 L = SkScalarToFDot8(r.fLeft - rx); |
- FDot8 T = SkScalarToFDot8(r.fTop - ry); |
- FDot8 R = SkScalarToFDot8(r.fRight + rx); |
- FDot8 B = SkScalarToFDot8(r.fBottom + ry); |
+ FDot8 outerL = SkScalarToFDot8(r.fLeft - rx); |
+ FDot8 outerT = SkScalarToFDot8(r.fTop - ry); |
+ FDot8 outerR = SkScalarToFDot8(r.fRight + rx); |
+ FDot8 outerB = SkScalarToFDot8(r.fBottom + ry); |
SkIRect outer; |
// set outer to the outer rect of the outer section |
- outer.set(FDot8Floor(L), FDot8Floor(T), FDot8Ceil(R), FDot8Ceil(B)); |
+ outer.set(FDot8Floor(outerL), FDot8Floor(outerT), FDot8Ceil(outerR), FDot8Ceil(outerB)); |
SkBlitterClipper clipper; |
if (clip) { |
@@ -1002,28 +1011,40 @@ void SkScan::AntiFrameRect(const SkRect& r, const SkPoint& strokeSize, |
// now we can ignore clip for the rest of the function |
} |
- // stroke the outer hull |
- antifilldot8(L, T, R, B, blitter, false); |
- |
- // set outer to the outer rect of the middle section |
- outer.set(FDot8Ceil(L), FDot8Ceil(T), FDot8Floor(R), FDot8Floor(B)); |
- |
// in case we lost a bit with diameter/2 |
rx = strokeSize.fX - rx; |
ry = strokeSize.fY - ry; |
+ |
// inset by the radius |
- L = SkScalarToFDot8(r.fLeft + rx); |
- T = SkScalarToFDot8(r.fTop + ry); |
- R = SkScalarToFDot8(r.fRight - rx); |
- B = SkScalarToFDot8(r.fBottom - ry); |
+ FDot8 innerL = SkScalarToFDot8(r.fLeft + rx); |
+ FDot8 innerT = SkScalarToFDot8(r.fTop + ry); |
+ FDot8 innerR = SkScalarToFDot8(r.fRight - rx); |
+ FDot8 innerB = SkScalarToFDot8(r.fBottom - ry); |
+ |
+ // For sub-unit strokes, tweak the hulls such that one of the edges coincides with the pixel |
+ // edge. This ensures that the general rect stroking logic below |
+ // a) doesn't blit the same scanline twice |
+ // b) computes the correct coverage when both edges fall within the same pixel |
+ if (strokeSize.fX < 1 || strokeSize.fY < 1) { |
+ align_thin_stroke(outerL, innerL); |
+ align_thin_stroke(outerT, innerT); |
+ align_thin_stroke(innerR, outerR); |
+ align_thin_stroke(innerB, outerB); |
+ } |
- if (L >= R || T >= B) { |
+ // stroke the outer hull |
+ antifilldot8(outerL, outerT, outerR, outerB, blitter, false); |
+ |
+ // set outer to the outer rect of the middle section |
+ outer.set(FDot8Ceil(outerL), FDot8Ceil(outerT), FDot8Floor(outerR), FDot8Floor(outerB)); |
+ |
+ if (innerL >= innerR || innerT >= innerB) { |
fillcheckrect(outer.fLeft, outer.fTop, outer.fRight, outer.fBottom, |
blitter); |
} else { |
SkIRect inner; |
// set inner to the inner rect of the middle section |
- inner.set(FDot8Floor(L), FDot8Floor(T), FDot8Ceil(R), FDot8Ceil(B)); |
+ inner.set(FDot8Floor(innerL), FDot8Floor(innerT), FDot8Ceil(innerR), FDot8Ceil(innerB)); |
// draw the frame in 4 pieces |
fillcheckrect(outer.fLeft, outer.fTop, outer.fRight, inner.fTop, |
@@ -1038,7 +1059,7 @@ void SkScan::AntiFrameRect(const SkRect& r, const SkPoint& strokeSize, |
// now stroke the inner rect, which is similar to antifilldot8() except that |
// it treats the fractional coordinates with the inverse bias (since its |
// inner). |
- innerstrokedot8(L, T, R, B, blitter); |
+ innerstrokedot8(innerL, innerT, innerR, innerB, blitter); |
} |
} |