Add a simple tool for isolating a path from an SKP
authorcsmartdalton <csmartdalton@google.com>
Mon, 27 Mar 2017 18:32:29 +0000 (12:32 -0600)
committerSkia Commit-Bot <skia-commit-bot@chromium.org>
Mon, 27 Mar 2017 19:19:19 +0000 (19:19 +0000)
BUG=skia:

Change-Id: I5ca9bbd43919e3f65ea940847c68f85cc78dfeda
Reviewed-on: https://skia-review.googlesource.com/10130
Commit-Queue: Chris Dalton <csmartdalton@google.com>
Reviewed-by: Jim Van Verth <jvanverth@google.com>
BUILD.gn
gn/samples.gni
samplecode/SampleApp.cpp
samplecode/SamplePathFinder.cpp [new file with mode: 0644]

index b38f003..41694d3 100644 (file)
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1113,6 +1113,7 @@ if (skia_enable_tools) {
               ]
     deps = [
       ":experimental_svg_model",
+      ":flags",
       ":gm",
       ":tool_utils",
       ":views",
index 7f8f3b9..13a762c 100644 (file)
@@ -70,6 +70,7 @@ samples_sources = [
   "$_samplecode/SamplePathText.cpp",
   "$_samplecode/SamplePathClip.cpp",
   "$_samplecode/SamplePathEffects.cpp",
+  "$_samplecode/SamplePathFinder.cpp",
   "$_samplecode/SamplePathFuzz.cpp",
   "$_samplecode/SamplePathOverstroke.cpp",
   "$_samplecode/SamplePdfFileViewer.cpp",
index 6b9a888..bd7d567 100644 (file)
@@ -91,6 +91,17 @@ public:
     }
 };
 
+extern SampleView* CreateSamplePathFinderView(const char filename[]);
+
+class PathFinderFactory : public SkViewFactory {
+    SkString fFilename;
+public:
+    PathFinderFactory(const SkString& filename) : fFilename(filename) {}
+    SkView* operator() () const override {
+        return CreateSamplePathFinderView(fFilename.c_str());
+    }
+};
+
 extern SampleView* CreateSampleSVGFileView(const SkString& filename);
 
 class SVGFileFactory : public SkViewFactory {
@@ -726,6 +737,7 @@ static void restrict_samples(SkTDArray<const SkViewFactory*>& factories, const S
 DEFINE_string(slide, "", "Start on this sample.");
 DEFINE_string(pictureDir, "", "Read pictures from here.");
 DEFINE_string(picture, "", "Path to single picture.");
+DEFINE_string(pathfinder, "", "SKP file with a single path to isolate.");
 DEFINE_string(svg, "", "Path to single SVG file.");
 DEFINE_string(svgDir, "", "Read SVGs from here.");
 DEFINE_string(sequence, "", "Path to file containing the desired samples/gms to show.");
@@ -765,6 +777,11 @@ SampleWindow::SampleWindow(void* hwnd, int argc, char** argv, DeviceManager* dev
         fCurrIndex = fSamples.count();
         *fSamples.append() = new PictFileFactory(path);
     }
+    if (!FLAGS_pathfinder.isEmpty()) {
+        SkString path(FLAGS_pathfinder[0]);
+        fCurrIndex = fSamples.count();
+        *fSamples.append() = new PathFinderFactory(path);
+    }
     if (!FLAGS_svg.isEmpty()) {
         SkString path(FLAGS_svg[0]);
         fCurrIndex = fSamples.count();
diff --git a/samplecode/SamplePathFinder.cpp b/samplecode/SamplePathFinder.cpp
new file mode 100644 (file)
index 0000000..2cbfdc3
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SampleCode.h"
+#include "SkCanvas.h"
+#include "SkCommandLineFlags.h"
+#include "SkOSPath.h"
+#include "SkPath.h"
+#include "SkPicture.h"
+#include "SkStream.h"
+#include <stack>
+
+DEFINE_string(pathfinderTrail, "", "List of keystrokes to execute upon loading a pathfinder.");
+
+/**
+ * This is a simple utility designed to extract the paths from an SKP file and then isolate a single
+ * one of them. Use the 'x' and 'X' keys to guide a binary search:
+ *
+ *   'x': Throw out half the paths.
+ *   'X': Toggle which half gets tossed and which half is kept.
+ *   'Z': Back up one level.
+ *   'D': Dump the path.
+ */
+class PathFinderView : public SampleView, public SkCanvas {
+public:
+    PathFinderView(const char name[] = nullptr)
+        : SkCanvas(4096, 4096, nullptr)
+        , fFilename(name) {
+        SkFILEStream stream(fFilename.c_str());
+        if (!stream.isValid()) {
+            SkDebugf("couldn't load picture at \"%s\"\n", fFilename.c_str());
+            return;
+        }
+        sk_sp<SkPicture> pic = SkPicture::MakeFromStream(&stream);
+        if (!pic) {
+            SkDebugf("couldn't load picture at \"%s\"\n", fFilename.c_str());
+            return;
+        }
+        pic->playback(this);
+        for (int i = 0; i < FLAGS_pathfinderTrail.count(); ++i) {
+            const char* key = FLAGS_pathfinderTrail[i];
+            while (*key) {
+                this->handleKeystroke(*key++);
+            }
+        }
+    }
+
+    ~PathFinderView() override {}
+
+private:
+    // Called through SkPicture::playback during construction.
+    void onDrawPath(const SkPath& path, const SkPaint& paint) override {
+        fPaths.push_back() = {path, paint, this->getTotalMatrix()};
+    }
+
+    // overrides from SkEventSink
+    bool onQuery(SkEvent* evt) override {
+        if (SampleCode::TitleQ(*evt)) {
+            SkString name("PATHFINDER:");
+            const char* basename = strrchr(fFilename.c_str(), SkOSPath::SEPARATOR);
+            name.append(basename ? basename+1: fFilename.c_str());
+            SampleCode::TitleR(evt, name.c_str());
+            return true;
+        }
+        SkUnichar key;
+        if (SampleCode::CharQ(*evt, &key)) {
+            if (this->handleKeystroke(key)) {
+                return true;
+            }
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+
+    bool handleKeystroke(SkUnichar key) {
+        switch (key) {
+            case 'X':
+                if (!fTossedPaths.empty()) {
+                    SkTSwap(fPaths, fTossedPaths);
+                    if ('X' == fTrail.back()) {
+                        fTrail.pop_back();
+                    } else {
+                        fTrail.push_back('X');
+                    }
+                    this->inval(nullptr);
+                }
+                return true;
+            case 'x':
+                if (fPaths.count() > 1) {
+                    int midpt = (fPaths.count() + 1) / 2;
+                    fPathHistory.emplace(fPaths, fTossedPaths);
+                    fTossedPaths.reset(fPaths.begin() + midpt, fPaths.count() - midpt);
+                    fPaths.resize_back(midpt);
+                    fTrail.push_back('x');
+                    this->inval(nullptr);
+                }
+                return true;
+            case 'Z': {
+                if (!fPathHistory.empty()) {
+                    fPaths = fPathHistory.top().first;
+                    fTossedPaths = fPathHistory.top().second;
+                    fPathHistory.pop();
+                    char ch;
+                    do {
+                        ch = fTrail.back();
+                        fTrail.pop_back();
+                    } while (ch != 'x');
+                    this->inval(nullptr);
+                }
+                return true;
+            }
+            case 'D':
+                SkDebugf("SampleApp --pathfinder %s", fFilename.c_str());
+                if (!fTrail.empty()) {
+                    SkDebugf(" --pathfinderTrail ", fFilename.c_str());
+                    for (char ch : fTrail) {
+                        SkDebugf("%c", ch);
+                    }
+                }
+                SkDebugf("\n");
+                for (const FoundPath& foundPath : fPaths) {
+                    foundPath.fPath.dump();
+                }
+                return true;
+        }
+        return false;
+    }
+
+    void onDrawContent(SkCanvas* canvas) override {
+        for (const FoundPath& path : fPaths) {
+            SkAutoCanvasRestore acr(canvas, true);
+            canvas->concat(path.fViewMatrix);
+            canvas->drawPath(path.fPath, path.fPaint);
+        }
+    }
+
+    struct FoundPath {
+        SkPath     fPath;
+        SkPaint    fPaint;
+        SkMatrix   fViewMatrix;
+    };
+
+    SkString              fFilename;
+    SkTArray<FoundPath>   fPaths;
+    SkTArray<FoundPath>   fTossedPaths;
+    SkTArray<char>        fTrail;
+
+    std::stack<std::pair<SkTArray<FoundPath>, SkTArray<FoundPath>>> fPathHistory;
+
+    typedef SampleView INHERITED;
+};
+
+SampleView* CreateSamplePathFinderView(const char filename[]) {
+    return new PathFinderView(filename);
+}