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 "SkString.h"
15 #include "SkTDArray.h"
16 #include "SkTHash.h"
17 #include "SkTypes.h"
18 
19 class SkPDFObjNumMap;
20 class SkPDFObject;
21 class SkPDFSubstituteMap;
22 class SkWStream;
23 
24 /** \class SkPDFObject
25 
26     A PDF Object is the base class for primitive elements in a PDF file.  A
27     common subtype is used to ease the use of indirect object references,
28     which are common in the PDF format.
29 
30 */
31 class SkPDFObject : public SkRefCnt {
32 public:
33     SK_DECLARE_INST_COUNT(SkPDFObject);
34 
35     /** Subclasses must implement this method to print the object to the
36      *  PDF file.
37      *  @param catalog  The object catalog to use.
38      *  @param stream   The writable output stream to send the output to.
39      */
40     // TODO(halcanary): make this method const
41     virtual void emitObject(SkWStream* stream,
42                             const SkPDFObjNumMap& objNumMap,
43                             const SkPDFSubstituteMap& substitutes) = 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,const SkPDFSubstituteMap & substitutes)50     virtual void addResources(SkPDFObjNumMap* catalog,
51                               const SkPDFSubstituteMap& substitutes) const {}
52 
53 private:
54     typedef SkRefCnt INHERITED;
55 };
56 
57 ////////////////////////////////////////////////////////////////////////////////
58 
59 /**
60    A SkPDFUnion is a non-virtualized implementation of the
61    non-compound, non-specialized PDF Object types: Name, String,
62    Number, Boolean.
63  */
64 class SkPDFUnion {
65 public:
66     // u.move() is analogous to std::move(u). It returns an rvalue.
move()67     SkPDFUnion move() { return static_cast<SkPDFUnion&&>(*this); }
68     // Move contstructor and assignemnt operator destroy the argument
69     // and steal their references (if needed).
70     SkPDFUnion(SkPDFUnion&& other);
71     SkPDFUnion& operator=(SkPDFUnion&& other);
72 
73     ~SkPDFUnion();
74 
75     /** The following nine functions are the standard way of creating
76         SkPDFUnion objects. */
77 
78     static SkPDFUnion Int(int32_t);
79 
80     static SkPDFUnion Int(size_t);
81 
82     static SkPDFUnion Bool(bool);
83 
84     static SkPDFUnion Scalar(SkScalar);
85 
86     /** These two functions do NOT take ownership of ptr, and do NOT
87         copy the string.  Suitable for passing in static const
88         strings. For example:
89           SkPDFUnion n = SkPDFUnion::Name("Length");
90           SkPDFUnion u = SkPDFUnion::String("Identity"); */
91 
92     /** SkPDFUnion::Name(const char*) assumes that the passed string
93         is already a valid name (that is: it has no control or
94         whitespace characters).  This will not copy the name. */
95     static SkPDFUnion Name(const char*);
96 
97     /** SkPDFUnion::String will encode the passed string.  This will
98         not copy the name. */
99     static SkPDFUnion String(const char*);
100 
101     /** SkPDFUnion::Name(const SkString&) does not assume that the
102         passed string is already a valid name and it will escape the
103         string. */
104     static SkPDFUnion Name(const SkString&);
105 
106     /** SkPDFUnion::String will encode the passed string. */
107     static SkPDFUnion String(const SkString&);
108 
109     /** This function DOES take ownership of the object. E.g.
110           SkAutoTUnref<SkPDFDict> dict(new SkPDFDict);
111           dict->insert(.....);
112           SkPDFUnion u = SkPDFUnion::Object(dict.detach()) */
113     static SkPDFUnion Object(SkPDFObject*);
114 
115     /** This function DOES take ownership of the object. E.g.
116           SkAutoTUnref<SkPDFBitmap> image(
117                  SkPDFBitmap::Create(fCanon, bitmap));
118           SkPDFUnion u = SkPDFUnion::ObjRef(image.detach()) */
119     static SkPDFUnion ObjRef(SkPDFObject*);
120 
121     /** These two non-virtual methods mirror SkPDFObject's
122         corresponding virtuals. */
123     void emitObject(SkWStream*,
124                     const SkPDFObjNumMap&,
125                     const SkPDFSubstituteMap&) const;
126     void addResources(SkPDFObjNumMap*, const SkPDFSubstituteMap&) const;
127 
128     bool isName() const;
129 
130 private:
131     union {
132         int32_t fIntValue;
133         bool fBoolValue;
134         SkScalar fScalarValue;
135         const char* fStaticString;
136         char fSkString[sizeof(SkString)];
137         SkPDFObject* fObject;
138     };
139     enum class Type : char {
140         /** It is an error to call emitObject() or addResources() on an
141             kDestroyed object. */
142         kDestroyed = 0,
143         kInt,
144         kBool,
145         kScalar,
146         kName,
147         kString,
148         kNameSkS,
149         kStringSkS,
150         kObjRef,
151         kObject,
152     };
153     Type fType;
154 
155     SkPDFUnion(Type);
156     // We do not now need copy constructor and copy assignment, so we
157     // will disable this functionality.
158     SkPDFUnion& operator=(const SkPDFUnion&) = delete;
159     SkPDFUnion(const SkPDFUnion&) = delete;
160 };
161 SK_COMPILE_ASSERT(sizeof(SkString) == sizeof(void*), SkString_size);
162 
163 ////////////////////////////////////////////////////////////////////////////////
164 
165 #if 0  // Enable if needed.
166 /** This class is a SkPDFUnion with SkPDFObject virtuals attached.
167     The only use case of this is when a non-compound PDF object is
168     referenced indirectly. */
169 class SkPDFAtom : public SkPDFObject {
170 public:
171     void emitObject(SkWStream* stream,
172                     const SkPDFObjNumMap& objNumMap,
173                     const SkPDFSubstituteMap& substitutes) final;
174     void addResources(SkPDFObjNumMap*, const SkPDFSubstituteMap&) const final;
175     SkPDFAtom(SkPDFUnion&& v) : fValue(v.move()) {}
176 
177 private:
178     const SkPDFUnion fValue;
179     typedef SkPDFObject INHERITED;
180 };
181 #endif  // 0
182 
183 ////////////////////////////////////////////////////////////////////////////////
184 
185 /** \class SkPDFArray
186 
187     An array object in a PDF.
188 */
189 class SkPDFArray : public SkPDFObject {
190 public:
191     SK_DECLARE_INST_COUNT(SkPDFArray)
192 
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) 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     SK_DECLARE_INST_COUNT(SkPDFDict)
243 
244     /** Create a PDF dictionary. Maximum number of entries is 4095.
245      */
246     SkPDFDict();
247 
248     /** Create a PDF dictionary with a Type entry.
249      *  @param type   The value of the Type entry.
250      */
251     explicit SkPDFDict(const char type[]);
252 
253     virtual ~SkPDFDict();
254 
255     // The SkPDFObject interface.
256     void emitObject(SkWStream* stream,
257                     const SkPDFObjNumMap& objNumMap,
258                     const SkPDFSubstituteMap& substitutes) override;
259     void addResources(SkPDFObjNumMap*,
260                       const SkPDFSubstituteMap&) const override;
261 
262     /** The size of the dictionary.
263      */
264     int size() const;
265 
266     /** Add the value to the dictionary with the given key.  Takes
267      *  ownership of the object.
268      *  @param key   The text of the key for this dictionary entry.
269      *  @param value The value for this dictionary entry.
270      */
271     void insertObject(const char key[], SkPDFObject* value);
272     void insertObject(const SkString& key, SkPDFObject* value);
273     void insertObjRef(const char key[], SkPDFObject* value);
274     void insertObjRef(const SkString& key, SkPDFObject* value);
275 
276     /** Add the value to the dictionary with the given key.
277      *  @param key   The text of the key for this dictionary entry.
278      *  @param value The value for this dictionary entry.
279      */
280     void insertBool(const char key[], bool value);
281     void insertInt(const char key[], int32_t value);
282     void insertInt(const char key[], size_t value);
283     void insertScalar(const char key[], SkScalar value);
284     void insertName(const char key[], const char nameValue[]);
285     void insertName(const char key[], const SkString& nameValue);
286     void insertString(const char key[], const char value[]);
287     void insertString(const char key[], const SkString& value);
288 
289     /** Remove all entries from the dictionary.
290      */
291     void clear();
292 
293 private:
294     struct Record {
295         SkPDFUnion fKey;
296         SkPDFUnion fValue;
297     };
298     SkTDArray<Record> fRecords;
299     static const int kMaxLen = 4095;
300 
301     void set(SkPDFUnion&& name, SkPDFUnion&& value);
302 
303     typedef SkPDFObject INHERITED;
304 };
305 
306 ////////////////////////////////////////////////////////////////////////////////
307 
308 /** \class SkPDFObjNumMap
309 
310     The PDF Object Number Map manages object numbers.  It is used to
311     create the PDF cross reference table.
312 */
313 class SkPDFObjNumMap : SkNoncopyable {
314 public:
315     /** Add the passed object to the catalog.
316      *  @param obj         The object to add.
317      *  @return True iff the object was not already added to the catalog.
318      */
319     bool addObject(SkPDFObject* obj);
320 
321     /** Get the object number for the passed object.
322      *  @param obj         The object of interest.
323      */
324     int32_t getObjectNumber(SkPDFObject* obj) const;
325 
objects()326     const SkTDArray<SkPDFObject*>& objects() const { return fObjects; }
327 
328 private:
329     SkTDArray<SkPDFObject*> fObjects;
330     SkTHashMap<SkPDFObject*, int32_t> fObjectNumbers;
331 };
332 
333 ////////////////////////////////////////////////////////////////////////////////
334 
335 /** \class SkPDFSubstituteMap
336 
337     The PDF Substitute Map manages substitute objects and owns the
338     substitutes.
339 */
340 class SkPDFSubstituteMap : SkNoncopyable {
341 public:
342     ~SkPDFSubstituteMap();
343     /** Set substitute object for the passed object.
344         Refs substitute.
345      */
346     void setSubstitute(SkPDFObject* original, SkPDFObject* substitute);
347 
348     /** Find and return any substitute object set for the passed object. If
349      *  there is none, return the passed object.
350      */
351     SkPDFObject* getSubstitute(SkPDFObject* object) const;
352 
operator()353     SkPDFObject* operator()(SkPDFObject* o) const {
354         return this->getSubstitute(o);
355     }
356 
357 private:
358     SkTHashMap<SkPDFObject*, SkPDFObject*> fSubstituteMap;
359 };
360 
361 #endif
362