1/*
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#ifndef SkPDFDocumentPriv_DEFINED
8#define SkPDFDocumentPriv_DEFINED
9
10#include "include/core/SkCanvas.h"
11#include "include/core/SkStream.h"
12#include "include/docs/SkPDFDocument.h"
13#include "include/private/SkMutex.h"
14#include "include/private/SkTHash.h"
15#include "src/pdf/SkPDFMetadata.h"
16#include "src/pdf/SkPDFTag.h"
17
18#include <atomic>
19#include <vector>
20#include <memory>
21
22class SkExecutor;
23class SkPDFDevice;
24class SkPDFFont;
25struct SkAdvancedTypefaceMetrics;
26struct SkBitmapKey;
27struct SkPDFFillGraphicState;
28struct SkPDFImageShaderKey;
29struct SkPDFStrokeGraphicState;
30
31namespace SkPDFGradientShader {
32struct Key;
33struct KeyHash;
34}
35
36const char* SkPDFGetNodeIdKey();
37
38// Logically part of SkPDFDocument, but separate to keep similar functionality together.
39class SkPDFOffsetMap {
40public:
41 void markStartOfDocument(const SkWStream*);
42 void markStartOfObject(int referenceNumber, const SkWStream*);
43 int objectCount() const;
44 int emitCrossReferenceTable(SkWStream* s) const;
45private:
46 std::vector<int> fOffsets;
47 size_t fBaseOffset = SIZE_MAX;
48};
49
50
51struct SkPDFNamedDestination {
52 sk_sp<SkData> fName;
53 SkPoint fPoint;
54 SkPDFIndirectReference fPage;
55};
56
57
58struct SkPDFLink {
59 enum class Type {
60 kNone,
61 kUrl,
62 kNamedDestination,
63 };
64
65 SkPDFLink(Type type, SkData* data, const SkRect& rect, int nodeId)
66 : fType(type)
67 , fData(sk_ref_sp(data))
68 , fRect(rect)
69 , fNodeId(nodeId) {}
70 const Type fType;
71 // The url or named destination, depending on |fType|.
72 const sk_sp<SkData> fData;
73 const SkRect fRect;
74 const int fNodeId;
75};
76
77
78/** Concrete implementation of SkDocument that creates PDF files. This
79 class does not produced linearized or optimized PDFs; instead it
80 it attempts to use a minimum amount of RAM. */
81class SkPDFDocument : public SkDocument {
82public:
83 SkPDFDocument(SkWStream*, SkPDF::Metadata);
84 ~SkPDFDocument() override;
85 SkCanvas* onBeginPage(SkScalar, SkScalar) override;
86 void onEndPage() override;
87 void onClose(SkWStream*) override;
88 void onAbort() override;
89
90 /**
91 Serialize the object, as well as any other objects it
92 indirectly refers to. If any any other objects have been added
93 to the SkPDFObjNumMap without serializing them, they will be
94 serialized as well.
95
96 It might go without saying that objects should not be changed
97 after calling serialize, since those changes will be too late.
98 */
99 SkPDFIndirectReference emit(const SkPDFObject&, SkPDFIndirectReference);
100 SkPDFIndirectReference emit(const SkPDFObject& o) { return this->emit(o, this->reserveRef()); }
101
102 template <typename T>
103 void emitStream(const SkPDFDict& dict, T writeStream, SkPDFIndirectReference ref) {
104 SkAutoMutexExclusive lock(fMutex);
105 SkWStream* stream = this->beginObject(ref);
106 dict.emitObject(stream);
107 stream->writeText(" stream\n");
108 writeStream(stream);
109 stream->writeText("\nendstream");
110 this->endObject();
111 }
112
113 const SkPDF::Metadata& metadata() const { return fMetadata; }
114
115 SkPDFIndirectReference getPage(size_t pageIndex) const;
116 SkPDFIndirectReference currentPage() const {
117 return SkASSERT(!fPageRefs.empty()), fPageRefs.back();
118 }
119 // Returns -1 if no mark ID.
120 int getMarkIdForNodeId(int nodeId);
121
122 std::unique_ptr<SkPDFArray> getAnnotations();
123
124 SkPDFIndirectReference reserveRef() { return SkPDFIndirectReference{fNextObjectNumber++}; }
125
126 SkExecutor* executor() const { return fExecutor; }
127 void incrementJobCount();
128 void signalJobComplete();
129 size_t currentPageIndex() { return fPages.size(); }
130 size_t pageCount() { return fPageRefs.size(); }
131
132 const SkMatrix& currentPageTransform() const;
133
134 // Canonicalized objects
135 SkTHashMap<SkPDFImageShaderKey, SkPDFIndirectReference> fImageShaderMap;
136 SkTHashMap<SkPDFGradientShader::Key, SkPDFIndirectReference, SkPDFGradientShader::KeyHash>
137 fGradientPatternMap;
138 SkTHashMap<SkBitmapKey, SkPDFIndirectReference> fPDFBitmapMap;
139 SkTHashMap<uint32_t, std::unique_ptr<SkAdvancedTypefaceMetrics>> fTypefaceMetrics;
140 SkTHashMap<uint32_t, std::vector<SkString>> fType1GlyphNames;
141 SkTHashMap<uint32_t, std::vector<SkUnichar>> fToUnicodeMap;
142 SkTHashMap<uint32_t, SkPDFIndirectReference> fFontDescriptors;
143 SkTHashMap<uint32_t, SkPDFIndirectReference> fType3FontDescriptors;
144 SkTHashMap<uint64_t, SkPDFFont> fFontMap;
145 SkTHashMap<SkPDFStrokeGraphicState, SkPDFIndirectReference> fStrokeGSMap;
146 SkTHashMap<SkPDFFillGraphicState, SkPDFIndirectReference> fFillGSMap;
147 SkPDFIndirectReference fInvertFunction;
148 SkPDFIndirectReference fNoSmaskGraphicState;
149 std::vector<std::unique_ptr<SkPDFLink>> fCurrentPageLinks;
150 std::vector<SkPDFNamedDestination> fNamedDestinations;
151
152private:
153 SkPDFOffsetMap fOffsetMap;
154 SkCanvas fCanvas;
155 std::vector<std::unique_ptr<SkPDFDict>> fPages;
156 std::vector<SkPDFIndirectReference> fPageRefs;
157
158 sk_sp<SkPDFDevice> fPageDevice;
159 std::atomic<int> fNextObjectNumber = {1};
160 std::atomic<int> fJobCount = {0};
161 SkUUID fUUID;
162 SkPDFIndirectReference fInfoDict;
163 SkPDFIndirectReference fXMP;
164 SkPDF::Metadata fMetadata;
165 SkScalar fRasterScale = 1;
166 SkScalar fInverseRasterScale = 1;
167 SkExecutor* fExecutor = nullptr;
168
169 // For tagged PDFs.
170 SkPDFTagTree fTagTree;
171
172 SkMutex fMutex;
173 SkSemaphore fSemaphore;
174
175 void waitForJobs();
176 SkWStream* beginObject(SkPDFIndirectReference);
177 void endObject();
178};
179
180#endif // SkPDFDocumentPriv_DEFINED
181