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
17class SkData;
18class SkPDFObjNumMap;
19class SkPDFObject;
20class SkStreamAsset;
21class SkString;
22class 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*/
35class SkPDFObject : public SkRefCnt {
36public:
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     */
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     */
57    virtual void drop() {}
58
59    virtual ~SkPDFObject() {}
60private:
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 */
71class SkPDFUnion {
72public:
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
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
126private:
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};
158static_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. */
166class SkPDFAtom final : public SkPDFObject {
167public:
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
173private:
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*/
185class SkPDFArray final : public SkPDFObject {
186public:
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
221private:
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*/
231class SkPDFDict : public SkPDFObject {
232public:
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
280private:
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 */
296class SkPDFSharedStream final : public SkPDFObject {
297public:
298    SkPDFSharedStream(std::unique_ptr<SkStreamAsset> data);
299    ~SkPDFSharedStream() override;
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
306private:
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
319class SkPDFStream final : public SkPDFObject {
320
321public:
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
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
338protected:
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
346private:
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*/
360class SkPDFObjNumMap : SkNoncopyable {
361public:
362    /** Add the passed object to the catalog, as well as all its dependencies.
363     *  @param obj   The object to add.  If nullptr, this is a noop.
364     */
365    void addObjectRecursively(SkPDFObject* obj);
366
367    /** Get the object number for the passed object.
368     *  @param obj         The object of interest.
369     */
370    int32_t getObjectNumber(SkPDFObject* obj) const;
371
372    const SkTArray<sk_sp<SkPDFObject>>& objects() const { return fObjects; }
373
374private:
375    SkTArray<sk_sp<SkPDFObject>> fObjects;
376    SkTHashMap<SkPDFObject*, int32_t> fObjectNumbers;
377};
378
379////////////////////////////////////////////////////////////////////////////////
380
381#ifdef SK_PDF_IMAGE_STATS
382extern SkAtomic<int> gDrawImageCalls;
383extern SkAtomic<int> gJpegImageObjects;
384extern SkAtomic<int> gRegularImageObjects;
385extern void SkPDFImageDumpStats();
386#endif // SK_PDF_IMAGE_STATS
387
388#endif
389