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