Home | History | Annotate | Download | only in utils
      1 /*
      2  * Copyright 2016 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 "SkMultiPictureDocument.h"
      9 #include "SkMultiPictureDocumentPriv.h"
     10 #include "SkNWayCanvas.h"
     11 #include "SkPicture.h"
     12 #include "SkPictureRecorder.h"
     13 #include "SkStream.h"
     14 #include "SkTArray.h"
     15 
     16 #include <limits.h>
     17 
     18 /*
     19   File format:
     20       BEGINNING_OF_FILE:
     21         kMagic
     22         uint32_t version_number (==2)
     23         uint32_t page_count
     24         {
     25           float sizeX
     26           float sizeY
     27         } * page_count
     28         skp file
     29 */
     30 
     31 namespace {
     32 // The unique file signature for this file type.
     33 static constexpr char kMagic[] = "Skia Multi-Picture Doc\n\n";
     34 
     35 static constexpr char kEndPage[] = "SkMultiPictureEndPage";
     36 
     37 const uint32_t kVersion = 2;
     38 
     39 static SkSize join(const SkTArray<SkSize>& sizes) {
     40     SkSize joined = {0, 0};
     41     for (SkSize s : sizes) {
     42         joined = SkSize{SkTMax(joined.width(), s.width()), SkTMax(joined.height(), s.height())};
     43     }
     44     return joined;
     45 }
     46 
     47 struct MultiPictureDocument final : public SkDocument {
     48     SkPictureRecorder fPictureRecorder;
     49     SkSize fCurrentPageSize;
     50     SkTArray<sk_sp<SkPicture>> fPages;
     51     SkTArray<SkSize> fSizes;
     52     MultiPictureDocument(SkWStream* s, void (*d)(SkWStream*, bool))
     53         : SkDocument(s, d) {}
     54     ~MultiPictureDocument() override { this->close(); }
     55 
     56     SkCanvas* onBeginPage(SkScalar w, SkScalar h) override {
     57         fCurrentPageSize.set(w, h);
     58         return fPictureRecorder.beginRecording(w, h);
     59     }
     60     void onEndPage() override {
     61         fSizes.push_back(fCurrentPageSize);
     62         fPages.push_back(fPictureRecorder.finishRecordingAsPicture());
     63     }
     64     void onClose(SkWStream* wStream) override {
     65         SkASSERT(wStream);
     66         SkASSERT(wStream->bytesWritten() == 0);
     67         wStream->writeText(kMagic);
     68         wStream->write32(kVersion);
     69         wStream->write32(SkToU32(fPages.count()));
     70         for (SkSize s : fSizes) {
     71             wStream->write(&s, sizeof(s));
     72         }
     73         SkSize bigsize = join(fSizes);
     74         SkCanvas* c = fPictureRecorder.beginRecording(SkRect::MakeSize(bigsize));
     75         for (const sk_sp<SkPicture>& page : fPages) {
     76             c->drawPicture(page);
     77             c->drawAnnotation(SkRect::MakeEmpty(), kEndPage, nullptr);
     78         }
     79         sk_sp<SkPicture> p = fPictureRecorder.finishRecordingAsPicture();
     80         p->serialize(wStream);
     81         fPages.reset();
     82         fSizes.reset();
     83         return;
     84     }
     85     void onAbort() override {
     86         fPages.reset();
     87         fSizes.reset();
     88     }
     89 };
     90 }
     91 
     92 sk_sp<SkDocument> SkMakeMultiPictureDocument(SkWStream* wStream) {
     93     return sk_make_sp<MultiPictureDocument>(wStream, nullptr);
     94 }
     95 
     96 ////////////////////////////////////////////////////////////////////////////////
     97 
     98 int SkMultiPictureDocumentReadPageCount(SkStreamSeekable* stream) {
     99     if (!stream) {
    100         return 0;
    101     }
    102     stream->seek(0);
    103     const size_t size = sizeof(kMagic) - 1;
    104     char buffer[size];
    105     if (size != stream->read(buffer, size) || 0 != memcmp(kMagic, buffer, size)) {
    106         stream = nullptr;
    107         return 0;
    108     }
    109     uint32_t versionNumber = stream->readU32();
    110     if (versionNumber != kVersion) {
    111         return 0;
    112     }
    113     uint32_t pageCount = stream->readU32();
    114     if (pageCount > INT_MAX) {
    115         return 0;
    116     }
    117     // leave stream position right here.
    118     return (int)pageCount;
    119 }
    120 
    121 bool SkMultiPictureDocumentReadPageSizes(SkStreamSeekable* stream,
    122                                          SkDocumentPage* dstArray,
    123                                          int dstArrayCount) {
    124     if (!dstArray || dstArrayCount < 1) {
    125         return false;
    126     }
    127     int pageCount = SkMultiPictureDocumentReadPageCount(stream);
    128     if (pageCount < 1 || pageCount != dstArrayCount) {
    129         return false;
    130     }
    131     for (int i = 0; i < pageCount; ++i) {
    132         SkSize& s = dstArray[i].fSize;
    133         if (sizeof(s) != stream->read(&s, sizeof(s))) {
    134             return false;
    135         }
    136     }
    137     // leave stream position right here.
    138     return true;
    139 }
    140 
    141 namespace {
    142 struct PagerCanvas : public SkNWayCanvas {
    143     SkPictureRecorder fRecorder;
    144     SkDocumentPage* fDst;
    145     int fCount;
    146     int fIndex = 0;
    147     PagerCanvas(SkISize wh, SkDocumentPage* dst, int count)
    148             : SkNWayCanvas(wh.width(), wh.height()), fDst(dst), fCount(count) {
    149         this->nextCanvas();
    150     }
    151     void nextCanvas() {
    152         if (fIndex < fCount) {
    153             SkRect bounds = SkRect::MakeSize(fDst[fIndex].fSize);
    154             this->addCanvas(fRecorder.beginRecording(bounds));
    155         }
    156     }
    157     void onDrawAnnotation(const SkRect& r, const char* key, SkData* d) override {
    158         if (0 == strcmp(key, kEndPage)) {
    159             this->removeAll();
    160             if (fIndex < fCount) {
    161                 fDst[fIndex].fPicture = fRecorder.finishRecordingAsPicture();
    162                 ++fIndex;
    163             }
    164             this->nextCanvas();
    165         } else {
    166             this->SkNWayCanvas::onDrawAnnotation(r, key, d);
    167         }
    168     }
    169 };
    170 }  // namespace
    171 
    172 bool SkMultiPictureDocumentRead(SkStreamSeekable* stream,
    173                                 SkDocumentPage* dstArray,
    174                                 int dstArrayCount) {
    175     if (!SkMultiPictureDocumentReadPageSizes(stream, dstArray, dstArrayCount)) {
    176         return false;
    177     }
    178     SkSize joined = {0.0f, 0.0f};
    179     for (int i = 0; i < dstArrayCount; ++i) {
    180         joined = SkSize{SkTMax(joined.width(), dstArray[i].fSize.width()),
    181                         SkTMax(joined.height(), dstArray[i].fSize.height())};
    182     }
    183 
    184     auto picture = SkPicture::MakeFromStream(stream);
    185 
    186     PagerCanvas canvas(joined.toCeil(), dstArray, dstArrayCount);
    187     // Must call playback(), not drawPicture() to reach
    188     // PagerCanvas::onDrawAnnotation().
    189     picture->playback(&canvas);
    190     if (canvas.fIndex != dstArrayCount) {
    191         SkDEBUGF(("Malformed SkMultiPictureDocument\n"));
    192     }
    193     return true;
    194 }
    195