blob: 38ab3c3ffd67202d5b0cede38ecc0c22ddbc0c96 [file] [log] [blame]
Chris Dalton2d18f412018-02-20 13:23:32 -07001/*
2 * Copyright 2018 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 "BisectSlide.h"
9
Chris Dalton2d18f412018-02-20 13:23:32 -070010#include "SkOSPath.h"
11#include "SkPicture.h"
12#include "SkStream.h"
Hal Canary0f666812018-03-22 15:21:12 -040013
14#ifdef SK_XML
15#include "SkDOM.h"
Chris Dalton2d18f412018-02-20 13:23:32 -070016#include "../experimental/svg/model/SkSVGDOM.h"
Hal Canary0f666812018-03-22 15:21:12 -040017#endif
Chris Dalton2d18f412018-02-20 13:23:32 -070018
19sk_sp<BisectSlide> BisectSlide::Create(const char filepath[]) {
20 SkFILEStream stream(filepath);
21 if (!stream.isValid()) {
22 SkDebugf("BISECT: invalid input file at \"%s\"\n", filepath);
23 return nullptr;
24 }
25
26 sk_sp<BisectSlide> bisect(new BisectSlide(filepath));
27 if (bisect->fFilePath.endsWith(".svg")) {
Hal Canary0f666812018-03-22 15:21:12 -040028#ifdef SK_XML
Chris Dalton2d18f412018-02-20 13:23:32 -070029 SkDOM xml;
30 if (!xml.build(stream)) {
31 SkDebugf("BISECT: XML parsing failed: \"%s\"\n", filepath);
32 return nullptr;
33 }
34 sk_sp<SkSVGDOM> svg = SkSVGDOM::MakeFromDOM(xml);
35 if (!svg) {
36 SkDebugf("BISECT: couldn't load svg at \"%s\"\n", filepath);
37 return nullptr;
38 }
39 svg->setContainerSize(SkSize::Make(bisect->getDimensions()));
40 svg->render(bisect.get());
Hal Canary0f666812018-03-22 15:21:12 -040041#else
42 return nullptr;
43#endif
Chris Dalton2d18f412018-02-20 13:23:32 -070044 } else {
45 sk_sp<SkPicture> skp = SkPicture::MakeFromStream(&stream);
46 if (!skp) {
47 SkDebugf("BISECT: couldn't load skp at \"%s\"\n", filepath);
48 return nullptr;
49 }
50 skp->playback(bisect.get());
51 }
52
53 return bisect;
54}
55
56BisectSlide::BisectSlide(const char filepath[])
57 : SkCanvas(4096, 4096, nullptr)
58 , fFilePath(filepath) {
59 const char* basename = strrchr(fFilePath.c_str(), SkOSPath::SEPARATOR);
60 fName.printf("BISECT_%s", basename ? basename + 1 : fFilePath.c_str());
61}
62
63// Called through SkPicture::playback only during creation.
64void BisectSlide::onDrawPath(const SkPath& path, const SkPaint& paint) {
65 SkRect bounds;
66 SkIRect ibounds;
67 this->getTotalMatrix().mapRect(&bounds, path.getBounds());
68 bounds.roundOut(&ibounds);
69 fDrawBounds.join(ibounds);
70 fFoundPaths.push_back() = {path, paint, this->getTotalMatrix()};
71}
72
73bool BisectSlide::onChar(SkUnichar c) {
74 switch (c) {
75 case 'X':
76 if (!fTossedPaths.empty()) {
77 SkTSwap(fFoundPaths, fTossedPaths);
78 if ('X' == fTrail.back()) {
79 fTrail.pop_back();
80 } else {
81 fTrail.push_back('X');
82 }
83 }
84 return true;
85
86 case 'x':
87 if (fFoundPaths.count() > 1) {
88 int midpt = (fFoundPaths.count() + 1) / 2;
89 fPathHistory.emplace(fFoundPaths, fTossedPaths);
90 fTossedPaths.reset(fFoundPaths.begin() + midpt, fFoundPaths.count() - midpt);
91 fFoundPaths.resize_back(midpt);
92 fTrail.push_back('x');
93 }
94 return true;
95
96 case 'Z': {
97 if (!fPathHistory.empty()) {
98 fFoundPaths = fPathHistory.top().first;
99 fTossedPaths = fPathHistory.top().second;
100 fPathHistory.pop();
101 char ch;
102 do {
103 ch = fTrail.back();
104 fTrail.pop_back();
105 } while (ch != 'x');
106 }
107 return true;
108 }
109
110 case 'D':
111 SkDebugf("viewer --bisect %s", fFilePath.c_str());
112 if (!fTrail.empty()) {
113 SkDebugf(" ");
114 for (char ch : fTrail) {
115 SkDebugf("%c", ch);
116 }
117 }
118 SkDebugf("\n");
119 for (const FoundPath& foundPath : fFoundPaths) {
120 foundPath.fPath.dump();
121 }
122 return true;
123 }
124
125 return false;
126}
127
128void BisectSlide::draw(SkCanvas* canvas) {
129 SkAutoCanvasRestore acr(canvas, true);
130 canvas->translate(-fDrawBounds.left(), -fDrawBounds.top());
131
132 for (const FoundPath& path : fFoundPaths) {
133 SkAutoCanvasRestore acr(canvas, true);
134 canvas->concat(path.fViewMatrix);
135 canvas->drawPath(path.fPath, path.fPaint);
136 }
137}