combine vertical overlapping edges
authorcaryclark <caryclark@google.com>
Sat, 30 Jan 2016 22:07:20 +0000 (14:07 -0800)
committerCommit bot <commit-bot@chromium.org>
Sat, 30 Jan 2016 22:07:20 +0000 (14:07 -0800)
Paths outside clips, and sometimes paths inside clips, devolve
to multiple adjacent or overlapping vertical edges. Combine
these edges when possible to reduce the overall edge count.

R=reed@google.com
BUG=573166
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1654433002

Review URL: https://codereview.chromium.org/1654433002

src/core/SkEdgeBuilder.cpp
src/core/SkEdgeBuilder.h

index 92c8330..dc39038 100644 (file)
@@ -22,11 +22,70 @@ SkEdgeBuilder::SkEdgeBuilder() : fAlloc(16*1024) {
     fEdgeList = nullptr;
 }
 
+SkEdgeBuilder::Combine SkEdgeBuilder::CombineVertical(const SkEdge* edge, SkEdge* last) {
+    if (last->fCurveCount || last->fDX || edge->fX != last->fX) {
+        return kNo_Combine;
+    }
+    if (edge->fWinding == last->fWinding) {
+        if (edge->fLastY + 1 == last->fFirstY) {
+            last->fFirstY = edge->fFirstY;
+            return kPartial_Combine;
+        }
+        if (edge->fFirstY == last->fLastY + 1) {
+            last->fLastY = edge->fLastY;
+            return kPartial_Combine;
+        }
+        return kNo_Combine;
+    }
+    if (edge->fFirstY == last->fFirstY) {
+        if (edge->fLastY == last->fLastY) {
+            return kTotal_Combine;
+        }
+        if (edge->fLastY < last->fLastY) {
+            last->fFirstY = edge->fLastY + 1;
+            return kPartial_Combine;
+        }
+        last->fFirstY = last->fLastY + 1;
+        last->fLastY = edge->fLastY;
+        last->fWinding = edge->fWinding;
+        return kPartial_Combine;
+    }
+    if (edge->fLastY == last->fLastY) {
+        if (edge->fFirstY > last->fFirstY) {
+            last->fLastY = edge->fFirstY - 1;
+            return kPartial_Combine;
+        }
+        last->fLastY = last->fFirstY - 1;
+        last->fFirstY = edge->fFirstY;
+        last->fWinding = edge->fWinding;
+        return kPartial_Combine;
+    }
+    return kNo_Combine;
+}
+
+static bool vertical_line(const SkEdge* edge) {
+#ifdef SK_SUPPORT_LEGACY_VERTICAL_EDGE  // this disables combining vertical overlapping edges
+    return false;
+#endif
+    return !edge->fDX && !edge->fCurveCount;
+}
+
 void SkEdgeBuilder::addLine(const SkPoint pts[]) {
     SkEdge* edge = typedAllocThrow<SkEdge>(fAlloc);
     if (edge->setLine(pts[0], pts[1], fShiftUp)) {
+        if (vertical_line(edge) && fList.count()) {
+            Combine combine = CombineVertical(edge, *(fList.end() - 1));
+            if (kNo_Combine != combine) {
+                if (kTotal_Combine == combine) {
+                    fList.pop();
+                }
+                goto unallocate_edge;
+            }
+        }
         fList.push(edge);
     } else {
+unallocate_edge:
+        ;
         // TODO: unallocate edge from storage...
     }
 }
@@ -79,6 +138,11 @@ static void setShiftedClip(SkRect* dst, const SkIRect& src, int shift) {
              SkIntToScalar(src.fBottom >> shift));
 }
 
+SkEdgeBuilder::Combine SkEdgeBuilder::checkVertical(const SkEdge* edge, SkEdge** edgePtr) {
+    return !vertical_line(edge) || edgePtr <= fEdgeList ? kNo_Combine :
+            CombineVertical(edge, edgePtr[-1]);
+}
+
 int SkEdgeBuilder::buildPoly(const SkPath& path, const SkIRect* iclip, int shiftUp,
                              bool canCullToTheRight) {
     SkPath::Iter    iter(path, true);
@@ -119,7 +183,12 @@ int SkEdgeBuilder::buildPoly(const SkPath& path, const SkIRect* iclip, int shift
                     SkASSERT(lineCount <= SkLineClipper::kMaxClippedLineSegments);
                     for (int i = 0; i < lineCount; i++) {
                         if (edge->setLine(lines[i], lines[i + 1], shiftUp)) {
-                            *edgePtr++ = edge++;
+                            Combine combine = checkVertical(edge, edgePtr);
+                            if (kNo_Combine == combine) {
+                                *edgePtr++ = edge++;
+                            } else if (kTotal_Combine == combine) {
+                                --edgePtr;
+                            }
                         }
                     }
                     break;
@@ -139,7 +208,12 @@ int SkEdgeBuilder::buildPoly(const SkPath& path, const SkIRect* iclip, int shift
                     break;
                 case SkPath::kLine_Verb:
                     if (edge->setLine(pts[0], pts[1], shiftUp)) {
-                        *edgePtr++ = edge++;
+                        Combine combine = checkVertical(edge, edgePtr);
+                        if (kNo_Combine == combine) {
+                            *edgePtr++ = edge++;
+                        } else if (kTotal_Combine == combine) {
+                            --edgePtr;
+                        }
                     }
                     break;
                 default:
index 625465b..047460d 100644 (file)
@@ -27,6 +27,15 @@ public:
     SkEdge** edgeList() { return fEdgeList; }
 
 private:
+    enum Combine {
+        kNo_Combine,
+        kPartial_Combine,
+        kTotal_Combine
+    };
+
+    static Combine CombineVertical(const SkEdge* edge, SkEdge* last);
+    Combine checkVertical(const SkEdge* edge, SkEdge** edgePtr);
+
     SkChunkAlloc        fAlloc;
     SkTDArray<SkEdge*>  fList;