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