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