From 95acbad4fee03a2fa2c0419da70a1b85e21739ef Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Fri, 13 Jan 2017 13:35:49 -0500 Subject: ensure path bounds after rounding contain path edges when using SK_RASTERIZE_EVEN_ROUNDING BUG=skia: Change-Id: I34e93de8fd4faa44336c2698d06595e9c4de86c3 Reviewed-on: https://skia-review.googlesource.com/7040 Reviewed-by: Cary Clark Commit-Queue: Cary Clark --- src/core/SkScan_Path.cpp | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'src/core') diff --git a/src/core/SkScan_Path.cpp b/src/core/SkScan_Path.cpp index 6d28f4b1ae..9f81eac1d5 100644 --- a/src/core/SkScan_Path.cpp +++ b/src/core/SkScan_Path.cpp @@ -608,6 +608,19 @@ static inline int round_down_to_int(SkScalar x) { return (int)ceil(xx); } +#ifdef SK_RASTERIZE_EVEN_ROUNDING +/** + * Variant of SkDScalarRoundToInt that biases the input up by a half an FDot6 unit to account + * for potential FDot6 rounding in downstream FDot6 calculations. + */ +static inline int round_biased_to_int(SkScalar x) { + const double bias = 0.5 / SK_FDot6One; + double xx = x; + xx += 0.5 + bias; + return (int)floor(xx); +} +#endif + /** * Variant of SkRect::round() that explicitly performs the rounding step (i.e. floor(x + 0.5)) * using double instead of SkScalar (float). It does this by calling SkDScalarRoundToInt(), @@ -625,11 +638,28 @@ static inline int round_down_to_int(SkScalar x) { * SkASSERT(0 == iright); // <--- fails * iright = SkDScalarRoundToInt(right); * SkASSERT(0 == iright); // <--- succeeds + * + * + * If using SK_RASTERIZE_EVEN_ROUNDING, we need to ensure that bottom and right account for + * edges bounded by this rect being rounded to FDot6 format before being later rounded to an + * integer. For example, a value like 0.499 can be below 0.5, but round to 0.5 as FDot6, which + * would finally round to the integer 1, instead of just rounding to 0. + * + * To handle this, a small bias of half an FDot6 increment is added before actually rounding to + * an integer value. This simulates the rounding of SkScalarRoundToFDot6 without incurring the + * range loss of converting to FDot6 format first, preserving the integer range for the SkIRect. + * Thus, bottom and right are rounded in this manner (biased up), ensuring the rect is large + * enough. Top and left can round as normal since they will round (biased down) to values less + * or equal to the desired rect origin. */ static void round_asymmetric_to_int(const SkRect& src, SkIRect* dst) { SkASSERT(dst); dst->set(round_down_to_int(src.fLeft), round_down_to_int(src.fTop), +#ifdef SK_RASTERIZE_EVEN_ROUNDING + round_biased_to_int(src.fRight), round_biased_to_int(src.fBottom)); +#else SkDScalarRoundToInt(src.fRight), SkDScalarRoundToInt(src.fBottom)); +#endif } void SkScan::FillPath(const SkPath& path, const SkRegion& origClip, -- cgit v1.2.3