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