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