diff options
Diffstat (limited to 'src/utils')
-rw-r--r-- | src/utils/SkMultiPictureDocument.cpp | 129 | ||||
-rw-r--r-- | src/utils/SkMultiPictureDocument.h | 52 | ||||
-rw-r--r-- | src/utils/SkMultiPictureDocumentPriv.h | 27 | ||||
-rw-r--r-- | src/utils/SkMultiPictureDocumentReader.cpp | 93 | ||||
-rw-r--r-- | src/utils/SkMultiPictureDocumentReader.h | 46 |
5 files changed, 152 insertions, 195 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; +} diff --git a/src/utils/SkMultiPictureDocument.h b/src/utils/SkMultiPictureDocument.h index ac782606ff..0ca8c2de72 100644 --- a/src/utils/SkMultiPictureDocument.h +++ b/src/utils/SkMultiPictureDocument.h @@ -7,42 +7,32 @@ #ifndef SkMultiPictureDocument_DEFINED #define SkMultiPictureDocument_DEFINED -/* - This format is not intended to be used in production. - - For clients looking for a way to represent a document in memory, - - struct Doc { - std::vector<sk_sp<SkPicture>> fPages; - std::vector<SkSize> fPageSizes; - }; - - or - - struct Page { - sk_sp<SkPicture> fPage; - SkSize fPageSize; - }; - std::vector<Page> pages; +#include "SkDocument.h" - would work much better. +class SkStreamSeekable; - Multi-SkPicture (MSKP) files are still useful for debugging and - testing. +/** + * Writes into a file format that is similar to SkPicture::serialize() + */ +SK_API sk_sp<SkDocument> SkMakeMultiPictureDocument(SkWStream* dst); - The downsides of this format are currently: - - no way to extract a single page; must read the entire file at once. - - must use `dm` to convert to another format before passing into - standard skp tools. - - `dm` can extract the first page to skp, but no others. +struct SkDocumentPage { + sk_sp<SkPicture> fPicture; + SkSize fSize; +}; - TODO(halcanary): replace with somthing that addresses these issues. +/** + * Returns the number of pages in the SkMultiPictureDocument. */ +SK_API int SkMultiPictureDocumentReadPageCount(SkStreamSeekable* src); -#include "SkDocument.h" - -/** Writes into an experimental, undocumented file format that is - useful for debugging documents printed via Skia. */ -SK_API sk_sp<SkDocument> SkMakeMultiPictureDocument(SkWStream* dst); +/** + * Read the SkMultiPictureDocument into the provided array of pages. + * dstArrayCount must equal SkMultiPictureDocumentReadPageCount(). + * Return false on error. + */ +SK_API bool SkMultiPictureDocumentRead(SkStreamSeekable* src, + SkDocumentPage* dstArray, + int dstArrayCount); #endif // SkMultiPictureDocument_DEFINED diff --git a/src/utils/SkMultiPictureDocumentPriv.h b/src/utils/SkMultiPictureDocumentPriv.h index 6d5ab47d21..aff5b55337 100644 --- a/src/utils/SkMultiPictureDocumentPriv.h +++ b/src/utils/SkMultiPictureDocumentPriv.h @@ -8,25 +8,14 @@ #ifndef SkMultiPictureDocumentPriv_DEFINED #define SkMultiPictureDocumentPriv_DEFINED -#include "SkTArray.h" -#include "SkSize.h" +#include "SkMultiPictureDocument.h" -namespace SkMultiPictureDocumentProtocol { -static constexpr char kMagic[] = "Skia Multi-Picture Doc\n\n"; - -static constexpr char kEndPage[] = "SkMultiPictureEndPage"; - -const uint32_t kVersion = 2; - -inline 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; -} - -} +/** + * Additional API allows one to read the array of page-sizes without parsing + * the entire file. Used by DM. + */ +bool SkMultiPictureDocumentReadPageSizes(SkStreamSeekable* src, + SkDocumentPage* dstArray, + int dstArrayCount); #endif // SkMultiPictureDocumentPriv_DEFINED diff --git a/src/utils/SkMultiPictureDocumentReader.cpp b/src/utils/SkMultiPictureDocumentReader.cpp deleted file mode 100644 index 3924f3eb42..0000000000 --- a/src/utils/SkMultiPictureDocumentReader.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * 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 "SkMultiPictureDocumentPriv.h" -#include "SkMultiPictureDocumentReader.h" -#include "SkPicture.h" -#include "SkStream.h" -#include "SkPictureRecorder.h" -#include "SkNWayCanvas.h" - -bool SkMultiPictureDocumentReader::init(SkStreamSeekable* stream) { - if (!stream) { - return false; - } - stream->seek(0); - const size_t size = sizeof(SkMultiPictureDocumentProtocol::kMagic) - 1; - char buffer[size]; - if (size != stream->read(buffer, size) || - 0 != memcmp(SkMultiPictureDocumentProtocol::kMagic, buffer, size)) { - stream = nullptr; - return false; - } - bool good = true; - uint32_t versionNumber = stream->readU32(); - if (versionNumber != SkMultiPictureDocumentProtocol::kVersion) { - return false; - } - uint32_t pageCount = stream->readU32(); - fSizes.reset(pageCount); - for (uint32_t i = 0; i < pageCount; ++i) { - SkSize size; - good &= sizeof(size) == stream->read(&size, sizeof(size)); - fSizes[i] = size; - } - fOffset = stream->getPosition(); - return good; -} - -namespace { -struct PagerCanvas : public SkNWayCanvas { - SkPictureRecorder fRecorder; - const SkTArray<SkSize>* fSizes; - SkTArray<sk_sp<SkPicture>>* fDest; - PagerCanvas(SkISize wh, - const SkTArray<SkSize>* s, - SkTArray<sk_sp<SkPicture>>* d) - : SkNWayCanvas(wh.width(), wh.height()), fSizes(s), fDest(d) { - this->nextCanvas(); - } - void nextCanvas() { - int i = fDest->count(); - if (i < fSizes->count()) { - SkRect bounds = SkRect::MakeSize((*fSizes)[i]); - this->addCanvas(fRecorder.beginRecording(bounds)); - } - } - void onDrawAnnotation(const SkRect& r, const char* key, SkData* d) override { - if (0 == strcmp(key, SkMultiPictureDocumentProtocol::kEndPage)) { - this->removeAll(); - if (fRecorder.getRecordingCanvas()) { - fDest->emplace_back(fRecorder.finishRecordingAsPicture()); - } - this->nextCanvas(); - } else { - this->SkNWayCanvas::onDrawAnnotation(r, key, d); - } - } -}; -} // namespace - -sk_sp<SkPicture> SkMultiPictureDocumentReader::readPage(SkStreamSeekable* stream, - int pageNumber) const { - SkASSERT(pageNumber >= 0); - SkASSERT(pageNumber < fSizes.count()); - if (0 == fPages.count()) { - stream->seek(fOffset); // jump to beginning of skp - auto picture = SkPicture::MakeFromStream(stream); - SkISize size = SkMultiPictureDocumentProtocol::Join(fSizes).toCeil(); - PagerCanvas canvas(size, &fSizes, &this->fPages); - // Must call playback(), not drawPicture() to reach - // PagerCanvas::onDrawAnnotation(). - picture->playback(&canvas); - if (fPages.count() != fSizes.count()) { - SkDEBUGF(("Malformed SkMultiPictureDocument\n")); - } - } - // Allow for malformed document. - return pageNumber < fPages.count() ? fPages[pageNumber] : nullptr; -} diff --git a/src/utils/SkMultiPictureDocumentReader.h b/src/utils/SkMultiPictureDocumentReader.h deleted file mode 100644 index e0473a6539..0000000000 --- a/src/utils/SkMultiPictureDocumentReader.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2016 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ -#ifndef SkMultiPictureDocumentReader_DEFINED -#define SkMultiPictureDocumentReader_DEFINED - -#include "../private/SkTArray.h" -#include "SkPicture.h" -#include "SkSize.h" -#include "SkStream.h" - -/** A lightweight helper class for reading a Skia MultiPictureDocument. */ -class SkMultiPictureDocumentReader { -public: - /** Initialize the MultiPictureDocument. Does not take ownership - of the SkStreamSeekable. */ - bool init(SkStreamSeekable*); - - /** Return to factory settings. */ - void reset() { - fSizes.reset(); - fPages.reset(); - } - - /** Call this after calling init() (otherwise you'll always get zero). */ - int pageCount() const { return fSizes.count(); } - - /** Deserialize a page from the stream. Call init() first. The - SkStreamSeekable doesn't need to be the same object, but - should point to the same information as before. */ - sk_sp<SkPicture> readPage(SkStreamSeekable*, int) const; - - /** Fetch the size of the given page, without deserializing the - entire page. */ - SkSize pageSize(int i) const { return fSizes[i]; } - -private: - SkTArray<SkSize> fSizes; - size_t fOffset; - mutable SkTArray<sk_sp<SkPicture>> fPages; -}; - -#endif // SkMultiPictureDocumentReader_DEFINED |