18c67909e0443d0419edbb3743fed57df063850f6csmartdalton/*
28c67909e0443d0419edbb3743fed57df063850f6csmartdalton * Copyright 2017 Google Inc.
38c67909e0443d0419edbb3743fed57df063850f6csmartdalton *
48c67909e0443d0419edbb3743fed57df063850f6csmartdalton * Use of this source code is governed by a BSD-style license that can be
58c67909e0443d0419edbb3743fed57df063850f6csmartdalton * found in the LICENSE file.
68c67909e0443d0419edbb3743fed57df063850f6csmartdalton */
78c67909e0443d0419edbb3743fed57df063850f6csmartdalton
88c67909e0443d0419edbb3743fed57df063850f6csmartdalton#include "SampleCode.h"
98c67909e0443d0419edbb3743fed57df063850f6csmartdalton#include "SkCanvas.h"
108c67909e0443d0419edbb3743fed57df063850f6csmartdalton#include "SkCommandLineFlags.h"
118c67909e0443d0419edbb3743fed57df063850f6csmartdalton#include "SkOSPath.h"
128c67909e0443d0419edbb3743fed57df063850f6csmartdalton#include "SkPath.h"
138c67909e0443d0419edbb3743fed57df063850f6csmartdalton#include "SkPicture.h"
148c67909e0443d0419edbb3743fed57df063850f6csmartdalton#include "SkStream.h"
158c67909e0443d0419edbb3743fed57df063850f6csmartdalton#include <stack>
168c67909e0443d0419edbb3743fed57df063850f6csmartdalton
178c67909e0443d0419edbb3743fed57df063850f6csmartdaltonDEFINE_string(pathfinderTrail, "", "List of keystrokes to execute upon loading a pathfinder.");
188c67909e0443d0419edbb3743fed57df063850f6csmartdalton
198c67909e0443d0419edbb3743fed57df063850f6csmartdalton/**
208c67909e0443d0419edbb3743fed57df063850f6csmartdalton * This is a simple utility designed to extract the paths from an SKP file and then isolate a single
218c67909e0443d0419edbb3743fed57df063850f6csmartdalton * one of them. Use the 'x' and 'X' keys to guide a binary search:
228c67909e0443d0419edbb3743fed57df063850f6csmartdalton *
238c67909e0443d0419edbb3743fed57df063850f6csmartdalton *   'x': Throw out half the paths.
248c67909e0443d0419edbb3743fed57df063850f6csmartdalton *   'X': Toggle which half gets tossed and which half is kept.
258c67909e0443d0419edbb3743fed57df063850f6csmartdalton *   'Z': Back up one level.
268c67909e0443d0419edbb3743fed57df063850f6csmartdalton *   'D': Dump the path.
278c67909e0443d0419edbb3743fed57df063850f6csmartdalton */
288c67909e0443d0419edbb3743fed57df063850f6csmartdaltonclass PathFinderView : public SampleView, public SkCanvas {
298c67909e0443d0419edbb3743fed57df063850f6csmartdaltonpublic:
308c67909e0443d0419edbb3743fed57df063850f6csmartdalton    PathFinderView(const char name[] = nullptr)
318c67909e0443d0419edbb3743fed57df063850f6csmartdalton        : SkCanvas(4096, 4096, nullptr)
328c67909e0443d0419edbb3743fed57df063850f6csmartdalton        , fFilename(name) {
338c67909e0443d0419edbb3743fed57df063850f6csmartdalton        SkFILEStream stream(fFilename.c_str());
348c67909e0443d0419edbb3743fed57df063850f6csmartdalton        if (!stream.isValid()) {
358c67909e0443d0419edbb3743fed57df063850f6csmartdalton            SkDebugf("couldn't load picture at \"%s\"\n", fFilename.c_str());
368c67909e0443d0419edbb3743fed57df063850f6csmartdalton            return;
378c67909e0443d0419edbb3743fed57df063850f6csmartdalton        }
388c67909e0443d0419edbb3743fed57df063850f6csmartdalton        sk_sp<SkPicture> pic = SkPicture::MakeFromStream(&stream);
398c67909e0443d0419edbb3743fed57df063850f6csmartdalton        if (!pic) {
408c67909e0443d0419edbb3743fed57df063850f6csmartdalton            SkDebugf("couldn't load picture at \"%s\"\n", fFilename.c_str());
418c67909e0443d0419edbb3743fed57df063850f6csmartdalton            return;
428c67909e0443d0419edbb3743fed57df063850f6csmartdalton        }
438c67909e0443d0419edbb3743fed57df063850f6csmartdalton        pic->playback(this);
448c67909e0443d0419edbb3743fed57df063850f6csmartdalton        for (int i = 0; i < FLAGS_pathfinderTrail.count(); ++i) {
458c67909e0443d0419edbb3743fed57df063850f6csmartdalton            const char* key = FLAGS_pathfinderTrail[i];
468c67909e0443d0419edbb3743fed57df063850f6csmartdalton            while (*key) {
478c67909e0443d0419edbb3743fed57df063850f6csmartdalton                this->handleKeystroke(*key++);
488c67909e0443d0419edbb3743fed57df063850f6csmartdalton            }
498c67909e0443d0419edbb3743fed57df063850f6csmartdalton        }
508c67909e0443d0419edbb3743fed57df063850f6csmartdalton    }
518c67909e0443d0419edbb3743fed57df063850f6csmartdalton
528c67909e0443d0419edbb3743fed57df063850f6csmartdalton    ~PathFinderView() override {}
538c67909e0443d0419edbb3743fed57df063850f6csmartdalton
548c67909e0443d0419edbb3743fed57df063850f6csmartdaltonprivate:
558c67909e0443d0419edbb3743fed57df063850f6csmartdalton    // Called through SkPicture::playback during construction.
568c67909e0443d0419edbb3743fed57df063850f6csmartdalton    void onDrawPath(const SkPath& path, const SkPaint& paint) override {
578c67909e0443d0419edbb3743fed57df063850f6csmartdalton        fPaths.push_back() = {path, paint, this->getTotalMatrix()};
588c67909e0443d0419edbb3743fed57df063850f6csmartdalton    }
598c67909e0443d0419edbb3743fed57df063850f6csmartdalton
608c67909e0443d0419edbb3743fed57df063850f6csmartdalton    // overrides from SkEventSink
618c67909e0443d0419edbb3743fed57df063850f6csmartdalton    bool onQuery(SkEvent* evt) override {
628c67909e0443d0419edbb3743fed57df063850f6csmartdalton        if (SampleCode::TitleQ(*evt)) {
638c67909e0443d0419edbb3743fed57df063850f6csmartdalton            SkString name("PATHFINDER:");
648c67909e0443d0419edbb3743fed57df063850f6csmartdalton            const char* basename = strrchr(fFilename.c_str(), SkOSPath::SEPARATOR);
658c67909e0443d0419edbb3743fed57df063850f6csmartdalton            name.append(basename ? basename+1: fFilename.c_str());
668c67909e0443d0419edbb3743fed57df063850f6csmartdalton            SampleCode::TitleR(evt, name.c_str());
678c67909e0443d0419edbb3743fed57df063850f6csmartdalton            return true;
688c67909e0443d0419edbb3743fed57df063850f6csmartdalton        }
698c67909e0443d0419edbb3743fed57df063850f6csmartdalton        SkUnichar key;
708c67909e0443d0419edbb3743fed57df063850f6csmartdalton        if (SampleCode::CharQ(*evt, &key)) {
718c67909e0443d0419edbb3743fed57df063850f6csmartdalton            if (this->handleKeystroke(key)) {
728c67909e0443d0419edbb3743fed57df063850f6csmartdalton                return true;
738c67909e0443d0419edbb3743fed57df063850f6csmartdalton            }
748c67909e0443d0419edbb3743fed57df063850f6csmartdalton        }
758c67909e0443d0419edbb3743fed57df063850f6csmartdalton        return this->INHERITED::onQuery(evt);
768c67909e0443d0419edbb3743fed57df063850f6csmartdalton    }
778c67909e0443d0419edbb3743fed57df063850f6csmartdalton
788c67909e0443d0419edbb3743fed57df063850f6csmartdalton    bool handleKeystroke(SkUnichar key) {
798c67909e0443d0419edbb3743fed57df063850f6csmartdalton        switch (key) {
808c67909e0443d0419edbb3743fed57df063850f6csmartdalton            case 'X':
818c67909e0443d0419edbb3743fed57df063850f6csmartdalton                if (!fTossedPaths.empty()) {
828c67909e0443d0419edbb3743fed57df063850f6csmartdalton                    SkTSwap(fPaths, fTossedPaths);
838c67909e0443d0419edbb3743fed57df063850f6csmartdalton                    if ('X' == fTrail.back()) {
848c67909e0443d0419edbb3743fed57df063850f6csmartdalton                        fTrail.pop_back();
858c67909e0443d0419edbb3743fed57df063850f6csmartdalton                    } else {
868c67909e0443d0419edbb3743fed57df063850f6csmartdalton                        fTrail.push_back('X');
878c67909e0443d0419edbb3743fed57df063850f6csmartdalton                    }
888c67909e0443d0419edbb3743fed57df063850f6csmartdalton                    this->inval(nullptr);
898c67909e0443d0419edbb3743fed57df063850f6csmartdalton                }
908c67909e0443d0419edbb3743fed57df063850f6csmartdalton                return true;
918c67909e0443d0419edbb3743fed57df063850f6csmartdalton            case 'x':
928c67909e0443d0419edbb3743fed57df063850f6csmartdalton                if (fPaths.count() > 1) {
938c67909e0443d0419edbb3743fed57df063850f6csmartdalton                    int midpt = (fPaths.count() + 1) / 2;
948c67909e0443d0419edbb3743fed57df063850f6csmartdalton                    fPathHistory.emplace(fPaths, fTossedPaths);
958c67909e0443d0419edbb3743fed57df063850f6csmartdalton                    fTossedPaths.reset(fPaths.begin() + midpt, fPaths.count() - midpt);
968c67909e0443d0419edbb3743fed57df063850f6csmartdalton                    fPaths.resize_back(midpt);
978c67909e0443d0419edbb3743fed57df063850f6csmartdalton                    fTrail.push_back('x');
988c67909e0443d0419edbb3743fed57df063850f6csmartdalton                    this->inval(nullptr);
998c67909e0443d0419edbb3743fed57df063850f6csmartdalton                }
1008c67909e0443d0419edbb3743fed57df063850f6csmartdalton                return true;
1018c67909e0443d0419edbb3743fed57df063850f6csmartdalton            case 'Z': {
1028c67909e0443d0419edbb3743fed57df063850f6csmartdalton                if (!fPathHistory.empty()) {
1038c67909e0443d0419edbb3743fed57df063850f6csmartdalton                    fPaths = fPathHistory.top().first;
1048c67909e0443d0419edbb3743fed57df063850f6csmartdalton                    fTossedPaths = fPathHistory.top().second;
1058c67909e0443d0419edbb3743fed57df063850f6csmartdalton                    fPathHistory.pop();
1068c67909e0443d0419edbb3743fed57df063850f6csmartdalton                    char ch;
1078c67909e0443d0419edbb3743fed57df063850f6csmartdalton                    do {
1088c67909e0443d0419edbb3743fed57df063850f6csmartdalton                        ch = fTrail.back();
1098c67909e0443d0419edbb3743fed57df063850f6csmartdalton                        fTrail.pop_back();
1108c67909e0443d0419edbb3743fed57df063850f6csmartdalton                    } while (ch != 'x');
1118c67909e0443d0419edbb3743fed57df063850f6csmartdalton                    this->inval(nullptr);
1128c67909e0443d0419edbb3743fed57df063850f6csmartdalton                }
1138c67909e0443d0419edbb3743fed57df063850f6csmartdalton                return true;
1148c67909e0443d0419edbb3743fed57df063850f6csmartdalton            }
1158c67909e0443d0419edbb3743fed57df063850f6csmartdalton            case 'D':
1168c67909e0443d0419edbb3743fed57df063850f6csmartdalton                SkDebugf("SampleApp --pathfinder %s", fFilename.c_str());
1178c67909e0443d0419edbb3743fed57df063850f6csmartdalton                if (!fTrail.empty()) {
1188c67909e0443d0419edbb3743fed57df063850f6csmartdalton                    SkDebugf(" --pathfinderTrail ", fFilename.c_str());
1198c67909e0443d0419edbb3743fed57df063850f6csmartdalton                    for (char ch : fTrail) {
1208c67909e0443d0419edbb3743fed57df063850f6csmartdalton                        SkDebugf("%c", ch);
1218c67909e0443d0419edbb3743fed57df063850f6csmartdalton                    }
1228c67909e0443d0419edbb3743fed57df063850f6csmartdalton                }
1238c67909e0443d0419edbb3743fed57df063850f6csmartdalton                SkDebugf("\n");
1248c67909e0443d0419edbb3743fed57df063850f6csmartdalton                for (const FoundPath& foundPath : fPaths) {
1258c67909e0443d0419edbb3743fed57df063850f6csmartdalton                    foundPath.fPath.dump();
1268c67909e0443d0419edbb3743fed57df063850f6csmartdalton                }
1278c67909e0443d0419edbb3743fed57df063850f6csmartdalton                return true;
1288c67909e0443d0419edbb3743fed57df063850f6csmartdalton        }
1298c67909e0443d0419edbb3743fed57df063850f6csmartdalton        return false;
1308c67909e0443d0419edbb3743fed57df063850f6csmartdalton    }
1318c67909e0443d0419edbb3743fed57df063850f6csmartdalton
1328c67909e0443d0419edbb3743fed57df063850f6csmartdalton    void onDrawContent(SkCanvas* canvas) override {
1338c67909e0443d0419edbb3743fed57df063850f6csmartdalton        for (const FoundPath& path : fPaths) {
1348c67909e0443d0419edbb3743fed57df063850f6csmartdalton            SkAutoCanvasRestore acr(canvas, true);
1358c67909e0443d0419edbb3743fed57df063850f6csmartdalton            canvas->concat(path.fViewMatrix);
1368c67909e0443d0419edbb3743fed57df063850f6csmartdalton            canvas->drawPath(path.fPath, path.fPaint);
1378c67909e0443d0419edbb3743fed57df063850f6csmartdalton        }
1388c67909e0443d0419edbb3743fed57df063850f6csmartdalton    }
1398c67909e0443d0419edbb3743fed57df063850f6csmartdalton
1408c67909e0443d0419edbb3743fed57df063850f6csmartdalton    struct FoundPath {
1418c67909e0443d0419edbb3743fed57df063850f6csmartdalton        SkPath     fPath;
1428c67909e0443d0419edbb3743fed57df063850f6csmartdalton        SkPaint    fPaint;
1438c67909e0443d0419edbb3743fed57df063850f6csmartdalton        SkMatrix   fViewMatrix;
1448c67909e0443d0419edbb3743fed57df063850f6csmartdalton    };
1458c67909e0443d0419edbb3743fed57df063850f6csmartdalton
1468c67909e0443d0419edbb3743fed57df063850f6csmartdalton    SkString              fFilename;
1478c67909e0443d0419edbb3743fed57df063850f6csmartdalton    SkTArray<FoundPath>   fPaths;
1488c67909e0443d0419edbb3743fed57df063850f6csmartdalton    SkTArray<FoundPath>   fTossedPaths;
1498c67909e0443d0419edbb3743fed57df063850f6csmartdalton    SkTArray<char>        fTrail;
1508c67909e0443d0419edbb3743fed57df063850f6csmartdalton
1518c67909e0443d0419edbb3743fed57df063850f6csmartdalton    std::stack<std::pair<SkTArray<FoundPath>, SkTArray<FoundPath>>> fPathHistory;
1528c67909e0443d0419edbb3743fed57df063850f6csmartdalton
1538c67909e0443d0419edbb3743fed57df063850f6csmartdalton    typedef SampleView INHERITED;
1548c67909e0443d0419edbb3743fed57df063850f6csmartdalton};
1558c67909e0443d0419edbb3743fed57df063850f6csmartdalton
1568c67909e0443d0419edbb3743fed57df063850f6csmartdaltonSampleView* CreateSamplePathFinderView(const char filename[]) {
1578c67909e0443d0419edbb3743fed57df063850f6csmartdalton    return new PathFinderView(filename);
1588c67909e0443d0419edbb3743fed57df063850f6csmartdalton}
159