blob: 214e6ad5371e518cd84e698eabed74be5c27ba24 [file] [log] [blame]
halcanary45420a92016-06-02 12:41:14 -07001/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
halcanary59d64022016-06-14 11:06:37 -07008#include <vector>
9
halcanary45420a92016-06-02 12:41:14 -070010#include "SkMultiPictureDocument.h"
11#include "SkMultiPictureDocumentPriv.h"
12#include "SkPicture.h"
13#include "SkPictureRecorder.h"
14#include "SkStream.h"
15
16/*
17 File format:
18 BEGINNING_OF_FILE:
19 kMagic
20 uint32_t version_number
21 uint32_t page_count
22 {
23 uint64_t offset
24 float sizeX
25 float sizeY
26 } * page_count
27 FIRST_OFFSET:
28 skp file
29 SECOND_OFFSET:
30 skp file
31 ...
32 LAST_OFFSET:
33 skp file
34 "\nEndOfMultiPicture\n"
35*/
36
37namespace {
38static SkCanvas* trim(SkCanvas* canvas,
39 SkScalar w, SkScalar h,
40 const SkRect& trimBox) {
41 // Only trim if necessary.
42 if (trimBox != SkRect::MakeWH(w, h)) {
43 // All SkDocument implementations implement trimBox using a
44 // clip+translate.
45 canvas->clipRect(trimBox);
46 canvas->translate(trimBox.x(), trimBox.y());
47 }
48 return canvas;
49}
50
51struct NullWStream : public SkWStream {
52 NullWStream() : fN(0) {}
53 bool write(const void*, size_t n) override {
54 fN += n;
55 return true;
56 }
57 size_t bytesWritten() const override { return fN; }
58 size_t fN;
59};
60
halcanary59d64022016-06-14 11:06:37 -070061struct Page {
62 Page(SkSize s, sk_sp<SkPicture> c) : fSize(s), fContent(std::move(c)) {}
halcanary9be37202016-08-08 07:21:42 -070063 Page(Page&&) = default;
halcanary59d64022016-06-14 11:06:37 -070064 Page(const Page&) = default;
65 Page& operator=(const Page&) = default;
halcanary9be37202016-08-08 07:21:42 -070066 Page& operator=(Page&&) = default;
halcanary59d64022016-06-14 11:06:37 -070067 SkSize fSize;
68 sk_sp<SkPicture> fContent;
69};
70
halcanary45420a92016-06-02 12:41:14 -070071struct MultiPictureDocument final : public SkDocument {
72 SkPictureRecorder fPictureRecorder;
halcanary59d64022016-06-14 11:06:37 -070073 SkSize fCurrentPageSize;
74 std::vector<Page> fPages;
halcanary45420a92016-06-02 12:41:14 -070075 MultiPictureDocument(SkWStream* s, void (*d)(SkWStream*, bool))
76 : SkDocument(s, d) {}
77 ~MultiPictureDocument() { this->close(); }
78
79 SkCanvas* onBeginPage(SkScalar w, SkScalar h, const SkRect& c) override {
halcanary59d64022016-06-14 11:06:37 -070080 fCurrentPageSize.set(w, h);
halcanary45420a92016-06-02 12:41:14 -070081 return trim(fPictureRecorder.beginRecording(w, h), w, h, c);
82 }
83 void onEndPage() override {
halcanary59d64022016-06-14 11:06:37 -070084 fPages.emplace_back(fCurrentPageSize,
85 fPictureRecorder.finishRecordingAsPicture());
halcanary45420a92016-06-02 12:41:14 -070086 }
87 bool onClose(SkWStream* wStream) override {
88 SkASSERT(wStream);
89 SkASSERT(wStream->bytesWritten() == 0);
90 bool good = true;
91 good &= wStream->writeText(SkMultiPictureDocumentProtocol::kMagic);
92 good &= wStream->write32(SkToU32(1)); // version
halcanary59d64022016-06-14 11:06:37 -070093 good &= wStream->write32(SkToU32(fPages.size()));
halcanary45420a92016-06-02 12:41:14 -070094 uint64_t offset = wStream->bytesWritten();
halcanary59d64022016-06-14 11:06:37 -070095 offset += fPages.size() * sizeof(SkMultiPictureDocumentProtocol::Entry);
halcanary45420a92016-06-02 12:41:14 -070096 for (const auto& page : fPages) {
halcanary45420a92016-06-02 12:41:14 -070097 SkMultiPictureDocumentProtocol::Entry entry{
halcanary59d64022016-06-14 11:06:37 -070098 offset, page.fSize.width(), page.fSize.height()};
halcanary45420a92016-06-02 12:41:14 -070099 good &= wStream->write(&entry, sizeof(entry));
100 NullWStream buffer;
halcanary59d64022016-06-14 11:06:37 -0700101 page.fContent->serialize(&buffer);
halcanary45420a92016-06-02 12:41:14 -0700102 offset += buffer.bytesWritten();
103 }
104 for (const auto& page : fPages) {
halcanary59d64022016-06-14 11:06:37 -0700105 page.fContent->serialize(wStream);
halcanary45420a92016-06-02 12:41:14 -0700106 }
107 SkASSERT(wStream->bytesWritten() == offset);
108 good &= wStream->writeText("\nEndOfMultiPicture\n");
halcanary59d64022016-06-14 11:06:37 -0700109 fPages.clear();
halcanary45420a92016-06-02 12:41:14 -0700110 return good;
111 }
halcanary59d64022016-06-14 11:06:37 -0700112 void onAbort() override { fPages.clear(); }
halcanary45420a92016-06-02 12:41:14 -0700113};
114}
115
116sk_sp<SkDocument> SkMakeMultiPictureDocument(SkWStream* wStream) {
117 return sk_make_sp<MultiPictureDocument>(wStream, nullptr);
118}