blob: f7081e6d56e1a897658d7d37fba12fd8f51ff8e0 [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"
Hal Canaryc640d0d2018-06-13 09:59:02 -04009
halcanary45420a92016-06-02 12:41:14 -070010#include "SkMultiPictureDocumentPriv.h"
Hal Canary45cde312017-04-03 16:06:42 -040011#include "SkNWayCanvas.h"
halcanary45420a92016-06-02 12:41:14 -070012#include "SkPicture.h"
13#include "SkPictureRecorder.h"
Mike Reed47fdf6c2017-12-20 14:12:07 -050014#include "SkSerialProcs.h"
halcanary45420a92016-06-02 12:41:14 -070015#include "SkStream.h"
halcanaryc966ef92016-08-23 09:15:04 -070016#include "SkTArray.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040017#include "SkTo.h"
halcanary45420a92016-06-02 12:41:14 -070018
Hal Canary45cde312017-04-03 16:06:42 -040019#include <limits.h>
20
halcanary45420a92016-06-02 12:41:14 -070021/*
22 File format:
23 BEGINNING_OF_FILE:
24 kMagic
halcanaryc966ef92016-08-23 09:15:04 -070025 uint32_t version_number (==2)
halcanary45420a92016-06-02 12:41:14 -070026 uint32_t page_count
27 {
halcanary45420a92016-06-02 12:41:14 -070028 float sizeX
29 float sizeY
30 } * page_count
halcanary45420a92016-06-02 12:41:14 -070031 skp file
halcanary45420a92016-06-02 12:41:14 -070032*/
33
34namespace {
Hal Canary45cde312017-04-03 16:06:42 -040035// The unique file signature for this file type.
36static constexpr char kMagic[] = "Skia Multi-Picture Doc\n\n";
37
38static constexpr char kEndPage[] = "SkMultiPictureEndPage";
39
40const uint32_t kVersion = 2;
41
42static SkSize join(const SkTArray<SkSize>& sizes) {
Hal Canaryfafe1352017-04-11 12:12:02 -040043 SkSize joined = {0, 0};
Hal Canary45cde312017-04-03 16:06:42 -040044 for (SkSize s : sizes) {
Hal Canaryfafe1352017-04-11 12:12:02 -040045 joined = SkSize{SkTMax(joined.width(), s.width()), SkTMax(joined.height(), s.height())};
Hal Canary45cde312017-04-03 16:06:42 -040046 }
47 return joined;
48}
49
halcanary45420a92016-06-02 12:41:14 -070050struct MultiPictureDocument final : public SkDocument {
Mike Reed47fdf6c2017-12-20 14:12:07 -050051 const SkSerialProcs fProcs;
halcanary45420a92016-06-02 12:41:14 -070052 SkPictureRecorder fPictureRecorder;
halcanary59d64022016-06-14 11:06:37 -070053 SkSize fCurrentPageSize;
halcanaryc966ef92016-08-23 09:15:04 -070054 SkTArray<sk_sp<SkPicture>> fPages;
55 SkTArray<SkSize> fSizes;
Hal Canaryc5980d02018-01-08 15:02:36 -050056 MultiPictureDocument(SkWStream* s, const SkSerialProcs* procs)
57 : SkDocument(s)
Mike Reed47fdf6c2017-12-20 14:12:07 -050058 , fProcs(procs ? *procs : SkSerialProcs())
59 {}
Brian Salomond3b65972017-03-22 12:05:03 -040060 ~MultiPictureDocument() override { this->close(); }
halcanary45420a92016-06-02 12:41:14 -070061
Hal Canaryb1de5f92017-07-01 22:17:15 -040062 SkCanvas* onBeginPage(SkScalar w, SkScalar h) override {
halcanary59d64022016-06-14 11:06:37 -070063 fCurrentPageSize.set(w, h);
Hal Canaryb1de5f92017-07-01 22:17:15 -040064 return fPictureRecorder.beginRecording(w, h);
halcanary45420a92016-06-02 12:41:14 -070065 }
66 void onEndPage() override {
halcanaryc966ef92016-08-23 09:15:04 -070067 fSizes.push_back(fCurrentPageSize);
68 fPages.push_back(fPictureRecorder.finishRecordingAsPicture());
halcanary45420a92016-06-02 12:41:14 -070069 }
reedd14df7c2016-09-22 14:12:46 -070070 void onClose(SkWStream* wStream) override {
halcanary45420a92016-06-02 12:41:14 -070071 SkASSERT(wStream);
72 SkASSERT(wStream->bytesWritten() == 0);
Hal Canary45cde312017-04-03 16:06:42 -040073 wStream->writeText(kMagic);
74 wStream->write32(kVersion);
reedd14df7c2016-09-22 14:12:46 -070075 wStream->write32(SkToU32(fPages.count()));
halcanaryc966ef92016-08-23 09:15:04 -070076 for (SkSize s : fSizes) {
reedd14df7c2016-09-22 14:12:46 -070077 wStream->write(&s, sizeof(s));
halcanary45420a92016-06-02 12:41:14 -070078 }
Hal Canary45cde312017-04-03 16:06:42 -040079 SkSize bigsize = join(fSizes);
halcanaryc966ef92016-08-23 09:15:04 -070080 SkCanvas* c = fPictureRecorder.beginRecording(SkRect::MakeSize(bigsize));
81 for (const sk_sp<SkPicture>& page : fPages) {
82 c->drawPicture(page);
Hal Canary45cde312017-04-03 16:06:42 -040083 c->drawAnnotation(SkRect::MakeEmpty(), kEndPage, nullptr);
halcanary45420a92016-06-02 12:41:14 -070084 }
halcanaryc966ef92016-08-23 09:15:04 -070085 sk_sp<SkPicture> p = fPictureRecorder.finishRecordingAsPicture();
Mike Reed47fdf6c2017-12-20 14:12:07 -050086 p->serialize(wStream, &fProcs);
halcanaryc966ef92016-08-23 09:15:04 -070087 fPages.reset();
88 fSizes.reset();
reedd14df7c2016-09-22 14:12:46 -070089 return;
halcanary45420a92016-06-02 12:41:14 -070090 }
halcanaryc966ef92016-08-23 09:15:04 -070091 void onAbort() override {
92 fPages.reset();
93 fSizes.reset();
94 }
halcanary45420a92016-06-02 12:41:14 -070095};
96}
97
Mike Reed47fdf6c2017-12-20 14:12:07 -050098sk_sp<SkDocument> SkMakeMultiPictureDocument(SkWStream* wStream, const SkSerialProcs* procs) {
Hal Canaryc5980d02018-01-08 15:02:36 -050099 return sk_make_sp<MultiPictureDocument>(wStream, procs);
halcanary45420a92016-06-02 12:41:14 -0700100}
Hal Canary45cde312017-04-03 16:06:42 -0400101
102////////////////////////////////////////////////////////////////////////////////
103
104int SkMultiPictureDocumentReadPageCount(SkStreamSeekable* stream) {
105 if (!stream) {
106 return 0;
107 }
108 stream->seek(0);
109 const size_t size = sizeof(kMagic) - 1;
110 char buffer[size];
111 if (size != stream->read(buffer, size) || 0 != memcmp(kMagic, buffer, size)) {
112 stream = nullptr;
113 return 0;
114 }
Ben Wagner255ab8d2016-10-07 15:50:53 -0400115 uint32_t versionNumber;
116 if (!stream->readU32(&versionNumber) || versionNumber != kVersion) {
Hal Canary45cde312017-04-03 16:06:42 -0400117 return 0;
118 }
Ben Wagner255ab8d2016-10-07 15:50:53 -0400119 uint32_t pageCount;
120 if (!stream->readU32(&pageCount) || pageCount > INT_MAX) {
Hal Canary45cde312017-04-03 16:06:42 -0400121 return 0;
122 }
123 // leave stream position right here.
Ben Wagner255ab8d2016-10-07 15:50:53 -0400124 return SkTo<int>(pageCount);
Hal Canary45cde312017-04-03 16:06:42 -0400125}
126
127bool SkMultiPictureDocumentReadPageSizes(SkStreamSeekable* stream,
128 SkDocumentPage* dstArray,
129 int dstArrayCount) {
130 if (!dstArray || dstArrayCount < 1) {
131 return false;
132 }
133 int pageCount = SkMultiPictureDocumentReadPageCount(stream);
134 if (pageCount < 1 || pageCount != dstArrayCount) {
135 return false;
136 }
137 for (int i = 0; i < pageCount; ++i) {
138 SkSize& s = dstArray[i].fSize;
139 if (sizeof(s) != stream->read(&s, sizeof(s))) {
140 return false;
141 }
142 }
143 // leave stream position right here.
144 return true;
145}
146
147namespace {
148struct PagerCanvas : public SkNWayCanvas {
149 SkPictureRecorder fRecorder;
150 SkDocumentPage* fDst;
151 int fCount;
152 int fIndex = 0;
153 PagerCanvas(SkISize wh, SkDocumentPage* dst, int count)
154 : SkNWayCanvas(wh.width(), wh.height()), fDst(dst), fCount(count) {
155 this->nextCanvas();
156 }
157 void nextCanvas() {
158 if (fIndex < fCount) {
159 SkRect bounds = SkRect::MakeSize(fDst[fIndex].fSize);
160 this->addCanvas(fRecorder.beginRecording(bounds));
161 }
162 }
163 void onDrawAnnotation(const SkRect& r, const char* key, SkData* d) override {
164 if (0 == strcmp(key, kEndPage)) {
165 this->removeAll();
166 if (fIndex < fCount) {
167 fDst[fIndex].fPicture = fRecorder.finishRecordingAsPicture();
168 ++fIndex;
169 }
170 this->nextCanvas();
171 } else {
172 this->SkNWayCanvas::onDrawAnnotation(r, key, d);
173 }
174 }
175};
176} // namespace
177
178bool SkMultiPictureDocumentRead(SkStreamSeekable* stream,
179 SkDocumentPage* dstArray,
Mike Reed47fdf6c2017-12-20 14:12:07 -0500180 int dstArrayCount,
181 const SkDeserialProcs* procs) {
Hal Canary45cde312017-04-03 16:06:42 -0400182 if (!SkMultiPictureDocumentReadPageSizes(stream, dstArray, dstArrayCount)) {
183 return false;
184 }
Hal Canaryfafe1352017-04-11 12:12:02 -0400185 SkSize joined = {0.0f, 0.0f};
Hal Canary45cde312017-04-03 16:06:42 -0400186 for (int i = 0; i < dstArrayCount; ++i) {
Hal Canaryfafe1352017-04-11 12:12:02 -0400187 joined = SkSize{SkTMax(joined.width(), dstArray[i].fSize.width()),
188 SkTMax(joined.height(), dstArray[i].fSize.height())};
Hal Canary45cde312017-04-03 16:06:42 -0400189 }
190
Mike Reed47fdf6c2017-12-20 14:12:07 -0500191 auto picture = SkPicture::MakeFromStream(stream, procs);
Hal Canary45cde312017-04-03 16:06:42 -0400192
193 PagerCanvas canvas(joined.toCeil(), dstArray, dstArrayCount);
194 // Must call playback(), not drawPicture() to reach
195 // PagerCanvas::onDrawAnnotation().
196 picture->playback(&canvas);
197 if (canvas.fIndex != dstArrayCount) {
198 SkDEBUGF(("Malformed SkMultiPictureDocument\n"));
199 }
200 return true;
201}