summaryrefslogtreecommitdiffstats
path: root/gfx/skia/skia/src/utils/SkMultiPictureDocument.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/skia/skia/src/utils/SkMultiPictureDocument.cpp')
-rw-r--r--gfx/skia/skia/src/utils/SkMultiPictureDocument.cpp224
1 files changed, 224 insertions, 0 deletions
diff --git a/gfx/skia/skia/src/utils/SkMultiPictureDocument.cpp b/gfx/skia/skia/src/utils/SkMultiPictureDocument.cpp
new file mode 100644
index 0000000000..39fc8ab90e
--- /dev/null
+++ b/gfx/skia/skia/src/utils/SkMultiPictureDocument.cpp
@@ -0,0 +1,224 @@
+/*
+ * 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 "src/utils/SkMultiPictureDocument.h"
+
+#include "include/core/SkCanvas.h"
+#include "include/core/SkData.h"
+#include "include/core/SkDocument.h"
+#include "include/core/SkPicture.h"
+#include "include/core/SkPictureRecorder.h"
+#include "include/core/SkRect.h"
+#include "include/core/SkScalar.h"
+#include "include/core/SkSerialProcs.h"
+#include "include/core/SkStream.h"
+#include "include/private/base/SkDebug.h"
+#include "include/private/base/SkTArray.h"
+#include "include/private/base/SkTo.h"
+#include "include/utils/SkNWayCanvas.h"
+#include "src/utils/SkMultiPictureDocumentPriv.h"
+
+#include <algorithm>
+#include <climits>
+#include <cstdint>
+#include <cstring>
+#include <functional>
+
+/*
+ File format:
+ BEGINNING_OF_FILE:
+ kMagic
+ uint32_t version_number (==2)
+ uint32_t page_count
+ {
+ float sizeX
+ float sizeY
+ } * page_count
+ skp file
+*/
+
+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 = {0, 0};
+ for (SkSize s : sizes) {
+ joined = SkSize{std::max(joined.width(), s.width()), std::max(joined.height(), s.height())};
+ }
+ return joined;
+}
+
+struct MultiPictureDocument final : public SkDocument {
+ const SkSerialProcs fProcs;
+ SkPictureRecorder fPictureRecorder;
+ SkSize fCurrentPageSize;
+ SkTArray<sk_sp<SkPicture>> fPages;
+ SkTArray<SkSize> fSizes;
+ std::function<void(const SkPicture*)> fOnEndPage;
+ MultiPictureDocument(SkWStream* s, const SkSerialProcs* procs,
+ std::function<void(const SkPicture*)> onEndPage)
+ : SkDocument(s)
+ , fProcs(procs ? *procs : SkSerialProcs())
+ , fOnEndPage(onEndPage)
+ {}
+ ~MultiPictureDocument() override { this->close(); }
+
+ SkCanvas* onBeginPage(SkScalar w, SkScalar h) override {
+ fCurrentPageSize.set(w, h);
+ return fPictureRecorder.beginRecording(w, h);
+ }
+ void onEndPage() override {
+ fSizes.push_back(fCurrentPageSize);
+ sk_sp<SkPicture> lastPage = fPictureRecorder.finishRecordingAsPicture();
+ fPages.push_back(lastPage);
+ if (fOnEndPage) {
+ fOnEndPage(lastPage.get());
+ }
+ }
+ void onClose(SkWStream* wStream) override {
+ SkASSERT(wStream);
+ SkASSERT(wStream->bytesWritten() == 0);
+ wStream->writeText(kMagic);
+ wStream->write32(kVersion);
+ wStream->write32(SkToU32(fPages.size()));
+ for (SkSize s : fSizes) {
+ wStream->write(&s, sizeof(s));
+ }
+ SkSize bigsize = join(fSizes);
+ SkCanvas* c = fPictureRecorder.beginRecording(SkRect::MakeSize(bigsize));
+ for (const sk_sp<SkPicture>& page : fPages) {
+ c->drawPicture(page);
+ // Annotations must include some data.
+ c->drawAnnotation(SkRect::MakeEmpty(), kEndPage, SkData::MakeWithCString("X"));
+ }
+ sk_sp<SkPicture> p = fPictureRecorder.finishRecordingAsPicture();
+ p->serialize(wStream, &fProcs);
+ fPages.clear();
+ fSizes.clear();
+ return;
+ }
+ void onAbort() override {
+ fPages.clear();
+ fSizes.clear();
+ }
+};
+} // namespace
+
+sk_sp<SkDocument> SkMakeMultiPictureDocument(SkWStream* wStream, const SkSerialProcs* procs,
+ std::function<void(const SkPicture*)> onEndPage) {
+ return sk_make_sp<MultiPictureDocument>(wStream, procs, onEndPage);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+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;
+ if (!stream->readU32(&versionNumber) || versionNumber != kVersion) {
+ return 0;
+ }
+ uint32_t pageCount;
+ if (!stream->readU32(&pageCount) || pageCount > INT_MAX) {
+ return 0;
+ }
+ // leave stream position right here.
+ return SkTo<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,
+ const SkDeserialProcs* procs) {
+ if (!SkMultiPictureDocumentReadPageSizes(stream, dstArray, dstArrayCount)) {
+ return false;
+ }
+ SkSize joined = {0.0f, 0.0f};
+ for (int i = 0; i < dstArrayCount; ++i) {
+ joined = SkSize{std::max(joined.width(), dstArray[i].fSize.width()),
+ std::max(joined.height(), dstArray[i].fSize.height())};
+ }
+
+ auto picture = SkPicture::MakeFromStream(stream, procs);
+ if (!picture) {
+ return false;
+ }
+
+ 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: canvas.fIndex=%d dstArrayCount=%d\n",
+ canvas.fIndex, dstArrayCount);
+ }
+ return true;
+}