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