1 /* 2 * Copyright 2014 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 "DMPDFTask.h" 9 #include "DMPDFRasterizeTask.h" 10 #include "DMUtil.h" 11 #include "DMWriteTask.h" 12 #include "SkCommandLineFlags.h" 13 #include "SkDocument.h" 14 15 // The PDF backend is not threadsafe. If you run dm with --pdf repeatedly, you 16 // will quickly find yourself crashed. (while catchsegv out/Release/dm;; end). 17 // 18 // TODO(mtklein): re-enable by default, maybe moving to its own single thread. 19 DEFINE_bool(pdf, false, "PDF backend master switch."); 20 21 namespace DM { 22 23 PDFTask::PDFTask(const char* config, 24 Reporter* reporter, 25 TaskRunner* taskRunner, 26 skiagm::GMRegistry::Factory factory, 27 RasterizePdfProc rasterizePdfProc) 28 : CpuTask(reporter, taskRunner) 29 , fGM(factory(NULL)) 30 , fName(UnderJoin(fGM->getName(), config)) 31 , fRasterize(rasterizePdfProc) {} 32 33 PDFTask::PDFTask(Reporter* reporter, 34 TaskRunner* taskRunner, 35 const SkPicture* picture, 36 SkString filename, 37 RasterizePdfProc rasterizePdfProc) 38 : CpuTask(reporter, taskRunner) 39 , fPicture(SkRef(picture)) 40 , fName(UnderJoin(FileToTaskName(filename).c_str(), "pdf")) 41 , fRasterize(rasterizePdfProc) {} 42 43 namespace { 44 45 class SinglePagePDF { 46 public: 47 SinglePagePDF(SkScalar width, SkScalar height) 48 : fDocument(SkDocument::CreatePDF(&fWriteStream)) 49 , fCanvas(fDocument->beginPage(width, height)) {} 50 51 SkCanvas* canvas() { return fCanvas; } 52 53 SkStreamAsset* end() { 54 fCanvas->flush(); 55 fDocument->endPage(); 56 fDocument->close(); 57 return fWriteStream.detachAsStream(); 58 } 59 60 private: 61 SkDynamicMemoryWStream fWriteStream; 62 SkAutoTUnref<SkDocument> fDocument; 63 SkCanvas* fCanvas; 64 }; 65 66 } // namespace 67 68 void PDFTask::draw() { 69 SkAutoTDelete<SkStreamAsset> pdfData; 70 bool rasterize = true; 71 if (fGM.get()) { 72 rasterize = 0 == (fGM->getFlags() & skiagm::GM::kSkipPDFRasterization_Flag); 73 SinglePagePDF pdf(fGM->width(), fGM->height()); 74 CanvasPreflight(pdf.canvas()); 75 //TODO(mtklein): GM doesn't do this. Why not? 76 //pdf.canvas()->concat(fGM->getInitialTransform()); 77 fGM->draw(pdf.canvas()); 78 pdfData.reset(pdf.end()); 79 } else { 80 SinglePagePDF pdf(fPicture->cullRect().width(), fPicture->cullRect().height()); 81 CanvasPreflight(pdf.canvas()); 82 fPicture->playback(pdf.canvas()); 83 pdfData.reset(pdf.end()); 84 } 85 86 SkASSERT(pdfData.get()); 87 if (rasterize) { 88 this->spawnChild(SkNEW_ARGS(PDFRasterizeTask, 89 (*this, pdfData->duplicate(), fRasterize))); 90 } 91 const char* sourceType = fGM.get() ? "GM" : "SKP"; 92 this->spawnChild(SkNEW_ARGS(WriteTask, 93 (*this, sourceType, pdfData->duplicate(), ".pdf"))); 94 } 95 96 bool PDFTask::shouldSkip() const { 97 if (!FLAGS_pdf) { 98 return true; 99 } 100 if (fGM.get() && 0 != (fGM->getFlags() & skiagm::GM::kSkipPDF_Flag)) { 101 return true; 102 } 103 return false; 104 } 105 106 } // namespace DM 107