1 /*
2 * Copyright 2010 The Android Open Source Project
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
8 #ifndef SkPDFTypes_DEFINED
9 #define SkPDFTypes_DEFINED
10
11 #include "include/core/SkScalar.h"
12 #include "include/core/SkSpan.h"
13 #include "include/core/SkTypes.h"
14 #include "src/pdf/SkPDFUnion.h"
15
16 #include <cstddef>
17 #include <cstdint>
18 #include <memory>
19 #include <utility>
20 #include <vector>
21
22 class SkPDFDocument;
23 class SkStreamAsset;
24 class SkString;
25 class SkWStream;
26
27 #ifndef SK_PDF_MASK_QUALITY
28 // If MASK_QUALITY is in [0,100], will be used for JpegEncoder.
29 // Otherwise, just encode masks losslessly.
30 #define SK_PDF_MASK_QUALITY 50
31 // Since these masks are used for blurry shadows, we shouldn't need
32 // high quality. Raise this value if your shadows have visible JPEG
33 // artifacts.
34 // If SkJpegEncoder::Encode fails, we will fall back to the lossless
35 // encoding.
36 #endif
37
38 struct SkPDFIndirectReference {
39 int fValue = -1;
40 explicit operator bool() const { return fValue != -1; }
41
42 bool operator==(SkPDFIndirectReference v) const {
43 return fValue == v.fValue;
44 }
45
46 bool operator!=(SkPDFIndirectReference v) const {
47 return fValue != v.fValue;
48 }
49 };
50
51 /** \class SkPDFObject
52
53 A PDF Object is the base class for primitive elements in a PDF file. A
54 common subtype is used to ease the use of indirect object references,
55 which are common in the PDF format.
56
57 */
58 class SkPDFObject {
59 public:
60 SkPDFObject() = default;
61
62 /** Subclasses must implement this method to print the object to the
63 * PDF file.
64 * @param catalog The object catalog to use.
65 * @param stream The writable output stream to send the output to.
66 */
67 virtual void emitObject(SkWStream* stream) const = 0;
68
69 virtual ~SkPDFObject() = default;
70
71 private:
72 SkPDFObject(SkPDFObject&&) = delete;
73 SkPDFObject(const SkPDFObject&) = delete;
74 SkPDFObject& operator=(SkPDFObject&&) = delete;
75 SkPDFObject& operator=(const SkPDFObject&) = delete;
76 };
77
78 ////////////////////////////////////////////////////////////////////////////////
79
80 /** \class SkPDFArray
81
82 An array object in a PDF.
83 */
84 class SkPDFArray : public SkPDFObject {
85 public:
86 /** Create a PDF array. Maximum length is 8191.
87 */
88 SkPDFArray();
89 ~SkPDFArray() override;
90
91 // The SkPDFObject interface.
92 void emitObject(SkWStream* stream) const override;
93
94 /** The size of the array.
95 */
96 size_t size() const;
97
98 /** Preallocate space for the given number of entries.
99 * @param length The number of array slots to preallocate.
100 */
101 void reserve(int length);
102
103 /** Appends a value to the end of the array.
104 * @param value The value to add to the array.
105 */
106 void appendInt(int32_t);
107 void appendColorComponent(uint8_t);
108 void appendBool(bool);
109 void appendScalar(SkScalar);
110 void appendName(const char[]);
111 void appendName(SkString);
112 void appendByteString(const char[]);
113 void appendTextString(const char[]);
114 void appendByteString(SkString);
115 void appendTextString(SkString);
116 void appendObject(std::unique_ptr<SkPDFObject>&&);
117 void appendRef(SkPDFIndirectReference);
118
119 protected:
values()120 SkSpan<const SkPDFUnion> values() const { return SkSpan(fValues); }
121
122 private:
123 std::vector<SkPDFUnion> fValues;
124 void append(SkPDFUnion&& value);
125 };
126
SkPDFArray_Append(SkPDFArray * a,int v)127 static inline void SkPDFArray_Append(SkPDFArray* a, int v) { a->appendInt(v); }
128
SkPDFArray_Append(SkPDFArray * a,SkScalar v)129 static inline void SkPDFArray_Append(SkPDFArray* a, SkScalar v) { a->appendScalar(v); }
130
131 template <typename T, typename... Args>
SkPDFArray_Append(SkPDFArray * a,T v,Args...args)132 static inline void SkPDFArray_Append(SkPDFArray* a, T v, Args... args) {
133 SkPDFArray_Append(a, v);
134 SkPDFArray_Append(a, args...);
135 }
136
SkPDFArray_Append(SkPDFArray * a)137 static inline void SkPDFArray_Append(SkPDFArray* a) {}
138
139 template <typename... Args>
SkPDFMakeArray(Args...args)140 static inline std::unique_ptr<SkPDFArray> SkPDFMakeArray(Args... args) {
141 std::unique_ptr<SkPDFArray> ret(new SkPDFArray());
142 ret->reserve(sizeof...(Args));
143 SkPDFArray_Append(ret.get(), args...);
144 return ret;
145 }
146
147 /** \class SkPDFOptionalArray
148 *
149 * An SkPDFArray which may be emitted as a non-array if it contains a single entry.
150 * Search the specification for "or an array" for where this can be used.
151 */
152 class SkPDFOptionalArray final : public SkPDFArray {
153 void emitObject(SkWStream* stream) const override;
154 };
155
156 /** \class SkPDFDict
157
158 A dictionary object in a PDF.
159 */
160 class SkPDFDict final : public SkPDFObject {
161 public:
162 /** Create a PDF dictionary.
163 * @param type The value of the Type entry, nullptr for no type.
164 */
165 explicit SkPDFDict(const char type[] = nullptr);
166
167 ~SkPDFDict() override;
168
169 // The SkPDFObject interface.
170 void emitObject(SkWStream* stream) const override;
171
172 /** The size of the dictionary.
173 */
174 size_t size() const;
175
176 /** Preallocate space for n key-value pairs */
177 void reserve(int n);
178
179 /** Add the value to the dictionary with the given key.
180 * @param key The text of the key for this dictionary entry.
181 * @param value The value for this dictionary entry.
182 */
183 void insertObject(const char key[], std::unique_ptr<SkPDFObject>&&);
184 void insertObject(SkString, std::unique_ptr<SkPDFObject>&&);
185 void insertRef(const char key[], SkPDFIndirectReference);
186 void insertRef(SkString, SkPDFIndirectReference);
187
188 /** Add the value to the dictionary with the given key.
189 * @param key The text of the key for this dictionary entry.
190 * @param value The value for this dictionary entry.
191 */
192 void insertBool(const char key[], bool value);
193 void insertInt(const char key[], int32_t value);
194 void insertInt(const char key[], size_t value);
195 void insertScalar(const char key[], SkScalar value);
196 void insertColorComponentF(const char key[], SkScalar value);
197 void insertName(const char key[], const char nameValue[]);
198 void insertName(const char key[], SkString nameValue);
199 void insertByteString(const char key[], const char value[]);
200 void insertTextString(const char key[], const char value[]);
201 void insertByteString(const char key[], SkString value);
202 void insertTextString(const char key[], SkString value);
203 void insertUnion(const char key[], SkPDFUnion&&);
204
205 private:
206 std::vector<std::pair<SkPDFUnion, SkPDFUnion>> fRecords;
207 };
208
209 static inline std::unique_ptr<SkPDFDict> SkPDFMakeDict(const char* type = nullptr) {
210 return std::make_unique<SkPDFDict>(type);
211 }
212
213 enum class SkPDFSteamCompressionEnabled : bool {
214 No = false,
215 Yes = true,
216 };
217
218 // Exposed for unit testing.
219 void SkPDFWriteTextString(SkWStream* wStream, const char* cin, size_t len);
220 void SkPDFWriteByteString(SkWStream* wStream, const char* cin, size_t len);
221
222 SkPDFIndirectReference SkPDFStreamOut(
223 std::unique_ptr<SkPDFDict> dict,
224 std::unique_ptr<SkStreamAsset> stream,
225 SkPDFDocument* doc,
226 SkPDFSteamCompressionEnabled compress = SkPDFSteamCompressionEnabled::Yes);
227 #endif
228