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