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