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 kTFoot, //!< 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 appendString(const char* owner, const char* name, const char* value);
92 void appendFloatArray(const char* owner,
93 const char* name,
94 const std::vector<float>& value);
95 void appendStringArray(const char* owner,
96 const char* name,
97 const std::vector<SkString>& value);
98
99 private:
100 friend class ::SkPDFTagTree;
101
102 std::unique_ptr<SkPDFArray> fAttrs;
103 };
104
105 /** A node in a PDF structure tree, giving a semantic representation
106 of the content. Each node ID is associated with content
107 by passing the SkCanvas and node ID to SkPDF::SetNodeId() when drawing.
108 NodeIDs should be unique within each tree.
109 */
110 struct StructureElementNode {
111 SkString fTypeString;
112 std::vector<std::unique_ptr<StructureElementNode>> fChildVector;
113 int fNodeId = 0;
114 AttributeList fAttributes;
115 SkString fAlt;
116 SkString fLang;
117
118 // Deprecated. Use fChildVector instead.
119 StructureElementNode* fChildren = nullptr;
120 size_t fChildCount = 0;
121
122 // Deprecated. Use fTypeString instead.
123 DocumentStructureType fType = DocumentStructureType::kNonStruct;
124 };
125
126 /** Optional metadata to be passed into the PDF factory function.
127 */
128 struct Metadata {
129 /** The document's title.
130 */
131 SkString fTitle;
132
133 /** The name of the person who created the document.
134 */
135 SkString fAuthor;
136
137 /** The subject of the document.
138 */
139 SkString fSubject;
140
141 /** Keywords associated with the document. Commas may be used to delineate
142 keywords within the string.
143 */
144 SkString fKeywords;
145
146 /** If the document was converted to PDF from another format,
147 the name of the conforming product that created the
148 original document from which it was converted.
149 */
150 SkString fCreator;
151
152 /** The product that is converting this document to PDF.
153 */
154 SkString fProducer = SkString("Skia/PDF m" SKPDF_STRING(SK_MILESTONE));
155
156 /** The date and time the document was created.
157 The zero default value represents an unknown/unset time.
158 */
159 SkTime::DateTime fCreation = {0, 0, 0, 0, 0, 0, 0, 0};
160
161 /** The date and time the document was most recently modified.
162 The zero default value represents an unknown/unset time.
163 */
164 SkTime::DateTime fModified = {0, 0, 0, 0, 0, 0, 0, 0};
165
166 /** The DPI (pixels-per-inch) at which features without native PDF support
167 will be rasterized (e.g. draw image with perspective, draw text with
168 perspective, ...) A larger DPI would create a PDF that reflects the
169 original intent with better fidelity, but it can make for larger PDF
170 files too, which would use more memory while rendering, and it would be
171 slower to be processed or sent online or to printer.
172 */
173 SkScalar fRasterDPI = SK_ScalarDefaultRasterDPI;
174
175 /** If true, include XMP metadata, a document UUID, and sRGB output intent
176 information. This adds length to the document and makes it
177 non-reproducable, but are necessary features for PDF/A-2b conformance
178 */
179 bool fPDFA = false;
180
181 /** Encoding quality controls the trade-off between size and quality. By
182 default this is set to 101 percent, which corresponds to lossless
183 encoding. If this value is set to a value <= 100, and the image is
184 opaque, it will be encoded (using JPEG) with that quality setting.
185 */
186 int fEncodingQuality = 101;
187
188 /** An optional tree of structured document tags that provide
189 a semantic representation of the content. The caller
190 should retain ownership.
191 */
192 StructureElementNode* fStructureElementTreeRoot = nullptr;
193
194 /** Executor to handle threaded work within PDF Backend. If this is nullptr,
195 then all work will be done serially on the main thread. To have worker
196 threads assist with various tasks, set this to a valid SkExecutor
197 instance. Currently used for executing Deflate algorithm in parallel.
198
199 If set, the PDF output will be non-reproducible in the order and
200 internal numbering of objects, but should render the same.
201
202 Experimental.
203 */
204 SkExecutor* fExecutor = nullptr;
205
206 /** Preferred Subsetter. Only respected if both are compiled in.
207
208 The Sfntly subsetter is deprecated.
209
210 Experimental.
211 */
212 enum Subsetter {
213 kHarfbuzz_Subsetter,
214 kSfntly_Subsetter,
215 } fSubsetter = kHarfbuzz_Subsetter;
216 };
217
218 /** Associate a node ID with subsequent drawing commands in an
219 SkCanvas. The same node ID can appear in a StructureElementNode
220 in order to associate a document's structure element tree with
221 its content.
222
223 A node ID of zero indicates no node ID.
224
225 @param canvas The canvas used to draw to the PDF.
226 @param nodeId The node ID for subsequent drawing commands.
227 */
228 SK_API void SetNodeId(SkCanvas* dst, int nodeID);
229
230 /** Create a PDF-backed document, writing the results into a SkWStream.
231
232 PDF pages are sized in point units. 1 pt == 1/72 inch == 127/360 mm.
233
234 @param stream A PDF document will be written to this stream. The document may write
235 to the stream at anytime during its lifetime, until either close() is
236 called or the document is deleted.
237 @param metadata a PDFmetadata object. Any fields may be left empty.
238
239 @returns NULL if there is an error, otherwise a newly created PDF-backed SkDocument.
240 */
241 SK_API sk_sp<SkDocument> MakeDocument(SkWStream* stream, const Metadata& metadata);
242
MakeDocument(SkWStream * stream)243 static inline sk_sp<SkDocument> MakeDocument(SkWStream* stream) {
244 return MakeDocument(stream, Metadata());
245 }
246
247 } // namespace SkPDF
248
249 #undef SKPDF_STRING
250 #undef SKPDF_STRING_IMPL
251 #endif // SkPDFDocument_DEFINED
252