Home | History | Annotate | Download | only in samplecode
      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:
     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 
     54 private:
     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 
    156 SampleView* CreateSamplePathFinderView(const char filename[]) {
    157     return new PathFinderView(filename);
    158 }
    159