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