expose new tight-bounds method on SkPath
authorMike Reed <reed@google.com>
Fri, 3 Feb 2017 16:34:13 +0000 (11:34 -0500)
committerSkia Commit-Bot <skia-commit-bot@chromium.org>
Fri, 3 Feb 2017 17:26:43 +0000 (17:26 +0000)
BUG=skia:

Change-Id: Ie50df49c1758af203042a84dc2cd505046373d2c
Reviewed-on: https://skia-review.googlesource.com/7996
Reviewed-by: Florin Malita <fmalita@chromium.org>
Commit-Queue: Mike Reed <reed@google.com>

bench/PathBench.cpp
include/core/SkPath.h
src/core/SkPath.cpp
src/core/SkPathPriv.h
tests/PathTest.cpp

index de8be6c..10cffc2 100644 (file)
@@ -1079,10 +1079,10 @@ private:
 class TightBoundsBench : public Benchmark {
     SkPath      fPath;
     SkString    fName;
-    bool        (*fProc)(const SkPath&, SkRect*);
+    SkRect      (*fProc)(const SkPath&);
 
 public:
-    TightBoundsBench(bool (*proc)(const SkPath&, SkRect*), const char suffix[]) : fProc(proc) {
+    TightBoundsBench(SkRect (*proc)(const SkPath&), const char suffix[]) : fProc(proc) {
         fName.printf("tight_bounds_%s", suffix);
         
         const int N = 100;
@@ -1106,9 +1106,8 @@ protected:
     const char* onGetName() override { return fName.c_str(); }
     
     void onDraw(int loops, SkCanvas* canvas) override {
-        SkRect bounds;
         for (int i = 0; i < loops*100; ++i) {
-            fProc(fPath, &bounds);
+            fProc(fPath);
         }
     }
     
@@ -1186,8 +1185,11 @@ DEF_BENCH( return new ConservativelyContainsBench(ConservativelyContainsBench::k
 
 #include "SkPathOps.h"
 #include "SkPathPriv.h"
-DEF_BENCH( return new TightBoundsBench(SkPathPriv::ComputeTightBounds, "priv"); )
-DEF_BENCH( return new TightBoundsBench(TightBounds, "pathops"); )
+DEF_BENCH( return new TightBoundsBench([](const SkPath& path){ return path.computeTightBounds();},
+                                       "priv"); )
+DEF_BENCH( return new TightBoundsBench([](const SkPath& path) {
+        SkRect bounds; TightBounds(path, &bounds); return bounds;
+    }, "pathops"); )
 
 // These seem to be optimized away, which is troublesome for timing.
 /*
index 486a993..8bdfbc4 100644 (file)
@@ -358,6 +358,19 @@ public:
     }
 
     /**
+     *  Computes a bounds that is conservatively "snug" around the path. This assumes that the
+     *  path will be filled. It does not attempt to collapse away contours that are logically
+     *  empty (e.g. moveTo(x, y) + lineTo(x, y)) but will include them in the calculation.
+     *
+     *  It differs from getBounds() in that it will look at the snug bounds of curves, whereas
+     *  getBounds() just returns the bounds of the control-points. Thus computing this may be
+     *  slower than just calling getBounds().
+     *
+     *  If the path is empty (i.e. no points or verbs), it will return SkRect::MakeEmpty().
+     */
+    SkRect computeTightBounds() const;
+
+    /**
      * Does a conservative test to see whether a rectangle is inside a path. Currently it only
      * will ever return true for single convex contour paths. The empty-status of the rect is not
      * considered (e.g. a rect that is a point can be inside a path). Points or line segments where
index 4c18e63..84dfca1 100644 (file)
@@ -3435,23 +3435,22 @@ static int compute_cubic_extremas(const SkPoint src[3], SkPoint extremas[5]) {
     return n + 1;
 }
 
-bool SkPathPriv::ComputeTightBounds(const SkPath& path, SkRect* bounds) {
-    if (0 == path.countVerbs()) {
-        return false;
+SkRect SkPath::computeTightBounds() const {
+    if (0 == this->countVerbs()) {
+        return SkRect::MakeEmpty();
     }
 
-    if (path.getSegmentMasks() == SkPath::kLine_SegmentMask) {
-        *bounds = path.getBounds();
-        return true;
+    if (this->getSegmentMasks() == SkPath::kLine_SegmentMask) {
+        return this->getBounds();
     }
     
     SkPoint extremas[5]; // big enough to hold worst-case curve type (cubic) extremas + 1
     SkPoint pts[4];
-    SkPath::RawIter iter(path);
+    SkPath::RawIter iter(*this);
 
     // initial with the first MoveTo, so we don't have to check inside the switch
     Sk2s min, max;
-    min = max = from_point(path.getPoint(0));
+    min = max = from_point(this->getPoint(0));
     for (;;) {
         int count = 0;
         switch (iter.next(pts)) {
@@ -3484,7 +3483,8 @@ bool SkPathPriv::ComputeTightBounds(const SkPath& path, SkRect* bounds) {
         }
     }
 DONE:
-    min.store((SkPoint*)&bounds->fLeft);
-    max.store((SkPoint*)&bounds->fRight);
-    return true;
+    SkRect bounds;
+    min.store((SkPoint*)&bounds.fLeft);
+    max.store((SkPoint*)&bounds.fRight);
+    return bounds;
 }
index cbbb83e..029cb75 100644 (file)
@@ -121,8 +121,6 @@ public:
     static const SkScalar* ConicWeightData(const SkPath& path) {
         return path.fPathRef->conicWeights();
     }
-
-    static bool ComputeTightBounds(const SkPath&, SkRect*);
 };
 
 #endif
index 38bac25..694dab5 100644 (file)
@@ -4741,8 +4741,7 @@ DEF_TEST(path_tight_bounds, reporter) {
                 SkPath path;
                 rand_path(&path, rand, verb, n);
                 SkRect bounds = path.getBounds();
-                SkRect tight;
-                SkPathPriv::ComputeTightBounds(path, &tight);
+                SkRect tight = path.computeTightBounds();
                 REPORTER_ASSERT(reporter, bounds.contains(tight));
                 
                 SkRect tight2;