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 
9 #ifndef SkPDFTypes_DEFINED
10 #define SkPDFTypes_DEFINED
11 
12 #include "SkRefCnt.h"
13 #include "SkScalar.h"
14 #include "SkTHash.h"
15 #include "SkTypes.h"
16 
17 class SkData;
18 class SkPDFObjNumMap;
19 class SkPDFObject;
20 class SkStreamAsset;
21 class SkString;
22 class SkWStream;
23 
24 #ifdef SK_PDF_IMAGE_STATS
25 #include "SkAtomics.h"
26 #endif
27 
28 /** \class SkPDFObject
29 
30     A PDF Object is the base class for primitive elements in a PDF file.  A
31     common subtype is used to ease the use of indirect object references,
32     which are common in the PDF format.
33 
34 */
35 class SkPDFObject : public SkRefCnt {
36 public:
37     /** Subclasses must implement this method to print the object to the
38      *  PDF file.
39      *  @param catalog  The object catalog to use.
40      *  @param stream   The writable output stream to send the output to.
41      */
42     virtual void emitObject(SkWStream* stream,
43                             const SkPDFObjNumMap& objNumMap) const = 0;
44 
45     /**
46      *  Adds all transitive dependencies of this object to the
47      *  catalog.  Implementations should respect the catalog's object
48      *  substitution map.
49      */
addResources(SkPDFObjNumMap * catalog)50     virtual void addResources(SkPDFObjNumMap* catalog) const {}
51 
52     /**
53      *  Release all resources associated with this SkPDFObject.  It is
54      *  an error to call emitObject() or addResources() after calling
55      *  drop().
56      */
drop()57     virtual void drop() {}
58 
~SkPDFObject()59     virtual ~SkPDFObject() {}
60 private:
61     typedef SkRefCnt INHERITED;
62 };
63 
64 ////////////////////////////////////////////////////////////////////////////////
65 
66 /**
67    A SkPDFUnion is a non-virtualized implementation of the
68    non-compound, non-specialized PDF Object types: Name, String,
69    Number, Boolean.
70  */
71 class SkPDFUnion {
72 public:
73     // Move contstructor and assignemnt operator destroy the argument
74     // and steal their references (if needed).
75     SkPDFUnion(SkPDFUnion&& other);
76     SkPDFUnion& operator=(SkPDFUnion&& other);
77 
78     ~SkPDFUnion();
79 
80     /** The following nine functions are the standard way of creating
81         SkPDFUnion objects. */
82 
83     static SkPDFUnion Int(int32_t);
84 
Int(size_t v)85     static SkPDFUnion Int(size_t v) { return SkPDFUnion::Int(SkToS32(v)); }
86 
87     static SkPDFUnion Bool(bool);
88 
89     static SkPDFUnion Scalar(SkScalar);
90 
91     static SkPDFUnion ColorComponent(uint8_t);
92 
93     /** These two functions do NOT take ownership of char*, and do NOT
94         copy the string.  Suitable for passing in static const
95         strings. For example:
96           SkPDFUnion n = SkPDFUnion::Name("Length");
97           SkPDFUnion u = SkPDFUnion::String("Identity"); */
98 
99     /** SkPDFUnion::Name(const char*) assumes that the passed string
100         is already a valid name (that is: it has no control or
101         whitespace characters).  This will not copy the name. */
102     static SkPDFUnion Name(const char*);
103 
104     /** SkPDFUnion::String will encode the passed string.  This will
105         not copy the name. */
106     static SkPDFUnion String(const char*);
107 
108     /** SkPDFUnion::Name(const SkString&) does not assume that the
109         passed string is already a valid name and it will escape the
110         string. */
111     static SkPDFUnion Name(const SkString&);
112 
113     /** SkPDFUnion::String will encode the passed string. */
114     static SkPDFUnion String(const SkString&);
115 
116     static SkPDFUnion Object(sk_sp<SkPDFObject>);
117     static SkPDFUnion ObjRef(sk_sp<SkPDFObject>);
118 
119     /** These two non-virtual methods mirror SkPDFObject's
120         corresponding virtuals. */
121     void emitObject(SkWStream*, const SkPDFObjNumMap&) const;
122     void addResources(SkPDFObjNumMap*) const;
123 
124     bool isName() const;
125 
126 private:
127     union {
128         int32_t fIntValue;
129         bool fBoolValue;
130         SkScalar fScalarValue;
131         const char* fStaticString;
132         char fSkString[sizeof(SkString)];
133         SkPDFObject* fObject;
134     };
135     enum class Type : char {
136         /** It is an error to call emitObject() or addResources() on an
137             kDestroyed object. */
138         kDestroyed = 0,
139         kInt,
140         kColorComponent,
141         kBool,
142         kScalar,
143         kName,
144         kString,
145         kNameSkS,
146         kStringSkS,
147         kObjRef,
148         kObject,
149     };
150     Type fType;
151 
152     SkPDFUnion(Type);
153     // We do not now need copy constructor and copy assignment, so we
154     // will disable this functionality.
155     SkPDFUnion& operator=(const SkPDFUnion&) = delete;
156     SkPDFUnion(const SkPDFUnion&) = delete;
157 };
158 static_assert(sizeof(SkString) == sizeof(void*), "SkString_size");
159 
160 ////////////////////////////////////////////////////////////////////////////////
161 
162 #if 0  // Enable if needed.
163 /** This class is a SkPDFUnion with SkPDFObject virtuals attached.
164     The only use case of this is when a non-compound PDF object is
165     referenced indirectly. */
166 class SkPDFAtom final : public SkPDFObject {
167 public:
168     void emitObject(SkWStream* stream,
169                     const SkPDFObjNumMap& objNumMap) final;
170     void addResources(SkPDFObjNumMap* const final;
171     SkPDFAtom(SkPDFUnion&& v) : fValue(std::move(v) {}
172 
173 private:
174     const SkPDFUnion fValue;
175     typedef SkPDFObject INHERITED;
176 };
177 #endif  // 0
178 
179 ////////////////////////////////////////////////////////////////////////////////
180 
181 /** \class SkPDFArray
182 
183     An array object in a PDF.
184 */
185 class SkPDFArray final : public SkPDFObject {
186 public:
187     /** Create a PDF array. Maximum length is 8191.
188      */
189     SkPDFArray();
190     ~SkPDFArray() override;
191 
192     // The SkPDFObject interface.
193     void emitObject(SkWStream* stream,
194                     const SkPDFObjNumMap& objNumMap) const override;
195     void addResources(SkPDFObjNumMap*) const override;
196     void drop() override;
197 
198     /** The size of the array.
199      */
200     int size() const;
201 
202     /** Preallocate space for the given number of entries.
203      *  @param length The number of array slots to preallocate.
204      */
205     void reserve(int length);
206 
207     /** Appends a value to the end of the array.
208      *  @param value The value to add to the array.
209      */
210     void appendInt(int32_t);
211     void appendColorComponent(uint8_t);
212     void appendBool(bool);
213     void appendScalar(SkScalar);
214     void appendName(const char[]);
215     void appendName(const SkString&);
216     void appendString(const char[]);
217     void appendString(const SkString&);
218     void appendObject(sk_sp<SkPDFObject>);
219     void appendObjRef(sk_sp<SkPDFObject>);
220 
221 private:
222     SkTArray<SkPDFUnion> fValues;
223     void append(SkPDFUnion&& value);
224     SkDEBUGCODE(bool fDumped;)
225 };
226 
227 /** \class SkPDFDict
228 
229     A dictionary object in a PDF.
230 */
231 class SkPDFDict : public SkPDFObject {
232 public:
233     /** Create a PDF dictionary.
234      *  @param type   The value of the Type entry, nullptr for no type.
235      */
236     explicit SkPDFDict(const char type[] = nullptr);
237 
238     ~SkPDFDict() override;
239 
240     // The SkPDFObject interface.
241     void emitObject(SkWStream* stream,
242                     const SkPDFObjNumMap& objNumMap) const override;
243     void addResources(SkPDFObjNumMap*) const override;
244     void drop() override;
245 
246     /** The size of the dictionary.
247      */
248     int size() const;
249 
250     /** Add the value to the dictionary with the given key.
251      *  @param key   The text of the key for this dictionary entry.
252      *  @param value The value for this dictionary entry.
253      */
254     void insertObject(const char key[], sk_sp<SkPDFObject>);
255     void insertObject(const SkString& key, sk_sp<SkPDFObject>);
256     void insertObjRef(const char key[], sk_sp<SkPDFObject>);
257     void insertObjRef(const SkString& key, sk_sp<SkPDFObject>);
258 
259     /** Add the value to the dictionary with the given key.
260      *  @param key   The text of the key for this dictionary entry.
261      *  @param value The value for this dictionary entry.
262      */
263     void insertBool(const char key[], bool value);
264     void insertInt(const char key[], int32_t value);
265     void insertInt(const char key[], size_t value);
266     void insertScalar(const char key[], SkScalar value);
267     void insertName(const char key[], const char nameValue[]);
268     void insertName(const char key[], const SkString& nameValue);
269     void insertString(const char key[], const char value[]);
270     void insertString(const char key[], const SkString& value);
271 
272     /** Emit the dictionary, without the "<<" and ">>".
273      */
274     void emitAll(SkWStream* stream,
275                  const SkPDFObjNumMap& objNumMap) const;
276 
277 private:
278     struct Record {
279         SkPDFUnion fKey;
280         SkPDFUnion fValue;
281         Record(SkPDFUnion&&, SkPDFUnion&&);
282         Record(Record&&) = default;
283         Record& operator=(Record&&) = default;
284         Record(const Record&) = delete;
285         Record& operator=(const Record&) = delete;
286     };
287     SkTArray<Record> fRecords;
288     SkDEBUGCODE(bool fDumped;)
289 };
290 
291 /** \class SkPDFSharedStream
292 
293     This class takes an asset and assumes that it is backed by
294     long-lived shared data (for example, an open file
295     descriptor). That is: no memory savings can be made by holding on
296     to a compressed version instead.
297  */
298 class SkPDFSharedStream final : public SkPDFObject {
299 public:
300     SkPDFSharedStream(std::unique_ptr<SkStreamAsset> data);
301     ~SkPDFSharedStream() override;
dict()302     SkPDFDict* dict() { return &fDict; }
303     void emitObject(SkWStream*,
304                     const SkPDFObjNumMap&) const override;
305     void addResources(SkPDFObjNumMap*) const override;
306     void drop() override;
307 
308 private:
309     std::unique_ptr<SkStreamAsset> fAsset;
310     SkPDFDict fDict;
311     typedef SkPDFObject INHERITED;
312 };
313 
314 /** \class SkPDFStream
315 
316     This class takes an asset and assumes that it is the only owner of
317     the asset's data.  It immediately compresses the asset to save
318     memory.
319  */
320 
321 class SkPDFStream final : public SkPDFObject {
322 
323 public:
324     /** Create a PDF stream. A Length entry is automatically added to the
325      *  stream dictionary.
326      *  @param data   The data part of the stream.
327      *  @param stream The data part of the stream. */
328     explicit SkPDFStream(sk_sp<SkData> data);
329     explicit SkPDFStream(std::unique_ptr<SkStreamAsset> stream);
330     ~SkPDFStream() override;
331 
dict()332     SkPDFDict* dict() { return &fDict; }
333 
334     // The SkPDFObject interface.
335     void emitObject(SkWStream* stream,
336                     const SkPDFObjNumMap& objNumMap) const override;
337     void addResources(SkPDFObjNumMap*) const final;
338     void drop() override;
339 
340 protected:
341     /* Create a PDF stream with no data.  The setData method must be called to
342      * set the data. */
343     SkPDFStream();
344 
345     /** Only call this function once. */
346     void setData(std::unique_ptr<SkStreamAsset> stream);
347 
348 private:
349     std::unique_ptr<SkStreamAsset> fCompressedData;
350     SkPDFDict fDict;
351 
352     typedef SkPDFDict INHERITED;
353 };
354 
355 ////////////////////////////////////////////////////////////////////////////////
356 
357 /** \class SkPDFObjNumMap
358 
359     The PDF Object Number Map manages object numbers.  It is used to
360     create the PDF cross reference table.
361 */
362 class SkPDFObjNumMap : SkNoncopyable {
363 public:
364     /** Add the passed object to the catalog.
365      *  @param obj         The object to add.
366      *  @return True iff the object was not already added to the catalog.
367      */
368     bool addObject(SkPDFObject* obj);
369 
370     /** Add the passed object to the catalog, as well as all its dependencies.
371      *  @param obj   The object to add.  If nullptr, this is a noop.
372      */
373     void addObjectRecursively(SkPDFObject* obj);
374 
375     /** Get the object number for the passed object.
376      *  @param obj         The object of interest.
377      */
378     int32_t getObjectNumber(SkPDFObject* obj) const;
379 
objects()380     const SkTArray<sk_sp<SkPDFObject>>& objects() const { return fObjects; }
381 
382 private:
383     SkTArray<sk_sp<SkPDFObject>> fObjects;
384     SkTHashMap<SkPDFObject*, int32_t> fObjectNumbers;
385 };
386 
387 ////////////////////////////////////////////////////////////////////////////////
388 
389 #ifdef SK_PDF_IMAGE_STATS
390 extern SkAtomic<int> gDrawImageCalls;
391 extern SkAtomic<int> gJpegImageObjects;
392 extern SkAtomic<int> gRegularImageObjects;
393 extern void SkPDFImageDumpStats();
394 #endif // SK_PDF_IMAGE_STATS
395 
396 #endif
397