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.
streamId()128     int streamId() const { return fStreamId; }
offsetStart()129     int offsetStart() const { return fOffsetStart; }
offsetEnd()130     int offsetEnd() const { return fOffsetEnd; }
131 #endif  // PDF_TRACK_STREAM_OFFSETS
132 
SkPdfNativeObject()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.
inRendering()150     bool inRendering() const { return fInRendering != 0; }
startRendering()151     void startRendering() {fInRendering = 1;}
doneRendering()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.
hasData(DataType type)156     inline bool hasData(DataType type) {
157         return type == fDataType;
158     }
159 
160     // returns the cached value
data(DataType type)161     inline void* data(DataType type) {
162         return type == fDataType ? fData : NULL;
163     }
164 
165     // Stores something in the cache
setData(void * data,DataType type)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)
reset()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.
type()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
c_str()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
lenstr()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
dateValue()251     SkPdfDate& dateValue() const {
252         static SkPdfDate nyi;
253         return nyi;
254     }
255 
256     // TODO(edisonn): NYI
functionValue()257     SkPdfFunction& functionValue() const {
258         static SkPdfFunction nyi;
259         return nyi;
260     }
261 
262     // TODO(edisonn): NYI
fileSpecValue()263     SkPdfFileSpec& fileSpecValue() const {
264         static SkPdfFileSpec nyi;
265         return nyi;
266     }
267 
268     // TODO(edisonn): NYI
treeValue()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.
makeBoolean(bool value,SkPdfNativeObject * obj)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 
makeBoolean(bool value)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.
makeInteger(int64_t value,SkPdfNativeObject * obj)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.
makeReal(double value,SkPdfNativeObject * obj)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.
makeNull(SkPdfNativeObject * obj)307     static void makeNull(SkPdfNativeObject* obj) {
308         SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
309 
310         obj->fObjectType = kNull_PdfObjectType;
311     }
312 
makeNull()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.
makeNumeric(const unsigned char * start,const unsigned char * end,SkPdfNativeObject * obj)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.
makeReference(unsigned int id,unsigned int gen,SkPdfNativeObject * obj)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.
resetAndMakeReference(unsigned int id,unsigned int gen,SkPdfNativeObject * obj)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.
makeString(const unsigned char * start,SkPdfNativeObject * obj)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.
makeString(const unsigned char * start,const unsigned char * end,SkPdfNativeObject * obj)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.
makeString(const unsigned char * start,size_t bytes,SkPdfNativeObject * obj)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.
makeHexString(const unsigned char * start,SkPdfNativeObject * obj)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.
makeHexString(const unsigned char * start,const unsigned char * end,SkPdfNativeObject * obj)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.
makeHexString(const unsigned char * start,size_t bytes,SkPdfNativeObject * obj)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.
makeName(const unsigned char * start,SkPdfNativeObject * obj)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.
makeName(const unsigned char * start,const unsigned char * end,SkPdfNativeObject * obj)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.
makeName(const unsigned char * start,size_t bytes,SkPdfNativeObject * obj)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.
makeKeyword(const unsigned char * start,SkPdfNativeObject * obj)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.
makeKeyword(const unsigned char * start,const unsigned char * end,SkPdfNativeObject * obj)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.
makeKeyword(const unsigned char * start,size_t bytes,SkPdfNativeObject * obj)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.
makeEmptyArray(SkPdfNativeObject * obj)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.
appendInArray(SkPdfNativeObject * obj)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.
size()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.
objAtAIndex(int i)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.
objAtAIndex(int i)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.
removeLastInArray()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.
makeEmptyDictionary(SkPdfNativeObject * obj)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;
set(const SkPdfNativeObject * key,SkPdfNativeObject * 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;
set(const char * key,SkPdfNativeObject * 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;
set(const unsigned char * key,size_t len,SkPdfNativeObject * 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.
get(const SkPdfNativeObject * key)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.
get(const char * key)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.
get(const unsigned char * key,size_t len)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.
get(const SkPdfNativeObject * key)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.
get(const char * key)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.
get(const unsigned char * key,size_t len)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.
get(const char * key,const char * abr)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.
get(const char * key,const char * abr)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.
asDictionary()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.
asDictionary()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.
isReference()692     bool isReference() const {
693         SkPdfMarkObjectUsed();
694 
695         return fObjectType == kReference_PdfObjectType;
696     }
697 
698     // Returns true if the object is a Boolean.
isBoolean()699     bool isBoolean() const {
700         SkPdfMarkObjectUsed();
701 
702         return fObjectType == kBoolean_PdfObjectType;
703     }
704 
705     // Returns true if the object is an Integer.
isInteger()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.
isReal()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).
isNumber()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".
isKeywordReference()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.
isKeyword()736     bool isKeyword() const {
737         SkPdfMarkObjectUsed();
738 
739         return fObjectType == kKeyword_PdfObjectType;
740     }
741 
742     // Returns true if the object is a given Keyword.
isKeyword(const char * 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.
isName()762     bool isName() const {
763         SkPdfMarkObjectUsed();
764 
765         return fObjectType == kName_PdfObjectType;
766     }
767 
768     // Returns true if the object is a given Name.
isName(const char * 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.
isArray()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
isDate()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.
isDictionary()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
isFunction()801     bool isFunction() const {
802         SkPdfMarkObjectUsed();
803 
804         return false;  // NYI
805     }
806 
807     // Returns true if the object is a Rectangle.
isRectangle()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.
hasStream()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.
getStream()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.
getStream()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.
isAnyString()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.
isHexString()845     bool isHexString() const {
846         SkPdfMarkObjectUsed();
847 
848         return fObjectType == kHexString_PdfObjectType;
849     }
850 
851     // Returns true if the object is a Matrix.
isMatrix()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.
intValue()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.
realValue()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.
numberValue()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.
scalarValue()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.
referenceId()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.
referenceGeneration()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.
nameValue()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.
stringValue()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.
strRef()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
nameValue2()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.
stringValue2()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.
boolValue()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.
rectangleValue()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.
matrixValue()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.
GetFilteredStreamRef(unsigned char const ** buffer,size_t * len)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.
isStreamFiltered()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.
isStreamOwned()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.
GetUnfilteredStreamRef(unsigned char const ** buffer,size_t * len)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.
addStream(const unsigned char * buffer,size_t len)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 
appendSpaces(SkString * str,int level)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:
makeStringCore(const unsigned char * start,SkPdfNativeObject * obj,ObjectType type)1282     static void makeStringCore(const unsigned char* start, SkPdfNativeObject* obj,
1283                                ObjectType type) {
1284         makeStringCore(start, strlen((const char*)start), obj, type);
1285     }
1286 
makeStringCore(const unsigned char * start,const unsigned char * end,SkPdfNativeObject * obj,ObjectType type)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 
makeStringCore(const unsigned char * start,size_t bytes,SkPdfNativeObject * obj,ObjectType type)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 {
SkPdfName()1317     SkPdfName() : SkPdfNativeObject() {
1318         SkPdfNativeObject::makeName((const unsigned char*)"", this);
1319     }
1320 public:
SkPdfName(char * name)1321     SkPdfName(char* name) : SkPdfNativeObject() {
1322         this->makeName((const unsigned char*)name, this);
1323     }
1324 };
1325 
1326 #endif  // SkPdfNativeObject
1327