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 17DEFINE_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 */ 28class PathFinderView : public SampleView, public SkCanvas { 29public: 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 52 ~PathFinderView() override {} 53 54private: 55 // Called through SkPicture::playback during construction. 56 void onDrawPath(const SkPath& path, const SkPaint& paint) override { 57 fPaths.push_back() = {path, paint, this->getTotalMatrix()}; 58 } 59 60 // overrides from SkEventSink 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 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 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 156SampleView* CreateSamplePathFinderView(const char filename[]) { 157 return new PathFinderView(filename); 158} 159