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 
22 class SkExecutor;
23 class SkPDFDevice;
24 class SkPDFFont;
25 struct SkAdvancedTypefaceMetrics;
26 struct SkBitmapKey;
27 struct SkPDFFillGraphicState;
28 struct SkPDFImageShaderKey;
29 struct SkPDFStrokeGraphicState;
30 
31 namespace SkPDFGradientShader {
32 struct Key;
33 struct KeyHash;
34 }  // namespace SkPDFGradientShader
35 
36 const char* SkPDFGetNodeIdKey();
37 
38 // Logically part of SkPDFDocument, but separate to keep similar functionality together.
39 class SkPDFOffsetMap {
40 public:
41     void markStartOfDocument(const SkWStream*);
42     void markStartOfObject(int referenceNumber, const SkWStream*);
43     int objectCount() const;
44     int emitCrossReferenceTable(SkWStream* s) const;
45 private:
46     std::vector<int> fOffsets;
47     size_t fBaseOffset = SIZE_MAX;
48 };
49 
50 
51 struct SkPDFNamedDestination {
52     sk_sp<SkData> fName;
53     SkPoint fPoint;
54     SkPDFIndirectReference fPage;
55 };
56 
57 
58 struct SkPDFLink {
59     enum class Type {
60         kNone,
61         kUrl,
62         kNamedDestination,
63     };
64 
SkPDFLinkSkPDFLink65     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. */
81 class SkPDFDocument : public SkDocument {
82 public:
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);
emit(const SkPDFObject & o)100     SkPDFIndirectReference emit(const SkPDFObject& o) { return this->emit(o, this->reserveRef()); }
101 
102     template <typename T>
emitStream(const SkPDFDict & dict,T writeStream,SkPDFIndirectReference ref)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 
metadata()113     const SkPDF::Metadata& metadata() const { return fMetadata; }
114 
115     SkPDFIndirectReference getPage(size_t pageIndex) const;
currentPage()116     SkPDFIndirectReference currentPage() const {
117         return SkASSERT(!fPageRefs.empty()), fPageRefs.back();
118     }
119     // Used to allow marked content to refer to its corresponding structure
120     // tree node, via a page entry in the parent tree. Returns -1 if no
121     // mark ID.
122     int createMarkIdForNodeId(int nodeId);
123     // Used to allow annotations to refer to their corresponding structure
124     // tree node, via the struct parent tree. Returns -1 if no struct parent
125     // key.
126     int createStructParentKeyForNodeId(int nodeId);
127 
128     std::unique_ptr<SkPDFArray> getAnnotations();
129 
reserveRef()130     SkPDFIndirectReference reserveRef() { return SkPDFIndirectReference{fNextObjectNumber++}; }
131 
executor()132     SkExecutor* executor() const { return fExecutor; }
133     void incrementJobCount();
134     void signalJobComplete();
currentPageIndex()135     size_t currentPageIndex() { return fPages.size(); }
pageCount()136     size_t pageCount() { return fPageRefs.size(); }
137 
138     const SkMatrix& currentPageTransform() const;
139 
140     // Canonicalized objects
141     SkTHashMap<SkPDFImageShaderKey, SkPDFIndirectReference> fImageShaderMap;
142     SkTHashMap<SkPDFGradientShader::Key, SkPDFIndirectReference, SkPDFGradientShader::KeyHash>
143         fGradientPatternMap;
144     SkTHashMap<SkBitmapKey, SkPDFIndirectReference> fPDFBitmapMap;
145     SkTHashMap<uint32_t, std::unique_ptr<SkAdvancedTypefaceMetrics>> fTypefaceMetrics;
146     SkTHashMap<uint32_t, std::vector<SkString>> fType1GlyphNames;
147     SkTHashMap<uint32_t, std::vector<SkUnichar>> fToUnicodeMap;
148     SkTHashMap<uint32_t, SkPDFIndirectReference> fFontDescriptors;
149     SkTHashMap<uint32_t, SkPDFIndirectReference> fType3FontDescriptors;
150     SkTHashMap<uint64_t, SkPDFFont> fFontMap;
151     SkTHashMap<SkPDFStrokeGraphicState, SkPDFIndirectReference> fStrokeGSMap;
152     SkTHashMap<SkPDFFillGraphicState, SkPDFIndirectReference> fFillGSMap;
153     SkPDFIndirectReference fInvertFunction;
154     SkPDFIndirectReference fNoSmaskGraphicState;
155     std::vector<std::unique_ptr<SkPDFLink>> fCurrentPageLinks;
156     std::vector<SkPDFNamedDestination> fNamedDestinations;
157 
158 private:
159     SkPDFOffsetMap fOffsetMap;
160     SkCanvas fCanvas;
161     std::vector<std::unique_ptr<SkPDFDict>> fPages;
162     std::vector<SkPDFIndirectReference> fPageRefs;
163 
164     sk_sp<SkPDFDevice> fPageDevice;
165     std::atomic<int> fNextObjectNumber = {1};
166     std::atomic<int> fJobCount = {0};
167     SkUUID fUUID;
168     SkPDFIndirectReference fInfoDict;
169     SkPDFIndirectReference fXMP;
170     SkPDF::Metadata fMetadata;
171     SkScalar fRasterScale = 1;
172     SkScalar fInverseRasterScale = 1;
173     SkExecutor* fExecutor = nullptr;
174 
175     // For tagged PDFs.
176     SkPDFTagTree fTagTree;
177 
178     SkMutex fMutex;
179     SkSemaphore fSemaphore;
180 
181     void waitForJobs();
182     SkWStream* beginObject(SkPDFIndirectReference);
183     void endObject();
184 };
185 
186 #endif  // SkPDFDocumentPriv_DEFINED
187