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