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