SkPdfNativeObject.h revision c8fda9d96be0bd944d37a6e23f7adad5f247c51d
15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)/*
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Copyright 2013 Google Inc.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Use of this source code is governed by a BSD-style license that can be
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * found in the LICENSE file.
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
74e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
84e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#ifndef SkPdfNativeObject_DEFINED
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define SkPdfNativeObject_DEFINED
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdint.h>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkMatrix.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkPdfConfig.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkPdfNativeTokenizer.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkPdfNYI.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkPdfUtils.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkRect.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkString.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkTDArray.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkTDict.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SkPdfDictionary;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SkPdfStream;
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SkPdfAllocator;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(edisonn): remove these constants and clean up the code.
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define kFilteredStreamBit 0
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define kUnfilteredStreamBit 1
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define kOwnedStreamBit 2
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SkPdfNativeObject {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     enum ObjectType {
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         // The type will have only one of these values, but for error reporting, we make it an enum
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         // so it can easily report that something was expected to be one of a few types
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         kInvalid_PdfObjectType = 1 << 1,
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         kBoolean_PdfObjectType = 1 << 2,
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         kInteger_PdfObjectType = 1 << 3,
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         kReal_PdfObjectType = 1 << 4,
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         _kNumber_PdfObjectType = kInteger_PdfObjectType | kReal_PdfObjectType,
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         kString_PdfObjectType = 1 << 5,
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         kHexString_PdfObjectType = 1 << 6,
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         _kAnyString_PdfObjectType = kString_PdfObjectType | kHexString_PdfObjectType,
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         kName_PdfObjectType = 1 << 7,
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         kKeyword_PdfObjectType = 1 << 8,
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         _kStream_PdfObjectType = 1 << 9,  //  attached to a Dictionary, do not use
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         kArray_PdfObjectType = 1 << 10,
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         kDictionary_PdfObjectType = 1 << 11,
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         kNull_PdfObjectType = 1 << 12,
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         kReference_PdfObjectType = 1 << 13,
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         kUndefined_PdfObjectType = 1 << 14,  // per 1.4 spec, if the same key appear twice in the
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              // dictionary, the value is undefined.
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         _kObject_PdfObjectType = -1,
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     };
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     enum DataType {
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         kEmpty_Data,
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         kFont_Data,
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         kBitmap_Data,
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     };
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)private:
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(edisonn): assert reset operations while in rendering! The objects should be reset
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // only when rendering is completed.
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32_t fInRendering : 1;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32_t fUnused : 31;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct Reference {
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        unsigned int fId;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        unsigned int fGen;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    };
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ObjectType fObjectType;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    union {
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        bool fBooleanValue;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        int64_t fIntegerValue;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // TODO(edisonn): double, float, SkScalar?
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        double fRealValue;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NotOwnedString fStr;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SkTDArray<SkPdfNativeObject*>* fArray;
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        Reference fRef;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    };
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkTDict<SkPdfNativeObject*>* fMap;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(edisonn): rename data with cache
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void* fData;
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DataType fDataType;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Keep this the last entries
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef PDF_TRACK_OBJECT_USAGE
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mutable bool fUsed;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif   // PDF_TRACK_OBJECT_USAGE
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef PDF_TRACK_STREAM_OFFSETS
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)public:
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int fStreamId;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int fOffsetStart;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int fOffsetEnd;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // PDF_TRACK_STREAM_OFFSETS
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)public:
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef PDF_TRACK_STREAM_OFFSETS
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int streamId() const { return fStreamId; }
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int offsetStart() const { return fOffsetStart; }
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int offsetEnd() const { return fOffsetEnd; }
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // PDF_TRACK_STREAM_OFFSETS
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SkPdfNativeObject() : fInRendering(0)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        , fObjectType(kInvalid_PdfObjectType)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        , fMap(NULL)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        , fData(NULL)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        , fDataType(kEmpty_Data)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef PDF_TRACK_OBJECT_USAGE
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        , fUsed(false)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif   // PDF_TRACK_OBJECT_USAGE
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef PDF_TRACK_STREAM_OFFSETS
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        , fStreamId(-1)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        , fOffsetStart(-1)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        , fOffsetEnd(-1)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // PDF_TRACK_STREAM_OFFSETS
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {}
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool inRendering() const { return fInRendering != 0; }
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void startRendering() {fInRendering = 1;}
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void doneRendering() {fInRendering = 0;}
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    inline bool hasData(DataType type) {
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return type == fDataType;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    inline void* data(DataType type) {
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return type == fDataType ? fData : NULL;
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    inline void setData(void* data, DataType type) {
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        releaseData();
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        fDataType = type;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        fData = data;
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void releaseData();
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//    ~SkPdfNativeObject() {
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//        //reset();  must be called manually! Normally, will be called by allocator destructor.
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//    }
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void reset() {
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SkPdfMarkObjectUnused();
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        switch (fObjectType) {
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case kArray_PdfObjectType:
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                delete fArray;
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            case kDictionary_PdfObjectType:
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                delete fMap;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                if (isStreamOwned()) {
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    delete[] fStr.fBuffer;
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    fStr.fBuffer = NULL;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    fStr.fBytes = 0;
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                }
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break;
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            default:
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                break;
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        fObjectType = kInvalid_PdfObjectType;
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        releaseData();
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
182    ObjectType type() {
183        SkPdfMarkObjectUsed();
184
185        return fObjectType;
186    }
187
188    const char* c_str() const {
189        SkPdfMarkObjectUsed();
190
191        switch (fObjectType) {
192            case kString_PdfObjectType:
193            case kHexString_PdfObjectType:
194            case kKeyword_PdfObjectType:
195            case kName_PdfObjectType:
196                return (const char*)fStr.fBuffer;
197
198            default:
199                // TODO(edisonn): report/warning/assert?
200                return NULL;
201        }
202    }
203
204    size_t lenstr() const {
205        SkPdfMarkObjectUsed();
206
207        switch (fObjectType) {
208            case kString_PdfObjectType:
209            case kHexString_PdfObjectType:
210            case kKeyword_PdfObjectType:
211            case kName_PdfObjectType:
212                return fStr.fBytes;
213
214            default:
215                // TODO(edisonn): report/warning/assert?
216                return 0;
217        }
218    }
219
220
221    // TODO(edisonn): NYI
222    SkPdfDate& dateValue() const {
223        static SkPdfDate nyi;
224        return nyi;
225    }
226
227    // TODO(edisonn): NYI
228    SkPdfFunction& functionValue() const {
229        static SkPdfFunction nyi;
230        return nyi;
231    }
232
233    // TODO(edisonn): NYI
234    SkPdfFileSpec& fileSpecValue() const {
235        static SkPdfFileSpec nyi;
236        return nyi;
237    }
238
239    // TODO(edisonn): NYI
240    SkPdfTree& treeValue() const {
241        static SkPdfTree nyi;
242        return nyi;
243    }
244
245    static void makeBoolean(bool value, SkPdfNativeObject* obj) {
246
247        SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
248
249        obj->fObjectType = kBoolean_PdfObjectType;
250        obj->fBooleanValue = value;
251    }
252
253    static SkPdfNativeObject makeBoolean(bool value) {
254        SkPdfNativeObject obj;
255
256        obj.fObjectType = kBoolean_PdfObjectType;
257        obj.fBooleanValue = value;
258        return obj;
259    }
260
261    static void makeInteger(int64_t value, SkPdfNativeObject* obj) {
262        SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
263
264        obj->fObjectType = kInteger_PdfObjectType;
265        obj->fIntegerValue = value;
266    }
267
268    static void makeReal(double value, SkPdfNativeObject* obj) {
269        SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
270
271        obj->fObjectType = kReal_PdfObjectType;
272        obj->fRealValue = value;
273    }
274
275    static void makeNull(SkPdfNativeObject* obj) {
276        SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
277
278        obj->fObjectType = kNull_PdfObjectType;
279    }
280
281    static SkPdfNativeObject makeNull() {
282        SkPdfNativeObject obj;
283
284        obj.fObjectType = kNull_PdfObjectType;
285        return obj;
286    }
287
288    static SkPdfNativeObject kNull;
289
290    static void makeNumeric(const unsigned char* start, const unsigned char* end,
291                            SkPdfNativeObject* obj) {
292        SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
293
294        // TODO(edisonn): NYI properly
295        // if has dot (impl), or exceeds max int, is real, otherwise is int
296        bool isInt = true;
297        for (const unsigned char* current = start; current < end; current++) {
298            if (*current == '.') {
299                isInt = false;
300                break;
301            }
302            // TODO(edisonn): report parse issue with numbers like "24asdasd123"
303        }
304        if (isInt) {
305            makeInteger(atol((const char*)start), obj);
306        } else {
307            makeReal(atof((const char*)start), obj);
308        }
309    }
310
311    static void makeReference(unsigned int id, unsigned int gen, SkPdfNativeObject* obj) {
312        SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
313
314        obj->fObjectType = kReference_PdfObjectType;
315        obj->fRef.fId = id;
316        obj->fRef.fGen = gen;
317    }
318
319    static void resetAndMakeReference(unsigned int id, unsigned int gen, SkPdfNativeObject* obj) {
320        obj->reset();
321        makeReference(id, gen, obj);
322    }
323
324
325    static void makeString(const unsigned char* start, SkPdfNativeObject* obj) {
326        makeStringCore(start, strlen((const char*)start), obj, kString_PdfObjectType);
327    }
328
329    static void makeString(const unsigned char* start, const unsigned char* end,
330                           SkPdfNativeObject* obj) {
331        makeStringCore(start, end - start, obj, kString_PdfObjectType);
332    }
333
334    static void makeString(const unsigned char* start, size_t bytes, SkPdfNativeObject* obj) {
335        makeStringCore(start, bytes, obj, kString_PdfObjectType);
336    }
337
338
339    static void makeHexString(const unsigned char* start, SkPdfNativeObject* obj) {
340        makeStringCore(start, strlen((const char*)start), obj, kHexString_PdfObjectType);
341    }
342
343    static void makeHexString(const unsigned char* start, const unsigned char* end,
344                              SkPdfNativeObject* obj) {
345        makeStringCore(start, end - start, obj, kHexString_PdfObjectType);
346    }
347
348    static void makeHexString(const unsigned char* start, size_t bytes, SkPdfNativeObject* obj) {
349        makeStringCore(start, bytes, obj, kHexString_PdfObjectType);
350    }
351
352
353    static void makeName(const unsigned char* start, SkPdfNativeObject* obj) {
354        makeStringCore(start, strlen((const char*)start), obj, kName_PdfObjectType);
355    }
356
357    static void makeName(const unsigned char* start, const unsigned char* end,
358                         SkPdfNativeObject* obj) {
359        makeStringCore(start, end - start, obj, kName_PdfObjectType);
360    }
361
362    static void makeName(const unsigned char* start, size_t bytes, SkPdfNativeObject* obj) {
363        makeStringCore(start, bytes, obj, kName_PdfObjectType);
364    }
365
366
367    static void makeKeyword(const unsigned char* start, SkPdfNativeObject* obj) {
368        makeStringCore(start, strlen((const char*)start), obj, kKeyword_PdfObjectType);
369    }
370
371    static void makeKeyword(const unsigned char* start, const unsigned char* end,
372                            SkPdfNativeObject* obj) {
373        makeStringCore(start, end - start, obj, kKeyword_PdfObjectType);
374    }
375
376    static void makeKeyword(const unsigned char* start, size_t bytes, SkPdfNativeObject* obj) {
377        makeStringCore(start, bytes, obj, kKeyword_PdfObjectType);
378    }
379
380    static void makeEmptyArray(SkPdfNativeObject* obj) {
381        SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
382
383        obj->fObjectType = kArray_PdfObjectType;
384        obj->fArray = new SkTDArray<SkPdfNativeObject*>();
385    }
386
387    bool appendInArray(SkPdfNativeObject* obj) {
388        SkASSERT(fObjectType == kArray_PdfObjectType);
389        if (fObjectType != kArray_PdfObjectType) {
390            // TODO(edisonn): report/warning/assert?
391            return false;
392        }
393
394        fArray->push(obj);
395        return true;
396    }
397
398    size_t size() const {
399        SkPdfMarkObjectUsed();
400
401        SkASSERT(fObjectType == kArray_PdfObjectType);
402
403        return fArray->count();
404    }
405
406    SkPdfNativeObject* objAtAIndex(int i) {
407        SkPdfMarkObjectUsed();
408
409        SkASSERT(fObjectType == kArray_PdfObjectType);
410
411        return (*fArray)[i];
412    }
413
414    SkPdfNativeObject* removeLastInArray() {
415        SkPdfMarkObjectUsed();
416
417        SkASSERT(fObjectType == kArray_PdfObjectType);
418
419        SkPdfNativeObject* ret = NULL;
420        fArray->pop(&ret);
421
422        return ret;
423    }
424
425    const SkPdfNativeObject* objAtAIndex(int i) const {
426        SkPdfMarkObjectUsed();
427
428        SkASSERT(fObjectType == kArray_PdfObjectType);
429
430        return (*fArray)[i];
431    }
432
433    SkPdfNativeObject* operator[](int i) {
434        SkPdfMarkObjectUsed();
435
436        SkASSERT(fObjectType == kArray_PdfObjectType);
437
438        return (*fArray)[i];
439    }
440
441    const SkPdfNativeObject* operator[](int i) const {
442        SkPdfMarkObjectUsed();
443
444        SkASSERT(fObjectType == kArray_PdfObjectType);
445
446        return (*fArray)[i];
447    }
448
449    static void makeEmptyDictionary(SkPdfNativeObject* obj) {
450        SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
451
452        obj->fObjectType = kDictionary_PdfObjectType;
453        obj->fMap = new SkTDict<SkPdfNativeObject*>(1);
454        obj->fStr.fBuffer = NULL;
455        obj->fStr.fBytes = 0;
456    }
457
458    // TODO(edisonn): perf: get all the possible names from spec, and compute a hash function
459    // that would create no overlaps in the same dictionary
460    // or build a tree of chars that when followed goes to a unique id/index/hash
461    // TODO(edisonn): generate constants like kDictFoo, kNameDict_name
462    // which will be used in code
463    // add function SkPdfFastNameKey key(const char* key);
464    // TODO(edisonn): setting the same key twice, will make the value undefined!
465    bool set(const SkPdfNativeObject* key, SkPdfNativeObject* value) {
466        SkPdfMarkObjectUsed();
467
468        SkASSERT(fObjectType == kDictionary_PdfObjectType);
469        SkASSERT(key->fObjectType == kName_PdfObjectType);
470
471        if (key->fObjectType != kName_PdfObjectType || fObjectType != kDictionary_PdfObjectType) {
472            // TODO(edisonn): report/warn/assert?
473            return false;
474        }
475
476        return set(key->fStr.fBuffer, key->fStr.fBytes, value);
477    }
478
479    bool set(const char* key, SkPdfNativeObject* value) {
480        SkPdfMarkObjectUsed();
481
482        return set((const unsigned char*)key, strlen(key), value);
483    }
484
485    bool set(const unsigned char* key, size_t len, SkPdfNativeObject* value) {
486        SkPdfMarkObjectUsed();
487
488        SkASSERT(fObjectType == kDictionary_PdfObjectType);
489
490        if (fObjectType != kDictionary_PdfObjectType) {
491            // TODO(edisonn): report/warn/assert.
492            return false;
493        }
494
495        return fMap->set((const char*)key, len, value);
496    }
497
498    SkPdfNativeObject* get(const SkPdfNativeObject* key) {
499        SkPdfMarkObjectUsed();
500
501        SkASSERT(fObjectType == kDictionary_PdfObjectType);
502        SkASSERT(key->fObjectType == kName_PdfObjectType);
503
504        if (key->fObjectType != kName_PdfObjectType || fObjectType != kDictionary_PdfObjectType) {
505            // TODO(edisonn): report/warn/assert.
506            return NULL;
507        }
508
509        return get(key->fStr.fBuffer, key->fStr.fBytes);
510    }
511
512    SkPdfNativeObject* get(const char* key) {
513        SkPdfMarkObjectUsed();
514
515        return get((const unsigned char*)key, strlen(key));
516    }
517
518    SkPdfNativeObject* get(const unsigned char* key, size_t len) {
519        SkPdfMarkObjectUsed();
520
521        SkASSERT(fObjectType == kDictionary_PdfObjectType);
522        SkASSERT(key);
523        if (fObjectType != kDictionary_PdfObjectType) {
524            // TODO(edisonn): report/warn/assert.
525            return NULL;
526        }
527        SkPdfNativeObject* ret = NULL;
528        fMap->find((const char*)key, len, &ret);
529
530#ifdef PDF_TRACE
531        SkString _key;
532        _key.append((const char*)key, len);
533        printf("\nget(/%s) = %s\n", _key.c_str(),
534               ret ? ret->toString(0, len + 9).c_str() : "_NOT_FOUND");
535#endif
536
537        return ret;
538    }
539
540    const SkPdfNativeObject* get(const SkPdfNativeObject* key) const {
541        SkPdfMarkObjectUsed();
542
543        SkASSERT(fObjectType == kDictionary_PdfObjectType);
544        SkASSERT(key->fObjectType == kName_PdfObjectType);
545
546        if (key->fObjectType != kName_PdfObjectType || fObjectType != kDictionary_PdfObjectType) {
547            // TODO(edisonn): report/warn/assert.
548            return NULL;
549        }
550
551        return get(key->fStr.fBuffer, key->fStr.fBytes);
552    }
553
554    const SkPdfNativeObject* get(const char* key) const {
555        SkPdfMarkObjectUsed();
556
557        return get((const unsigned char*)key, strlen(key));
558    }
559
560    const SkPdfNativeObject* get(const unsigned char* key, size_t len) const {
561        SkPdfMarkObjectUsed();
562
563        SkASSERT(fObjectType == kDictionary_PdfObjectType);
564        SkASSERT(key);
565        if (fObjectType != kDictionary_PdfObjectType) {
566            // TODO(edisonn): report/warn/assert.
567            return NULL;
568        }
569        SkPdfNativeObject* ret = NULL;
570        fMap->find((const char*)key, len, &ret);
571
572#ifdef PDF_TRACE
573        SkString _key;
574        _key.append((const char*)key, len);
575        printf("\nget(/%s) = %s\n", _key.c_str(),
576               ret ? ret->toString(0, len + 9).c_str() : "_NOT_FOUND");
577#endif
578
579        return ret;
580    }
581
582    const SkPdfNativeObject* get(const char* key, const char* abr) const {
583        SkPdfMarkObjectUsed();
584
585        const SkPdfNativeObject* ret = get(key);
586        // TODO(edisonn): remove  || *abr == '\0' and pass NULL in the _autogen files instead.
587        if (ret != NULL || abr == NULL || *abr == '\0') {
588            return ret;
589        }
590        return get(abr);
591    }
592
593    SkPdfNativeObject* get(const char* key, const char* abr) {
594        SkPdfMarkObjectUsed();
595
596        SkPdfNativeObject* ret = get(key);
597        // TODO(edisonn): remove  || *abr == '\0' and pass NULL in the _autogen files instead.
598        if (ret != NULL || abr == NULL || *abr == '\0') {
599            return ret;
600        }
601        return get(abr);
602    }
603
604    SkPdfDictionary* asDictionary() {
605        SkPdfMarkObjectUsed();
606
607        SkASSERT(isDictionary());
608        if (!isDictionary()) {
609            return NULL;
610        }
611        return (SkPdfDictionary*) this;
612    }
613
614    const SkPdfDictionary* asDictionary() const {
615        SkPdfMarkObjectUsed();
616
617        SkASSERT(isDictionary());
618        if (!isDictionary()) {
619            return NULL;
620        }
621        return (SkPdfDictionary*) this;
622    }
623
624
625    bool isReference() const {
626        SkPdfMarkObjectUsed();
627
628        return fObjectType == kReference_PdfObjectType;
629    }
630
631    bool isBoolean() const {
632        SkPdfMarkObjectUsed();
633
634        return fObjectType == kBoolean_PdfObjectType;
635    }
636
637    bool isInteger() const {
638        SkPdfMarkObjectUsed();
639
640        return fObjectType == kInteger_PdfObjectType;
641    }
642private:
643    bool isReal() const {
644        SkPdfMarkObjectUsed();
645
646        return fObjectType == kReal_PdfObjectType;
647    }
648public:
649    bool isNumber() const {
650        SkPdfMarkObjectUsed();
651
652        return fObjectType == kInteger_PdfObjectType || fObjectType == kReal_PdfObjectType;
653    }
654
655    bool isKeywordReference() const {
656        SkPdfMarkObjectUsed();
657
658        return fObjectType == kKeyword_PdfObjectType && fStr.fBytes == 1 && fStr.fBuffer[0] == 'R';
659    }
660
661    bool isKeyword() const {
662        SkPdfMarkObjectUsed();
663
664        return fObjectType == kKeyword_PdfObjectType;
665    }
666
667    bool isKeyword(const char* keyword) const {
668        SkPdfMarkObjectUsed();
669
670        if (!isKeyword()) {
671            return false;
672        }
673
674        if (strlen(keyword) != fStr.fBytes) {
675            return false;
676        }
677
678        if (strncmp(keyword, (const char*)fStr.fBuffer, fStr.fBytes) != 0) {
679            return false;
680        }
681
682        return true;
683    }
684
685    bool isName() const {
686        SkPdfMarkObjectUsed();
687
688        return fObjectType == kName_PdfObjectType;
689    }
690
691    bool isName(const char* name) const {
692        SkPdfMarkObjectUsed();
693
694        return fObjectType == kName_PdfObjectType &&
695                fStr.fBytes == strlen(name) &&
696                strncmp((const char*)fStr.fBuffer, name, fStr.fBytes) == 0;
697    }
698
699    bool isArray() const {
700        SkPdfMarkObjectUsed();
701
702        return fObjectType == kArray_PdfObjectType;
703    }
704
705    bool isDate() const {
706        SkPdfMarkObjectUsed();
707
708        return fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType;
709    }
710
711    bool isDictionary() const {
712        SkPdfMarkObjectUsed();
713
714        return fObjectType == kDictionary_PdfObjectType;
715    }
716
717    bool isFunction() const {
718        SkPdfMarkObjectUsed();
719
720        return false;  // NYI
721    }
722
723    bool isRectangle() const {
724        SkPdfMarkObjectUsed();
725
726        // TODO(edisonn): add also that each of these 4 objects are numbers.
727        return fObjectType == kArray_PdfObjectType && fArray->count() == 4;
728    }
729
730    // TODO(edisonn): has stream .. or is stream ... TBD
731    bool hasStream() const {
732        SkPdfMarkObjectUsed();
733
734        return isDictionary() && fStr.fBuffer != NULL;
735    }
736
737    // TODO(edisonn): has stream .. or is stream ... TBD
738    const SkPdfStream* getStream() const {
739        SkPdfMarkObjectUsed();
740
741        return hasStream() ? (const SkPdfStream*)this : NULL;
742    }
743
744    SkPdfStream* getStream() {
745        SkPdfMarkObjectUsed();
746
747        return hasStream() ? (SkPdfStream*)this : NULL;
748    }
749
750    bool isAnyString() const {
751        SkPdfMarkObjectUsed();
752
753        return fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType;
754    }
755
756    bool isHexString() const {
757        SkPdfMarkObjectUsed();
758
759        return fObjectType == kHexString_PdfObjectType;
760    }
761
762    bool isMatrix() const {
763        SkPdfMarkObjectUsed();
764
765        // TODO(edisonn): add also that each of these 6 objects are numbers.
766        return fObjectType == kArray_PdfObjectType && fArray->count() == 6;
767    }
768
769    inline int64_t intValue() const {
770        SkPdfMarkObjectUsed();
771
772        SkASSERT(fObjectType == kInteger_PdfObjectType);
773
774        if (fObjectType != kInteger_PdfObjectType) {
775            // TODO(edisonn): report/warn/assert.
776            return 0;
777        }
778        return fIntegerValue;
779    }
780private:
781    inline double realValue() const {
782        SkPdfMarkObjectUsed();
783
784        SkASSERT(fObjectType == kReal_PdfObjectType);
785
786        if (fObjectType != kReal_PdfObjectType) {
787            // TODO(edisonn): report/warn/assert.
788            return 0;
789        }
790        return fRealValue;
791    }
792public:
793    inline double numberValue() const {
794        SkPdfMarkObjectUsed();
795
796        SkASSERT(isNumber());
797
798        if (!isNumber()) {
799            // TODO(edisonn): report/warn/assert.
800            return 0;
801        }
802        return fObjectType == kReal_PdfObjectType ? fRealValue : fIntegerValue;
803    }
804
805    inline SkScalar scalarValue() const {
806        SkPdfMarkObjectUsed();
807
808        SkASSERT(isNumber());
809
810        if (!isNumber()) {
811            // TODO(edisonn): report/warn/assert.
812            return SkIntToScalar(0);
813        }
814        return fObjectType == kReal_PdfObjectType ? SkDoubleToScalar(fRealValue) :
815                                                    SkIntToScalar(fIntegerValue);
816    }
817
818    int referenceId() const {
819        SkPdfMarkObjectUsed();
820
821        SkASSERT(fObjectType == kReference_PdfObjectType);
822        return fRef.fId;
823    }
824
825    int referenceGeneration() const {
826        SkPdfMarkObjectUsed();
827
828        SkASSERT(fObjectType == kReference_PdfObjectType);
829        return fRef.fGen;
830    }
831
832    inline const char* nameValue() const {
833        SkPdfMarkObjectUsed();
834
835        SkASSERT(fObjectType == kName_PdfObjectType);
836
837        if (fObjectType != kName_PdfObjectType) {
838            // TODO(edisonn): report/warn/assert.
839            return "";
840        }
841        return (const char*)fStr.fBuffer;
842    }
843
844    inline const char* stringValue() const {
845        SkPdfMarkObjectUsed();
846
847        SkASSERT(fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType);
848
849        if (fObjectType != kString_PdfObjectType && fObjectType != kHexString_PdfObjectType) {
850            // TODO(edisonn): report/warn/assert.
851            return "";
852        }
853        return (const char*)fStr.fBuffer;
854    }
855
856    inline NotOwnedString strRef() {
857        SkPdfMarkObjectUsed();
858
859        switch (fObjectType) {
860            case kString_PdfObjectType:
861            case kHexString_PdfObjectType:
862            case kKeyword_PdfObjectType:
863            case kName_PdfObjectType:
864                return fStr;
865
866            default:
867                // TODO(edisonn): report/warning
868                return NotOwnedString();
869        }
870    }
871
872    // TODO(edisonn): nameValue2 and stringValue2 are used to make code generation easy,
873    // but it is not a performat way to do it, since it will create an extra copy
874    // remove these functions and make code generated faster
875    inline SkString nameValue2() const {
876        SkPdfMarkObjectUsed();
877
878        SkASSERT(fObjectType == kName_PdfObjectType);
879
880        if (fObjectType != kName_PdfObjectType) {
881            // TODO(edisonn): log err
882            return SkString();
883        }
884        return SkString((const char*)fStr.fBuffer, fStr.fBytes);
885    }
886
887    inline SkString stringValue2() const {
888        SkPdfMarkObjectUsed();
889
890        SkASSERT(fObjectType == kString_PdfObjectType || fObjectType == kHexString_PdfObjectType);
891
892        if (fObjectType != kString_PdfObjectType && fObjectType != kHexString_PdfObjectType) {
893            // TODO(edisonn): report/warn/assert.
894            return SkString();
895        }
896        return SkString((const char*)fStr.fBuffer, fStr.fBytes);
897    }
898
899    inline bool boolValue() const {
900        SkPdfMarkObjectUsed();
901
902        SkASSERT(fObjectType == kBoolean_PdfObjectType);
903
904        if (fObjectType != kBoolean_PdfObjectType) {
905            // TODO(edisonn): report/warn/assert.
906            return false;
907        }
908        return fBooleanValue;
909    }
910
911    SkRect rectangleValue() const {
912        SkPdfMarkObjectUsed();
913
914        SkASSERT(isRectangle());
915        if (!isRectangle()) {
916            return SkRect::MakeEmpty();
917        }
918
919        double array[4];
920        for (int i = 0; i < 4; i++) {
921            // TODO(edisonn): version where we could resolve references?
922            const SkPdfNativeObject* elem = objAtAIndex(i);
923            if (elem == NULL || !elem->isNumber()) {
924                // TODO(edisonn): report/warn/assert.
925                return SkRect::MakeEmpty();
926            }
927            array[i] = elem->numberValue();
928        }
929
930        return SkRect::MakeLTRB(SkDoubleToScalar(array[0]),
931                                SkDoubleToScalar(array[1]),
932                                SkDoubleToScalar(array[2]),
933                                SkDoubleToScalar(array[3]));
934    }
935
936    SkMatrix matrixValue() const {
937        SkPdfMarkObjectUsed();
938
939        SkASSERT(isMatrix());
940        if (!isMatrix()) {
941            return SkMatrix::I();
942        }
943
944        double array[6];
945        for (int i = 0; i < 6; i++) {
946            // TODO(edisonn): version where we could resolve references?
947            const SkPdfNativeObject* elem = objAtAIndex(i);
948            if (elem == NULL || !elem->isNumber()) {
949                // TODO(edisonn): report/warn/assert.
950                return SkMatrix::I();
951            }
952            array[i] = elem->numberValue();
953        }
954
955        return SkMatrixFromPdfMatrix(array);
956    }
957
958    bool filterStream();
959
960
961    bool GetFilteredStreamRef(unsigned char const** buffer, size_t* len) {
962        SkPdfMarkObjectUsed();
963
964        // TODO(edisonn): add params that could let the last filter in place
965        // if it is jpeg or png to fast load images.
966        if (!hasStream()) {
967            return false;
968        }
969
970        filterStream();
971
972        if (buffer) {
973            *buffer = fStr.fBuffer;
974        }
975
976        if (len) {
977            *len = fStr.fBytes >> 2;  // last 2 bits - TODO(edisonn): clean up.
978        }
979
980        return true;
981    }
982
983    bool isStreamFiltered() const {
984        SkPdfMarkObjectUsed();
985
986        return hasStream() && ((fStr.fBytes & 1) == kFilteredStreamBit);
987    }
988
989    bool isStreamOwned() const {
990        SkPdfMarkObjectUsed();
991
992        return hasStream() && ((fStr.fBytes & 2) == kOwnedStreamBit);
993    }
994
995    bool GetUnfilteredStreamRef(unsigned char const** buffer, size_t* len) const {
996        SkPdfMarkObjectUsed();
997
998        if (isStreamFiltered()) {
999            return false;
1000        }
1001
1002        if (!hasStream()) {
1003            return false;
1004        }
1005
1006        if (buffer) {
1007            *buffer = fStr.fBuffer;
1008        }
1009
1010        if (len) {
1011            *len = fStr.fBytes >> 2;  // remove last 2 bits - TODO(edisonn): clean up.
1012        }
1013
1014        return true;
1015    }
1016
1017    bool addStream(const unsigned char* buffer, size_t len) {
1018        SkPdfMarkObjectUsed();
1019
1020        SkASSERT(!hasStream());
1021        SkASSERT(isDictionary());
1022
1023        if (!isDictionary() || hasStream()) {
1024            return false;
1025        }
1026
1027        fStr.fBuffer = buffer;
1028        fStr.fBytes = (len << 2) + kUnfilteredStreamBit;
1029
1030        return true;
1031    }
1032
1033    static void appendSpaces(SkString* str, int level) {
1034        for (int i = 0 ; i < level; i++) {
1035            str->append(" ");
1036        }
1037    }
1038
1039    static void append(SkString* str, const char* data, size_t len, const char* prefix = "\\x") {
1040        for (unsigned int i = 0 ; i < len; i++) {
1041            if (data[i] == kNUL_PdfWhiteSpace) {
1042                str->append(prefix);
1043                str->append("00");
1044            } else if (data[i] == kHT_PdfWhiteSpace) {
1045                str->append(prefix);
1046                str->append("09");
1047            } else if (data[i] == kLF_PdfWhiteSpace) {
1048                str->append(prefix);
1049                str->append("0A");
1050            } else if (data[i] == kFF_PdfWhiteSpace) {
1051                str->append(prefix);
1052                str->append("0C");
1053            } else if (data[i] == kCR_PdfWhiteSpace) {
1054                str->append(prefix);
1055                str->append("0D");
1056            } else {
1057                str->append(data + i, 1);
1058            }
1059        }
1060    }
1061
1062    SkString toString(int firstRowLevel = 0, int level = 0) {
1063        SkString str;
1064        appendSpaces(&str, firstRowLevel);
1065        switch (fObjectType) {
1066            case kInvalid_PdfObjectType:
1067                str.append("__Invalid");
1068                break;
1069
1070            case kBoolean_PdfObjectType:
1071                str.appendf("%s", fBooleanValue ? "true" : "false");
1072                break;
1073
1074            case kInteger_PdfObjectType:
1075                str.appendf("%i", (int)fIntegerValue);
1076                break;
1077
1078            case kReal_PdfObjectType:
1079                str.appendf("%f", fRealValue);
1080                break;
1081
1082            case kString_PdfObjectType:
1083                str.append("\"");
1084                append(&str, (const char*)fStr.fBuffer, fStr.fBytes);
1085                str.append("\"");
1086                break;
1087
1088            case kHexString_PdfObjectType:
1089                str.append("<");
1090                for (unsigned int i = 0 ; i < fStr.fBytes; i++) {
1091                    str.appendf("%02x", (unsigned int)fStr.fBuffer[i]);
1092                }
1093                str.append(">");
1094                break;
1095
1096            case kName_PdfObjectType:
1097                str.append("/");
1098                append(&str, (const char*)fStr.fBuffer, fStr.fBytes, "#");
1099                break;
1100
1101            case kKeyword_PdfObjectType:
1102                append(&str, (const char*)fStr.fBuffer, fStr.fBytes);
1103                break;
1104
1105            case kArray_PdfObjectType:
1106                str.append("[\n");
1107                for (unsigned int i = 0; i < size(); i++) {
1108                    str.append(objAtAIndex(i)->toString(level + 1, level + 1));
1109                    if (i < size() - 1) {
1110                        str.append(",");
1111                    }
1112                    str.append("\n");
1113                }
1114                appendSpaces(&str, level);
1115                str.append("]");
1116                break;
1117
1118            case kDictionary_PdfObjectType: {
1119                    SkTDict<SkPdfNativeObject*>::Iter iter(*fMap);
1120                    SkPdfNativeObject* obj = NULL;
1121                    const char* key = NULL;
1122                    str.append("<<\n");
1123                    while ((key = iter.next(&obj)) != NULL) {
1124                        appendSpaces(&str, level + 2);
1125                        str.appendf("/%s %s\n", key,
1126                                    obj->toString(0, level + strlen(key) + 4).c_str());
1127                    }
1128                    appendSpaces(&str, level);
1129                    str.append(">>");
1130                    if (hasStream()) {
1131                        const unsigned char* stream = NULL;
1132                        size_t length = 0;
1133                        if (GetFilteredStreamRef(&stream, &length)) {
1134                            str.append("stream\n");
1135                            append(&str, (const char*)stream, length > 256 ? 256 : length);
1136                            str.append("\nendstream");
1137                        } else {
1138                            str.append("stream STREAM_ERROR endstream");
1139                        }
1140                    }
1141                }
1142                break;
1143
1144            case kNull_PdfObjectType:
1145                str = "NULL";
1146                break;
1147
1148            case kReference_PdfObjectType:
1149                str.appendf("%i %i R", fRef.fId, fRef.fGen);
1150                break;
1151
1152            case kUndefined_PdfObjectType:
1153                str = "Undefined";
1154                break;
1155
1156            default:
1157                str = "Error";
1158                break;
1159        }
1160
1161        return str;
1162    }
1163
1164private:
1165    static void makeStringCore(const unsigned char* start, SkPdfNativeObject* obj,
1166                               ObjectType type) {
1167        makeStringCore(start, strlen((const char*)start), obj, type);
1168    }
1169
1170    static void makeStringCore(const unsigned char* start, const unsigned char* end,
1171                               SkPdfNativeObject* obj, ObjectType type) {
1172        makeStringCore(start, end - start, obj, type);
1173    }
1174
1175    static void makeStringCore(const unsigned char* start, size_t bytes, SkPdfNativeObject* obj,
1176                               ObjectType type) {
1177        SkASSERT(obj->fObjectType == kInvalid_PdfObjectType);
1178
1179        obj->fObjectType = type;
1180        obj->fStr.fBuffer = start;
1181        obj->fStr.fBytes = bytes;
1182    }
1183
1184    bool applyFilter(const char* name);
1185    bool applyFlateDecodeFilter();
1186    bool applyDCTDecodeFilter();
1187};
1188
1189class SkPdfStream : public SkPdfNativeObject {};
1190class SkPdfArray : public SkPdfNativeObject {};
1191class SkPdfString : public SkPdfNativeObject {};
1192class SkPdfHexString : public SkPdfNativeObject {};
1193class SkPdfInteger : public SkPdfNativeObject {};
1194class SkPdfReal : public SkPdfNativeObject {};
1195class SkPdfNumber : public SkPdfNativeObject {};
1196
1197class SkPdfName : public SkPdfNativeObject {
1198    SkPdfName() : SkPdfNativeObject() {
1199        SkPdfNativeObject::makeName((const unsigned char*)"", this);
1200    }
1201public:
1202    SkPdfName(char* name) : SkPdfNativeObject() {
1203        this->makeName((const unsigned char*)name, this);
1204    }
1205};
1206
1207#endif  // SkPdfNativeObject
1208