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