Home | History | Annotate | Download | only in pdf
      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 
     17 class SkData;
     18 class SkPDFObjNumMap;
     19 class SkPDFObject;
     20 class SkStreamAsset;
     21 class SkString;
     22 class 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 */
     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     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() {}
     60 private:
     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  */
     71 class SkPDFUnion {
     72 public:
     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 
    126 private:
    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 };
    158 static_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. */
    166 class SkPDFAtom final : public SkPDFObject {
    167 public:
    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 
    173 private:
    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 */
    185 class SkPDFArray final : public SkPDFObject {
    186 public:
    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 
    221 private:
    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 */
    231 class SkPDFDict : public SkPDFObject {
    232 public:
    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 
    280 private:
    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  */
    296 class SkPDFSharedStream final : public SkPDFObject {
    297 public:
    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 
    306 private:
    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 
    319 class SkPDFStream final : public SkPDFObject {
    320 
    321 public:
    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 
    338 protected:
    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 
    346 private:
    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 */
    360 class SkPDFObjNumMap : SkNoncopyable {
    361 public:
    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 
    374 private:
    375     SkTArray<sk_sp<SkPDFObject>> fObjects;
    376     SkTHashMap<SkPDFObject*, int32_t> fObjectNumbers;
    377 };
    378 
    379 ////////////////////////////////////////////////////////////////////////////////
    380 
    381 #ifdef SK_PDF_IMAGE_STATS
    382 extern SkAtomic<int> gDrawImageCalls;
    383 extern SkAtomic<int> gJpegImageObjects;
    384 extern SkAtomic<int> gRegularImageObjects;
    385 extern void SkPDFImageDumpStats();
    386 #endif // SK_PDF_IMAGE_STATS
    387 
    388 #endif
    389