1 /* 2 * Copyright (C) 2011 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "SkPDFCatalog.h" 18 #include "SkPDFTypes.h" 19 #include "SkStream.h" 20 21 #ifdef SK_BUILD_FOR_WIN 22 #define SNPRINTF _snprintf 23 #else 24 #define SNPRINTF snprintf 25 #endif 26 27 SkPDFObject::SkPDFObject() {} 28 SkPDFObject::~SkPDFObject() {} 29 30 size_t SkPDFObject::getOutputSize(SkPDFCatalog* catalog, bool indirect) { 31 SkDynamicMemoryWStream buffer; 32 emitObject(&buffer, catalog, indirect); 33 return buffer.getOffset(); 34 } 35 36 void SkPDFObject::getResources(SkTDArray<SkPDFObject*>* resourceList) {} 37 38 void SkPDFObject::emitIndirectObject(SkWStream* stream, SkPDFCatalog* catalog) { 39 catalog->emitObjectNumber(stream, this); 40 stream->writeText(" obj\n"); 41 emitObject(stream, catalog, false); 42 stream->writeText("\nendobj\n"); 43 } 44 45 SkPDFObjRef::SkPDFObjRef(SkPDFObject* obj) : fObj(obj) {} 46 SkPDFObjRef::~SkPDFObjRef() {} 47 48 size_t SkPDFObject::getIndirectOutputSize(SkPDFCatalog* catalog) { 49 return catalog->getObjectNumberSize(this) + strlen(" obj\n") + 50 this->getOutputSize(catalog, false) + strlen("\nendobj\n"); 51 } 52 53 void SkPDFObjRef::emitObject(SkWStream* stream, SkPDFCatalog* catalog, 54 bool indirect) { 55 SkASSERT(!indirect); 56 catalog->emitObjectNumber(stream, fObj.get()); 57 stream->writeText(" R"); 58 } 59 60 size_t SkPDFObjRef::getOutputSize(SkPDFCatalog* catalog, bool indirect) { 61 SkASSERT(!indirect); 62 return catalog->getObjectNumberSize(fObj.get()) + strlen(" R"); 63 } 64 65 SkPDFInt::SkPDFInt(int32_t value) : fValue(value) {} 66 SkPDFInt::~SkPDFInt() {} 67 68 void SkPDFInt::emitObject(SkWStream* stream, SkPDFCatalog* catalog, 69 bool indirect) { 70 if (indirect) 71 return emitIndirectObject(stream, catalog); 72 stream->writeDecAsText(fValue); 73 } 74 75 SkPDFBool::SkPDFBool(bool value) : fValue(value) {} 76 SkPDFBool::~SkPDFBool() {} 77 78 void SkPDFBool::emitObject(SkWStream* stream, SkPDFCatalog* catalog, 79 bool indirect) { 80 SkASSERT(!indirect); 81 if (fValue) { 82 stream->writeText("true"); 83 } else { 84 stream->writeText("false"); 85 } 86 } 87 88 size_t SkPDFBool::getOutputSize(SkPDFCatalog* catalog, bool indirect) { 89 SkASSERT(!indirect); 90 if (fValue) 91 return strlen("true"); 92 return strlen("false"); 93 } 94 95 SkPDFScalar::SkPDFScalar(SkScalar value) : fValue(value) {} 96 SkPDFScalar::~SkPDFScalar() {} 97 98 void SkPDFScalar::emitObject(SkWStream* stream, SkPDFCatalog* catalog, 99 bool indirect) { 100 if (indirect) 101 return emitIndirectObject(stream, catalog); 102 103 Append(fValue, stream); 104 } 105 106 // static 107 void SkPDFScalar::Append(SkScalar value, SkWStream* stream) { 108 // The range of reals in PDF/A is the same as SkFixed: +/- 32,767 and 109 // +/- 1/65,536 (though integers can range from 2^31 - 1 to -2^31). 110 // When using floats that are outside the whole value range, we can use 111 // integers instead. 112 113 114 #if defined(SK_SCALAR_IS_FIXED) 115 stream->writeScalarAsText(value); 116 return; 117 #endif // SK_SCALAR_IS_FIXED 118 119 #if !defined(SK_ALLOW_LARGE_PDF_SCALARS) 120 if (value > 32767 || value < -32767) { 121 stream->writeDecAsText(SkScalarRound(value)); 122 return; 123 } 124 125 char buffer[SkStrAppendScalar_MaxSize]; 126 char* end = SkStrAppendFixed(buffer, SkScalarToFixed(value)); 127 stream->write(buffer, end - buffer); 128 return; 129 #endif // !SK_ALLOW_LARGE_PDF_SCALARS 130 131 #if defined(SK_SCALAR_IS_FLOAT) && defined(SK_ALLOW_LARGE_PDF_SCALARS) 132 // Floats have 24bits of significance, so anything outside that range is 133 // no more precise than an int. (Plus PDF doesn't support scientific 134 // notation, so this clamps to SK_Max/MinS32). 135 if (value > (1 << 24) || value < -(1 << 24)) { 136 stream->writeDecAsText(value); 137 return; 138 } 139 // Continue to enforce the PDF limits for small floats. 140 if (value < 1.0f/65536 && value > -1.0f/65536) { 141 stream->writeDecAsText(0); 142 return; 143 } 144 // SkStrAppendFloat might still use scientific notation, so use snprintf 145 // directly.. 146 static const int kFloat_MaxSize = 19; 147 char buffer[kFloat_MaxSize]; 148 int len = SNPRINTF(buffer, kFloat_MaxSize, "%#.8f", value); 149 // %f always prints trailing 0s, so strip them. 150 for (; buffer[len - 1] == '0' && len > 0; len--) { 151 buffer[len - 1] = '\0'; 152 } 153 if (buffer[len - 1] == '.') { 154 buffer[len - 1] = '\0'; 155 } 156 stream->writeText(buffer); 157 return; 158 #endif // SK_SCALAR_IS_FLOAT && SK_ALLOW_LARGE_PDF_SCALARS 159 } 160 161 SkPDFString::SkPDFString(const char value[]) 162 : fValue(formatString(value, strlen(value))) { 163 } 164 165 SkPDFString::SkPDFString(const SkString& value) 166 : fValue(formatString(value.c_str(), value.size())) { 167 } 168 169 SkPDFString::SkPDFString(const uint16_t* value, size_t len, bool wideChars) 170 : fValue(formatString(value, len, wideChars)) { 171 } 172 173 SkPDFString::~SkPDFString() {} 174 175 void SkPDFString::emitObject(SkWStream* stream, SkPDFCatalog* catalog, 176 bool indirect) { 177 if (indirect) 178 return emitIndirectObject(stream, catalog); 179 stream->write(fValue.c_str(), fValue.size()); 180 } 181 182 size_t SkPDFString::getOutputSize(SkPDFCatalog* catalog, bool indirect) { 183 if (indirect) 184 return getIndirectOutputSize(catalog); 185 return fValue.size(); 186 } 187 188 // static 189 SkString SkPDFString::formatString(const char* input, size_t len) { 190 return doFormatString(input, len, false, false); 191 } 192 193 SkString SkPDFString::formatString(const uint16_t* input, size_t len, 194 bool wideChars) { 195 return doFormatString(input, len, true, wideChars); 196 } 197 198 // static 199 SkString SkPDFString::doFormatString(const void* input, size_t len, 200 bool wideInput, bool wideOutput) { 201 SkASSERT(len <= kMaxLen); 202 const uint16_t* win = (const uint16_t*) input; 203 const char* cin = (const char*) input; 204 205 if (wideOutput) { 206 SkASSERT(wideInput); 207 SkString result; 208 result.append("<"); 209 for (size_t i = 0; i < len; i++) 210 result.appendHex(win[i], 4); 211 result.append(">"); 212 return result; 213 } 214 215 // 7-bit clean is a heuristic to decide what string format to use; 216 // a 7-bit clean string should require little escaping. 217 bool sevenBitClean = true; 218 for (size_t i = 0; i < len; i++) { 219 SkASSERT(!wideInput || !(win[i] & ~0xFF)); 220 char val = wideInput ? win[i] : cin[i]; 221 if (val > '~' || val < ' ') { 222 sevenBitClean = false; 223 break; 224 } 225 } 226 227 SkString result; 228 if (sevenBitClean) { 229 result.append("("); 230 for (size_t i = 0; i < len; i++) { 231 SkASSERT(!wideInput || !(win[i] & ~0xFF)); 232 char val = wideInput ? win[i] : cin[i]; 233 if (val == '\\' || val == '(' || val == ')') 234 result.append("\\"); 235 result.append(&val, 1); 236 } 237 result.append(")"); 238 } else { 239 result.append("<"); 240 for (size_t i = 0; i < len; i++) { 241 SkASSERT(!wideInput || !(win[i] & ~0xFF)); 242 unsigned char val = wideInput ? win[i] : cin[i]; 243 result.appendHex(val, 2); 244 } 245 result.append(">"); 246 } 247 248 return result; 249 } 250 251 SkPDFName::SkPDFName(const char name[]) : fValue(formatName(SkString(name))) {} 252 SkPDFName::SkPDFName(const SkString& name) : fValue(formatName(name)) {} 253 SkPDFName::~SkPDFName() {} 254 255 void SkPDFName::emitObject(SkWStream* stream, SkPDFCatalog* catalog, 256 bool indirect) { 257 SkASSERT(!indirect); 258 stream->write(fValue.c_str(), fValue.size()); 259 } 260 261 size_t SkPDFName::getOutputSize(SkPDFCatalog* catalog, bool indirect) { 262 SkASSERT(!indirect); 263 return fValue.size(); 264 } 265 266 // static 267 SkString SkPDFName::formatName(const SkString& input) { 268 SkASSERT(input.size() <= kMaxLen); 269 270 SkString result("/"); 271 for (size_t i = 0; i < input.size(); i++) { 272 if (input[i] & 0x80 || input[i] < '!' || input[i] == '#') { 273 result.append("#"); 274 result.appendHex(input[i], 2); 275 } else { 276 result.append(input.c_str() + i, 1); 277 } 278 } 279 280 return result; 281 } 282 283 SkPDFArray::SkPDFArray() {} 284 SkPDFArray::~SkPDFArray() { 285 fValue.safeUnrefAll(); 286 } 287 288 void SkPDFArray::emitObject(SkWStream* stream, SkPDFCatalog* catalog, 289 bool indirect) { 290 if (indirect) 291 return emitIndirectObject(stream, catalog); 292 293 stream->writeText("["); 294 for (int i = 0; i < fValue.count(); i++) { 295 fValue[i]->emitObject(stream, catalog, false); 296 if (i + 1 < fValue.count()) 297 stream->writeText(" "); 298 } 299 stream->writeText("]"); 300 } 301 302 size_t SkPDFArray::getOutputSize(SkPDFCatalog* catalog, bool indirect) { 303 if (indirect) 304 return getIndirectOutputSize(catalog); 305 306 size_t result = strlen("[]"); 307 if (fValue.count()) 308 result += fValue.count() - 1; 309 for (int i = 0; i < fValue.count(); i++) 310 result += fValue[i]->getOutputSize(catalog, false); 311 return result; 312 } 313 314 void SkPDFArray::reserve(int length) { 315 SkASSERT(length <= kMaxLen); 316 fValue.setReserve(length); 317 } 318 319 SkPDFObject* SkPDFArray::setAt(int offset, SkPDFObject* value) { 320 SkASSERT(offset < fValue.count()); 321 SkSafeUnref(fValue[offset]); 322 fValue[offset] = value; 323 SkSafeRef(fValue[offset]); 324 return value; 325 } 326 327 SkPDFObject* SkPDFArray::append(SkPDFObject* value) { 328 SkASSERT(fValue.count() < kMaxLen); 329 SkSafeRef(value); 330 fValue.push(value); 331 return value; 332 } 333 334 SkPDFDict::SkPDFDict() {} 335 336 SkPDFDict::SkPDFDict(const char type[]) { 337 insert("Type", new SkPDFName(type))->unref(); 338 } 339 340 SkPDFDict::~SkPDFDict() { 341 clear(); 342 } 343 344 void SkPDFDict::emitObject(SkWStream* stream, SkPDFCatalog* catalog, 345 bool indirect) { 346 if (indirect) 347 return emitIndirectObject(stream, catalog); 348 349 stream->writeText("<<"); 350 for (int i = 0; i < fValue.count(); i++) { 351 fValue[i].key->emitObject(stream, catalog, false); 352 stream->writeText(" "); 353 fValue[i].value->emitObject(stream, catalog, false); 354 stream->writeText("\n"); 355 } 356 stream->writeText(">>"); 357 } 358 359 size_t SkPDFDict::getOutputSize(SkPDFCatalog* catalog, bool indirect) { 360 if (indirect) 361 return getIndirectOutputSize(catalog); 362 363 size_t result = strlen("<<>>") + (fValue.count() * 2); 364 for (int i = 0; i < fValue.count(); i++) { 365 result += fValue[i].key->getOutputSize(catalog, false); 366 result += fValue[i].value->getOutputSize(catalog, false); 367 } 368 return result; 369 } 370 371 SkPDFObject* SkPDFDict::insert(SkPDFName* key, SkPDFObject* value) { 372 struct Rec* newEntry = fValue.append(); 373 newEntry->key = key; 374 SkSafeRef(newEntry->key); 375 newEntry->value = value; 376 SkSafeRef(newEntry->value); 377 return value; 378 } 379 380 SkPDFObject* SkPDFDict::insert(const char key[], SkPDFObject* value) { 381 SkRefPtr<SkPDFName> keyName = new SkPDFName(key); 382 keyName->unref(); // SkRefPtr and new both took a reference. 383 return insert(keyName.get(), value); 384 } 385 386 void SkPDFDict::clear() { 387 for (int i = 0; i < fValue.count(); i++) { 388 SkSafeUnref(fValue[i].key); 389 SkSafeUnref(fValue[i].value); 390 } 391 fValue.reset(); 392 } 393