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 10 #include "SkPDFCatalog.h" 11 #include "SkPDFTypes.h" 12 #include "SkStream.h" 13 14 #ifdef SK_BUILD_FOR_WIN 15 #define SNPRINTF _snprintf 16 #else 17 #define SNPRINTF snprintf 18 #endif 19 20 /////////////////////////////////////////////////////////////////////////////// 21 22 void SkPDFObject::emit(SkWStream* stream, SkPDFCatalog* catalog, 23 bool indirect) { 24 SkPDFObject* realObject = catalog->getSubstituteObject(this); 25 return realObject->emitObject(stream, catalog, indirect); 26 } 27 28 size_t SkPDFObject::getOutputSize(SkPDFCatalog* catalog, bool indirect) { 29 SkDynamicMemoryWStream buffer; 30 emit(&buffer, catalog, indirect); 31 return buffer.getOffset(); 32 } 33 34 void SkPDFObject::getResources(const SkTSet<SkPDFObject*>& knownResourceObjects, 35 SkTSet<SkPDFObject*>* newResourceObjects) {} 36 37 void SkPDFObject::emitIndirectObject(SkWStream* stream, SkPDFCatalog* catalog) { 38 catalog->emitObjectNumber(stream, this); 39 stream->writeText(" obj\n"); 40 emit(stream, catalog, false); 41 stream->writeText("\nendobj\n"); 42 } 43 44 size_t SkPDFObject::getIndirectOutputSize(SkPDFCatalog* catalog) { 45 return catalog->getObjectNumberSize(this) + strlen(" obj\n") + 46 this->getOutputSize(catalog, false) + strlen("\nendobj\n"); 47 } 48 49 void SkPDFObject::AddResourceHelper(SkPDFObject* resource, 50 SkTDArray<SkPDFObject*>* list) { 51 list->push(resource); 52 resource->ref(); 53 } 54 55 void SkPDFObject::GetResourcesHelper( 56 const SkTDArray<SkPDFObject*>* resources, 57 const SkTSet<SkPDFObject*>& knownResourceObjects, 58 SkTSet<SkPDFObject*>* newResourceObjects) { 59 if (resources->count()) { 60 newResourceObjects->setReserve( 61 newResourceObjects->count() + resources->count()); 62 for (int i = 0; i < resources->count(); i++) { 63 if (!knownResourceObjects.contains((*resources)[i]) && 64 !newResourceObjects->contains((*resources)[i])) { 65 newResourceObjects->add((*resources)[i]); 66 (*resources)[i]->ref(); 67 (*resources)[i]->getResources(knownResourceObjects, 68 newResourceObjects); 69 } 70 } 71 } 72 } 73 74 SkPDFObjRef::SkPDFObjRef(SkPDFObject* obj) : fObj(obj) { 75 SkSafeRef(obj); 76 } 77 78 SkPDFObjRef::~SkPDFObjRef() {} 79 80 void SkPDFObjRef::emitObject(SkWStream* stream, SkPDFCatalog* catalog, 81 bool indirect) { 82 SkASSERT(!indirect); 83 catalog->emitObjectNumber(stream, fObj.get()); 84 stream->writeText(" R"); 85 } 86 87 size_t SkPDFObjRef::getOutputSize(SkPDFCatalog* catalog, bool indirect) { 88 SkASSERT(!indirect); 89 return catalog->getObjectNumberSize(fObj.get()) + strlen(" R"); 90 } 91 92 SkPDFInt::SkPDFInt(int32_t value) : fValue(value) {} 93 SkPDFInt::~SkPDFInt() {} 94 95 void SkPDFInt::emitObject(SkWStream* stream, SkPDFCatalog* catalog, 96 bool indirect) { 97 if (indirect) { 98 return emitIndirectObject(stream, catalog); 99 } 100 stream->writeDecAsText(fValue); 101 } 102 103 SkPDFBool::SkPDFBool(bool value) : fValue(value) {} 104 SkPDFBool::~SkPDFBool() {} 105 106 void SkPDFBool::emitObject(SkWStream* stream, SkPDFCatalog* catalog, 107 bool indirect) { 108 SkASSERT(!indirect); 109 if (fValue) { 110 stream->writeText("true"); 111 } else { 112 stream->writeText("false"); 113 } 114 } 115 116 size_t SkPDFBool::getOutputSize(SkPDFCatalog* catalog, bool indirect) { 117 SkASSERT(!indirect); 118 if (fValue) { 119 return strlen("true"); 120 } 121 return strlen("false"); 122 } 123 124 SkPDFScalar::SkPDFScalar(SkScalar value) : fValue(value) {} 125 SkPDFScalar::~SkPDFScalar() {} 126 127 void SkPDFScalar::emitObject(SkWStream* stream, SkPDFCatalog* catalog, 128 bool indirect) { 129 if (indirect) { 130 return emitIndirectObject(stream, catalog); 131 } 132 133 Append(fValue, stream); 134 } 135 136 // static 137 void SkPDFScalar::Append(SkScalar value, SkWStream* stream) { 138 // The range of reals in PDF/A is the same as SkFixed: +/- 32,767 and 139 // +/- 1/65,536 (though integers can range from 2^31 - 1 to -2^31). 140 // When using floats that are outside the whole value range, we can use 141 // integers instead. 142 143 #if !defined(SK_ALLOW_LARGE_PDF_SCALARS) 144 if (value > 32767 || value < -32767) { 145 stream->writeDecAsText(SkScalarRoundToInt(value)); 146 return; 147 } 148 149 char buffer[SkStrAppendScalar_MaxSize]; 150 char* end = SkStrAppendFixed(buffer, SkScalarToFixed(value)); 151 stream->write(buffer, end - buffer); 152 return; 153 #endif // !SK_ALLOW_LARGE_PDF_SCALARS 154 155 #if defined(SK_ALLOW_LARGE_PDF_SCALARS) 156 // Floats have 24bits of significance, so anything outside that range is 157 // no more precise than an int. (Plus PDF doesn't support scientific 158 // notation, so this clamps to SK_Max/MinS32). 159 if (value > (1 << 24) || value < -(1 << 24)) { 160 stream->writeDecAsText(value); 161 return; 162 } 163 // Continue to enforce the PDF limits for small floats. 164 if (value < 1.0f/65536 && value > -1.0f/65536) { 165 stream->writeDecAsText(0); 166 return; 167 } 168 // SkStrAppendFloat might still use scientific notation, so use snprintf 169 // directly.. 170 static const int kFloat_MaxSize = 19; 171 char buffer[kFloat_MaxSize]; 172 int len = SNPRINTF(buffer, kFloat_MaxSize, "%#.8f", value); 173 // %f always prints trailing 0s, so strip them. 174 for (; buffer[len - 1] == '0' && len > 0; len--) { 175 buffer[len - 1] = '\0'; 176 } 177 if (buffer[len - 1] == '.') { 178 buffer[len - 1] = '\0'; 179 } 180 stream->writeText(buffer); 181 return; 182 #endif // SK_ALLOW_LARGE_PDF_SCALARS 183 } 184 185 SkPDFString::SkPDFString(const char value[]) 186 : fValue(FormatString(value, strlen(value))) { 187 } 188 189 SkPDFString::SkPDFString(const SkString& value) 190 : fValue(FormatString(value.c_str(), value.size())) { 191 } 192 193 SkPDFString::SkPDFString(const uint16_t* value, size_t len, bool wideChars) 194 : fValue(FormatString(value, len, wideChars)) { 195 } 196 197 SkPDFString::~SkPDFString() {} 198 199 void SkPDFString::emitObject(SkWStream* stream, SkPDFCatalog* catalog, 200 bool indirect) { 201 if (indirect) 202 return emitIndirectObject(stream, catalog); 203 stream->write(fValue.c_str(), fValue.size()); 204 } 205 206 size_t SkPDFString::getOutputSize(SkPDFCatalog* catalog, bool indirect) { 207 if (indirect) 208 return getIndirectOutputSize(catalog); 209 return fValue.size(); 210 } 211 212 // static 213 SkString SkPDFString::FormatString(const char* input, size_t len) { 214 return DoFormatString(input, len, false, false); 215 } 216 217 SkString SkPDFString::FormatString(const uint16_t* input, size_t len, 218 bool wideChars) { 219 return DoFormatString(input, len, true, wideChars); 220 } 221 222 // static 223 SkString SkPDFString::DoFormatString(const void* input, size_t len, 224 bool wideInput, bool wideOutput) { 225 SkASSERT(len <= kMaxLen); 226 const uint16_t* win = (const uint16_t*) input; 227 const char* cin = (const char*) input; 228 229 if (wideOutput) { 230 SkASSERT(wideInput); 231 SkString result; 232 result.append("<"); 233 for (size_t i = 0; i < len; i++) { 234 result.appendHex(win[i], 4); 235 } 236 result.append(">"); 237 return result; 238 } 239 240 // 7-bit clean is a heuristic to decide what string format to use; 241 // a 7-bit clean string should require little escaping. 242 bool sevenBitClean = true; 243 for (size_t i = 0; i < len; i++) { 244 SkASSERT(!wideInput || !(win[i] & ~0xFF)); 245 char val = wideInput ? win[i] : cin[i]; 246 if (val > '~' || val < ' ') { 247 sevenBitClean = false; 248 break; 249 } 250 } 251 252 SkString result; 253 if (sevenBitClean) { 254 result.append("("); 255 for (size_t i = 0; i < len; i++) { 256 SkASSERT(!wideInput || !(win[i] & ~0xFF)); 257 char val = wideInput ? win[i] : cin[i]; 258 if (val == '\\' || val == '(' || val == ')') { 259 result.append("\\"); 260 } 261 result.append(&val, 1); 262 } 263 result.append(")"); 264 } else { 265 result.append("<"); 266 for (size_t i = 0; i < len; i++) { 267 SkASSERT(!wideInput || !(win[i] & ~0xFF)); 268 unsigned char val = wideInput ? win[i] : cin[i]; 269 result.appendHex(val, 2); 270 } 271 result.append(">"); 272 } 273 274 return result; 275 } 276 277 SkPDFName::SkPDFName(const char name[]) : fValue(FormatName(SkString(name))) {} 278 SkPDFName::SkPDFName(const SkString& name) : fValue(FormatName(name)) {} 279 SkPDFName::~SkPDFName() {} 280 281 bool SkPDFName::operator==(const SkPDFName& b) const { 282 return fValue == b.fValue; 283 } 284 285 void SkPDFName::emitObject(SkWStream* stream, SkPDFCatalog* catalog, 286 bool indirect) { 287 SkASSERT(!indirect); 288 stream->write(fValue.c_str(), fValue.size()); 289 } 290 291 size_t SkPDFName::getOutputSize(SkPDFCatalog* catalog, bool indirect) { 292 SkASSERT(!indirect); 293 return fValue.size(); 294 } 295 296 // static 297 SkString SkPDFName::FormatName(const SkString& input) { 298 SkASSERT(input.size() <= kMaxLen); 299 // TODO(vandebo) If more escaping is needed, improve the linear scan. 300 static const char escaped[] = "#/%()<>[]{}"; 301 302 SkString result("/"); 303 for (size_t i = 0; i < input.size(); i++) { 304 if (input[i] & 0x80 || input[i] < '!' || strchr(escaped, input[i])) { 305 result.append("#"); 306 // Mask with 0xFF to avoid sign extension. i.e. #FFFFFF81 307 result.appendHex(input[i] & 0xFF, 2); 308 } else { 309 result.append(input.c_str() + i, 1); 310 } 311 } 312 313 return result; 314 } 315 316 SkPDFArray::SkPDFArray() {} 317 SkPDFArray::~SkPDFArray() { 318 fValue.unrefAll(); 319 } 320 321 void SkPDFArray::emitObject(SkWStream* stream, SkPDFCatalog* catalog, 322 bool indirect) { 323 if (indirect) { 324 return emitIndirectObject(stream, catalog); 325 } 326 327 stream->writeText("["); 328 for (int i = 0; i < fValue.count(); i++) { 329 fValue[i]->emit(stream, catalog, false); 330 if (i + 1 < fValue.count()) { 331 stream->writeText(" "); 332 } 333 } 334 stream->writeText("]"); 335 } 336 337 size_t SkPDFArray::getOutputSize(SkPDFCatalog* catalog, bool indirect) { 338 if (indirect) { 339 return getIndirectOutputSize(catalog); 340 } 341 342 size_t result = strlen("[]"); 343 if (fValue.count()) { 344 result += fValue.count() - 1; 345 } 346 for (int i = 0; i < fValue.count(); i++) { 347 result += fValue[i]->getOutputSize(catalog, false); 348 } 349 return result; 350 } 351 352 void SkPDFArray::reserve(int length) { 353 SkASSERT(length <= kMaxLen); 354 fValue.setReserve(length); 355 } 356 357 SkPDFObject* SkPDFArray::setAt(int offset, SkPDFObject* value) { 358 SkASSERT(offset < fValue.count()); 359 value->ref(); 360 fValue[offset]->unref(); 361 fValue[offset] = value; 362 return value; 363 } 364 365 SkPDFObject* SkPDFArray::append(SkPDFObject* value) { 366 SkASSERT(fValue.count() < kMaxLen); 367 value->ref(); 368 fValue.push(value); 369 return value; 370 } 371 372 void SkPDFArray::appendInt(int32_t value) { 373 SkASSERT(fValue.count() < kMaxLen); 374 fValue.push(new SkPDFInt(value)); 375 } 376 377 void SkPDFArray::appendScalar(SkScalar value) { 378 SkASSERT(fValue.count() < kMaxLen); 379 fValue.push(new SkPDFScalar(value)); 380 } 381 382 void SkPDFArray::appendName(const char name[]) { 383 SkASSERT(fValue.count() < kMaxLen); 384 fValue.push(new SkPDFName(name)); 385 } 386 387 /////////////////////////////////////////////////////////////////////////////// 388 389 SkPDFDict::SkPDFDict() {} 390 391 SkPDFDict::SkPDFDict(const char type[]) { 392 insertName("Type", type); 393 } 394 395 SkPDFDict::~SkPDFDict() { 396 clear(); 397 } 398 399 int SkPDFDict::size() const { 400 SkAutoMutexAcquire lock(fMutex); 401 return fValue.count(); 402 } 403 404 405 void SkPDFDict::emitObject(SkWStream* stream, SkPDFCatalog* catalog, 406 bool indirect) { 407 if (indirect) { 408 return emitIndirectObject(stream, catalog); 409 } 410 411 SkAutoMutexAcquire lock(fMutex); // If another thread triggers a 412 // resize while this thread is in 413 // the for-loop, we can be left 414 // with a bad fValue[i] reference. 415 stream->writeText("<<"); 416 for (int i = 0; i < fValue.count(); i++) { 417 SkASSERT(fValue[i].key); 418 SkASSERT(fValue[i].value); 419 fValue[i].key->emitObject(stream, catalog, false); 420 stream->writeText(" "); 421 fValue[i].value->emit(stream, catalog, false); 422 stream->writeText("\n"); 423 } 424 stream->writeText(">>"); 425 } 426 427 size_t SkPDFDict::getOutputSize(SkPDFCatalog* catalog, bool indirect) { 428 if (indirect) { 429 return getIndirectOutputSize(catalog); 430 } 431 432 SkAutoMutexAcquire lock(fMutex); // If another thread triggers a 433 // resize while this thread is in 434 // the for-loop, we can be left 435 // with a bad fValue[i] reference. 436 size_t result = strlen("<<>>") + (fValue.count() * 2); 437 for (int i = 0; i < fValue.count(); i++) { 438 SkASSERT(fValue[i].key); 439 SkASSERT(fValue[i].value); 440 result += fValue[i].key->getOutputSize(catalog, false); 441 result += fValue[i].value->getOutputSize(catalog, false); 442 } 443 return result; 444 } 445 446 SkPDFObject* SkPDFDict::append(SkPDFName* key, SkPDFObject* value) { 447 SkASSERT(key); 448 SkASSERT(value); 449 SkAutoMutexAcquire lock(fMutex); // If the SkTDArray resizes while 450 // two threads access array, one 451 // is left with a bad pointer. 452 *(fValue.append()) = Rec(key, value); 453 return value; 454 } 455 456 SkPDFObject* SkPDFDict::insert(SkPDFName* key, SkPDFObject* value) { 457 return this->append(SkRef(key), SkRef(value)); 458 } 459 460 SkPDFObject* SkPDFDict::insert(const char key[], SkPDFObject* value) { 461 return this->append(new SkPDFName(key), SkRef(value)); 462 } 463 464 void SkPDFDict::insertInt(const char key[], int32_t value) { 465 (void)this->append(new SkPDFName(key), new SkPDFInt(value)); 466 } 467 468 void SkPDFDict::insertScalar(const char key[], SkScalar value) { 469 (void)this->append(new SkPDFName(key), new SkPDFScalar(value)); 470 } 471 472 void SkPDFDict::insertName(const char key[], const char name[]) { 473 (void)this->append(new SkPDFName(key), new SkPDFName(name)); 474 } 475 476 void SkPDFDict::clear() { 477 SkAutoMutexAcquire lock(fMutex); 478 for (int i = 0; i < fValue.count(); i++) { 479 SkASSERT(fValue[i].key); 480 SkASSERT(fValue[i].value); 481 fValue[i].key->unref(); 482 fValue[i].value->unref(); 483 } 484 fValue.reset(); 485 } 486 487 void SkPDFDict::remove(const char key[]) { 488 SkASSERT(key); 489 SkPDFName name(key); 490 SkAutoMutexAcquire lock(fMutex); 491 for (int i = 0; i < fValue.count(); i++) { 492 SkASSERT(fValue[i].key); 493 if (*(fValue[i].key) == name) { 494 fValue[i].key->unref(); 495 SkASSERT(fValue[i].value); 496 fValue[i].value->unref(); 497 fValue.removeShuffle(i); 498 return; 499 } 500 } 501 } 502 503 void SkPDFDict::mergeFrom(const SkPDFDict& other) { 504 SkAutoMutexAcquire lockOther(other.fMutex); 505 SkTDArray<Rec> copy(other.fValue); 506 lockOther.release(); // Do not hold both mutexes at once. 507 508 SkAutoMutexAcquire lock(fMutex); 509 for (int i = 0; i < copy.count(); i++) { 510 *(fValue.append()) = Rec(SkRef(copy[i].key), SkRef(copy[i].value)); 511 } 512 } 513