1 /* 2 * Copyright 2011 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 #include "SkData.h" 9 #include "SkDeflate.h" 10 #include "SkMakeUnique.h" 11 #include "SkPDFTypes.h" 12 #include "SkPDFUtils.h" 13 #include "SkStream.h" 14 #include "SkStreamPriv.h" 15 16 //////////////////////////////////////////////////////////////////////////////// 17 18 SkString* pun(char* x) { return reinterpret_cast<SkString*>(x); } 19 const SkString* pun(const char* x) { 20 return reinterpret_cast<const SkString*>(x); 21 } 22 23 SkPDFUnion::SkPDFUnion(Type t) : fType(t) {} 24 25 SkPDFUnion::~SkPDFUnion() { 26 switch (fType) { 27 case Type::kNameSkS: 28 case Type::kStringSkS: 29 pun(fSkString)->~SkString(); 30 return; 31 case Type::kObjRef: 32 case Type::kObject: 33 SkASSERT(fObject); 34 fObject->unref(); 35 return; 36 default: 37 return; 38 } 39 } 40 41 SkPDFUnion& SkPDFUnion::operator=(SkPDFUnion&& other) { 42 if (this != &other) { 43 this->~SkPDFUnion(); 44 new (this) SkPDFUnion(std::move(other)); 45 } 46 return *this; 47 } 48 49 SkPDFUnion::SkPDFUnion(SkPDFUnion&& other) { 50 SkASSERT(this != &other); 51 memcpy(this, &other, sizeof(*this)); 52 other.fType = Type::kDestroyed; 53 } 54 55 #if 0 56 SkPDFUnion SkPDFUnion::copy() const { 57 SkPDFUnion u(fType); 58 memcpy(&u, this, sizeof(u)); 59 switch (fType) { 60 case Type::kNameSkS: 61 case Type::kStringSkS: 62 new (pun(u.fSkString)) SkString(*pun(fSkString)); 63 return u; 64 case Type::kObjRef: 65 case Type::kObject: 66 SkRef(u.fObject); 67 return u; 68 default: 69 return u; 70 } 71 } 72 SkPDFUnion& SkPDFUnion::operator=(const SkPDFUnion& other) { 73 return *this = other.copy(); 74 } 75 SkPDFUnion::SkPDFUnion(const SkPDFUnion& other) { 76 *this = other.copy(); 77 } 78 #endif 79 80 bool SkPDFUnion::isName() const { 81 return Type::kName == fType || Type::kNameSkS == fType; 82 } 83 84 #ifdef SK_DEBUG 85 // Most names need no escaping. Such names are handled as static 86 // const strings. 87 bool is_valid_name(const char* n) { 88 static const char kControlChars[] = "/%()<>[]{}"; 89 while (*n) { 90 if (*n < '!' || *n > '~' || strchr(kControlChars, *n)) { 91 return false; 92 } 93 ++n; 94 } 95 return true; 96 } 97 #endif // SK_DEBUG 98 99 // Given an arbitrary string, write it as a valid name (not including 100 // leading slash). 101 static void write_name_escaped(SkWStream* o, const char* name) { 102 static const char kToEscape[] = "#/%()<>[]{}"; 103 for (const uint8_t* n = reinterpret_cast<const uint8_t*>(name); *n; ++n) { 104 uint8_t v = *n; 105 if (v < '!' || v > '~' || strchr(kToEscape, v)) { 106 char buffer[3] = {'#', 107 SkHexadecimalDigits::gUpper[v >> 4], 108 SkHexadecimalDigits::gUpper[v & 0xF]}; 109 o->write(buffer, sizeof(buffer)); 110 } else { 111 o->write(n, 1); 112 } 113 } 114 } 115 116 void SkPDFUnion::emitObject(SkWStream* stream, 117 const SkPDFObjNumMap& objNumMap) const { 118 switch (fType) { 119 case Type::kInt: 120 stream->writeDecAsText(fIntValue); 121 return; 122 case Type::kColorComponent: 123 SkPDFUtils::AppendColorComponent(SkToU8(fIntValue), stream); 124 return; 125 case Type::kBool: 126 stream->writeText(fBoolValue ? "true" : "false"); 127 return; 128 case Type::kScalar: 129 SkPDFUtils::AppendScalar(fScalarValue, stream); 130 return; 131 case Type::kName: 132 stream->writeText("/"); 133 SkASSERT(is_valid_name(fStaticString)); 134 stream->writeText(fStaticString); 135 return; 136 case Type::kString: 137 SkASSERT(fStaticString); 138 SkPDFUtils::WriteString(stream, fStaticString, 139 strlen(fStaticString)); 140 return; 141 case Type::kNameSkS: 142 stream->writeText("/"); 143 write_name_escaped(stream, pun(fSkString)->c_str()); 144 return; 145 case Type::kStringSkS: 146 SkPDFUtils::WriteString(stream, pun(fSkString)->c_str(), 147 pun(fSkString)->size()); 148 return; 149 case Type::kObjRef: 150 stream->writeDecAsText(objNumMap.getObjectNumber(fObject)); 151 stream->writeText(" 0 R"); // Generation number is always 0. 152 return; 153 case Type::kObject: 154 fObject->emitObject(stream, objNumMap); 155 return; 156 default: 157 SkDEBUGFAIL("SkPDFUnion::emitObject with bad type"); 158 } 159 } 160 161 void SkPDFUnion::addResources(SkPDFObjNumMap* objNumMap) const { 162 switch (fType) { 163 case Type::kInt: 164 case Type::kColorComponent: 165 case Type::kBool: 166 case Type::kScalar: 167 case Type::kName: 168 case Type::kString: 169 case Type::kNameSkS: 170 case Type::kStringSkS: 171 return; // These have no resources. 172 case Type::kObjRef: 173 objNumMap->addObjectRecursively(fObject); 174 return; 175 case Type::kObject: 176 fObject->addResources(objNumMap); 177 return; 178 default: 179 SkDEBUGFAIL("SkPDFUnion::addResources with bad type"); 180 } 181 } 182 183 SkPDFUnion SkPDFUnion::Int(int32_t value) { 184 SkPDFUnion u(Type::kInt); 185 u.fIntValue = value; 186 return u; 187 } 188 189 SkPDFUnion SkPDFUnion::ColorComponent(uint8_t value) { 190 SkPDFUnion u(Type::kColorComponent); 191 u.fIntValue = value; 192 return u; 193 } 194 195 SkPDFUnion SkPDFUnion::Bool(bool value) { 196 SkPDFUnion u(Type::kBool); 197 u.fBoolValue = value; 198 return u; 199 } 200 201 SkPDFUnion SkPDFUnion::Scalar(SkScalar value) { 202 SkPDFUnion u(Type::kScalar); 203 u.fScalarValue = value; 204 return u; 205 } 206 207 SkPDFUnion SkPDFUnion::Name(const char* value) { 208 SkPDFUnion u(Type::kName); 209 SkASSERT(value); 210 SkASSERT(is_valid_name(value)); 211 u.fStaticString = value; 212 return u; 213 } 214 215 SkPDFUnion SkPDFUnion::String(const char* value) { 216 SkPDFUnion u(Type::kString); 217 SkASSERT(value); 218 u.fStaticString = value; 219 return u; 220 } 221 222 SkPDFUnion SkPDFUnion::Name(const SkString& s) { 223 SkPDFUnion u(Type::kNameSkS); 224 new (pun(u.fSkString)) SkString(s); 225 return u; 226 } 227 228 SkPDFUnion SkPDFUnion::String(const SkString& s) { 229 SkPDFUnion u(Type::kStringSkS); 230 new (pun(u.fSkString)) SkString(s); 231 return u; 232 } 233 234 SkPDFUnion SkPDFUnion::ObjRef(sk_sp<SkPDFObject> objSp) { 235 SkPDFUnion u(Type::kObjRef); 236 SkASSERT(objSp.get()); 237 u.fObject = objSp.release(); // take ownership into union{} 238 return u; 239 } 240 241 SkPDFUnion SkPDFUnion::Object(sk_sp<SkPDFObject> objSp) { 242 SkPDFUnion u(Type::kObject); 243 SkASSERT(objSp.get()); 244 u.fObject = objSp.release(); // take ownership into union{} 245 return u; 246 } 247 248 //////////////////////////////////////////////////////////////////////////////// 249 250 #if 0 // Enable if needed. 251 void SkPDFAtom::emitObject(SkWStream* stream, 252 const SkPDFObjNumMap& objNumMap) const { 253 fValue.emitObject(stream, objNumMap); 254 } 255 void SkPDFAtom::addResources(SkPDFObjNumMap* map) const { 256 fValue.addResources(map); 257 } 258 #endif // 0 259 260 //////////////////////////////////////////////////////////////////////////////// 261 262 SkPDFArray::SkPDFArray() { SkDEBUGCODE(fDumped = false;) } 263 264 SkPDFArray::~SkPDFArray() { this->drop(); } 265 266 void SkPDFArray::drop() { 267 fValues.reset(); 268 SkDEBUGCODE(fDumped = true;) 269 } 270 271 int SkPDFArray::size() const { return fValues.count(); } 272 273 void SkPDFArray::reserve(int length) { 274 fValues.reserve(length); 275 } 276 277 void SkPDFArray::emitObject(SkWStream* stream, 278 const SkPDFObjNumMap& objNumMap) const { 279 SkASSERT(!fDumped); 280 stream->writeText("["); 281 for (int i = 0; i < fValues.count(); i++) { 282 fValues[i].emitObject(stream, objNumMap); 283 if (i + 1 < fValues.count()) { 284 stream->writeText(" "); 285 } 286 } 287 stream->writeText("]"); 288 } 289 290 void SkPDFArray::addResources(SkPDFObjNumMap* catalog) const { 291 SkASSERT(!fDumped); 292 for (const SkPDFUnion& value : fValues) { 293 value.addResources(catalog); 294 } 295 } 296 297 void SkPDFArray::append(SkPDFUnion&& value) { 298 fValues.emplace_back(std::move(value)); 299 } 300 301 void SkPDFArray::appendInt(int32_t value) { 302 this->append(SkPDFUnion::Int(value)); 303 } 304 305 void SkPDFArray::appendColorComponent(uint8_t value) { 306 this->append(SkPDFUnion::ColorComponent(value)); 307 } 308 309 void SkPDFArray::appendBool(bool value) { 310 this->append(SkPDFUnion::Bool(value)); 311 } 312 313 void SkPDFArray::appendScalar(SkScalar value) { 314 this->append(SkPDFUnion::Scalar(value)); 315 } 316 317 void SkPDFArray::appendName(const char name[]) { 318 this->append(SkPDFUnion::Name(SkString(name))); 319 } 320 321 void SkPDFArray::appendName(const SkString& name) { 322 this->append(SkPDFUnion::Name(name)); 323 } 324 325 void SkPDFArray::appendString(const SkString& value) { 326 this->append(SkPDFUnion::String(value)); 327 } 328 329 void SkPDFArray::appendString(const char value[]) { 330 this->append(SkPDFUnion::String(value)); 331 } 332 333 void SkPDFArray::appendObject(sk_sp<SkPDFObject> objSp) { 334 this->append(SkPDFUnion::Object(std::move(objSp))); 335 } 336 337 void SkPDFArray::appendObjRef(sk_sp<SkPDFObject> objSp) { 338 this->append(SkPDFUnion::ObjRef(std::move(objSp))); 339 } 340 341 /////////////////////////////////////////////////////////////////////////////// 342 343 SkPDFDict::~SkPDFDict() { this->drop(); } 344 345 void SkPDFDict::drop() { 346 fRecords.reset(); 347 SkDEBUGCODE(fDumped = true;) 348 } 349 350 SkPDFDict::SkPDFDict(const char type[]) { 351 SkDEBUGCODE(fDumped = false;) 352 if (type) { 353 this->insertName("Type", type); 354 } 355 } 356 357 void SkPDFDict::emitObject(SkWStream* stream, 358 const SkPDFObjNumMap& objNumMap) const { 359 stream->writeText("<<"); 360 this->emitAll(stream, objNumMap); 361 stream->writeText(">>"); 362 } 363 364 void SkPDFDict::emitAll(SkWStream* stream, 365 const SkPDFObjNumMap& objNumMap) const { 366 SkASSERT(!fDumped); 367 for (int i = 0; i < fRecords.count(); i++) { 368 fRecords[i].fKey.emitObject(stream, objNumMap); 369 stream->writeText(" "); 370 fRecords[i].fValue.emitObject(stream, objNumMap); 371 if (i + 1 < fRecords.count()) { 372 stream->writeText("\n"); 373 } 374 } 375 } 376 377 void SkPDFDict::addResources(SkPDFObjNumMap* catalog) const { 378 SkASSERT(!fDumped); 379 for (int i = 0; i < fRecords.count(); i++) { 380 fRecords[i].fKey.addResources(catalog); 381 fRecords[i].fValue.addResources(catalog); 382 } 383 } 384 385 int SkPDFDict::size() const { return fRecords.count(); } 386 387 void SkPDFDict::reserve(int n) { 388 fRecords.reserve(n); 389 } 390 391 void SkPDFDict::insertObjRef(const char key[], sk_sp<SkPDFObject> objSp) { 392 fRecords.emplace_back(Record{SkPDFUnion::Name(key), SkPDFUnion::ObjRef(std::move(objSp))}); 393 } 394 395 void SkPDFDict::insertObjRef(const SkString& key, sk_sp<SkPDFObject> objSp) { 396 fRecords.emplace_back(Record{SkPDFUnion::Name(key), SkPDFUnion::ObjRef(std::move(objSp))}); 397 } 398 399 void SkPDFDict::insertObject(const char key[], sk_sp<SkPDFObject> objSp) { 400 fRecords.emplace_back(Record{SkPDFUnion::Name(key), SkPDFUnion::Object(std::move(objSp))}); 401 } 402 void SkPDFDict::insertObject(const SkString& key, sk_sp<SkPDFObject> objSp) { 403 fRecords.emplace_back(Record{SkPDFUnion::Name(key), SkPDFUnion::Object(std::move(objSp))}); 404 } 405 406 void SkPDFDict::insertBool(const char key[], bool value) { 407 fRecords.emplace_back(Record{SkPDFUnion::Name(key), SkPDFUnion::Bool(value)}); 408 } 409 410 void SkPDFDict::insertInt(const char key[], int32_t value) { 411 fRecords.emplace_back(Record{SkPDFUnion::Name(key), SkPDFUnion::Int(value)}); 412 } 413 414 void SkPDFDict::insertInt(const char key[], size_t value) { 415 this->insertInt(key, SkToS32(value)); 416 } 417 418 void SkPDFDict::insertScalar(const char key[], SkScalar value) { 419 fRecords.emplace_back(Record{SkPDFUnion::Name(key), SkPDFUnion::Scalar(value)}); 420 } 421 422 void SkPDFDict::insertName(const char key[], const char name[]) { 423 fRecords.emplace_back(Record{SkPDFUnion::Name(key), SkPDFUnion::Name(name)}); 424 } 425 426 void SkPDFDict::insertName(const char key[], const SkString& name) { 427 fRecords.emplace_back(Record{SkPDFUnion::Name(key), SkPDFUnion::Name(name)}); 428 } 429 430 void SkPDFDict::insertString(const char key[], const char value[]) { 431 fRecords.emplace_back(Record{SkPDFUnion::Name(key), SkPDFUnion::String(value)}); 432 } 433 434 void SkPDFDict::insertString(const char key[], const SkString& value) { 435 fRecords.emplace_back(Record{SkPDFUnion::Name(key), SkPDFUnion::String(value)}); 436 } 437 438 //////////////////////////////////////////////////////////////////////////////// 439 440 SkPDFSharedStream::SkPDFSharedStream(std::unique_ptr<SkStreamAsset> data) 441 : fAsset(std::move(data)) { 442 SkASSERT(fAsset); 443 } 444 445 SkPDFSharedStream::~SkPDFSharedStream() { this->drop(); } 446 447 void SkPDFSharedStream::drop() { 448 fAsset = nullptr;; 449 fDict.drop(); 450 } 451 452 #ifdef SK_PDF_LESS_COMPRESSION 453 void SkPDFSharedStream::emitObject( 454 SkWStream* stream, 455 const SkPDFObjNumMap& objNumMap) const { 456 SkASSERT(fAsset); 457 std::unique_ptr<SkStreamAsset> dup(fAsset->duplicate()); 458 SkASSERT(dup && dup->hasLength()); 459 size_t length = dup->getLength(); 460 stream->writeText("<<"); 461 fDict.emitAll(stream, objNumMap); 462 stream->writeText("\n"); 463 SkPDFUnion::Name("Length").emitObject(stream, objNumMap); 464 stream->writeText(" "); 465 SkPDFUnion::Int(length).emitObject(stream, objNumMap); 466 stream->writeText("\n>>stream\n"); 467 SkStreamCopy(stream, dup.get()); 468 stream->writeText("\nendstream"); 469 } 470 #else 471 void SkPDFSharedStream::emitObject( 472 SkWStream* stream, 473 const SkPDFObjNumMap& objNumMap) const { 474 SkASSERT(fAsset); 475 SkDynamicMemoryWStream buffer; 476 SkDeflateWStream deflateWStream(&buffer); 477 // Since emitObject is const, this function doesn't change the dictionary. 478 std::unique_ptr<SkStreamAsset> dup(fAsset->duplicate()); // Cheap copy 479 SkASSERT(dup); 480 SkStreamCopy(&deflateWStream, dup.get()); 481 deflateWStream.finalize(); 482 size_t length = buffer.bytesWritten(); 483 stream->writeText("<<"); 484 fDict.emitAll(stream, objNumMap); 485 stream->writeText("\n"); 486 SkPDFUnion::Name("Length").emitObject(stream, objNumMap); 487 stream->writeText(" "); 488 SkPDFUnion::Int(length).emitObject(stream, objNumMap); 489 stream->writeText("\n"); 490 SkPDFUnion::Name("Filter").emitObject(stream, objNumMap); 491 stream->writeText(" "); 492 SkPDFUnion::Name("FlateDecode").emitObject(stream, objNumMap); 493 stream->writeText(">>"); 494 stream->writeText(" stream\n"); 495 buffer.writeToAndReset(stream); 496 stream->writeText("\nendstream"); 497 } 498 #endif 499 500 void SkPDFSharedStream::addResources( 501 SkPDFObjNumMap* catalog) const { 502 SkASSERT(fAsset); 503 fDict.addResources(catalog); 504 } 505 506 507 //////////////////////////////////////////////////////////////////////////////// 508 509 SkPDFStream:: SkPDFStream(sk_sp<SkData> data) { 510 this->setData(skstd::make_unique<SkMemoryStream>(std::move(data))); 511 } 512 513 SkPDFStream::SkPDFStream(std::unique_ptr<SkStreamAsset> stream) { 514 this->setData(std::move(stream)); 515 } 516 517 SkPDFStream::SkPDFStream() {} 518 519 SkPDFStream::~SkPDFStream() {} 520 521 void SkPDFStream::addResources(SkPDFObjNumMap* catalog) const { 522 SkASSERT(fCompressedData); 523 fDict.addResources(catalog); 524 } 525 526 void SkPDFStream::drop() { 527 fCompressedData.reset(nullptr); 528 fDict.drop(); 529 } 530 531 void SkPDFStream::emitObject(SkWStream* stream, 532 const SkPDFObjNumMap& objNumMap) const { 533 SkASSERT(fCompressedData); 534 fDict.emitObject(stream, objNumMap); 535 // duplicate (a cheap operation) preserves const on fCompressedData. 536 std::unique_ptr<SkStreamAsset> dup(fCompressedData->duplicate()); 537 SkASSERT(dup); 538 SkASSERT(dup->hasLength()); 539 stream->writeText(" stream\n"); 540 stream->writeStream(dup.get(), dup->getLength()); 541 stream->writeText("\nendstream"); 542 } 543 544 void SkPDFStream::setData(std::unique_ptr<SkStreamAsset> stream) { 545 SkASSERT(!fCompressedData); // Only call this function once. 546 SkASSERT(stream); 547 // Code assumes that the stream starts at the beginning. 548 549 #ifdef SK_PDF_LESS_COMPRESSION 550 fCompressedData = std::move(stream); 551 SkASSERT(fCompressedData && fCompressedData->hasLength()); 552 fDict.insertInt("Length", fCompressedData->getLength()); 553 #else 554 555 SkASSERT(stream->hasLength()); 556 SkDynamicMemoryWStream compressedData; 557 SkDeflateWStream deflateWStream(&compressedData); 558 if (stream->getLength() > 0) { 559 SkStreamCopy(&deflateWStream, stream.get()); 560 } 561 deflateWStream.finalize(); 562 size_t compressedLength = compressedData.bytesWritten(); 563 size_t originalLength = stream->getLength(); 564 565 if (originalLength <= compressedLength + strlen("/Filter_/FlateDecode_")) { 566 SkAssertResult(stream->rewind()); 567 fCompressedData = std::move(stream); 568 fDict.insertInt("Length", originalLength); 569 return; 570 } 571 fCompressedData = compressedData.detachAsStream(); 572 fDict.insertName("Filter", "FlateDecode"); 573 fDict.insertInt("Length", compressedLength); 574 #endif 575 } 576 577 //////////////////////////////////////////////////////////////////////////////// 578 579 bool SkPDFObjNumMap::addObject(SkPDFObject* obj) { 580 if (fObjectNumbers.find(obj)) { 581 return false; 582 } 583 fObjectNumbers.set(obj, fObjectNumbers.count() + 1); 584 fObjects.emplace_back(sk_ref_sp(obj)); 585 return true; 586 } 587 588 void SkPDFObjNumMap::addObjectRecursively(SkPDFObject* obj) { 589 if (obj && this->addObject(obj)) { 590 obj->addResources(this); 591 } 592 } 593 594 int32_t SkPDFObjNumMap::getObjectNumber(SkPDFObject* obj) const { 595 int32_t* objectNumberFound = fObjectNumbers.find(obj); 596 SkASSERT(objectNumberFound); 597 return *objectNumberFound; 598 } 599 600 #ifdef SK_PDF_IMAGE_STATS 601 SkAtomic<int> gDrawImageCalls(0); 602 SkAtomic<int> gJpegImageObjects(0); 603 SkAtomic<int> gRegularImageObjects(0); 604 605 void SkPDFImageDumpStats() { 606 SkDebugf("\ntotal PDF drawImage/drawBitmap calls: %d\n" 607 "total PDF jpeg images: %d\n" 608 "total PDF regular images: %d\n", 609 gDrawImageCalls.load(), 610 gJpegImageObjects.load(), 611 gRegularImageObjects.load()); 612 } 613 #endif // SK_PDF_IMAGE_STATS 614