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