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
19class SkPDFObjNumMap;
20class SkPDFObject;
21class SkPDFSubstituteMap;
22class 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*/
31class SkPDFObject : public SkRefCnt {
32public:
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     */
50    virtual void addResources(SkPDFObjNumMap* catalog,
51                              const SkPDFSubstituteMap& substitutes) const {}
52
53private:
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 */
64class SkPDFUnion {
65public:
66    // u.move() is analogous to std::move(u). It returns an rvalue.
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
130private:
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};
161SK_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. */
169class SkPDFAtom : public SkPDFObject {
170public:
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
177private:
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*/
189class SkPDFArray : public SkPDFObject {
190public:
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
230private:
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*/
240class SkPDFDict : public SkPDFObject {
241public:
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
293private:
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*/
313class SkPDFObjNumMap : SkNoncopyable {
314public:
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
326    const SkTDArray<SkPDFObject*>& objects() const { return fObjects; }
327
328private:
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*/
340class SkPDFSubstituteMap : SkNoncopyable {
341public:
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
353    SkPDFObject* operator()(SkPDFObject* o) const {
354        return this->getSubstitute(o);
355    }
356
357private:
358    SkTHashMap<SkPDFObject*, SkPDFObject*> fSubstituteMap;
359};
360
361#endif
362