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 SK_DEFINE_INST_COUNT(SkPDFArray) 21 SK_DEFINE_INST_COUNT(SkPDFBool) 22 SK_DEFINE_INST_COUNT(SkPDFDict) 23 SK_DEFINE_INST_COUNT(SkPDFInt) 24 SK_DEFINE_INST_COUNT(SkPDFName) 25 SK_DEFINE_INST_COUNT(SkPDFObject) 26 SK_DEFINE_INST_COUNT(SkPDFObjRef) 27 SK_DEFINE_INST_COUNT(SkPDFScalar) 28 SK_DEFINE_INST_COUNT(SkPDFString) 29 30 /////////////////////////////////////////////////////////////////////////////// 31 32 void SkPDFObject::emit(SkWStream* stream, SkPDFCatalog* catalog, 33 bool indirect) { 34 SkPDFObject* realObject = catalog->getSubstituteObject(this); 35 return realObject->emitObject(stream, catalog, indirect); 36 } 37 38 size_t SkPDFObject::getOutputSize(SkPDFCatalog* catalog, bool indirect) { 39 SkDynamicMemoryWStream buffer; 40 emit(&buffer, catalog, indirect); 41 return buffer.getOffset(); 42 } 43 44 void SkPDFObject::getResources(const SkTSet<SkPDFObject*>& knownResourceObjects, 45 SkTSet<SkPDFObject*>* newResourceObjects) {} 46 47 void 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 54 size_t SkPDFObject::getIndirectOutputSize(SkPDFCatalog* catalog) { 55 return catalog->getObjectNumberSize(this) + strlen(" obj\n") + 56 this->getOutputSize(catalog, false) + strlen("\nendobj\n"); 57 } 58 59 void SkPDFObject::AddResourceHelper(SkPDFObject* resource, 60 SkTDArray<SkPDFObject*>* list) { 61 list->push(resource); 62 resource->ref(); 63 } 64 65 void 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 84 SkPDFObjRef::SkPDFObjRef(SkPDFObject* obj) : fObj(obj) { 85 SkSafeRef(obj); 86 } 87 88 SkPDFObjRef::~SkPDFObjRef() {} 89 90 void SkPDFObjRef::emitObject(SkWStream* stream, SkPDFCatalog* catalog, 91 bool indirect) { 92 SkASSERT(!indirect); 93 catalog->emitObjectNumber(stream, fObj.get()); 94 stream->writeText(" R"); 95 } 96 97 size_t SkPDFObjRef::getOutputSize(SkPDFCatalog* catalog, bool indirect) { 98 SkASSERT(!indirect); 99 return catalog->getObjectNumberSize(fObj.get()) + strlen(" R"); 100 } 101 102 SkPDFInt::SkPDFInt(int32_t value) : fValue(value) {} 103 SkPDFInt::~SkPDFInt() {} 104 105 void SkPDFInt::emitObject(SkWStream* stream, SkPDFCatalog* catalog, 106 bool indirect) { 107 if (indirect) { 108 return emitIndirectObject(stream, catalog); 109 } 110 stream->writeDecAsText(fValue); 111 } 112 113 SkPDFBool::SkPDFBool(bool value) : fValue(value) {} 114 SkPDFBool::~SkPDFBool() {} 115 116 void 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 126 size_t SkPDFBool::getOutputSize(SkPDFCatalog* catalog, bool indirect) { 127 SkASSERT(!indirect); 128 if (fValue) { 129 return strlen("true"); 130 } 131 return strlen("false"); 132 } 133 134 SkPDFScalar::SkPDFScalar(SkScalar value) : fValue(value) {} 135 SkPDFScalar::~SkPDFScalar() {} 136 137 void 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 147 void 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 201 SkPDFString::SkPDFString(const char value[]) 202 : fValue(FormatString(value, strlen(value))) { 203 } 204 205 SkPDFString::SkPDFString(const SkString& value) 206 : fValue(FormatString(value.c_str(), value.size())) { 207 } 208 209 SkPDFString::SkPDFString(const uint16_t* value, size_t len, bool wideChars) 210 : fValue(FormatString(value, len, wideChars)) { 211 } 212 213 SkPDFString::~SkPDFString() {} 214 215 void 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 222 size_t SkPDFString::getOutputSize(SkPDFCatalog* catalog, bool indirect) { 223 if (indirect) 224 return getIndirectOutputSize(catalog); 225 return fValue.size(); 226 } 227 228 // static 229 SkString SkPDFString::FormatString(const char* input, size_t len) { 230 return DoFormatString(input, len, false, false); 231 } 232 233 SkString SkPDFString::FormatString(const uint16_t* input, size_t len, 234 bool wideChars) { 235 return DoFormatString(input, len, true, wideChars); 236 } 237 238 // static 239 SkString 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 293 SkPDFName::SkPDFName(const char name[]) : fValue(FormatName(SkString(name))) {} 294 SkPDFName::SkPDFName(const SkString& name) : fValue(FormatName(name)) {} 295 SkPDFName::~SkPDFName() {} 296 297 bool SkPDFName::operator==(const SkPDFName& b) const { 298 return fValue == b.fValue; 299 } 300 301 void SkPDFName::emitObject(SkWStream* stream, SkPDFCatalog* catalog, 302 bool indirect) { 303 SkASSERT(!indirect); 304 stream->write(fValue.c_str(), fValue.size()); 305 } 306 307 size_t SkPDFName::getOutputSize(SkPDFCatalog* catalog, bool indirect) { 308 SkASSERT(!indirect); 309 return fValue.size(); 310 } 311 312 // static 313 SkString 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 332 SkPDFArray::SkPDFArray() {} 333 SkPDFArray::~SkPDFArray() { 334 fValue.unrefAll(); 335 } 336 337 void 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 353 size_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 368 void SkPDFArray::reserve(int length) { 369 SkASSERT(length <= kMaxLen); 370 fValue.setReserve(length); 371 } 372 373 SkPDFObject* 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 381 SkPDFObject* SkPDFArray::append(SkPDFObject* value) { 382 SkASSERT(fValue.count() < kMaxLen); 383 value->ref(); 384 fValue.push(value); 385 return value; 386 } 387 388 void SkPDFArray::appendInt(int32_t value) { 389 SkASSERT(fValue.count() < kMaxLen); 390 fValue.push(new SkPDFInt(value)); 391 } 392 393 void SkPDFArray::appendScalar(SkScalar value) { 394 SkASSERT(fValue.count() < kMaxLen); 395 fValue.push(new SkPDFScalar(value)); 396 } 397 398 void SkPDFArray::appendName(const char name[]) { 399 SkASSERT(fValue.count() < kMaxLen); 400 fValue.push(new SkPDFName(name)); 401 } 402 403 /////////////////////////////////////////////////////////////////////////////// 404 405 SkPDFDict::SkPDFDict() {} 406 407 SkPDFDict::SkPDFDict(const char type[]) { 408 insertName("Type", type); 409 } 410 411 SkPDFDict::~SkPDFDict() { 412 clear(); 413 } 414 415 void 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 431 size_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 444 SkPDFObject* 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 453 SkPDFObject* 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 461 void 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 467 void 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 473 void 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 479 void 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 487 SkPDFDict::Iter::Iter(const SkPDFDict& dict) 488 : fIter(dict.fValue.begin()), 489 fStop(dict.fValue.end()) { 490 } 491 492 SkPDFName* 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