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 "SkRefCnt.h"
12 #include "SkScalar.h"
13 #include "SkTHash.h"
14 #include "SkTo.h"
15 #include "SkTypes.h"
16 #include "SkMakeUnique.h"
17 
18 #include <new>
19 #include <type_traits>
20 #include <utility>
21 #include <vector>
22 #include <memory>
23 
24 class SkData;
25 class SkPDFArray;
26 
27 class SkPDFDict;
28 class SkPDFDocument;
29 class SkPDFObject;
30 class SkPDFUnion;
31 class SkStreamAsset;
32 class SkString;
33 class SkWStream;
34 struct SkPDFObjectSerializer;
35 
36 struct SkPDFIndirectReference {
37     int fValue = -1;
38     explicit operator bool() { return fValue != -1; }
39 };
40 
41 inline static bool operator==(SkPDFIndirectReference u, SkPDFIndirectReference v) {
42     return u.fValue == v.fValue;
43 }
44 
45 inline static bool operator!=(SkPDFIndirectReference u, SkPDFIndirectReference v) {
46     return u.fValue != v.fValue;
47 }
48 
49 /** \class SkPDFObject
50 
51     A PDF Object is the base class for primitive elements in a PDF file.  A
52     common subtype is used to ease the use of indirect object references,
53     which are common in the PDF format.
54 
55 */
56 class SkPDFObject {
57 public:
58     SkPDFObject() = default;
59 
60     /** Subclasses must implement this method to print the object to the
61      *  PDF file.
62      *  @param catalog  The object catalog to use.
63      *  @param stream   The writable output stream to send the output to.
64      */
65     virtual void emitObject(SkWStream* stream) const = 0;
66 
67     virtual ~SkPDFObject() = default;
68 
69 private:
70     SkPDFObject(SkPDFObject&&) = delete;
71     SkPDFObject(const SkPDFObject&) = delete;
72     SkPDFObject& operator=(SkPDFObject&&) = delete;
73     SkPDFObject& operator=(const SkPDFObject&) = delete;
74 };
75 
76 ////////////////////////////////////////////////////////////////////////////////
77 
78 /** \class SkPDFArray
79 
80     An array object in a PDF.
81 */
82 class SkPDFArray final : public SkPDFObject {
83 public:
84     /** Create a PDF array. Maximum length is 8191.
85      */
86     SkPDFArray();
87     ~SkPDFArray() override;
88 
89     // The SkPDFObject interface.
90     void emitObject(SkWStream* stream) const override;
91 
92     /** The size of the array.
93      */
94     size_t size() const;
95 
96     /** Preallocate space for the given number of entries.
97      *  @param length The number of array slots to preallocate.
98      */
99     void reserve(int length);
100 
101     /** Appends a value to the end of the array.
102      *  @param value The value to add to the array.
103      */
104     void appendInt(int32_t);
105     void appendColorComponent(uint8_t);
106     void appendBool(bool);
107     void appendScalar(SkScalar);
108     void appendName(const char[]);
109     void appendName(SkString);
110     void appendString(const char[]);
111     void appendString(SkString);
112     void appendObject(std::unique_ptr<SkPDFObject>&&);
113     void appendRef(SkPDFIndirectReference);
114 
115 private:
116     std::vector<SkPDFUnion> fValues;
117     void append(SkPDFUnion&& value);
118 };
119 
120 static inline void SkPDFArray_Append(SkPDFArray* a, int v) { a->appendInt(v); }
121 
122 static inline void SkPDFArray_Append(SkPDFArray* a, SkScalar v) { a->appendScalar(v); }
123 
124 template <typename T, typename... Args>
125 static inline void SkPDFArray_Append(SkPDFArray* a, T v, Args... args) {
126     SkPDFArray_Append(a, v);
127     SkPDFArray_Append(a, args...);
128 }
129 
130 static inline void SkPDFArray_Append(SkPDFArray* a) {}
131 
132 template <typename... Args>
133 static inline std::unique_ptr<SkPDFArray> SkPDFMakeArray(Args... args) {
134     std::unique_ptr<SkPDFArray> ret(new SkPDFArray());
135     ret->reserve(sizeof...(Args));
136     SkPDFArray_Append(ret.get(), args...);
137     return ret;
138 }
139 
140 /** \class SkPDFDict
141 
142     A dictionary object in a PDF.
143 */
144 class SkPDFDict final : public SkPDFObject {
145 public:
146     /** Create a PDF dictionary.
147      *  @param type   The value of the Type entry, nullptr for no type.
148      */
149     explicit SkPDFDict(const char type[] = nullptr);
150 
151     ~SkPDFDict() override;
152 
153     // The SkPDFObject interface.
154     void emitObject(SkWStream* stream) const override;
155 
156     /** The size of the dictionary.
157      */
158     size_t size() const;
159 
160     /** Preallocate space for n key-value pairs */
161     void reserve(int n);
162 
163     /** Add the value to the dictionary with the given key.
164      *  @param key   The text of the key for this dictionary entry.
165      *  @param value The value for this dictionary entry.
166      */
167     void insertObject(const char key[], std::unique_ptr<SkPDFObject>&&);
168     void insertObject(SkString, std::unique_ptr<SkPDFObject>&&);
169     void insertRef(const char key[], SkPDFIndirectReference);
170     void insertRef(SkString, SkPDFIndirectReference);
171 
172     /** Add the value to the dictionary with the given key.
173      *  @param key   The text of the key for this dictionary entry.
174      *  @param value The value for this dictionary entry.
175      */
176     void insertBool(const char key[], bool value);
177     void insertInt(const char key[], int32_t value);
178     void insertInt(const char key[], size_t value);
179     void insertScalar(const char key[], SkScalar value);
180     void insertColorComponentF(const char key[], SkScalar value);
181     void insertName(const char key[], const char nameValue[]);
182     void insertName(const char key[], SkString nameValue);
183     void insertString(const char key[], const char value[]);
184     void insertString(const char key[], SkString value);
185 
186 private:
187     std::vector<std::pair<SkPDFUnion, SkPDFUnion>> fRecords;
188 };
189 
190 static inline std::unique_ptr<SkPDFDict> SkPDFMakeDict(const char* type = nullptr) {
191     return std::unique_ptr<SkPDFDict>(new SkPDFDict(type));
192 }
193 
194 #ifdef SK_PDF_LESS_COMPRESSION
195     static constexpr bool kSkPDFDefaultDoDeflate = false;
196 #else
197     static constexpr bool kSkPDFDefaultDoDeflate = true;
198 #endif
199 
200 SkPDFIndirectReference SkPDFStreamOut(std::unique_ptr<SkPDFDict> dict,
201                                       std::unique_ptr<SkStreamAsset> stream,
202                                       SkPDFDocument* doc,
203                                       bool deflate = kSkPDFDefaultDoDeflate);
204 #endif
205