diff options
Diffstat (limited to 'src/utils')
-rw-r--r-- | src/utils/SkMultiPictureDocument.cpp | 106 | ||||
-rw-r--r-- | src/utils/SkMultiPictureDocument.h | 16 | ||||
-rw-r--r-- | src/utils/SkMultiPictureDocumentPriv.h | 23 | ||||
-rw-r--r-- | src/utils/SkMultiPictureDocumentReader.cpp | 49 | ||||
-rw-r--r-- | src/utils/SkMultiPictureDocumentReader.h | 45 |
5 files changed, 239 insertions, 0 deletions
diff --git a/src/utils/SkMultiPictureDocument.cpp b/src/utils/SkMultiPictureDocument.cpp new file mode 100644 index 0000000000..1cbf0aebc1 --- /dev/null +++ b/src/utils/SkMultiPictureDocument.cpp @@ -0,0 +1,106 @@ +/* + * 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" +#include "SkPicture.h" +#include "SkPictureRecorder.h" +#include "SkStream.h" + +/* + File format: + BEGINNING_OF_FILE: + kMagic + uint32_t version_number + uint32_t page_count + { + uint64_t offset + float sizeX + float sizeY + } * page_count + FIRST_OFFSET: + skp file + SECOND_OFFSET: + skp file + ... + LAST_OFFSET: + skp file + "\nEndOfMultiPicture\n" +*/ + +namespace { +static SkCanvas* trim(SkCanvas* canvas, + SkScalar w, SkScalar h, + const SkRect& trimBox) { + // Only trim if necessary. + if (trimBox != SkRect::MakeWH(w, h)) { + // All SkDocument implementations implement trimBox using a + // clip+translate. + canvas->clipRect(trimBox); + canvas->translate(trimBox.x(), trimBox.y()); + } + return canvas; +} + +struct NullWStream : public SkWStream { + NullWStream() : fN(0) {} + bool write(const void*, size_t n) override { + fN += n; + return true; + } + size_t bytesWritten() const override { return fN; } + size_t fN; +}; + +struct MultiPictureDocument final : public SkDocument { + SkPictureRecorder fPictureRecorder; + SkTArray<sk_sp<SkPicture>> fPages; + MultiPictureDocument(SkWStream* s, void (*d)(SkWStream*, bool)) + : SkDocument(s, d) {} + ~MultiPictureDocument() { this->close(); } + + SkCanvas* onBeginPage(SkScalar w, SkScalar h, const SkRect& c) override { + return trim(fPictureRecorder.beginRecording(w, h), w, h, c); + } + void onEndPage() override { + fPages.emplace_back(fPictureRecorder.finishRecordingAsPicture()); + } + bool onClose(SkWStream* wStream) override { + SkASSERT(wStream); + SkASSERT(wStream->bytesWritten() == 0); + bool good = true; + good &= wStream->writeText(SkMultiPictureDocumentProtocol::kMagic); + good &= wStream->write32(SkToU32(1)); // version + good &= wStream->write32(SkToU32(fPages.count())); + uint64_t offset = wStream->bytesWritten(); + offset += fPages.count() * sizeof(SkMultiPictureDocumentProtocol::Entry); + for (const auto& page : fPages) { + SkRect cullRect = page->cullRect(); + // We recorded a picture at the origin. + SkASSERT(cullRect.x() == 0 && cullRect.y() == 0); + SkMultiPictureDocumentProtocol::Entry entry{ + offset, (float)cullRect.right(), (float)cullRect.bottom()}; + good &= wStream->write(&entry, sizeof(entry)); + NullWStream buffer; + page->serialize(&buffer); + offset += buffer.bytesWritten(); + } + for (const auto& page : fPages) { + page->serialize(wStream); + } + SkASSERT(wStream->bytesWritten() == offset); + good &= wStream->writeText("\nEndOfMultiPicture\n"); + fPages.reset(); + return good; + } + void onAbort() override { fPages.reset(); } +}; +} + +sk_sp<SkDocument> SkMakeMultiPictureDocument(SkWStream* wStream) { + return sk_make_sp<MultiPictureDocument>(wStream, nullptr); +} diff --git a/src/utils/SkMultiPictureDocument.h b/src/utils/SkMultiPictureDocument.h new file mode 100644 index 0000000000..1da105e1b6 --- /dev/null +++ b/src/utils/SkMultiPictureDocument.h @@ -0,0 +1,16 @@ +/* + * 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 SkMultiPictureDocument_DEFINED +#define SkMultiPictureDocument_DEFINED + +#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); + +#endif // SkMultiPictureDocument_DEFINED diff --git a/src/utils/SkMultiPictureDocumentPriv.h b/src/utils/SkMultiPictureDocumentPriv.h new file mode 100644 index 0000000000..124dad7c6b --- /dev/null +++ b/src/utils/SkMultiPictureDocumentPriv.h @@ -0,0 +1,23 @@ +/* + * 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 SkMultiPictureDocumentPriv_DEFINED +#define SkMultiPictureDocumentPriv_DEFINED + +#include "stdint.h" + +namespace SkMultiPictureDocumentProtocol { +static constexpr char kMagic[] = "Skia Multi-Picture Doc\n\n"; + +struct Entry { + uint64_t offset; + float sizeX; + float sizeY; +}; +} + +#endif // SkMultiPictureDocumentPriv_DEFINED diff --git a/src/utils/SkMultiPictureDocumentReader.cpp b/src/utils/SkMultiPictureDocumentReader.cpp new file mode 100644 index 0000000000..6bc77bfc76 --- /dev/null +++ b/src/utils/SkMultiPictureDocumentReader.cpp @@ -0,0 +1,49 @@ +/* + * 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" + +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 != 1) { + return false; + } + uint32_t pageCount = stream->readU32(); + fSizes.reset(pageCount); + fOffsets.reset(pageCount); + for (uint32_t i = 0; i < pageCount; ++i) { + SkMultiPictureDocumentProtocol::Entry entry; + good &= sizeof(entry) == stream->read(&entry, sizeof(entry)); + fSizes[i] = SkSize::Make(entry.sizeX, entry.sizeY); + good &= SkTFitsIn<size_t>(entry.offset); + fOffsets[i] = static_cast<size_t>(entry.offset); + } + return good; +} + +sk_sp<SkPicture> SkMultiPictureDocumentReader::readPage(SkStreamSeekable* stream, + int pageNumber) const { + SkASSERT(pageNumber >= 0); + SkASSERT(pageNumber < fOffsets.count()); + SkAssertResult(stream->seek(fOffsets[pageNumber])); + return SkPicture::MakeFromStream(stream); +} diff --git a/src/utils/SkMultiPictureDocumentReader.h b/src/utils/SkMultiPictureDocumentReader.h new file mode 100644 index 0000000000..8e0a630e52 --- /dev/null +++ b/src/utils/SkMultiPictureDocumentReader.h @@ -0,0 +1,45 @@ +/* + * 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(); + fOffsets.reset(); + } + + /** Call this after calling init() */ + 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; + SkTArray<size_t> fOffsets; +}; + +#endif // SkMultiPictureDocumentReader_DEFINED |