| 1 | // Copyright 2018 Google LLC. |
| 2 | // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. |
| 3 | #ifndef SkPDFDocument_DEFINED |
| 4 | #define SkPDFDocument_DEFINED |
| 5 | |
| 6 | #include "include/core/SkDocument.h" |
| 7 | |
| 8 | #include <vector> |
| 9 | |
| 10 | #include "include/core/SkColor.h" |
| 11 | #include "include/core/SkMilestone.h" |
| 12 | #include "include/core/SkScalar.h" |
| 13 | #include "include/core/SkString.h" |
| 14 | #include "include/core/SkTime.h" |
| 15 | #include "include/private/SkNoncopyable.h" |
| 16 | |
| 17 | #define SKPDF_STRING(X) SKPDF_STRING_IMPL(X) |
| 18 | #define SKPDF_STRING_IMPL(X) #X |
| 19 | |
| 20 | class SkExecutor; |
| 21 | class SkPDFArray; |
| 22 | class SkPDFTagTree; |
| 23 | |
| 24 | namespace SkPDF { |
| 25 | |
| 26 | /** Table 333 in PDF 32000-1:2008 ยง14.8.4.2 |
| 27 | */ |
| 28 | enum class DocumentStructureType { |
| 29 | kDocument, //!< Document |
| 30 | kPart, //!< Part |
| 31 | kArt, //!< Article |
| 32 | kSect, //!< Section |
| 33 | kDiv, //!< Division |
| 34 | kBlockQuote, //!< Block quotation |
| 35 | kCaption, //!< Caption |
| 36 | kTOC, //!< Table of Contents |
| 37 | kTOCI, //!< Table of Contents Item |
| 38 | kIndex, //!< Index |
| 39 | kNonStruct, //!< Nonstructural element |
| 40 | kPrivate, //!< Private element |
| 41 | kH, //!< Heading |
| 42 | kH1, //!< Heading level 1 |
| 43 | kH2, //!< Heading level 2 |
| 44 | kH3, //!< Heading level 3 |
| 45 | kH4, //!< Heading level 4 |
| 46 | kH5, //!< Heading level 5 |
| 47 | kH6, //!< Heading level 6 |
| 48 | kP, //!< Paragraph |
| 49 | kL, //!< List |
| 50 | kLI, //!< List item |
| 51 | kLbl, //!< List item label |
| 52 | kLBody, //!< List item body |
| 53 | kTable, //!< Table |
| 54 | kTR, //!< Table row |
| 55 | kTH, //!< Table header cell |
| 56 | kTD, //!< Table data cell |
| 57 | kTHead, //!< Table header row group |
| 58 | kTBody, //!< Table body row group |
| 59 | , //!< table footer row group |
| 60 | kSpan, //!< Span |
| 61 | kQuote, //!< Quotation |
| 62 | kNote, //!< Note |
| 63 | kReference, //!< Reference |
| 64 | kBibEntry, //!< Bibliography entry |
| 65 | kCode, //!< Code |
| 66 | kLink, //!< Link |
| 67 | kAnnot, //!< Annotation |
| 68 | kRuby, //!< Ruby annotation |
| 69 | kRB, //!< Ruby base text |
| 70 | kRT, //!< Ruby annotation text |
| 71 | kRP, //!< Ruby punctuation |
| 72 | kWarichu, //!< Warichu annotation |
| 73 | kWT, //!< Warichu text |
| 74 | kWP, //!< Warichu punctuation |
| 75 | kFigure, //!< Figure |
| 76 | kFormula, //!< Formula |
| 77 | kForm, //!< Form control (not like an HTML FORM element) |
| 78 | }; |
| 79 | |
| 80 | /** Attributes for nodes in the PDF tree. */ |
| 81 | class SK_API AttributeList : SkNoncopyable { |
| 82 | public: |
| 83 | AttributeList(); |
| 84 | ~AttributeList(); |
| 85 | |
| 86 | // Each attribute must have an owner (e.g. "Layout", "List", "Table", etc) |
| 87 | // and an attribute name (e.g. "BBox", "RowSpan", etc.) from PDF32000_2008 14.8.5, |
| 88 | // and then a value of the proper type according to the spec. |
| 89 | void appendInt(const char* owner, const char* name, int value); |
| 90 | void appendFloat(const char* owner, const char* name, float value); |
| 91 | void appendName(const char* owner, const char* attrName, const char* value); |
| 92 | void appendString(const char* owner, const char* attrName, const char* value); |
| 93 | void appendFloatArray(const char* owner, |
| 94 | const char* name, |
| 95 | const std::vector<float>& value); |
| 96 | // Deprecated. |
| 97 | void appendStringArray(const char* owner, |
| 98 | const char* attrName, |
| 99 | const std::vector<SkString>& values); |
| 100 | void appendNodeIdArray(const char* owner, |
| 101 | const char* attrName, |
| 102 | const std::vector<int>& nodeIds); |
| 103 | |
| 104 | private: |
| 105 | friend class ::SkPDFTagTree; |
| 106 | |
| 107 | std::unique_ptr<SkPDFArray> fAttrs; |
| 108 | }; |
| 109 | |
| 110 | /** A node in a PDF structure tree, giving a semantic representation |
| 111 | of the content. Each node ID is associated with content |
| 112 | by passing the SkCanvas and node ID to SkPDF::SetNodeId() when drawing. |
| 113 | NodeIDs should be unique within each tree. |
| 114 | */ |
| 115 | struct StructureElementNode { |
| 116 | SkString fTypeString; |
| 117 | std::vector<std::unique_ptr<StructureElementNode>> fChildVector; |
| 118 | int fNodeId = 0; |
| 119 | std::vector<int> fAdditionalNodeIds; |
| 120 | AttributeList fAttributes; |
| 121 | SkString fAlt; |
| 122 | SkString fLang; |
| 123 | |
| 124 | // Deprecated. Use fTypeString instead. |
| 125 | DocumentStructureType fType = DocumentStructureType::kNonStruct; |
| 126 | }; |
| 127 | |
| 128 | /** Optional metadata to be passed into the PDF factory function. |
| 129 | */ |
| 130 | struct Metadata { |
| 131 | /** The document's title. |
| 132 | */ |
| 133 | SkString fTitle; |
| 134 | |
| 135 | /** The name of the person who created the document. |
| 136 | */ |
| 137 | SkString fAuthor; |
| 138 | |
| 139 | /** The subject of the document. |
| 140 | */ |
| 141 | SkString fSubject; |
| 142 | |
| 143 | /** Keywords associated with the document. Commas may be used to delineate |
| 144 | keywords within the string. |
| 145 | */ |
| 146 | SkString fKeywords; |
| 147 | |
| 148 | /** If the document was converted to PDF from another format, |
| 149 | the name of the conforming product that created the |
| 150 | original document from which it was converted. |
| 151 | */ |
| 152 | SkString fCreator; |
| 153 | |
| 154 | /** The product that is converting this document to PDF. |
| 155 | */ |
| 156 | SkString fProducer = SkString("Skia/PDF m" SKPDF_STRING(SK_MILESTONE)); |
| 157 | |
| 158 | /** The date and time the document was created. |
| 159 | The zero default value represents an unknown/unset time. |
| 160 | */ |
| 161 | SkTime::DateTime fCreation = {0, 0, 0, 0, 0, 0, 0, 0}; |
| 162 | |
| 163 | /** The date and time the document was most recently modified. |
| 164 | The zero default value represents an unknown/unset time. |
| 165 | */ |
| 166 | SkTime::DateTime fModified = {0, 0, 0, 0, 0, 0, 0, 0}; |
| 167 | |
| 168 | /** The DPI (pixels-per-inch) at which features without native PDF support |
| 169 | will be rasterized (e.g. draw image with perspective, draw text with |
| 170 | perspective, ...) A larger DPI would create a PDF that reflects the |
| 171 | original intent with better fidelity, but it can make for larger PDF |
| 172 | files too, which would use more memory while rendering, and it would be |
| 173 | slower to be processed or sent online or to printer. |
| 174 | */ |
| 175 | SkScalar fRasterDPI = SK_ScalarDefaultRasterDPI; |
| 176 | |
| 177 | /** If true, include XMP metadata, a document UUID, and sRGB output intent |
| 178 | information. This adds length to the document and makes it |
| 179 | non-reproducable, but are necessary features for PDF/A-2b conformance |
| 180 | */ |
| 181 | bool fPDFA = false; |
| 182 | |
| 183 | /** Encoding quality controls the trade-off between size and quality. By |
| 184 | default this is set to 101 percent, which corresponds to lossless |
| 185 | encoding. If this value is set to a value <= 100, and the image is |
| 186 | opaque, it will be encoded (using JPEG) with that quality setting. |
| 187 | */ |
| 188 | int fEncodingQuality = 101; |
| 189 | |
| 190 | /** An optional tree of structured document tags that provide |
| 191 | a semantic representation of the content. The caller |
| 192 | should retain ownership. |
| 193 | */ |
| 194 | StructureElementNode* fStructureElementTreeRoot = nullptr; |
| 195 | |
| 196 | /** Executor to handle threaded work within PDF Backend. If this is nullptr, |
| 197 | then all work will be done serially on the main thread. To have worker |
| 198 | threads assist with various tasks, set this to a valid SkExecutor |
| 199 | instance. Currently used for executing Deflate algorithm in parallel. |
| 200 | |
| 201 | If set, the PDF output will be non-reproducible in the order and |
| 202 | internal numbering of objects, but should render the same. |
| 203 | |
| 204 | Experimental. |
| 205 | */ |
| 206 | SkExecutor* fExecutor = nullptr; |
| 207 | |
| 208 | /** Preferred Subsetter. Only respected if both are compiled in. |
| 209 | |
| 210 | The Sfntly subsetter is deprecated. |
| 211 | |
| 212 | Experimental. |
| 213 | */ |
| 214 | enum Subsetter { |
| 215 | kHarfbuzz_Subsetter, |
| 216 | kSfntly_Subsetter, |
| 217 | } fSubsetter = kHarfbuzz_Subsetter; |
| 218 | }; |
| 219 | |
| 220 | /** Associate a node ID with subsequent drawing commands in an |
| 221 | SkCanvas. The same node ID can appear in a StructureElementNode |
| 222 | in order to associate a document's structure element tree with |
| 223 | its content. |
| 224 | |
| 225 | A node ID of zero indicates no node ID. |
| 226 | |
| 227 | @param canvas The canvas used to draw to the PDF. |
| 228 | @param nodeId The node ID for subsequent drawing commands. |
| 229 | */ |
| 230 | SK_API void SetNodeId(SkCanvas* dst, int nodeID); |
| 231 | |
| 232 | /** Create a PDF-backed document, writing the results into a SkWStream. |
| 233 | |
| 234 | PDF pages are sized in point units. 1 pt == 1/72 inch == 127/360 mm. |
| 235 | |
| 236 | @param stream A PDF document will be written to this stream. The document may write |
| 237 | to the stream at anytime during its lifetime, until either close() is |
| 238 | called or the document is deleted. |
| 239 | @param metadata a PDFmetadata object. Any fields may be left empty. |
| 240 | |
| 241 | @returns NULL if there is an error, otherwise a newly created PDF-backed SkDocument. |
| 242 | */ |
| 243 | SK_API sk_sp<SkDocument> MakeDocument(SkWStream* stream, const Metadata& metadata); |
| 244 | |
| 245 | static inline sk_sp<SkDocument> MakeDocument(SkWStream* stream) { |
| 246 | return MakeDocument(stream, Metadata()); |
| 247 | } |
| 248 | |
| 249 | } // namespace SkPDF |
| 250 | |
| 251 | #undef SKPDF_STRING |
| 252 | #undef SKPDF_STRING_IMPL |
| 253 | #endif // SkPDFDocument_DEFINED |
| 254 | |