• 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 
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     /** Preallocate space for n key-value pairs */
251     void reserve(int n);
252 
253     /** Add the value to the dictionary with the given key.
254      *  @param key   The text of the key for this dictionary entry.
255      *  @param value The value for this dictionary entry.
256      */
257     void insertObject(const char key[], sk_sp<SkPDFObject>);
258     void insertObject(const SkString& key, sk_sp<SkPDFObject>);
259     void insertObjRef(const char key[], sk_sp<SkPDFObject>);
260     void insertObjRef(const SkString& key, sk_sp<SkPDFObject>);
261 
262     /** Add the value to the dictionary with the given key.
263      *  @param key   The text of the key for this dictionary entry.
264      *  @param value The value for this dictionary entry.
265      */
266     void insertBool(const char key[], bool value);
267     void insertInt(const char key[], int32_t value);
268     void insertInt(const char key[], size_t value);
269     void insertScalar(const char key[], SkScalar value);
270     void insertName(const char key[], const char nameValue[]);
271     void insertName(const char key[], const SkString& nameValue);
272     void insertString(const char key[], const char value[]);
273     void insertString(const char key[], const SkString& value);
274 
275     /** Emit the dictionary, without the "<<" and ">>".
276      */
277     void emitAll(SkWStream* stream,
278                  const SkPDFObjNumMap& objNumMap) const;
279 
280 private:
281     struct Record {
282         SkPDFUnion fKey;
283         SkPDFUnion fValue;
284     };
285     SkTArray<Record> fRecords;
286     SkDEBUGCODE(bool fDumped;)
287 };
288 
289 /** \class SkPDFSharedStream
290 
291     This class takes an asset and assumes that it is backed by
292     long-lived shared data (for example, an open file
293     descriptor). That is: no memory savings can be made by holding on
294     to a compressed version instead.
295  */
296 class SkPDFSharedStream final : public SkPDFObject {
297 public:
298     SkPDFSharedStream(std::unique_ptr<SkStreamAsset> data);
299     ~SkPDFSharedStream() override;
dict()300     SkPDFDict* dict() { return &fDict; }
301     void emitObject(SkWStream*,
302                     const SkPDFObjNumMap&) const override;
303     void addResources(SkPDFObjNumMap*) const override;
304     void drop() override;
305 
306 private:
307     std::unique_ptr<SkStreamAsset> fAsset;
308     SkPDFDict fDict;
309     typedef SkPDFObject INHERITED;
310 };
311 
312 /** \class SkPDFStream
313 
314     This class takes an asset and assumes that it is the only owner of
315     the asset's data.  It immediately compresses the asset to save
316     memory.
317  */
318 
319 class SkPDFStream final : public SkPDFObject {
320 
321 public:
322     /** Create a PDF stream. A Length entry is automatically added to the
323      *  stream dictionary.
324      *  @param data   The data part of the stream.
325      *  @param stream The data part of the stream. */
326     explicit SkPDFStream(sk_sp<SkData> data);
327     explicit SkPDFStream(std::unique_ptr<SkStreamAsset> stream);
328     ~SkPDFStream() override;
329 
dict()330     SkPDFDict* dict() { return &fDict; }
331 
332     // The SkPDFObject interface.
333     void emitObject(SkWStream* stream,
334                     const SkPDFObjNumMap& objNumMap) const override;
335     void addResources(SkPDFObjNumMap*) const final;
336     void drop() override;
337 
338 protected:
339     /* Create a PDF stream with no data.  The setData method must be called to
340      * set the data. */
341     SkPDFStream();
342 
343     /** Only call this function once. */
344     void setData(std::unique_ptr<SkStreamAsset> stream);
345 
346 private:
347     std::unique_ptr<SkStreamAsset> fCompressedData;
348     SkPDFDict fDict;
349 
350     typedef SkPDFDict INHERITED;
351 };
352 
353 ////////////////////////////////////////////////////////////////////////////////
354 
355 /** \class SkPDFObjNumMap
356 
357     The PDF Object Number Map manages object numbers.  It is used to
358     create the PDF cross reference table.
359 */
360 class SkPDFObjNumMap : SkNoncopyable {
361 public:
362     /** Add the passed object to the catalog.
363      *  @param obj         The object to add.
364      *  @return True iff the object was not already added to the catalog.
365      */
366     bool addObject(SkPDFObject* obj);
367 
368     /** Add the passed object to the catalog, as well as all its dependencies.
369      *  @param obj   The object to add.  If nullptr, this is a noop.
370      */
371     void addObjectRecursively(SkPDFObject* obj);
372 
373     /** Get the object number for the passed object.
374      *  @param obj         The object of interest.
375      */
376     int32_t getObjectNumber(SkPDFObject* obj) const;
377 
objects()378     const SkTArray<sk_sp<SkPDFObject>>& objects() const { return fObjects; }
379 
380 private:
381     SkTArray<sk_sp<SkPDFObject>> fObjects;
382     SkTHashMap<SkPDFObject*, int32_t> fObjectNumbers;
383 };
384 
385 ////////////////////////////////////////////////////////////////////////////////
386 
387 #ifdef SK_PDF_IMAGE_STATS
388 extern SkAtomic<int> gDrawImageCalls;
389 extern SkAtomic<int> gJpegImageObjects;
390 extern SkAtomic<int> gRegularImageObjects;
391 extern void SkPDFImageDumpStats();
392 #endif // SK_PDF_IMAGE_STATS
393 
394 #endif
395