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     /** Add the value to the dictionary with the given key.
    251      *  @param key   The text of the key for this dictionary entry.
    252      *  @param value The value for this dictionary entry.
    253      */
    254     void insertObject(const char key[], sk_sp<SkPDFObject>);
    255     void insertObject(const SkString& key, sk_sp<SkPDFObject>);
    256     void insertObjRef(const char key[], sk_sp<SkPDFObject>);
    257     void insertObjRef(const SkString& key, sk_sp<SkPDFObject>);
    258 
    259     /** Add the value to the dictionary with the given key.
    260      *  @param key   The text of the key for this dictionary entry.
    261      *  @param value The value for this dictionary entry.
    262      */
    263     void insertBool(const char key[], bool value);
    264     void insertInt(const char key[], int32_t value);
    265     void insertInt(const char key[], size_t value);
    266     void insertScalar(const char key[], SkScalar value);
    267     void insertName(const char key[], const char nameValue[]);
    268     void insertName(const char key[], const SkString& nameValue);
    269     void insertString(const char key[], const char value[]);
    270     void insertString(const char key[], const SkString& value);
    271 
    272     /** Emit the dictionary, without the "<<" and ">>".
    273      */
    274     void emitAll(SkWStream* stream,
    275                  const SkPDFObjNumMap& objNumMap) const;
    276 
    277 private:
    278     struct Record {
    279         SkPDFUnion fKey;
    280         SkPDFUnion fValue;
    281         Record(SkPDFUnion&&, SkPDFUnion&&);
    282         Record(Record&&) = default;
    283         Record& operator=(Record&&) = default;
    284         Record(const Record&) = delete;
    285         Record& operator=(const Record&) = delete;
    286     };
    287     SkTArray<Record> fRecords;
    288     SkDEBUGCODE(bool fDumped;)
    289 };
    290 
    291 /** \class SkPDFSharedStream
    292 
    293     This class takes an asset and assumes that it is backed by
    294     long-lived shared data (for example, an open file
    295     descriptor). That is: no memory savings can be made by holding on
    296     to a compressed version instead.
    297  */
    298 class SkPDFSharedStream final : public SkPDFObject {
    299 public:
    300     SkPDFSharedStream(std::unique_ptr<SkStreamAsset> data);
    301     ~SkPDFSharedStream() override;
    302     SkPDFDict* dict() { return &fDict; }
    303     void emitObject(SkWStream*,
    304                     const SkPDFObjNumMap&) const override;
    305     void addResources(SkPDFObjNumMap*) const override;
    306     void drop() override;
    307 
    308 private:
    309     std::unique_ptr<SkStreamAsset> fAsset;
    310     SkPDFDict fDict;
    311     typedef SkPDFObject INHERITED;
    312 };
    313 
    314 /** \class SkPDFStream
    315 
    316     This class takes an asset and assumes that it is the only owner of
    317     the asset's data.  It immediately compresses the asset to save
    318     memory.
    319  */
    320 
    321 class SkPDFStream final : public SkPDFObject {
    322 
    323 public:
    324     /** Create a PDF stream. A Length entry is automatically added to the
    325      *  stream dictionary.
    326      *  @param data   The data part of the stream.
    327      *  @param stream The data part of the stream. */
    328     explicit SkPDFStream(sk_sp<SkData> data);
    329     explicit SkPDFStream(std::unique_ptr<SkStreamAsset> stream);
    330     ~SkPDFStream() override;
    331 
    332     SkPDFDict* dict() { return &fDict; }
    333 
    334     // The SkPDFObject interface.
    335     void emitObject(SkWStream* stream,
    336                     const SkPDFObjNumMap& objNumMap) const override;
    337     void addResources(SkPDFObjNumMap*) const final;
    338     void drop() override;
    339 
    340 protected:
    341     /* Create a PDF stream with no data.  The setData method must be called to
    342      * set the data. */
    343     SkPDFStream();
    344 
    345     /** Only call this function once. */
    346     void setData(std::unique_ptr<SkStreamAsset> stream);
    347 
    348 private:
    349     std::unique_ptr<SkStreamAsset> fCompressedData;
    350     SkPDFDict fDict;
    351 
    352     typedef SkPDFDict INHERITED;
    353 };
    354 
    355 ////////////////////////////////////////////////////////////////////////////////
    356 
    357 /** \class SkPDFObjNumMap
    358 
    359     The PDF Object Number Map manages object numbers.  It is used to
    360     create the PDF cross reference table.
    361 */
    362 class SkPDFObjNumMap : SkNoncopyable {
    363 public:
    364     /** Add the passed object to the catalog.
    365      *  @param obj         The object to add.
    366      *  @return True iff the object was not already added to the catalog.
    367      */
    368     bool addObject(SkPDFObject* obj);
    369 
    370     /** Add the passed object to the catalog, as well as all its dependencies.
    371      *  @param obj   The object to add.  If nullptr, this is a noop.
    372      */
    373     void addObjectRecursively(SkPDFObject* obj);
    374 
    375     /** Get the object number for the passed object.
    376      *  @param obj         The object of interest.
    377      */
    378     int32_t getObjectNumber(SkPDFObject* obj) const;
    379 
    380     const SkTArray<sk_sp<SkPDFObject>>& objects() const { return fObjects; }
    381 
    382 private:
    383     SkTArray<sk_sp<SkPDFObject>> fObjects;
    384     SkTHashMap<SkPDFObject*, int32_t> fObjectNumbers;
    385 };
    386 
    387 ////////////////////////////////////////////////////////////////////////////////
    388 
    389 #ifdef SK_PDF_IMAGE_STATS
    390 extern SkAtomic<int> gDrawImageCalls;
    391 extern SkAtomic<int> gJpegImageObjects;
    392 extern SkAtomic<int> gRegularImageObjects;
    393 extern void SkPDFImageDumpStats();
    394 #endif // SK_PDF_IMAGE_STATS
    395 
    396 #endif
    397