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 22void SkPDFObject::emit(SkWStream* stream, SkPDFCatalog* catalog, 23 bool indirect) { 24 SkPDFObject* realObject = catalog->getSubstituteObject(this); 25 return realObject->emitObject(stream, catalog, indirect); 26} 27 28size_t SkPDFObject::getOutputSize(SkPDFCatalog* catalog, bool indirect) { 29 SkDynamicMemoryWStream buffer; 30 emit(&buffer, catalog, indirect); 31 return buffer.getOffset(); 32} 33 34void SkPDFObject::getResources(const SkTSet<SkPDFObject*>& knownResourceObjects, 35 SkTSet<SkPDFObject*>* newResourceObjects) {} 36 37void 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 44size_t SkPDFObject::getIndirectOutputSize(SkPDFCatalog* catalog) { 45 return catalog->getObjectNumberSize(this) + strlen(" obj\n") + 46 this->getOutputSize(catalog, false) + strlen("\nendobj\n"); 47} 48 49void SkPDFObject::AddResourceHelper(SkPDFObject* resource, 50 SkTDArray<SkPDFObject*>* list) { 51 list->push(resource); 52 resource->ref(); 53} 54 55void 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 74SkPDFObjRef::SkPDFObjRef(SkPDFObject* obj) : fObj(obj) { 75 SkSafeRef(obj); 76} 77 78SkPDFObjRef::~SkPDFObjRef() {} 79 80void SkPDFObjRef::emitObject(SkWStream* stream, SkPDFCatalog* catalog, 81 bool indirect) { 82 SkASSERT(!indirect); 83 catalog->emitObjectNumber(stream, fObj.get()); 84 stream->writeText(" R"); 85} 86 87size_t SkPDFObjRef::getOutputSize(SkPDFCatalog* catalog, bool indirect) { 88 SkASSERT(!indirect); 89 return catalog->getObjectNumberSize(fObj.get()) + strlen(" R"); 90} 91 92SkPDFInt::SkPDFInt(int32_t value) : fValue(value) {} 93SkPDFInt::~SkPDFInt() {} 94 95void SkPDFInt::emitObject(SkWStream* stream, SkPDFCatalog* catalog, 96 bool indirect) { 97 if (indirect) { 98 return emitIndirectObject(stream, catalog); 99 } 100 stream->writeDecAsText(fValue); 101} 102 103SkPDFBool::SkPDFBool(bool value) : fValue(value) {} 104SkPDFBool::~SkPDFBool() {} 105 106void 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 116size_t SkPDFBool::getOutputSize(SkPDFCatalog* catalog, bool indirect) { 117 SkASSERT(!indirect); 118 if (fValue) { 119 return strlen("true"); 120 } 121 return strlen("false"); 122} 123 124SkPDFScalar::SkPDFScalar(SkScalar value) : fValue(value) {} 125SkPDFScalar::~SkPDFScalar() {} 126 127void 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 137void 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 185SkPDFString::SkPDFString(const char value[]) 186 : fValue(FormatString(value, strlen(value))) { 187} 188 189SkPDFString::SkPDFString(const SkString& value) 190 : fValue(FormatString(value.c_str(), value.size())) { 191} 192 193SkPDFString::SkPDFString(const uint16_t* value, size_t len, bool wideChars) 194 : fValue(FormatString(value, len, wideChars)) { 195} 196 197SkPDFString::~SkPDFString() {} 198 199void 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 206size_t SkPDFString::getOutputSize(SkPDFCatalog* catalog, bool indirect) { 207 if (indirect) 208 return getIndirectOutputSize(catalog); 209 return fValue.size(); 210} 211 212// static 213SkString SkPDFString::FormatString(const char* input, size_t len) { 214 return DoFormatString(input, len, false, false); 215} 216 217SkString SkPDFString::FormatString(const uint16_t* input, size_t len, 218 bool wideChars) { 219 return DoFormatString(input, len, true, wideChars); 220} 221 222// static 223SkString 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 277SkPDFName::SkPDFName(const char name[]) : fValue(FormatName(SkString(name))) {} 278SkPDFName::SkPDFName(const SkString& name) : fValue(FormatName(name)) {} 279SkPDFName::~SkPDFName() {} 280 281bool SkPDFName::operator==(const SkPDFName& b) const { 282 return fValue == b.fValue; 283} 284 285void SkPDFName::emitObject(SkWStream* stream, SkPDFCatalog* catalog, 286 bool indirect) { 287 SkASSERT(!indirect); 288 stream->write(fValue.c_str(), fValue.size()); 289} 290 291size_t SkPDFName::getOutputSize(SkPDFCatalog* catalog, bool indirect) { 292 SkASSERT(!indirect); 293 return fValue.size(); 294} 295 296// static 297SkString 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 316SkPDFArray::SkPDFArray() {} 317SkPDFArray::~SkPDFArray() { 318 fValue.unrefAll(); 319} 320 321void 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 337size_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 352void SkPDFArray::reserve(int length) { 353 SkASSERT(length <= kMaxLen); 354 fValue.setReserve(length); 355} 356 357SkPDFObject* 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 365SkPDFObject* SkPDFArray::append(SkPDFObject* value) { 366 SkASSERT(fValue.count() < kMaxLen); 367 value->ref(); 368 fValue.push(value); 369 return value; 370} 371 372void SkPDFArray::appendInt(int32_t value) { 373 SkASSERT(fValue.count() < kMaxLen); 374 fValue.push(new SkPDFInt(value)); 375} 376 377void SkPDFArray::appendScalar(SkScalar value) { 378 SkASSERT(fValue.count() < kMaxLen); 379 fValue.push(new SkPDFScalar(value)); 380} 381 382void SkPDFArray::appendName(const char name[]) { 383 SkASSERT(fValue.count() < kMaxLen); 384 fValue.push(new SkPDFName(name)); 385} 386 387/////////////////////////////////////////////////////////////////////////////// 388 389SkPDFDict::SkPDFDict() {} 390 391SkPDFDict::SkPDFDict(const char type[]) { 392 insertName("Type", type); 393} 394 395SkPDFDict::~SkPDFDict() { 396 clear(); 397} 398 399void SkPDFDict::emitObject(SkWStream* stream, SkPDFCatalog* catalog, 400 bool indirect) { 401 if (indirect) { 402 return emitIndirectObject(stream, catalog); 403 } 404 405 stream->writeText("<<"); 406 for (int i = 0; i < fValue.count(); i++) { 407 fValue[i].key->emitObject(stream, catalog, false); 408 stream->writeText(" "); 409 fValue[i].value->emit(stream, catalog, false); 410 stream->writeText("\n"); 411 } 412 stream->writeText(">>"); 413} 414 415size_t SkPDFDict::getOutputSize(SkPDFCatalog* catalog, bool indirect) { 416 if (indirect) { 417 return getIndirectOutputSize(catalog); 418 } 419 420 size_t result = strlen("<<>>") + (fValue.count() * 2); 421 for (int i = 0; i < fValue.count(); i++) { 422 result += fValue[i].key->getOutputSize(catalog, false); 423 result += fValue[i].value->getOutputSize(catalog, false); 424 } 425 return result; 426} 427 428SkPDFObject* SkPDFDict::insert(SkPDFName* key, SkPDFObject* value) { 429 key->ref(); 430 value->ref(); 431 struct Rec* newEntry = fValue.append(); 432 newEntry->key = key; 433 newEntry->value = value; 434 return value; 435} 436 437SkPDFObject* SkPDFDict::insert(const char key[], SkPDFObject* value) { 438 value->ref(); 439 struct Rec* newEntry = fValue.append(); 440 newEntry->key = new SkPDFName(key); 441 newEntry->value = value; 442 return value; 443} 444 445void SkPDFDict::insertInt(const char key[], int32_t value) { 446 struct Rec* newEntry = fValue.append(); 447 newEntry->key = new SkPDFName(key); 448 newEntry->value = new SkPDFInt(value); 449} 450 451void SkPDFDict::insertScalar(const char key[], SkScalar value) { 452 struct Rec* newEntry = fValue.append(); 453 newEntry->key = new SkPDFName(key); 454 newEntry->value = new SkPDFScalar(value); 455} 456 457void SkPDFDict::insertName(const char key[], const char name[]) { 458 struct Rec* newEntry = fValue.append(); 459 newEntry->key = new SkPDFName(key); 460 newEntry->value = new SkPDFName(name); 461} 462 463void SkPDFDict::clear() { 464 for (int i = 0; i < fValue.count(); i++) { 465 fValue[i].key->unref(); 466 fValue[i].value->unref(); 467 } 468 fValue.reset(); 469} 470 471SkPDFDict::Iter::Iter(const SkPDFDict& dict) 472 : fIter(dict.fValue.begin()), 473 fStop(dict.fValue.end()) { 474} 475 476SkPDFName* SkPDFDict::Iter::next(SkPDFObject** value) { 477 if (fIter != fStop) { 478 const Rec* cur = fIter; 479 fIter++; 480 *value = cur->value; 481 return cur->key; 482 } 483 *value = NULL; 484 return NULL; 485} 486