blob: 4ff2d079e3dd4f0c6632b25c6e17a0b1e46410d7 [file] [log] [blame]
halcanary45420a92016-06-02 12:41:14 -07001/*
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"
Hal Canary45cde312017-04-03 16:06:42 -040010#include "SkNWayCanvas.h"
halcanary45420a92016-06-02 12:41:14 -070011#include "SkPicture.h"
12#include "SkPictureRecorder.h"
13#include "SkStream.h"
halcanaryc966ef92016-08-23 09:15:04 -070014#include "SkTArray.h"
halcanary45420a92016-06-02 12:41:14 -070015
Hal Canary45cde312017-04-03 16:06:42 -040016#include <limits.h>
17
halcanary45420a92016-06-02 12:41:14 -070018/*
19 File format:
20 BEGINNING_OF_FILE:
21 kMagic
halcanaryc966ef92016-08-23 09:15:04 -070022 uint32_t version_number (==2)
halcanary45420a92016-06-02 12:41:14 -070023 uint32_t page_count
24 {
halcanary45420a92016-06-02 12:41:14 -070025 float sizeX
26 float sizeY
27 } * page_count
halcanary45420a92016-06-02 12:41:14 -070028 skp file
halcanary45420a92016-06-02 12:41:14 -070029*/
30
31namespace {
Hal Canary45cde312017-04-03 16:06:42 -040032// The unique file signature for this file type.
33static constexpr char kMagic[] = "Skia Multi-Picture Doc\n\n";
34
35static constexpr char kEndPage[] = "SkMultiPictureEndPage";
36
37const uint32_t kVersion = 2;
38
39static SkSize join(const SkTArray<SkSize>& sizes) {
Hal Canaryfafe1352017-04-11 12:12:02 -040040 SkSize joined = {0, 0};
Hal Canary45cde312017-04-03 16:06:42 -040041 for (SkSize s : sizes) {
Hal Canaryfafe1352017-04-11 12:12:02 -040042 joined = SkSize{SkTMax(joined.width(), s.width()), SkTMax(joined.height(), s.height())};
Hal Canary45cde312017-04-03 16:06:42 -040043 }
44 return joined;
45}
46
halcanary45420a92016-06-02 12:41:14 -070047struct MultiPictureDocument final : public SkDocument {
48 SkPictureRecorder fPictureRecorder;
halcanary59d64022016-06-14 11:06:37 -070049 SkSize fCurrentPageSize;
halcanaryc966ef92016-08-23 09:15:04 -070050 SkTArray<sk_sp<SkPicture>> fPages;
51 SkTArray<SkSize> fSizes;
halcanary45420a92016-06-02 12:41:14 -070052 MultiPictureDocument(SkWStream* s, void (*d)(SkWStream*, bool))
53 : SkDocument(s, d) {}
Brian Salomond3b65972017-03-22 12:05:03 -040054 ~MultiPictureDocument() override { this->close(); }
halcanary45420a92016-06-02 12:41:14 -070055
Hal Canaryb1de5f92017-07-01 22:17:15 -040056 SkCanvas* onBeginPage(SkScalar w, SkScalar h) override {
halcanary59d64022016-06-14 11:06:37 -070057 fCurrentPageSize.set(w, h);
Hal Canaryb1de5f92017-07-01 22:17:15 -040058 return fPictureRecorder.beginRecording(w, h);
halcanary45420a92016-06-02 12:41:14 -070059 }
60 void onEndPage() override {
halcanaryc966ef92016-08-23 09:15:04 -070061 fSizes.push_back(fCurrentPageSize);
62 fPages.push_back(fPictureRecorder.finishRecordingAsPicture());
halcanary45420a92016-06-02 12:41:14 -070063 }
reedd14df7c2016-09-22 14:12:46 -070064 void onClose(SkWStream* wStream) override {
halcanary45420a92016-06-02 12:41:14 -070065 SkASSERT(wStream);
66 SkASSERT(wStream->bytesWritten() == 0);
Hal Canary45cde312017-04-03 16:06:42 -040067 wStream->writeText(kMagic);
68 wStream->write32(kVersion);
reedd14df7c2016-09-22 14:12:46 -070069 wStream->write32(SkToU32(fPages.count()));
halcanaryc966ef92016-08-23 09:15:04 -070070 for (SkSize s : fSizes) {
reedd14df7c2016-09-22 14:12:46 -070071 wStream->write(&s, sizeof(s));
halcanary45420a92016-06-02 12:41:14 -070072 }
Hal Canary45cde312017-04-03 16:06:42 -040073 SkSize bigsize = join(fSizes);
halcanaryc966ef92016-08-23 09:15:04 -070074 SkCanvas* c = fPictureRecorder.beginRecording(SkRect::MakeSize(bigsize));
75 for (const sk_sp<SkPicture>& page : fPages) {
76 c->drawPicture(page);
Hal Canary45cde312017-04-03 16:06:42 -040077 c->drawAnnotation(SkRect::MakeEmpty(), kEndPage, nullptr);
halcanary45420a92016-06-02 12:41:14 -070078 }
halcanaryc966ef92016-08-23 09:15:04 -070079 sk_sp<SkPicture> p = fPictureRecorder.finishRecordingAsPicture();
80 p->serialize(wStream);
81 fPages.reset();
82 fSizes.reset();
reedd14df7c2016-09-22 14:12:46 -070083 return;
halcanary45420a92016-06-02 12:41:14 -070084 }
halcanaryc966ef92016-08-23 09:15:04 -070085 void onAbort() override {
86 fPages.reset();
87 fSizes.reset();
88 }
halcanary45420a92016-06-02 12:41:14 -070089};
90}
91
92sk_sp<SkDocument> SkMakeMultiPictureDocument(SkWStream* wStream) {
93 return sk_make_sp<MultiPictureDocument>(wStream, nullptr);
94}
Hal Canary45cde312017-04-03 16:06:42 -040095
96////////////////////////////////////////////////////////////////////////////////
97
98int 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
121bool 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
141namespace {
142struct 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
172bool SkMultiPictureDocumentRead(SkStreamSeekable* stream,
173 SkDocumentPage* dstArray,
174 int dstArrayCount) {
175 if (!SkMultiPictureDocumentReadPageSizes(stream, dstArray, dstArrayCount)) {
176 return false;
177 }
Hal Canaryfafe1352017-04-11 12:12:02 -0400178 SkSize joined = {0.0f, 0.0f};
Hal Canary45cde312017-04-03 16:06:42 -0400179 for (int i = 0; i < dstArrayCount; ++i) {
Hal Canaryfafe1352017-04-11 12:12:02 -0400180 joined = SkSize{SkTMax(joined.width(), dstArray[i].fSize.width()),
181 SkTMax(joined.height(), dstArray[i].fSize.height())};
Hal Canary45cde312017-04-03 16:06:42 -0400182 }
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}