diff options
Diffstat (limited to 'src/utils/SkMultiPictureDocument.cpp')
-rw-r--r-- | src/utils/SkMultiPictureDocument.cpp | 129 |
1 files changed, 123 insertions, 6 deletions
diff --git a/src/utils/SkMultiPictureDocument.cpp b/src/utils/SkMultiPictureDocument.cpp index d987818f86..4251442fcf 100644 --- a/src/utils/SkMultiPictureDocument.cpp +++ b/src/utils/SkMultiPictureDocument.cpp @@ -7,11 +7,14 @@ #include "SkMultiPictureDocument.h" #include "SkMultiPictureDocumentPriv.h" +#include "SkNWayCanvas.h" #include "SkPicture.h" #include "SkPictureRecorder.h" #include "SkStream.h" #include "SkTArray.h" +#include <limits.h> + /* File format: BEGINNING_OF_FILE: @@ -26,6 +29,22 @@ */ namespace { +// 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) { + SkSize joined = SkSize::Make(0, 0); + for (SkSize s : sizes) { + joined = SkSize::Make(SkTMax(joined.width(), s.width()), + SkTMax(joined.height(), s.height())); + } + return joined; +} + static SkCanvas* trim(SkCanvas* canvas, SkScalar w, SkScalar h, const SkRect& trimBox) { @@ -59,19 +78,17 @@ struct MultiPictureDocument final : public SkDocument { void onClose(SkWStream* wStream) override { SkASSERT(wStream); SkASSERT(wStream->bytesWritten() == 0); - wStream->writeText(SkMultiPictureDocumentProtocol::kMagic); - wStream->write32(SkMultiPictureDocumentProtocol::kVersion); + wStream->writeText(kMagic); + wStream->write32(kVersion); wStream->write32(SkToU32(fPages.count())); for (SkSize s : fSizes) { wStream->write(&s, sizeof(s)); } - SkSize bigsize = SkMultiPictureDocumentProtocol::Join(fSizes); + SkSize bigsize = join(fSizes); SkCanvas* c = fPictureRecorder.beginRecording(SkRect::MakeSize(bigsize)); for (const sk_sp<SkPicture>& page : fPages) { c->drawPicture(page); - c->drawAnnotation(SkRect::MakeEmpty(), - SkMultiPictureDocumentProtocol::kEndPage, - nullptr); + c->drawAnnotation(SkRect::MakeEmpty(), kEndPage, nullptr); } sk_sp<SkPicture> p = fPictureRecorder.finishRecordingAsPicture(); p->serialize(wStream); @@ -89,3 +106,103 @@ struct MultiPictureDocument final : public SkDocument { sk_sp<SkDocument> SkMakeMultiPictureDocument(SkWStream* wStream) { return sk_make_sp<MultiPictureDocument>(wStream, nullptr); } + +//////////////////////////////////////////////////////////////////////////////// + +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, + int dstArrayCount) { + if (!SkMultiPictureDocumentReadPageSizes(stream, dstArray, dstArrayCount)) { + return false; + } + SkSize joined = SkSize::Make(0.0f, 0.0f); + for (int i = 0; i < dstArrayCount; ++i) { + joined = SkSize::Make(SkTMax(joined.width(), dstArray[i].fSize.width()), + SkTMax(joined.height(), dstArray[i].fSize.height())); + } + + auto picture = SkPicture::MakeFromStream(stream); + + 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; +} |