2016-06-02 19:41:14 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2016 Google Inc.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "SkMultiPictureDocument.h"
|
|
|
|
#include "SkMultiPictureDocumentPriv.h"
|
2017-04-03 20:06:42 +00:00
|
|
|
#include "SkNWayCanvas.h"
|
2016-06-02 19:41:14 +00:00
|
|
|
#include "SkPicture.h"
|
|
|
|
#include "SkPictureRecorder.h"
|
2017-12-20 19:12:07 +00:00
|
|
|
#include "SkSerialProcs.h"
|
2016-06-02 19:41:14 +00:00
|
|
|
#include "SkStream.h"
|
2016-08-23 16:15:04 +00:00
|
|
|
#include "SkTArray.h"
|
2016-06-02 19:41:14 +00:00
|
|
|
|
2017-04-03 20:06:42 +00:00
|
|
|
#include <limits.h>
|
|
|
|
|
2016-06-02 19:41:14 +00:00
|
|
|
/*
|
|
|
|
File format:
|
|
|
|
BEGINNING_OF_FILE:
|
|
|
|
kMagic
|
2016-08-23 16:15:04 +00:00
|
|
|
uint32_t version_number (==2)
|
2016-06-02 19:41:14 +00:00
|
|
|
uint32_t page_count
|
|
|
|
{
|
|
|
|
float sizeX
|
|
|
|
float sizeY
|
|
|
|
} * page_count
|
|
|
|
skp file
|
|
|
|
*/
|
|
|
|
|
|
|
|
namespace {
|
2017-04-03 20:06:42 +00:00
|
|
|
// The unique file signature for this file type.
|
|
|
|
static constexpr char kMagic[] = "Skia Multi-Picture Doc\n\n";
|
|
|
|
|
|
|
|
static constexpr char kEndPage[] = "SkMultiPictureEndPage";
|
|
|
|
|
|
|
|
const uint32_t kVersion = 2;
|
|
|
|
|
|
|
|
static SkSize join(const SkTArray<SkSize>& sizes) {
|
2017-04-11 16:12:02 +00:00
|
|
|
SkSize joined = {0, 0};
|
2017-04-03 20:06:42 +00:00
|
|
|
for (SkSize s : sizes) {
|
2017-04-11 16:12:02 +00:00
|
|
|
joined = SkSize{SkTMax(joined.width(), s.width()), SkTMax(joined.height(), s.height())};
|
2017-04-03 20:06:42 +00:00
|
|
|
}
|
|
|
|
return joined;
|
|
|
|
}
|
|
|
|
|
2016-06-02 19:41:14 +00:00
|
|
|
struct MultiPictureDocument final : public SkDocument {
|
2017-12-20 19:12:07 +00:00
|
|
|
const SkSerialProcs fProcs;
|
2016-06-02 19:41:14 +00:00
|
|
|
SkPictureRecorder fPictureRecorder;
|
2016-06-14 18:06:37 +00:00
|
|
|
SkSize fCurrentPageSize;
|
2016-08-23 16:15:04 +00:00
|
|
|
SkTArray<sk_sp<SkPicture>> fPages;
|
|
|
|
SkTArray<SkSize> fSizes;
|
2018-01-08 20:02:36 +00:00
|
|
|
MultiPictureDocument(SkWStream* s, const SkSerialProcs* procs)
|
|
|
|
: SkDocument(s)
|
2017-12-20 19:12:07 +00:00
|
|
|
, fProcs(procs ? *procs : SkSerialProcs())
|
|
|
|
{}
|
2017-03-22 16:05:03 +00:00
|
|
|
~MultiPictureDocument() override { this->close(); }
|
2016-06-02 19:41:14 +00:00
|
|
|
|
2017-07-02 02:17:15 +00:00
|
|
|
SkCanvas* onBeginPage(SkScalar w, SkScalar h) override {
|
2016-06-14 18:06:37 +00:00
|
|
|
fCurrentPageSize.set(w, h);
|
2017-07-02 02:17:15 +00:00
|
|
|
return fPictureRecorder.beginRecording(w, h);
|
2016-06-02 19:41:14 +00:00
|
|
|
}
|
|
|
|
void onEndPage() override {
|
2016-08-23 16:15:04 +00:00
|
|
|
fSizes.push_back(fCurrentPageSize);
|
|
|
|
fPages.push_back(fPictureRecorder.finishRecordingAsPicture());
|
2016-06-02 19:41:14 +00:00
|
|
|
}
|
2016-09-22 21:12:46 +00:00
|
|
|
void onClose(SkWStream* wStream) override {
|
2016-06-02 19:41:14 +00:00
|
|
|
SkASSERT(wStream);
|
|
|
|
SkASSERT(wStream->bytesWritten() == 0);
|
2017-04-03 20:06:42 +00:00
|
|
|
wStream->writeText(kMagic);
|
|
|
|
wStream->write32(kVersion);
|
2016-09-22 21:12:46 +00:00
|
|
|
wStream->write32(SkToU32(fPages.count()));
|
2016-08-23 16:15:04 +00:00
|
|
|
for (SkSize s : fSizes) {
|
2016-09-22 21:12:46 +00:00
|
|
|
wStream->write(&s, sizeof(s));
|
2016-06-02 19:41:14 +00:00
|
|
|
}
|
2017-04-03 20:06:42 +00:00
|
|
|
SkSize bigsize = join(fSizes);
|
2016-08-23 16:15:04 +00:00
|
|
|
SkCanvas* c = fPictureRecorder.beginRecording(SkRect::MakeSize(bigsize));
|
|
|
|
for (const sk_sp<SkPicture>& page : fPages) {
|
|
|
|
c->drawPicture(page);
|
2017-04-03 20:06:42 +00:00
|
|
|
c->drawAnnotation(SkRect::MakeEmpty(), kEndPage, nullptr);
|
2016-06-02 19:41:14 +00:00
|
|
|
}
|
2016-08-23 16:15:04 +00:00
|
|
|
sk_sp<SkPicture> p = fPictureRecorder.finishRecordingAsPicture();
|
2017-12-20 19:12:07 +00:00
|
|
|
p->serialize(wStream, &fProcs);
|
2016-08-23 16:15:04 +00:00
|
|
|
fPages.reset();
|
|
|
|
fSizes.reset();
|
2016-09-22 21:12:46 +00:00
|
|
|
return;
|
2016-06-02 19:41:14 +00:00
|
|
|
}
|
2016-08-23 16:15:04 +00:00
|
|
|
void onAbort() override {
|
|
|
|
fPages.reset();
|
|
|
|
fSizes.reset();
|
|
|
|
}
|
2016-06-02 19:41:14 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2017-12-20 19:12:07 +00:00
|
|
|
sk_sp<SkDocument> SkMakeMultiPictureDocument(SkWStream* wStream, const SkSerialProcs* procs) {
|
2018-01-08 20:02:36 +00:00
|
|
|
return sk_make_sp<MultiPictureDocument>(wStream, procs);
|
2016-06-02 19:41:14 +00:00
|
|
|
}
|
2017-04-03 20:06:42 +00:00
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
int SkMultiPictureDocumentReadPageCount(SkStreamSeekable* stream) {
|
|
|
|
if (!stream) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
stream->seek(0);
|
|
|
|
const size_t size = sizeof(kMagic) - 1;
|
|
|
|
char buffer[size];
|
|
|
|
if (size != stream->read(buffer, size) || 0 != memcmp(kMagic, buffer, size)) {
|
|
|
|
stream = nullptr;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
uint32_t versionNumber = stream->readU32();
|
|
|
|
if (versionNumber != kVersion) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
uint32_t pageCount = stream->readU32();
|
|
|
|
if (pageCount > INT_MAX) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
// leave stream position right here.
|
|
|
|
return (int)pageCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SkMultiPictureDocumentReadPageSizes(SkStreamSeekable* stream,
|
|
|
|
SkDocumentPage* dstArray,
|
|
|
|
int dstArrayCount) {
|
|
|
|
if (!dstArray || dstArrayCount < 1) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
int pageCount = SkMultiPictureDocumentReadPageCount(stream);
|
|
|
|
if (pageCount < 1 || pageCount != dstArrayCount) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
for (int i = 0; i < pageCount; ++i) {
|
|
|
|
SkSize& s = dstArray[i].fSize;
|
|
|
|
if (sizeof(s) != stream->read(&s, sizeof(s))) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// leave stream position right here.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
struct PagerCanvas : public SkNWayCanvas {
|
|
|
|
SkPictureRecorder fRecorder;
|
|
|
|
SkDocumentPage* fDst;
|
|
|
|
int fCount;
|
|
|
|
int fIndex = 0;
|
|
|
|
PagerCanvas(SkISize wh, SkDocumentPage* dst, int count)
|
|
|
|
: SkNWayCanvas(wh.width(), wh.height()), fDst(dst), fCount(count) {
|
|
|
|
this->nextCanvas();
|
|
|
|
}
|
|
|
|
void nextCanvas() {
|
|
|
|
if (fIndex < fCount) {
|
|
|
|
SkRect bounds = SkRect::MakeSize(fDst[fIndex].fSize);
|
|
|
|
this->addCanvas(fRecorder.beginRecording(bounds));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void onDrawAnnotation(const SkRect& r, const char* key, SkData* d) override {
|
|
|
|
if (0 == strcmp(key, kEndPage)) {
|
|
|
|
this->removeAll();
|
|
|
|
if (fIndex < fCount) {
|
|
|
|
fDst[fIndex].fPicture = fRecorder.finishRecordingAsPicture();
|
|
|
|
++fIndex;
|
|
|
|
}
|
|
|
|
this->nextCanvas();
|
|
|
|
} else {
|
|
|
|
this->SkNWayCanvas::onDrawAnnotation(r, key, d);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
bool SkMultiPictureDocumentRead(SkStreamSeekable* stream,
|
|
|
|
SkDocumentPage* dstArray,
|
2017-12-20 19:12:07 +00:00
|
|
|
int dstArrayCount,
|
|
|
|
const SkDeserialProcs* procs) {
|
2017-04-03 20:06:42 +00:00
|
|
|
if (!SkMultiPictureDocumentReadPageSizes(stream, dstArray, dstArrayCount)) {
|
|
|
|
return false;
|
|
|
|
}
|
2017-04-11 16:12:02 +00:00
|
|
|
SkSize joined = {0.0f, 0.0f};
|
2017-04-03 20:06:42 +00:00
|
|
|
for (int i = 0; i < dstArrayCount; ++i) {
|
2017-04-11 16:12:02 +00:00
|
|
|
joined = SkSize{SkTMax(joined.width(), dstArray[i].fSize.width()),
|
|
|
|
SkTMax(joined.height(), dstArray[i].fSize.height())};
|
2017-04-03 20:06:42 +00:00
|
|
|
}
|
|
|
|
|
2017-12-20 19:12:07 +00:00
|
|
|
auto picture = SkPicture::MakeFromStream(stream, procs);
|
2017-04-03 20:06:42 +00:00
|
|
|
|
|
|
|
PagerCanvas canvas(joined.toCeil(), dstArray, dstArrayCount);
|
|
|
|
// Must call playback(), not drawPicture() to reach
|
|
|
|
// PagerCanvas::onDrawAnnotation().
|
|
|
|
picture->playback(&canvas);
|
|
|
|
if (canvas.fIndex != dstArrayCount) {
|
|
|
|
SkDEBUGF(("Malformed SkMultiPictureDocument\n"));
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|