Home | History | Annotate | Download | only in native
      1 /*
      2  * Copyright 2013 Google Inc.
      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 #ifndef SkPdfNativeObject_DEFINED
      9 #define SkPdfNativeObject_DEFINED
     10 
     11 #include <stdint.h>
     12 #include <string.h>
     13 
     14 #include "SkMatrix.h"
     15 #include "SkPdfConfig.h"
     16 #include "SkPdfNativeTokenizer.h"
     17 #include "SkPdfNYI.h"
     18 #include "SkPdfUtils.h"
     19 #include "SkRect.h"
     20 #include "SkString.h"
     21 #include "SkTDArray.h"
     22 #include "SkTDict.h"
     23 
     24 class SkPdfDictionary;
     25 class SkPdfStream;
     26 class SkPdfAllocator;
     27 
     28 // TODO(edisonn): remove these constants and clean up the code.
     29 #define kFilteredStreamBit 0
     30 #define kUnfilteredStreamBit 1
     31 #define kOwnedStreamBit 2
     32 
     33 /** \class SkPdfNativeObject
     34  *
     35  *  The SkPdfNativeObject class is used to store a pdf object. Classes that inherit it are not
     36  *  allowed to add fields.
     37  *
     38  *  SkPdfAllocator will allocate them in chunks and will free them in destructor.
     39  *
     40  *  You can allocate one on the stack, as long as you call reset() at the end, and any objects it
     41  *  points to in an allocator. But if your object is a simple one, like number, then
     42  *  putting it on stack will be just fine.
     43  *
     44  */
     45 class SkPdfNativeObject {
     46  public:
     47      enum ObjectType {
     48          // The type will have only one of these values, but for error reporting, we make it an enum
     49          // so it can easily report that something was expected to be one of a few types
     50          kInvalid_PdfObjectType = 1 << 1,
     51 
     52          kBoolean_PdfObjectType = 1 << 2,
     53          kInteger_PdfObjectType = 1 << 3,
     54          kReal_PdfObjectType = 1 << 4,
     55          _kNumber_PdfObjectType = kInteger_PdfObjectType | kReal_PdfObjectType,
     56          kString_PdfObjectType = 1 << 5,
     57          kHexString_PdfObjectType = 1 << 6,
     58          _kAnyString_PdfObjectType = kString_PdfObjectType | kHexString_PdfObjectType,
     59          kName_PdfObjectType = 1 << 7,
     60          kKeyword_PdfObjectType = 1 << 8,
     61          _kStream_PdfObjectType = 1 << 9,  //  attached to a Dictionary, do not use
     62          kArray_PdfObjectType = 1 << 10,
     63          kDictionary_PdfObjectType = 1 << 11,
     64          kNull_PdfObjectType = 1 << 12,
     65 
     66          kReference_PdfObjectType = 1 << 13,
     67 
     68          kUndefined_PdfObjectType = 1 << 14,  // per 1.4 spec, if the same key appear twice in the
     69                                               // dictionary, the value is undefined.
     70 
     71          _kObject_PdfObjectType = -1,
     72      };
     73 
     74      enum DataType {
     75          kEmpty_Data,
     76          kFont_Data,
     77          kBitmap_Data,
     78      };
     79 
     80 private:
     81     // TODO(edisonn): assert reset operations while in rendering! The objects should be reset
     82     // only when rendering is completed.
     83     uint32_t fInRendering : 1;
     84     uint32_t fUnused : 31;
     85 
     86     struct Reference {
     87         unsigned int fId;
     88         unsigned int fGen;
     89     };
     90 
     91     ObjectType fObjectType;
     92 
     93     union {
     94         bool fBooleanValue;
     95         int64_t fIntegerValue;
     96         // TODO(edisonn): double, float, SkScalar?
     97         double fRealValue;
     98         NotOwnedString fStr;
     99 
    100         SkTDArray<SkPdfNativeObject*>* fArray;
    101         Reference fRef;
    102     };
    103     SkTDict<SkPdfNativeObject*>* fMap;
    104 
    105     // TODO(edisonn): rename data with cache
    106     void* fData;
    107     DataType fDataType;
    108 
    109 #ifdef PDF_TRACK_OBJECT_USAGE
    110     // Records if the object was used during rendering/proccessing. It can be used to track
    111     // what features are only partially implemented, by looking at what objects have not been
    112     // accessed.
    113     mutable bool fUsed;
    114 #endif   // PDF_TRACK_OBJECT_USAGE
    115 
    116 #ifdef PDF_TRACK_STREAM_OFFSETS
    117 public:
    118     // TODO(edisonn): replace them with char* start, end - and a mechanism to register streams.
    119     int fStreamId;
    120     int fOffsetStart;
    121     int fOffsetEnd;
    122 #endif  // PDF_TRACK_STREAM_OFFSETS
    123 
    124 public:
    125 
    126 #ifdef PDF_TRACK_STREAM_OFFSETS
    127     // TODO(edisonn): remove these ones.
    128     int streamId() const { return fStreamId; }
    129     int offsetStart() const { return fOffsetStart; }
    130     int offsetEnd() const { return fOffsetEnd; }
    131 #endif  // PDF_TRACK_STREAM_OFFSETS
    132 
    133     SkPdfNativeObject() : fInRendering(0)
    134                         , fObjectType(kInvalid_PdfObjectType)
    135                         , fMap(NULL)
    136                         , fData(NULL)
    137                         , fDataType(kEmpty_Data)
    138 #ifdef PDF_TRACK_OBJECT_USAGE
    139                         , fUsed(false)
    140 #endif   // PDF_TRACK_OBJECT_USAGE
    141 
    142 #ifdef PDF_TRACK_STREAM_OFFSETS
    143                         , fStreamId(-1)
    144                         , fOffsetStart(-1)
    145                         , fOffsetEnd(-1)
    146 #endif  // PDF_TRACK_STREAM_OFFSETS
    147     {}
    148 
    149     // Used to verify if a form is used in rendering, to check for infinite loops.
    150     bool inRendering() const { return fInRendering != 0; }
    151     void startRendering() {fInRendering = 1;}
    152     void doneRendering() {fInRendering = 0;}
    153 
    154     // Each object can cache one entry associated with it.
    155     // for example a SkPdfImage could cache an SkBitmap, of a SkPdfFont, could cache a SkTypeface.
    156     inline bool hasData(DataType type) {
    157         return type == fDataType;
    158     }
    159 
    160     // returns the cached value
    161     inline void* data(DataType type) {
    162         return type == fDataType ? fData : NULL;
    163     }
    164 
    165     // Stores something in the cache
    166     inline void setData(void* data, DataType type) {
    167         releaseData();
    168         fDataType = type;
    169         fData = data;
    170     }
    171 
    172     // destroys the cache
    173     void releaseData();
    174 
    175     // TODO(edisonn): add an assert that reset was called
    176 //    ~SkPdfNativeObject() {
    177 //        //reset();  must be called manually! Normally, will be called by allocator destructor.
    178 //    }
    179 
    180     // Resets a pdf object, deleting all resources directly referenced.
    181     // It will not reset/delete indirect resources.
    182     // (e.g. it deletes only the array holding pointers to objects, but does not del the objects)
    183     void reset() {
    184         SkPdfMarkObjectUnused();
    185 
    186         switch (fObjectType) {
    187             case kArray_PdfObjectType:
    188                 delete fArray;
    189                 break;
    190 
    191             case kDictionary_PdfObjectType:
    192                 delete fMap;
    193                 if (isStreamOwned()) {
    194                     delete[] fStr.fBuffer;
    195                     fStr.fBuffer = NULL;
    196                     fStr.fBytes = 0;
    197                 }
    198                 break;
    199 
    200             default:
    201                 break;
    202         }
    203         fObjectType = kInvalid_PdfObjectType;
    204         releaseData();
    205     }
    206 
    207     // returns the object type (Null, Integer, String, Dictionary, ... )
    208     // It does not specify what type of dictionary we have.
    209     ObjectType type() {
    210         SkPdfMarkObjectUsed();
    211 
    212         return fObjectType;
    213     }
    214 
    215     // Gives quick access to the buffer's address of a string/keyword/name
    216     const char* c_str() const {
    217         SkPdfMarkObjectUsed();
    218 
    219         switch (fObjectType) {
    220             case kString_PdfObjectType:
    221             case kHexString_PdfObjectType:
    222             case kKeyword_PdfObjectType:
    223             case kName_PdfObjectType:
    224                 return (const char*)fStr.fBuffer;
    225 
    226             default:
    227                 // TODO(edisonn): report/warning/assert?
    228                 return NULL;
    229         }
    230     }
    231 
    232     // Gives quick access to the length of a string/keyword/name
    233     size_t lenstr() const {
    234         SkPdfMarkObjectUsed();
    235 
    236         switch (fObjectType) {
    237             case kString_PdfObjectType:
    238             case kHexString_PdfObjectType:
    239             case kKeyword_PdfObjectType:
    240             case kName_PdfObjectType:
    241                 return fStr.fBytes;
    242 
    243             default:
    244                 // TODO(edisonn): report/warning/assert?
    245                 return 0;
    246         }
    247     }
    248 
    249 
    250     // TODO(edisonn): NYI
    251     SkPdfDate& dateValue() const {
    252         static SkPdfDate nyi;
    253         return nyi;
    254     }
    255 
    256     // TODO(edisonn): NYI
    257     SkPdfFunction& functionValue() const {
    258         static SkPdfFunction nyi;
    259         return nyi;
    260     }
    261 
    262     // TODO(edisonn): NYI
    263     SkPdfFileSpec& fileSpecValue() const {
    264         static SkPdfFileSpec nyi;
    265         return nyi;
    266     }
    267 
    268     // TODO(edisonn): NYI
    269     SkPdfTree& treeValue() const {
    270         static SkPdfTree nyi;
    271         return nyi;
    272     }
    273 
    274     // Creates a Boolean object. Assumes and asserts that it was never initialized.
    275     static void makeBoolean(bool value, SkPdfNativeObject* obj) {
    276         SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
    277 
    278         obj->fObjectType = kBoolean_PdfObjectType;
    279         obj->fBooleanValue = value;
    280     }
    281 
    282     static SkPdfNativeObject makeBoolean(bool value) {
    283         SkPdfNativeObject obj;
    284 
    285         obj.fObjectType = kBoolean_PdfObjectType;
    286         obj.fBooleanValue = value;
    287         return obj;
    288     }
    289 
    290     // Creates an Integer object. Assumes and asserts that it was never initialized.
    291     static void makeInteger(int64_t value, SkPdfNativeObject* obj) {
    292         SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
    293 
    294         obj->fObjectType = kInteger_PdfObjectType;
    295         obj->fIntegerValue = value;
    296     }
    297 
    298     // Creates a Real object. Assumes and asserts that it was never initialized.
    299     static void makeReal(double value, SkPdfNativeObject* obj) {
    300         SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
    301 
    302         obj->fObjectType = kReal_PdfObjectType;
    303         obj->fRealValue = value;
    304     }
    305 
    306     // Creates a Null object. Assumes and asserts that it was never initialized.
    307     static void makeNull(SkPdfNativeObject* obj) {
    308         SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
    309 
    310         obj->fObjectType = kNull_PdfObjectType;
    311     }
    312 
    313     static SkPdfNativeObject makeNull() {
    314         SkPdfNativeObject obj;
    315 
    316         obj.fObjectType = kNull_PdfObjectType;
    317         return obj;
    318     }
    319 
    320     // TODO(edisonn): this might not woirk well in Chrome
    321     static SkPdfNativeObject kNull;
    322 
    323     // Creates a Numeric object from a string. Assumes and asserts that it was never initialized.
    324     static void makeNumeric(const unsigned char* start, const unsigned char* end,
    325                             SkPdfNativeObject* obj) {
    326         SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
    327 
    328         // TODO(edisonn): NYI properly
    329         // if has dot (impl), or exceeds max int, is real, otherwise is int
    330         bool isInt = true;
    331         for (const unsigned char* current = start; current < end; current++) {
    332             if (*current == '.') {
    333                 isInt = false;
    334                 break;
    335             }
    336             // TODO(edisonn): report parse issue with numbers like "24asdasd123"
    337         }
    338         if (isInt) {
    339             makeInteger(atol((const char*)start), obj);
    340         } else {
    341             makeReal(atof((const char*)start), obj);
    342         }
    343     }
    344 
    345     // Creates a Reference object. Assumes and asserts that it was never initialized.
    346     static void makeReference(unsigned int id, unsigned int gen, SkPdfNativeObject* obj) {
    347         SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
    348 
    349         obj->fObjectType = kReference_PdfObjectType;
    350         obj->fRef.fId = id;
    351         obj->fRef.fGen = gen;
    352     }
    353 
    354     // Creates a Reference object. Resets the object before use.
    355     static void resetAndMakeReference(unsigned int id, unsigned int gen, SkPdfNativeObject* obj) {
    356         obj->reset();
    357         makeReference(id, gen, obj);
    358     }
    359 
    360     // Creates a String object. Assumes and asserts that it was never initialized.
    361     static void makeString(const unsigned char* start, SkPdfNativeObject* obj) {
    362         makeStringCore(start, strlen((const char*)start), obj, kString_PdfObjectType);
    363     }
    364 
    365     // Creates a String object. Assumes and asserts that it was never initialized.
    366     static void makeString(const unsigned char* start, const unsigned char* end,
    367                            SkPdfNativeObject* obj) {
    368         makeStringCore(start, end - start, obj, kString_PdfObjectType);
    369     }
    370 
    371     // Creates a String object. Assumes and asserts that it was never initialized.
    372     static void makeString(const unsigned char* start, size_t bytes, SkPdfNativeObject* obj) {
    373         makeStringCore(start, bytes, obj, kString_PdfObjectType);
    374     }
    375 
    376     // Creates a HexString object. Assumes and asserts that it was never initialized.
    377     static void makeHexString(const unsigned char* start, SkPdfNativeObject* obj) {
    378         makeStringCore(start, strlen((const char*)start), obj, kHexString_PdfObjectType);
    379     }
    380 
    381     // Creates a HexString object. Assumes and asserts that it was never initialized.
    382     static void makeHexString(const unsigned char* start, const unsigned char* end,
    383                               SkPdfNativeObject* obj) {
    384         makeStringCore(start, end - start, obj, kHexString_PdfObjectType);
    385     }
    386 
    387     // Creates a HexString object. Assumes and asserts that it was never initialized.
    388     static void makeHexString(const unsigned char* start, size_t bytes, SkPdfNativeObject* obj) {
    389         makeStringCore(start, bytes, obj, kHexString_PdfObjectType);
    390     }
    391 
    392     // Creates a Name object. Assumes and asserts that it was never initialized.
    393     static void makeName(const unsigned char* start, SkPdfNativeObject* obj) {
    394         makeStringCore(start, strlen((const char*)start), obj, kName_PdfObjectType);
    395     }
    396 
    397     // Creates a Name object. Assumes and asserts that it was never initialized.
    398     static void makeName(const unsigned char* start, const unsigned char* end,
    399                          SkPdfNativeObject* obj) {
    400         makeStringCore(start, end - start, obj, kName_PdfObjectType);
    401     }
    402 
    403     // Creates a Name object. Assumes and asserts that it was never initialized.
    404     static void makeName(const unsigned char* start, size_t bytes, SkPdfNativeObject* obj) {
    405         makeStringCore(start, bytes, obj, kName_PdfObjectType);
    406     }
    407 
    408     // Creates a Keyword object. Assumes and asserts that it was never initialized.
    409     static void makeKeyword(const unsigned char* start, SkPdfNativeObject* obj) {
    410         makeStringCore(start, strlen((const char*)start), obj, kKeyword_PdfObjectType);
    411     }
    412 
    413     // Creates a Keyword object. Assumes and asserts that it was never initialized.
    414     static void makeKeyword(const unsigned char* start, const unsigned char* end,
    415                             SkPdfNativeObject* obj) {
    416         makeStringCore(start, end - start, obj, kKeyword_PdfObjectType);
    417     }
    418 
    419     // Creates a Keyword object. Assumes and asserts that it was never initialized.
    420     static void makeKeyword(const unsigned char* start, size_t bytes, SkPdfNativeObject* obj) {
    421         makeStringCore(start, bytes, obj, kKeyword_PdfObjectType);
    422     }
    423 
    424     // Creates an empty Array object. Assumes and asserts that it was never initialized.
    425     static void makeEmptyArray(SkPdfNativeObject* obj) {
    426         SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
    427 
    428         obj->fObjectType = kArray_PdfObjectType;
    429         obj->fArray = new SkTDArray<SkPdfNativeObject*>();
    430     }
    431 
    432     // Appends an object into the array. Assumes <this> is an array.
    433     bool appendInArray(SkPdfNativeObject* obj) {
    434         SkASSERT(fObjectType == kArray_PdfObjectType);
    435         if (fObjectType != kArray_PdfObjectType) {
    436             // TODO(edisonn): report/warning/assert?
    437             return false;
    438         }
    439 
    440         fArray->push(obj);
    441         return true;
    442     }
    443 
    444     // Returns the size of an array.
    445     size_t size() const {
    446         SkPdfMarkObjectUsed();
    447 
    448         SkASSERT(fObjectType == kArray_PdfObjectType);
    449 
    450         return fArray->count();
    451     }
    452 
    453     // Returns one object of an array, by index.
    454     SkPdfNativeObject* objAtAIndex(int i) {
    455         SkPdfMarkObjectUsed();
    456 
    457         SkASSERT(fObjectType == kArray_PdfObjectType);
    458 
    459         return (*fArray)[i];
    460     }
    461 
    462     // Returns one object of an array, by index.
    463     const SkPdfNativeObject* objAtAIndex(int i) const {
    464         SkPdfMarkObjectUsed();
    465 
    466         SkASSERT(fObjectType == kArray_PdfObjectType);
    467 
    468         return (*fArray)[i];
    469     }
    470 
    471     // Returns one object of an array, by index.
    472     SkPdfNativeObject* operator[](int i) {
    473         SkPdfMarkObjectUsed();
    474 
    475         SkASSERT(fObjectType == kArray_PdfObjectType);
    476 
    477         return (*fArray)[i];
    478     }
    479 
    480     const SkPdfNativeObject* operator[](int i) const {
    481         SkPdfMarkObjectUsed();
    482 
    483         SkASSERT(fObjectType == kArray_PdfObjectType);
    484 
    485         return (*fArray)[i];
    486     }
    487 
    488     // Removes the last object in the array.
    489     SkPdfNativeObject* removeLastInArray() {
    490         SkPdfMarkObjectUsed();
    491 
    492         SkASSERT(fObjectType == kArray_PdfObjectType);
    493 
    494         SkPdfNativeObject* ret = NULL;
    495         fArray->pop(&ret);
    496 
    497         return ret;
    498     }
    499 
    500     // Creates an empty Dictionary object. Assumes and asserts that it was never initialized.
    501     static void makeEmptyDictionary(SkPdfNativeObject* obj) {
    502         SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
    503 
    504         obj->fObjectType = kDictionary_PdfObjectType;
    505         obj->fMap = new SkTDict<SkPdfNativeObject*>(1);
    506         obj->fStr.fBuffer = NULL;
    507         obj->fStr.fBytes = 0;
    508     }
    509 
    510     // TODO(edisonn): perf: get all the possible names from spec, and compute a hash function
    511     // that would create no overlaps in the same dictionary
    512     // or build a tree of chars that when followed goes to a unique id/index/hash
    513     // TODO(edisonn): generate constants like kDictFoo, kNameDict_name
    514     // which will be used in code
    515     // add function SkPdfFastNameKey key(const char* key);
    516     // TODO(edisonn): setting the same key twice, will make the value undefined!
    517 
    518     // this[key] = value;
    519     bool set(const SkPdfNativeObject* key, SkPdfNativeObject* value) {
    520         SkPdfMarkObjectUsed();
    521 
    522         SkASSERT(fObjectType == kDictionary_PdfObjectType);
    523         SkASSERT(key->fObjectType == kName_PdfObjectType);
    524 
    525         if (key->fObjectType != kName_PdfObjectType || fObjectType != kDictionary_PdfObjectType) {
    526             // TODO(edisonn): report/warn/assert?
    527             return false;
    528         }
    529 
    530         return set(key->fStr.fBuffer, key->fStr.fBytes, value);
    531     }
    532 
    533     // this[key] = value;
    534     bool set(const char* key, SkPdfNativeObject* value) {
    535         SkPdfMarkObjectUsed();
    536 
    537         return set((const unsigned char*)key, strlen(key), value);
    538     }
    539 
    540     // this[key] = value;
    541     bool set(const unsigned char* key, size_t len, SkPdfNativeObject* value) {
    542         SkPdfMarkObjectUsed();
    543 
    544         SkASSERT(fObjectType == kDictionary_PdfObjectType);
    545 
    546         if (fObjectType != kDictionary_PdfObjectType) {
    547             // TODO(edisonn): report/warn/assert.
    548             return false;
    549         }
    550 
    551         return fMap->set((const char*)key, len, value);
    552     }
    553 
    554     // Returns an object from a Dictionary, identified by it's name.
    555     SkPdfNativeObject* get(const SkPdfNativeObject* key) {
    556         SkPdfMarkObjectUsed();
    557 
    558         SkASSERT(fObjectType == kDictionary_PdfObjectType);
    559         SkASSERT(key->fObjectType == kName_PdfObjectType);
    560 
    561         if (key->fObjectType != kName_PdfObjectType || fObjectType != kDictionary_PdfObjectType) {
    562             // TODO(edisonn): report/warn/assert.
    563             return NULL;
    564         }
    565 
    566         return get(key->fStr.fBuffer, key->fStr.fBytes);
    567     }
    568 
    569     // Returns an object from a Dictionary, identified by it's name.
    570     SkPdfNativeObject* get(const char* key) {
    571         SkPdfMarkObjectUsed();
    572 
    573         return get((const unsigned char*)key, strlen(key));
    574     }
    575 
    576     // Returns an object from a Dictionary, identified by it's name.
    577     SkPdfNativeObject* get(const unsigned char* key, size_t len) {
    578         SkPdfMarkObjectUsed();
    579 
    580         SkASSERT(fObjectType == kDictionary_PdfObjectType);
    581         SkASSERT(key);
    582         if (fObjectType != kDictionary_PdfObjectType) {
    583             // TODO(edisonn): report/warn/assert.
    584             return NULL;
    585         }
    586         SkPdfNativeObject* ret = NULL;
    587         fMap->find((const char*)key, len, &ret);
    588 
    589 #ifdef PDF_TRACE
    590         SkString _key;
    591         _key.append((const char*)key, len);
    592         printf("\nget(/%s) = %s\n", _key.c_str(),
    593                ret ? ret->toString(0, len + 9).c_str() : "_NOT_FOUND");
    594 #endif
    595 
    596         return ret;
    597     }
    598 
    599     // Returns an object from a Dictionary, identified by it's name.
    600     const SkPdfNativeObject* get(const SkPdfNativeObject* key) const {
    601         SkPdfMarkObjectUsed();
    602 
    603         SkASSERT(fObjectType == kDictionary_PdfObjectType);
    604         SkASSERT(key->fObjectType == kName_PdfObjectType);
    605 
    606         if (key->fObjectType != kName_PdfObjectType || fObjectType != kDictionary_PdfObjectType) {
    607             // TODO(edisonn): report/warn/assert.
    608             return NULL;
    609         }
    610 
    611         return get(key->fStr.fBuffer, key->fStr.fBytes);
    612     }
    613 
    614     // Returns an object from a Dictionary, identified by it's name.
    615     const SkPdfNativeObject* get(const char* key) const {
    616         SkPdfMarkObjectUsed();
    617 
    618         return get((const unsigned char*)key, strlen(key));
    619     }
    620 
    621     // Returns an object from a Dictionary, identified by it's name.
    622     const SkPdfNativeObject* get(const unsigned char* key, size_t len) const {
    623         SkPdfMarkObjectUsed();
    624 
    625         SkASSERT(fObjectType == kDictionary_PdfObjectType);
    626         SkASSERT(key);
    627         if (fObjectType != kDictionary_PdfObjectType) {
    628             // TODO(edisonn): report/warn/assert.
    629             return NULL;
    630         }
    631         SkPdfNativeObject* ret = NULL;
    632         fMap->find((const char*)key, len, &ret);
    633 
    634 #ifdef PDF_TRACE
    635         SkString _key;
    636         _key.append((const char*)key, len);
    637         printf("\nget(/%s) = %s\n", _key.c_str(),
    638                ret ? ret->toString(0, len + 9).c_str() : "_NOT_FOUND");
    639 #endif
    640 
    641         return ret;
    642     }
    643 
    644     // Returns an object from a Dictionary, identified by it's name.
    645     const SkPdfNativeObject* get(const char* key, const char* abr) const {
    646         SkPdfMarkObjectUsed();
    647 
    648         const SkPdfNativeObject* ret = get(key);
    649         // TODO(edisonn): remove  || *abr == '\0' and pass NULL in the _autogen files instead.
    650         if (ret != NULL || abr == NULL || *abr == '\0') {
    651             return ret;
    652         }
    653         return get(abr);
    654     }
    655 
    656     // Returns an object from a Dictionary, identified by it's name.
    657     SkPdfNativeObject* get(const char* key, const char* abr) {
    658         SkPdfMarkObjectUsed();
    659 
    660         SkPdfNativeObject* ret = get(key);
    661         // TODO(edisonn): remove  || *abr == '\0' and pass NULL in the _autogen files instead.
    662         if (ret != NULL || abr == NULL || *abr == '\0') {
    663             return ret;
    664         }
    665         return get(abr);
    666     }
    667 
    668     // Casts the object to a Dictionary. Asserts if the object is not a Dictionary.
    669     SkPdfDictionary* asDictionary() {
    670         SkPdfMarkObjectUsed();
    671 
    672         SkASSERT(isDictionary());
    673         if (!isDictionary()) {
    674             return NULL;
    675         }
    676         return (SkPdfDictionary*) this;
    677     }
    678 
    679     // Casts the object to a Dictionary. Asserts if the object is not a Dictionary.
    680     const SkPdfDictionary* asDictionary() const {
    681         SkPdfMarkObjectUsed();
    682 
    683         SkASSERT(isDictionary());
    684         if (!isDictionary()) {
    685             return NULL;
    686         }
    687         return (SkPdfDictionary*) this;
    688     }
    689 
    690 
    691     // Returns true if the object is a Reference.
    692     bool isReference() const {
    693         SkPdfMarkObjectUsed();
    694 
    695         return fObjectType == kReference_PdfObjectType;
    696     }
    697 
    698     // Returns true if the object is a Boolean.
    699     bool isBoolean() const {
    700         SkPdfMarkObjectUsed();
    701 
    702         return fObjectType == kBoolean_PdfObjectType;
    703     }
    704 
    705     // Returns true if the object is an Integer.
    706     bool isInteger() const {
    707         SkPdfMarkObjectUsed();
    708 
    709         return fObjectType == kInteger_PdfObjectType;
    710     }
    711 
    712 private:
    713     // Returns true if the object is a Real number.
    714     bool isReal() const {
    715         SkPdfMarkObjectUsed();
    716 
    717         return fObjectType == kReal_PdfObjectType;
    718     }
    719 
    720 public:
    721     // Returns true if the object is a Number (either Integer or Real).
    722     bool isNumber() const {
    723         SkPdfMarkObjectUsed();
    724 
    725         return fObjectType == kInteger_PdfObjectType || fObjectType == kReal_PdfObjectType;
    726     }
    727 
    728     // Returns true if the object is a R keyword (used to identify references, e.g. "10 3 R".
    729     bool isKeywordReference() const {
    730         SkPdfMarkObjectUsed();
    731 
    732         return fObjectType == kKeyword_PdfObjectType && fStr.fBytes == 1 && fStr.fBuffer[0] == 'R';
    733     }
    734 
    735     // Returns true if the object is a Keyword.
    736     bool isKeyword() const {
    737         SkPdfMarkObjectUsed();
    738 
    739         return fObjectType == kKeyword_PdfObjectType;
    740     }
    741 
    742     // Returns true if the object is a given Keyword.
    743     bool isKeyword(const char* keyword) const {
    744         SkPdfMarkObjectUsed();
    745 
    746         if (!isKeyword()) {
    747             return false;
    748         }
    749 
    750         if (strlen(keyword) != fStr.fBytes) {
    751             return false;
    752         }
    753 
    754         if (strncmp(keyword, (const char*)fStr.fBuffer, fStr.fBytes) != 0) {
    755             return false;
    756         }
    757 
    758         return true;
    759     }
    760 
    761     // Returns true if the object is a Name.
    762     bool isName() const {
    763         SkPdfMarkObjectUsed();
    764 
    765         return fObjectType == kName_PdfObjectType;
    766     }
    767 
    768     // Returns true if the object is a given Name.
    769     bool isName(const char* name) const {
    770         SkPdfMarkObjectUsed();
    771 
    772         return fObjectType == kName_PdfObjectType &&
    773                 fStr.fBytes == strlen(name) &&
    774                 strncmp((const char*)fStr.fBuffer, name, fStr.fBytes) == 0;
    775     }
    776 
    777     // Returns true if the object is an Array.
    778     bool isArray() const {
    779         SkPdfMarkObjectUsed();
    780 
    781         return fObjectType == kArray_PdfObjectType;
    782     }
    783 
    784     // Returns true if the object is a Date.
    785     // TODO(edisonn): NYI
    786     bool isDate() const {
    787         SkPdfMarkObjectUsed();
    788 
    789         return fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType;
    790     }
    791 
    792     // Returns true if the object is a Dictionary.
    793     bool isDictionary() const {
    794         SkPdfMarkObjectUsed();
    795 
    796         return fObjectType == kDictionary_PdfObjectType;
    797     }
    798 
    799     // Returns true if the object is a Date.
    800     // TODO(edisonn): NYI
    801     bool isFunction() const {
    802         SkPdfMarkObjectUsed();
    803 
    804         return false;  // NYI
    805     }
    806 
    807     // Returns true if the object is a Rectangle.
    808     bool isRectangle() const {
    809         SkPdfMarkObjectUsed();
    810 
    811         // TODO(edisonn): add also that each of these 4 objects are numbers.
    812         return fObjectType == kArray_PdfObjectType && fArray->count() == 4;
    813     }
    814 
    815     // TODO(edisonn): Design: decide if we should use hasStream or isStream
    816     // Returns true if the object has a stream associated with it.
    817     bool hasStream() const {
    818         SkPdfMarkObjectUsed();
    819 
    820         return isDictionary() && fStr.fBuffer != NULL;
    821     }
    822 
    823     // Returns the stream associated with the dictionary. As of now, it casts this to Stream.
    824     const SkPdfStream* getStream() const {
    825         SkPdfMarkObjectUsed();
    826 
    827         return hasStream() ? (const SkPdfStream*)this : NULL;
    828     }
    829 
    830     // Returns the stream associated with the dictionary. As of now, it casts this to Stream.
    831     SkPdfStream* getStream() {
    832         SkPdfMarkObjectUsed();
    833 
    834         return hasStream() ? (SkPdfStream*)this : NULL;
    835     }
    836 
    837     // Returns true if the object is a String or HexString.
    838     bool isAnyString() const {
    839         SkPdfMarkObjectUsed();
    840 
    841         return fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType;
    842     }
    843 
    844     // Returns true if the object is a HexString.
    845     bool isHexString() const {
    846         SkPdfMarkObjectUsed();
    847 
    848         return fObjectType == kHexString_PdfObjectType;
    849     }
    850 
    851     // Returns true if the object is a Matrix.
    852     bool isMatrix() const {
    853         SkPdfMarkObjectUsed();
    854 
    855         // TODO(edisonn): add also that each of these 6 objects are numbers.
    856         return fObjectType == kArray_PdfObjectType && fArray->count() == 6;
    857     }
    858 
    859     // Returns the int value stored in the object. Assert if the object is not an Integer.
    860     inline int64_t intValue() const {
    861         SkPdfMarkObjectUsed();
    862 
    863         SkASSERT(fObjectType == kInteger_PdfObjectType);
    864 
    865         if (fObjectType != kInteger_PdfObjectType) {
    866             // TODO(edisonn): report/warn/assert.
    867             return 0;
    868         }
    869         return fIntegerValue;
    870     }
    871 
    872 private:
    873     // Returns the real value stored in the object. Assert if the object is not a Real.
    874     inline double realValue() const {
    875         SkPdfMarkObjectUsed();
    876 
    877         SkASSERT(fObjectType == kReal_PdfObjectType);
    878 
    879         if (fObjectType != kReal_PdfObjectType) {
    880             // TODO(edisonn): report/warn/assert.
    881             return 0;
    882         }
    883         return fRealValue;
    884     }
    885 
    886 public:
    887     // Returns the numeric value stored in the object. Assert if the object is not a Real
    888     // or an Integer.
    889     inline double numberValue() const {
    890         SkPdfMarkObjectUsed();
    891 
    892         SkASSERT(isNumber());
    893 
    894         if (!isNumber()) {
    895             // TODO(edisonn): report/warn/assert.
    896             return 0;
    897         }
    898         return fObjectType == kReal_PdfObjectType ? fRealValue : fIntegerValue;
    899     }
    900 
    901     // Returns the numeric value stored in the object as a scalar. Assert if the object is not
    902     // a Realor an Integer.
    903     inline SkScalar scalarValue() const {
    904         SkPdfMarkObjectUsed();
    905 
    906         SkASSERT(isNumber());
    907 
    908         if (!isNumber()) {
    909             // TODO(edisonn): report/warn/assert.
    910             return SkIntToScalar(0);
    911         }
    912         return fObjectType == kReal_PdfObjectType ? SkDoubleToScalar(fRealValue) :
    913                                                     SkIntToScalar(fIntegerValue);
    914     }
    915 
    916     // Returns the id of the referenced object. Assert if the object is not a Reference.
    917     int referenceId() const {
    918         SkPdfMarkObjectUsed();
    919 
    920         SkASSERT(fObjectType == kReference_PdfObjectType);
    921         return fRef.fId;
    922     }
    923 
    924     // Returns the generation of the referenced object. Assert if the object is not a Reference.
    925     int referenceGeneration() const {
    926         SkPdfMarkObjectUsed();
    927 
    928         SkASSERT(fObjectType == kReference_PdfObjectType);
    929         return fRef.fGen;
    930     }
    931 
    932     // Returns the buffer of a Name object. Assert if the object is not a Name.
    933     inline const char* nameValue() const {
    934         SkPdfMarkObjectUsed();
    935 
    936         SkASSERT(fObjectType == kName_PdfObjectType);
    937 
    938         if (fObjectType != kName_PdfObjectType) {
    939             // TODO(edisonn): report/warn/assert.
    940             return "";
    941         }
    942         return (const char*)fStr.fBuffer;
    943     }
    944 
    945     // Returns the buffer of a (Hex)String object. Assert if the object is not a (Hex)String.
    946     inline const char* stringValue() const {
    947         SkPdfMarkObjectUsed();
    948 
    949         SkASSERT(fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType);
    950 
    951         if (fObjectType != kString_PdfObjectType && fObjectType != kHexString_PdfObjectType) {
    952             // TODO(edisonn): report/warn/assert.
    953             return "";
    954         }
    955         return (const char*)fStr.fBuffer;
    956     }
    957 
    958     // Returns the storage of any type that can hold a form of string.
    959     inline NotOwnedString strRef() {
    960         SkPdfMarkObjectUsed();
    961 
    962         switch (fObjectType) {
    963             case kString_PdfObjectType:
    964             case kHexString_PdfObjectType:
    965             case kKeyword_PdfObjectType:
    966             case kName_PdfObjectType:
    967                 return fStr;
    968 
    969             default:
    970                 // TODO(edisonn): report/warning
    971                 return NotOwnedString();
    972         }
    973     }
    974 
    975     // TODO(edisonn): nameValue2 and stringValue2 are used to make code generation easy,
    976     // but it is not a performat way to do it, since it will create an extra copy
    977     // remove these functions and make code generated faster
    978     inline SkString nameValue2() const {
    979         SkPdfMarkObjectUsed();
    980 
    981         SkASSERT(fObjectType == kName_PdfObjectType);
    982 
    983         if (fObjectType != kName_PdfObjectType) {
    984             // TODO(edisonn): log err
    985             return SkString();
    986         }
    987         return SkString((const char*)fStr.fBuffer, fStr.fBytes);
    988     }
    989 
    990     // Returns an SkString with the value of the (Hex)String object.
    991     inline SkString stringValue2() const {
    992         SkPdfMarkObjectUsed();
    993 
    994         SkASSERT(fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType);
    995 
    996         if (fObjectType != kString_PdfObjectType && fObjectType != kHexString_PdfObjectType) {
    997             // TODO(edisonn): report/warn/assert.
    998             return SkString();
    999         }
   1000         return SkString((const char*)fStr.fBuffer, fStr.fBytes);
   1001     }
   1002 
   1003     // Returns the boolean of the Bool object. Assert if the object is not a Bool.
   1004     inline bool boolValue() const {
   1005         SkPdfMarkObjectUsed();
   1006 
   1007         SkASSERT(fObjectType == kBoolean_PdfObjectType);
   1008 
   1009         if (fObjectType != kBoolean_PdfObjectType) {
   1010             // TODO(edisonn): report/warn/assert.
   1011             return false;
   1012         }
   1013         return fBooleanValue;
   1014     }
   1015 
   1016     // Returns the rectangle of the Rectangle object. Assert if the object is not a Rectangle.
   1017     SkRect rectangleValue() const {
   1018         SkPdfMarkObjectUsed();
   1019 
   1020         SkASSERT(isRectangle());
   1021         if (!isRectangle()) {
   1022             return SkRect::MakeEmpty();
   1023         }
   1024 
   1025         double array[4];
   1026         for (int i = 0; i < 4; i++) {
   1027             // TODO(edisonn): version where we could resolve references?
   1028             const SkPdfNativeObject* elem = objAtAIndex(i);
   1029             if (elem == NULL || !elem->isNumber()) {
   1030                 // TODO(edisonn): report/warn/assert.
   1031                 return SkRect::MakeEmpty();
   1032             }
   1033             array[i] = elem->numberValue();
   1034         }
   1035 
   1036         return SkRect::MakeLTRB(SkDoubleToScalar(array[0]),
   1037                                 SkDoubleToScalar(array[1]),
   1038                                 SkDoubleToScalar(array[2]),
   1039                                 SkDoubleToScalar(array[3]));
   1040     }
   1041 
   1042     // Returns the matrix of the Matrix object. Assert if the object is not a Matrix.
   1043     SkMatrix matrixValue() const {
   1044         SkPdfMarkObjectUsed();
   1045 
   1046         SkASSERT(isMatrix());
   1047         if (!isMatrix()) {
   1048             return SkMatrix::I();
   1049         }
   1050 
   1051         double array[6];
   1052         for (int i = 0; i < 6; i++) {
   1053             // TODO(edisonn): version where we could resolve references?
   1054             const SkPdfNativeObject* elem = objAtAIndex(i);
   1055             if (elem == NULL || !elem->isNumber()) {
   1056                 // TODO(edisonn): report/warn/assert.
   1057                 return SkMatrix::I();
   1058             }
   1059             array[i] = elem->numberValue();
   1060         }
   1061 
   1062         return SkMatrixFromPdfMatrix(array);
   1063     }
   1064 
   1065     // Runs all the filters of this stream, except the last one, if it is a DCT.
   1066     // Returns false on failure.
   1067     bool filterStream();
   1068 
   1069     // Runs all the filters of this stream, except the last one, if it is a DCT, a gives back
   1070     // the buffer and the length. The object continues to own the buffer.
   1071     // Returns false on failure.
   1072     bool GetFilteredStreamRef(unsigned char const** buffer, size_t* len) {
   1073         SkPdfMarkObjectUsed();
   1074 
   1075         // TODO(edisonn): add params that could let the last filter in place
   1076         // if it is jpeg or png to fast load images.
   1077         if (!hasStream()) {
   1078             return false;
   1079         }
   1080 
   1081         filterStream();
   1082 
   1083         if (buffer) {
   1084             *buffer = fStr.fBuffer;
   1085         }
   1086 
   1087         if (len) {
   1088             *len = fStr.fBytes >> 2;  // last 2 bits - TODO(edisonn): clean up.
   1089         }
   1090 
   1091         return true;
   1092     }
   1093 
   1094     // Returns true if the stream is already filtered.
   1095     bool isStreamFiltered() const {
   1096         SkPdfMarkObjectUsed();
   1097 
   1098         return hasStream() && ((fStr.fBytes & 1) == kFilteredStreamBit);
   1099     }
   1100 
   1101     // Returns true if this object own the buffer, or false if an Allocator own it.
   1102     bool isStreamOwned() const {
   1103         SkPdfMarkObjectUsed();
   1104 
   1105         return hasStream() && ((fStr.fBytes & 2) == kOwnedStreamBit);
   1106     }
   1107 
   1108     // Gives back the original buffer and the length. The object continues to own the buffer.
   1109     // Returns false if the stream is already filtered.
   1110     bool GetUnfilteredStreamRef(unsigned char const** buffer, size_t* len) const {
   1111         SkPdfMarkObjectUsed();
   1112 
   1113         if (isStreamFiltered()) {
   1114             return false;
   1115         }
   1116 
   1117         if (!hasStream()) {
   1118             return false;
   1119         }
   1120 
   1121         if (buffer) {
   1122             *buffer = fStr.fBuffer;
   1123         }
   1124 
   1125         if (len) {
   1126             *len = fStr.fBytes >> 2;  // remove last 2 bits - TODO(edisonn): clean up.
   1127         }
   1128 
   1129         return true;
   1130     }
   1131 
   1132     // Add a stream to this Dictionarry. Asserts we do not have yet a stream.
   1133     bool addStream(const unsigned char* buffer, size_t len) {
   1134         SkPdfMarkObjectUsed();
   1135 
   1136         SkASSERT(!hasStream());
   1137         SkASSERT(isDictionary());
   1138 
   1139         if (!isDictionary() || hasStream()) {
   1140             return false;
   1141         }
   1142 
   1143         fStr.fBuffer = buffer;
   1144         fStr.fBytes = (len << 2) + kUnfilteredStreamBit;
   1145 
   1146         return true;
   1147     }
   1148 
   1149     static void appendSpaces(SkString* str, int level) {
   1150         for (int i = 0 ; i < level; i++) {
   1151             str->append(" ");
   1152         }
   1153     }
   1154 
   1155     static void append(SkString* str, const char* data, size_t len, const char* prefix = "\\x") {
   1156         for (unsigned int i = 0 ; i < len; i++) {
   1157             if (data[i] == kNUL_PdfWhiteSpace) {
   1158                 str->append(prefix);
   1159                 str->append("00");
   1160             } else if (data[i] == kHT_PdfWhiteSpace) {
   1161                 str->append(prefix);
   1162                 str->append("09");
   1163             } else if (data[i] == kLF_PdfWhiteSpace) {
   1164                 str->append(prefix);
   1165                 str->append("0A");
   1166             } else if (data[i] == kFF_PdfWhiteSpace) {
   1167                 str->append(prefix);
   1168                 str->append("0C");
   1169             } else if (data[i] == kCR_PdfWhiteSpace) {
   1170                 str->append(prefix);
   1171                 str->append("0D");
   1172             } else {
   1173                 str->append(data + i, 1);
   1174             }
   1175         }
   1176     }
   1177 
   1178     // Returns the string representation of the object value.
   1179     SkString toString(int firstRowLevel = 0, int level = 0) {
   1180         SkString str;
   1181         appendSpaces(&str, firstRowLevel);
   1182         switch (fObjectType) {
   1183             case kInvalid_PdfObjectType:
   1184                 str.append("__Invalid");
   1185                 break;
   1186 
   1187             case kBoolean_PdfObjectType:
   1188                 str.appendf("%s", fBooleanValue ? "true" : "false");
   1189                 break;
   1190 
   1191             case kInteger_PdfObjectType:
   1192                 str.appendf("%i", (int)fIntegerValue);
   1193                 break;
   1194 
   1195             case kReal_PdfObjectType:
   1196                 str.appendf("%f", fRealValue);
   1197                 break;
   1198 
   1199             case kString_PdfObjectType:
   1200                 str.append("\"");
   1201                 append(&str, (const char*)fStr.fBuffer, fStr.fBytes);
   1202                 str.append("\"");
   1203                 break;
   1204 
   1205             case kHexString_PdfObjectType:
   1206                 str.append("<");
   1207                 for (unsigned int i = 0 ; i < fStr.fBytes; i++) {
   1208                     str.appendf("%02x", (unsigned int)fStr.fBuffer[i]);
   1209                 }
   1210                 str.append(">");
   1211                 break;
   1212 
   1213             case kName_PdfObjectType:
   1214                 str.append("/");
   1215                 append(&str, (const char*)fStr.fBuffer, fStr.fBytes, "#");
   1216                 break;
   1217 
   1218             case kKeyword_PdfObjectType:
   1219                 append(&str, (const char*)fStr.fBuffer, fStr.fBytes);
   1220                 break;
   1221 
   1222             case kArray_PdfObjectType:
   1223                 str.append("[\n");
   1224                 for (unsigned int i = 0; i < size(); i++) {
   1225                     str.append(objAtAIndex(i)->toString(level + 1, level + 1));
   1226                     if (i < size() - 1) {
   1227                         str.append(",");
   1228                     }
   1229                     str.append("\n");
   1230                 }
   1231                 appendSpaces(&str, level);
   1232                 str.append("]");
   1233                 break;
   1234 
   1235             case kDictionary_PdfObjectType: {
   1236                     SkTDict<SkPdfNativeObject*>::Iter iter(*fMap);
   1237                     SkPdfNativeObject* obj = NULL;
   1238                     const char* key = NULL;
   1239                     str.append("<<\n");
   1240                     while ((key = iter.next(&obj)) != NULL) {
   1241                         appendSpaces(&str, level + 2);
   1242                         str.appendf("/%s %s\n", key,
   1243                                     obj->toString(0, level + (int) strlen(key) + 4).c_str());
   1244                     }
   1245                     appendSpaces(&str, level);
   1246                     str.append(">>");
   1247                     if (hasStream()) {
   1248                         const unsigned char* stream = NULL;
   1249                         size_t length = 0;
   1250                         if (GetFilteredStreamRef(&stream, &length)) {
   1251                             str.append("stream\n");
   1252                             append(&str, (const char*)stream, length > 256 ? 256 : length);
   1253                             str.append("\nendstream");
   1254                         } else {
   1255                             str.append("stream STREAM_ERROR endstream");
   1256                         }
   1257                     }
   1258                 }
   1259                 break;
   1260 
   1261             case kNull_PdfObjectType:
   1262                 str = "NULL";
   1263                 break;
   1264 
   1265             case kReference_PdfObjectType:
   1266                 str.appendf("%i %i R", fRef.fId, fRef.fGen);
   1267                 break;
   1268 
   1269             case kUndefined_PdfObjectType:
   1270                 str = "Undefined";
   1271                 break;
   1272 
   1273             default:
   1274                 str = "Error";
   1275                 break;
   1276         }
   1277 
   1278         return str;
   1279     }
   1280 
   1281 private:
   1282     static void makeStringCore(const unsigned char* start, SkPdfNativeObject* obj,
   1283                                ObjectType type) {
   1284         makeStringCore(start, strlen((const char*)start), obj, type);
   1285     }
   1286 
   1287     static void makeStringCore(const unsigned char* start, const unsigned char* end,
   1288                                SkPdfNativeObject* obj, ObjectType type) {
   1289         makeStringCore(start, end - start, obj, type);
   1290     }
   1291 
   1292     static void makeStringCore(const unsigned char* start, size_t bytes, SkPdfNativeObject* obj,
   1293                                ObjectType type) {
   1294         SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
   1295 
   1296         obj->fObjectType = type;
   1297         obj->fStr.fBuffer = start;
   1298         obj->fStr.fBytes = bytes;
   1299     }
   1300 
   1301     bool applyFilter(const char* name);
   1302     bool applyFlateDecodeFilter();
   1303     bool applyDCTDecodeFilter();
   1304 };
   1305 
   1306 // These classes are provided for convenience. You still have to make sure an SkPdfInteger
   1307 // is indeed an Integer.
   1308 class SkPdfStream : public SkPdfNativeObject {};
   1309 class SkPdfArray : public SkPdfNativeObject {};
   1310 class SkPdfString : public SkPdfNativeObject {};
   1311 class SkPdfHexString : public SkPdfNativeObject {};
   1312 class SkPdfInteger : public SkPdfNativeObject {};
   1313 class SkPdfReal : public SkPdfNativeObject {};
   1314 class SkPdfNumber : public SkPdfNativeObject {};
   1315 
   1316 class SkPdfName : public SkPdfNativeObject {
   1317     SkPdfName() : SkPdfNativeObject() {
   1318         SkPdfNativeObject::makeName((const unsigned char*)"", this);
   1319     }
   1320 public:
   1321     SkPdfName(char* name) : SkPdfNativeObject() {
   1322         this->makeName((const unsigned char*)name, this);
   1323     }
   1324 };
   1325 
   1326 #endif  // SkPdfNativeObject
   1327