| 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 |