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