• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
join(const SkTArray<SkSize> & sizes)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;
MultiPictureDocument__anon4dea72130111::MultiPictureDocument52     MultiPictureDocument(SkWStream* s, void (*d)(SkWStream*, bool))
53         : SkDocument(s, d) {}
~MultiPictureDocument__anon4dea72130111::MultiPictureDocument54     ~MultiPictureDocument() override { this->close(); }
55 
onBeginPage__anon4dea72130111::MultiPictureDocument56     SkCanvas* onBeginPage(SkScalar w, SkScalar h) override {
57         fCurrentPageSize.set(w, h);
58         return fPictureRecorder.beginRecording(w, h);
59     }
onEndPage__anon4dea72130111::MultiPictureDocument60     void onEndPage() override {
61         fSizes.push_back(fCurrentPageSize);
62         fPages.push_back(fPictureRecorder.finishRecordingAsPicture());
63     }
onClose__anon4dea72130111::MultiPictureDocument64     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     }
onAbort__anon4dea72130111::MultiPictureDocument85     void onAbort() override {
86         fPages.reset();
87         fSizes.reset();
88     }
89 };
90 }
91 
SkMakeMultiPictureDocument(SkWStream * wStream)92 sk_sp<SkDocument> SkMakeMultiPictureDocument(SkWStream* wStream) {
93     return sk_make_sp<MultiPictureDocument>(wStream, nullptr);
94 }
95 
96 ////////////////////////////////////////////////////////////////////////////////
97 
SkMultiPictureDocumentReadPageCount(SkStreamSeekable * stream)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 
SkMultiPictureDocumentReadPageSizes(SkStreamSeekable * stream,SkDocumentPage * dstArray,int dstArrayCount)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;
PagerCanvas__anon4dea72130211::PagerCanvas147     PagerCanvas(SkISize wh, SkDocumentPage* dst, int count)
148             : SkNWayCanvas(wh.width(), wh.height()), fDst(dst), fCount(count) {
149         this->nextCanvas();
150     }
nextCanvas__anon4dea72130211::PagerCanvas151     void nextCanvas() {
152         if (fIndex < fCount) {
153             SkRect bounds = SkRect::MakeSize(fDst[fIndex].fSize);
154             this->addCanvas(fRecorder.beginRecording(bounds));
155         }
156     }
onDrawAnnotation__anon4dea72130211::PagerCanvas157     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 
SkMultiPictureDocumentRead(SkStreamSeekable * stream,SkDocumentPage * dstArray,int dstArrayCount)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