• 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 "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