• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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