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 18SkString* pun(char* x) { return reinterpret_cast<SkString*>(x); } 19const SkString* pun(const char* x) { 20 return reinterpret_cast<const SkString*>(x); 21} 22 23SkPDFUnion::SkPDFUnion(Type t) : fType(t) {} 24 25SkPDFUnion::~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 41SkPDFUnion& SkPDFUnion::operator=(SkPDFUnion&& other) { 42 if (this != &other) { 43 this->~SkPDFUnion(); 44 new (this) SkPDFUnion(std::move(other)); 45 } 46 return *this; 47} 48 49SkPDFUnion::SkPDFUnion(SkPDFUnion&& other) { 50 SkASSERT(this != &other); 51 memcpy(this, &other, sizeof(*this)); 52 other.fType = Type::kDestroyed; 53} 54 55#if 0 56SkPDFUnion 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} 72SkPDFUnion& SkPDFUnion::operator=(const SkPDFUnion& other) { 73 return *this = other.copy(); 74} 75SkPDFUnion::SkPDFUnion(const SkPDFUnion& other) { 76 *this = other.copy(); 77} 78#endif 79 80bool 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. 87bool 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). 101static 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 116void 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 161void 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 183SkPDFUnion SkPDFUnion::Int(int32_t value) { 184 SkPDFUnion u(Type::kInt); 185 u.fIntValue = value; 186 return u; 187} 188 189SkPDFUnion SkPDFUnion::ColorComponent(uint8_t value) { 190 SkPDFUnion u(Type::kColorComponent); 191 u.fIntValue = value; 192 return u; 193} 194 195SkPDFUnion SkPDFUnion::Bool(bool value) { 196 SkPDFUnion u(Type::kBool); 197 u.fBoolValue = value; 198 return u; 199} 200 201SkPDFUnion SkPDFUnion::Scalar(SkScalar value) { 202 SkPDFUnion u(Type::kScalar); 203 u.fScalarValue = value; 204 return u; 205} 206 207SkPDFUnion 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 215SkPDFUnion SkPDFUnion::String(const char* value) { 216 SkPDFUnion u(Type::kString); 217 SkASSERT(value); 218 u.fStaticString = value; 219 return u; 220} 221 222SkPDFUnion SkPDFUnion::Name(const SkString& s) { 223 SkPDFUnion u(Type::kNameSkS); 224 new (pun(u.fSkString)) SkString(s); 225 return u; 226} 227 228SkPDFUnion SkPDFUnion::String(const SkString& s) { 229 SkPDFUnion u(Type::kStringSkS); 230 new (pun(u.fSkString)) SkString(s); 231 return u; 232} 233 234SkPDFUnion 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 241SkPDFUnion 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. 251void SkPDFAtom::emitObject(SkWStream* stream, 252 const SkPDFObjNumMap& objNumMap) const { 253 fValue.emitObject(stream, objNumMap); 254} 255void SkPDFAtom::addResources(SkPDFObjNumMap* map) const { 256 fValue.addResources(map); 257} 258#endif // 0 259 260//////////////////////////////////////////////////////////////////////////////// 261 262SkPDFArray::SkPDFArray() { SkDEBUGCODE(fDumped = false;) } 263 264SkPDFArray::~SkPDFArray() { this->drop(); } 265 266void SkPDFArray::drop() { 267 fValues.reset(); 268 SkDEBUGCODE(fDumped = true;) 269} 270 271int SkPDFArray::size() const { return fValues.count(); } 272 273void SkPDFArray::reserve(int length) { 274 fValues.reserve(length); 275} 276 277void 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 290void SkPDFArray::addResources(SkPDFObjNumMap* catalog) const { 291 SkASSERT(!fDumped); 292 for (const SkPDFUnion& value : fValues) { 293 value.addResources(catalog); 294 } 295} 296 297void SkPDFArray::append(SkPDFUnion&& value) { 298 fValues.emplace_back(std::move(value)); 299} 300 301void SkPDFArray::appendInt(int32_t value) { 302 this->append(SkPDFUnion::Int(value)); 303} 304 305void SkPDFArray::appendColorComponent(uint8_t value) { 306 this->append(SkPDFUnion::ColorComponent(value)); 307} 308 309void SkPDFArray::appendBool(bool value) { 310 this->append(SkPDFUnion::Bool(value)); 311} 312 313void SkPDFArray::appendScalar(SkScalar value) { 314 this->append(SkPDFUnion::Scalar(value)); 315} 316 317void SkPDFArray::appendName(const char name[]) { 318 this->append(SkPDFUnion::Name(SkString(name))); 319} 320 321void SkPDFArray::appendName(const SkString& name) { 322 this->append(SkPDFUnion::Name(name)); 323} 324 325void SkPDFArray::appendString(const SkString& value) { 326 this->append(SkPDFUnion::String(value)); 327} 328 329void SkPDFArray::appendString(const char value[]) { 330 this->append(SkPDFUnion::String(value)); 331} 332 333void SkPDFArray::appendObject(sk_sp<SkPDFObject> objSp) { 334 this->append(SkPDFUnion::Object(std::move(objSp))); 335} 336 337void SkPDFArray::appendObjRef(sk_sp<SkPDFObject> objSp) { 338 this->append(SkPDFUnion::ObjRef(std::move(objSp))); 339} 340 341/////////////////////////////////////////////////////////////////////////////// 342 343SkPDFDict::~SkPDFDict() { this->drop(); } 344 345void SkPDFDict::drop() { 346 fRecords.reset(); 347 SkDEBUGCODE(fDumped = true;) 348} 349 350SkPDFDict::SkPDFDict(const char type[]) { 351 SkDEBUGCODE(fDumped = false;) 352 if (type) { 353 this->insertName("Type", type); 354 } 355} 356 357void SkPDFDict::emitObject(SkWStream* stream, 358 const SkPDFObjNumMap& objNumMap) const { 359 stream->writeText("<<"); 360 this->emitAll(stream, objNumMap); 361 stream->writeText(">>"); 362} 363 364void 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 377void 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 385int SkPDFDict::size() const { return fRecords.count(); } 386 387void SkPDFDict::reserve(int n) { 388 fRecords.reserve(n); 389} 390 391void SkPDFDict::insertObjRef(const char key[], sk_sp<SkPDFObject> objSp) { 392 fRecords.emplace_back(Record{SkPDFUnion::Name(key), SkPDFUnion::ObjRef(std::move(objSp))}); 393} 394 395void SkPDFDict::insertObjRef(const SkString& key, sk_sp<SkPDFObject> objSp) { 396 fRecords.emplace_back(Record{SkPDFUnion::Name(key), SkPDFUnion::ObjRef(std::move(objSp))}); 397} 398 399void SkPDFDict::insertObject(const char key[], sk_sp<SkPDFObject> objSp) { 400 fRecords.emplace_back(Record{SkPDFUnion::Name(key), SkPDFUnion::Object(std::move(objSp))}); 401} 402void SkPDFDict::insertObject(const SkString& key, sk_sp<SkPDFObject> objSp) { 403 fRecords.emplace_back(Record{SkPDFUnion::Name(key), SkPDFUnion::Object(std::move(objSp))}); 404} 405 406void SkPDFDict::insertBool(const char key[], bool value) { 407 fRecords.emplace_back(Record{SkPDFUnion::Name(key), SkPDFUnion::Bool(value)}); 408} 409 410void SkPDFDict::insertInt(const char key[], int32_t value) { 411 fRecords.emplace_back(Record{SkPDFUnion::Name(key), SkPDFUnion::Int(value)}); 412} 413 414void SkPDFDict::insertInt(const char key[], size_t value) { 415 this->insertInt(key, SkToS32(value)); 416} 417 418void SkPDFDict::insertScalar(const char key[], SkScalar value) { 419 fRecords.emplace_back(Record{SkPDFUnion::Name(key), SkPDFUnion::Scalar(value)}); 420} 421 422void SkPDFDict::insertName(const char key[], const char name[]) { 423 fRecords.emplace_back(Record{SkPDFUnion::Name(key), SkPDFUnion::Name(name)}); 424} 425 426void SkPDFDict::insertName(const char key[], const SkString& name) { 427 fRecords.emplace_back(Record{SkPDFUnion::Name(key), SkPDFUnion::Name(name)}); 428} 429 430void SkPDFDict::insertString(const char key[], const char value[]) { 431 fRecords.emplace_back(Record{SkPDFUnion::Name(key), SkPDFUnion::String(value)}); 432} 433 434void SkPDFDict::insertString(const char key[], const SkString& value) { 435 fRecords.emplace_back(Record{SkPDFUnion::Name(key), SkPDFUnion::String(value)}); 436} 437 438//////////////////////////////////////////////////////////////////////////////// 439 440SkPDFSharedStream::SkPDFSharedStream(std::unique_ptr<SkStreamAsset> data) 441 : fAsset(std::move(data)) { 442 SkASSERT(fAsset); 443} 444 445SkPDFSharedStream::~SkPDFSharedStream() { this->drop(); } 446 447void SkPDFSharedStream::drop() { 448 fAsset = nullptr;; 449 fDict.drop(); 450} 451 452#ifdef SK_PDF_LESS_COMPRESSION 453void 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 471void 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 500void SkPDFSharedStream::addResources( 501 SkPDFObjNumMap* catalog) const { 502 SkASSERT(fAsset); 503 fDict.addResources(catalog); 504} 505 506 507//////////////////////////////////////////////////////////////////////////////// 508 509SkPDFStream:: SkPDFStream(sk_sp<SkData> data) { 510 this->setData(skstd::make_unique<SkMemoryStream>(std::move(data))); 511} 512 513SkPDFStream::SkPDFStream(std::unique_ptr<SkStreamAsset> stream) { 514 this->setData(std::move(stream)); 515} 516 517SkPDFStream::SkPDFStream() {} 518 519SkPDFStream::~SkPDFStream() {} 520 521void SkPDFStream::addResources(SkPDFObjNumMap* catalog) const { 522 SkASSERT(fCompressedData); 523 fDict.addResources(catalog); 524} 525 526void SkPDFStream::drop() { 527 fCompressedData.reset(nullptr); 528 fDict.drop(); 529} 530 531void 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 544void 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 579void SkPDFObjNumMap::addObjectRecursively(SkPDFObject* obj) { 580 if (obj && !fObjectNumbers.find(obj)) { 581 fObjectNumbers.set(obj, fObjectNumbers.count() + 1); 582 fObjects.emplace_back(sk_ref_sp(obj)); 583 obj->addResources(this); 584 } 585} 586 587int32_t SkPDFObjNumMap::getObjectNumber(SkPDFObject* obj) const { 588 int32_t* objectNumberFound = fObjectNumbers.find(obj); 589 SkASSERT(objectNumberFound); 590 return *objectNumberFound; 591} 592 593#ifdef SK_PDF_IMAGE_STATS 594SkAtomic<int> gDrawImageCalls(0); 595SkAtomic<int> gJpegImageObjects(0); 596SkAtomic<int> gRegularImageObjects(0); 597 598void SkPDFImageDumpStats() { 599 SkDebugf("\ntotal PDF drawImage/drawBitmap calls: %d\n" 600 "total PDF jpeg images: %d\n" 601 "total PDF regular images: %d\n", 602 gDrawImageCalls.load(), 603 gJpegImageObjects.load(), 604 gRegularImageObjects.load()); 605} 606#endif // SK_PDF_IMAGE_STATS 607