1 /*
2 * Copyright 2017 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "SampleCode.h"
9 #include "SkCanvas.h"
10 #include "SkCommandLineFlags.h"
11 #include "SkOSPath.h"
12 #include "SkPath.h"
13 #include "SkPicture.h"
14 #include "SkStream.h"
15 #include <stack>
16
17 DEFINE_string(pathfinderTrail, "", "List of keystrokes to execute upon loading a pathfinder.");
18
19 /**
20 * This is a simple utility designed to extract the paths from an SKP file and then isolate a single
21 * one of them. Use the 'x' and 'X' keys to guide a binary search:
22 *
23 * 'x': Throw out half the paths.
24 * 'X': Toggle which half gets tossed and which half is kept.
25 * 'Z': Back up one level.
26 * 'D': Dump the path.
27 */
28 class PathFinderView : public SampleView, public SkCanvas {
29 public:
PathFinderView(const char name[]=nullptr)30 PathFinderView(const char name[] = nullptr)
31 : SkCanvas(4096, 4096, nullptr)
32 , fFilename(name) {
33 SkFILEStream stream(fFilename.c_str());
34 if (!stream.isValid()) {
35 SkDebugf("couldn't load picture at \"%s\"\n", fFilename.c_str());
36 return;
37 }
38 sk_sp<SkPicture> pic = SkPicture::MakeFromStream(&stream);
39 if (!pic) {
40 SkDebugf("couldn't load picture at \"%s\"\n", fFilename.c_str());
41 return;
42 }
43 pic->playback(this);
44 for (int i = 0; i < FLAGS_pathfinderTrail.count(); ++i) {
45 const char* key = FLAGS_pathfinderTrail[i];
46 while (*key) {
47 this->handleKeystroke(*key++);
48 }
49 }
50 }
51
~PathFinderView()52 ~PathFinderView() override {}
53
54 private:
55 // Called through SkPicture::playback during construction.
onDrawPath(const SkPath & path,const SkPaint & paint)56 void onDrawPath(const SkPath& path, const SkPaint& paint) override {
57 fPaths.push_back() = {path, paint, this->getTotalMatrix()};
58 }
59
60 // overrides from SkEventSink
onQuery(SkEvent * evt)61 bool onQuery(SkEvent* evt) override {
62 if (SampleCode::TitleQ(*evt)) {
63 SkString name("PATHFINDER:");
64 const char* basename = strrchr(fFilename.c_str(), SkOSPath::SEPARATOR);
65 name.append(basename ? basename+1: fFilename.c_str());
66 SampleCode::TitleR(evt, name.c_str());
67 return true;
68 }
69 SkUnichar key;
70 if (SampleCode::CharQ(*evt, &key)) {
71 if (this->handleKeystroke(key)) {
72 return true;
73 }
74 }
75 return this->INHERITED::onQuery(evt);
76 }
77
handleKeystroke(SkUnichar key)78 bool handleKeystroke(SkUnichar key) {
79 switch (key) {
80 case 'X':
81 if (!fTossedPaths.empty()) {
82 SkTSwap(fPaths, fTossedPaths);
83 if ('X' == fTrail.back()) {
84 fTrail.pop_back();
85 } else {
86 fTrail.push_back('X');
87 }
88 this->inval(nullptr);
89 }
90 return true;
91 case 'x':
92 if (fPaths.count() > 1) {
93 int midpt = (fPaths.count() + 1) / 2;
94 fPathHistory.emplace(fPaths, fTossedPaths);
95 fTossedPaths.reset(fPaths.begin() + midpt, fPaths.count() - midpt);
96 fPaths.resize_back(midpt);
97 fTrail.push_back('x');
98 this->inval(nullptr);
99 }
100 return true;
101 case 'Z': {
102 if (!fPathHistory.empty()) {
103 fPaths = fPathHistory.top().first;
104 fTossedPaths = fPathHistory.top().second;
105 fPathHistory.pop();
106 char ch;
107 do {
108 ch = fTrail.back();
109 fTrail.pop_back();
110 } while (ch != 'x');
111 this->inval(nullptr);
112 }
113 return true;
114 }
115 case 'D':
116 SkDebugf("SampleApp --pathfinder %s", fFilename.c_str());
117 if (!fTrail.empty()) {
118 SkDebugf(" --pathfinderTrail ", fFilename.c_str());
119 for (char ch : fTrail) {
120 SkDebugf("%c", ch);
121 }
122 }
123 SkDebugf("\n");
124 for (const FoundPath& foundPath : fPaths) {
125 foundPath.fPath.dump();
126 }
127 return true;
128 }
129 return false;
130 }
131
onDrawContent(SkCanvas * canvas)132 void onDrawContent(SkCanvas* canvas) override {
133 for (const FoundPath& path : fPaths) {
134 SkAutoCanvasRestore acr(canvas, true);
135 canvas->concat(path.fViewMatrix);
136 canvas->drawPath(path.fPath, path.fPaint);
137 }
138 }
139
140 struct FoundPath {
141 SkPath fPath;
142 SkPaint fPaint;
143 SkMatrix fViewMatrix;
144 };
145
146 SkString fFilename;
147 SkTArray<FoundPath> fPaths;
148 SkTArray<FoundPath> fTossedPaths;
149 SkTArray<char> fTrail;
150
151 std::stack<std::pair<SkTArray<FoundPath>, SkTArray<FoundPath>>> fPathHistory;
152
153 typedef SampleView INHERITED;
154 };
155
CreateSamplePathFinderView(const char filename[])156 SampleView* CreateSamplePathFinderView(const char filename[]) {
157 return new PathFinderView(filename);
158 }
159