diff options
author | caryclark <caryclark@google.com> | 2016-01-04 14:17:47 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-01-04 14:17:47 -0800 |
commit | 6df611574a3cf8abf2617af0d03a5553bb17360d (patch) | |
tree | 1e5bcb0e8c8048ad8958286ff4a7a37cf4829790 /src/core/SkScan_Path.cpp | |
parent | 512f3e3b2592097a39bde9331829b38d16c0f85d (diff) |
handle halfway case in scan converter
Scan edges that start at exactly -0.5 aren't trimmed by
clipping or by rounding, triggering a debug assert.
One way to fix this is to round the top and left
down instead of up.
Also, move the path initialization of gm/composeshader.cpp
to make debugging other path problems easier.
R=reed@google.com
BUG=skia:2715
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1544873002
Review URL: https://codereview.chromium.org/1544873002
Diffstat (limited to 'src/core/SkScan_Path.cpp')
-rw-r--r-- | src/core/SkScan_Path.cpp | 46 |
1 files changed, 41 insertions, 5 deletions
diff --git a/src/core/SkScan_Path.cpp b/src/core/SkScan_Path.cpp index 30a7c57659..804148db36 100644 --- a/src/core/SkScan_Path.cpp +++ b/src/core/SkScan_Path.cpp @@ -559,6 +559,42 @@ static bool clip_to_limit(const SkRegion& orig, SkRegion* reduced) { return true; } +/** + * Variant of SkScalarRoundToInt, identical to SkDScalarRoundToInt except when the input fraction + * is 0.5. In this case only, round the value down. This is used to round the top and left + * of a rectangle, and corresponds to the way the scan converter treats the top and left edges. + */ +static inline int round_down_to_int(SkScalar x) { + double xx = x; + xx += 0.5; + double floorXX = floor(xx); + return (int)floorXX - (xx == floorXX); +} + +/** + * 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(), + * which may be slower than calling SkScalarRountToInt(), but gives slightly more accurate + * results. Also rounds top and left using double, flooring when the fraction is exactly 0.5f. + * + * e.g. + * SkScalar left = 0.5f; + * int ileft = SkScalarRoundToInt(left); + * SkASSERT(0 == ileft); // <--- fails + * int ileft = round_down_to_int(left); + * SkASSERT(0 == ileft); // <--- succeeds + * SkScalar right = 0.49999997f; + * int iright = SkScalarRoundToInt(right); + * SkASSERT(0 == iright); // <--- fails + * iright = SkDScalarRoundToInt(right); + * SkASSERT(0 == iright); // <--- succeeds + */ +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), + SkDScalarRoundToInt(src.fRight), SkDScalarRoundToInt(src.fBottom)); +} + void SkScan::FillPath(const SkPath& path, const SkRegion& origClip, SkBlitter* blitter) { if (origClip.isEmpty()) { @@ -578,11 +614,11 @@ void SkScan::FillPath(const SkPath& path, const SkRegion& origClip, // don't reference "origClip" any more, just use clipPtr SkIRect ir; - // We deliberately call dround() instead of round(), since we can't afford to generate a - // bounds that is tighter than the corresponding SkEdges. The edge code basically converts - // the floats to fixed, and then "rounds". If we called round() instead of dround() here, - // we could generate the wrong ir for values like 0.4999997. - path.getBounds().dround(&ir); + // We deliberately call round_asymmetric_to_int() instead of round(), since we can't afford + // to generate a bounds that is tighter than the corresponding SkEdges. The edge code basically + // converts the floats to fixed, and then "rounds". If we called round() instead of + // round_asymmetric_to_int() here, we could generate the wrong ir for values like 0.4999997. + round_asymmetric_to_int(path.getBounds(), &ir); if (ir.isEmpty()) { if (path.isInverseFillType()) { blitter->blitRegion(*clipPtr); |