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