aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/SkScan_Path.cpp
diff options
context:
space:
mode:
authorGravatar caryclark <caryclark@google.com>2016-01-04 14:17:47 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2016-01-04 14:17:47 -0800
commit6df611574a3cf8abf2617af0d03a5553bb17360d (patch)
tree1e5bcb0e8c8048ad8958286ff4a7a37cf4829790 /src/core/SkScan_Path.cpp
parent512f3e3b2592097a39bde9331829b38d16c0f85d (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.cpp46
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);