OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 | 8 |
9 #include "SkData.h" | 9 #include "SkData.h" |
10 #include "SkGeometry.h" | 10 #include "SkGeometry.h" |
11 #include "SkPaint.h" | 11 #include "SkPaint.h" |
12 #include "SkPath.h" | 12 #include "SkPath.h" |
13 #include "SkPDFResourceDict.h" | 13 #include "SkPDFResourceDict.h" |
14 #include "SkPDFUtils.h" | 14 #include "SkPDFUtils.h" |
15 #include "SkStream.h" | 15 #include "SkStream.h" |
16 #include "SkString.h" | 16 #include "SkString.h" |
17 #include "SkPDFTypes.h" | 17 #include "SkPDFTypes.h" |
18 | 18 |
| 19 #include <cmath> |
| 20 |
19 //static | 21 //static |
20 SkPDFArray* SkPDFUtils::RectToArray(const SkRect& rect) { | 22 SkPDFArray* SkPDFUtils::RectToArray(const SkRect& rect) { |
21 SkPDFArray* result = new SkPDFArray(); | 23 SkPDFArray* result = new SkPDFArray(); |
22 result->reserve(4); | 24 result->reserve(4); |
23 result->appendScalar(rect.fLeft); | 25 result->appendScalar(rect.fLeft); |
24 result->appendScalar(rect.fTop); | 26 result->appendScalar(rect.fTop); |
25 result->appendScalar(rect.fRight); | 27 result->appendScalar(rect.fRight); |
26 result->appendScalar(rect.fBottom); | 28 result->appendScalar(rect.fBottom); |
27 return result; | 29 return result; |
28 } | 30 } |
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
247 SkPDFResourceDict::kPattern_ResourceType, | 249 SkPDFResourceDict::kPattern_ResourceType, |
248 objectIndex); | 250 objectIndex); |
249 content->writeText("/Pattern CS/Pattern cs/"); | 251 content->writeText("/Pattern CS/Pattern cs/"); |
250 content->writeText(resourceName.c_str()); | 252 content->writeText(resourceName.c_str()); |
251 content->writeText(" SCN/"); | 253 content->writeText(" SCN/"); |
252 content->writeText(resourceName.c_str()); | 254 content->writeText(resourceName.c_str()); |
253 content->writeText(" scn\n"); | 255 content->writeText(" scn\n"); |
254 } | 256 } |
255 | 257 |
256 void SkPDFUtils::AppendScalar(SkScalar value, SkWStream* stream) { | 258 void SkPDFUtils::AppendScalar(SkScalar value, SkWStream* stream) { |
257 // The range of reals in PDF/A is the same as SkFixed: +/- 32,767 and | 259 char result[kMaximumFloatDecimalLength]; |
258 // +/- 1/65,536 (though integers can range from 2^31 - 1 to -2^31). | 260 size_t len = SkPDFUtils::FloatToDecimal(SkScalarToFloat(value), result); |
259 // When using floats that are outside the whole value range, we can use | 261 SkASSERT(len < kMaximumFloatDecimalLength); |
260 // integers instead. | 262 stream->write(result, len); |
| 263 } |
261 | 264 |
262 #if !defined(SK_ALLOW_LARGE_PDF_SCALARS) | 265 /** Write a string into result, includeing a terminating '\0' (for |
263 if (value > 32767 || value < -32767) { | 266 unit testing). Return strlen(result) (for SkWStream::write) The |
264 stream->writeDecAsText(SkScalarRoundToInt(value)); | 267 resulting string will be in the form /[-]?([0-9]*.)?[0-9]+/ and |
265 return; | 268 sscanf(result, "%f", &x) will return the original value iff the |
| 269 value is finite. This function accepts all possible input values. |
| 270 |
| 271 Motivation: "PDF does not support [numbers] in exponential format |
| 272 (such as 6.02e23)." Otherwise, this function would rely on a |
| 273 sprintf-type function from the standard library. */ |
| 274 size_t SkPDFUtils::FloatToDecimal(float value, |
| 275 char result[kMaximumFloatDecimalLength]) { |
| 276 /* The longest result is -FLT_MIN. |
| 277 We serialize it as "-.0000000000000000000000000000000000000117549435" |
| 278 which has 48 characters plus a terminating '\0'. */ |
| 279 |
| 280 /* section C.1 of the PDF1.4 spec (http://goo.gl/0SCswJ) says that |
| 281 most PDF rasterizers will use fixed-point scalars that lack the |
| 282 dynamic range of floats. Even if this is the case, I want to |
| 283 serialize these (uncommon) very small and very large scalar |
| 284 values with enough precision to allow a floating-point |
| 285 rasterizer to read them in with perfect accuracy. |
| 286 Experimentally, rasterizers such as pdfium do seem to benefit |
| 287 from this. Rasterizers that rely on fixed-point scalars should |
| 288 gracefully ignore these values that they can not parse. */ |
| 289 char* output = &result[0]; |
| 290 const char* const end = &result[kMaximumFloatDecimalLength - 1]; |
| 291 // subtract one to leave space for '\0'. |
| 292 |
| 293 /* This function is written to accept any possible input value, |
| 294 including non-finite values such as INF and NAN. In that case, |
| 295 we ignore value-correctness and and output a syntacticly-valid |
| 296 number. */ |
| 297 if (value == SK_FloatInfinity) { |
| 298 value = FLT_MAX; // nearest finite float. |
266 } | 299 } |
| 300 if (value == SK_FloatNegativeInfinity) { |
| 301 value = -FLT_MAX; // nearest finite float. |
| 302 } |
| 303 if (!std::isfinite(value) || value == 0.0f) { |
| 304 // NAN is unsupported in PDF. Always output a valid number. |
| 305 // Also catch zero here, as a special case. |
| 306 *output++ = '0'; |
| 307 *output = '\0'; |
| 308 return output - result; |
| 309 } |
| 310 // Inspired by: |
| 311 // http://www.exploringbinary.com/quick-and-dirty-floating-point-to-decimal-
conversion/ |
267 | 312 |
268 char buffer[SkStrAppendScalar_MaxSize]; | 313 if (value < 0.0) { |
269 char* end = SkStrAppendFixed(buffer, SkScalarToFixed(value)); | 314 *output++ = '-'; |
270 stream->write(buffer, end - buffer); | 315 value = -value; |
271 return; | 316 } |
272 #endif // !SK_ALLOW_LARGE_PDF_SCALARS | 317 SkASSERT(value >= 0.0f); |
273 | 318 |
274 #if defined(SK_ALLOW_LARGE_PDF_SCALARS) | 319 // Must use double math to keep precision right. |
275 // Floats have 24bits of significance, so anything outside that range is | 320 double intPart; |
276 // no more precise than an int. (Plus PDF doesn't support scientific | 321 double fracPart = std::modf(static_cast<double>(value), &intPart); |
277 // notation, so this clamps to SK_Max/MinS32). | 322 SkASSERT(intPart + fracPart == static_cast<double>(value)); |
278 if (value > (1 << 24) || value < -(1 << 24)) { | 323 size_t significantDigits = 0; |
279 stream->writeDecAsText(value); | 324 const size_t maxSignificantDigits = 9; |
280 return; | 325 // Any fewer significant digits loses precision. The unit test |
| 326 // checks round-trip correctness. |
| 327 SkASSERT(intPart >= 0.0 && fracPart >= 0.0); // negative handled already. |
| 328 SkASSERT(intPart > 0.0 || fracPart > 0.0); // zero already caught. |
| 329 if (intPart > 0.0) { |
| 330 // put the intPart digits onto a stack for later reversal. |
| 331 char reversed[1 + FLT_MAX_10_EXP]; // 39 == 1 + FLT_MAX_10_EXP |
| 332 // the largest integer part is FLT_MAX; it has 39 decimal digits. |
| 333 size_t reversedIndex = 0; |
| 334 do { |
| 335 SkASSERT(reversedIndex < sizeof(reversed)); |
| 336 int digit = static_cast<int>(std::fmod(intPart, 10.0)); |
| 337 SkASSERT(digit >= 0 && digit <= 9); |
| 338 reversed[reversedIndex++] = '0' + digit; |
| 339 intPart = std::floor(intPart / 10.0); |
| 340 } while (intPart > 0.0); |
| 341 significantDigits = reversedIndex; |
| 342 SkASSERT(reversedIndex <= sizeof(reversed)); |
| 343 SkASSERT(output + reversedIndex <= end); |
| 344 while (reversedIndex-- > 0) { // pop from stack, append to result |
| 345 *output++ = reversed[reversedIndex]; |
| 346 } |
281 } | 347 } |
282 // Continue to enforce the PDF limits for small floats. | 348 if (fracPart > 0 && significantDigits < maxSignificantDigits) { |
283 if (value < 1.0f/65536 && value > -1.0f/65536) { | 349 *output++ = '.'; |
284 stream->writeDecAsText(0); | 350 SkASSERT(output <= end); |
285 return; | 351 do { |
| 352 fracPart = std::modf(fracPart * 10.0, &intPart); |
| 353 int digit = static_cast<int>(intPart); |
| 354 SkASSERT(digit >= 0 && digit <= 9); |
| 355 *output++ = '0' + digit; |
| 356 SkASSERT(output <= end); |
| 357 if (digit > 0 || significantDigits > 0) { |
| 358 // start counting significantDigits after first non-zero digit. |
| 359 ++significantDigits; |
| 360 } |
| 361 } while (fracPart > 0.0 |
| 362 && significantDigits < maxSignificantDigits |
| 363 && output < end); |
| 364 // When fracPart == 0, additional digits will be zero. |
| 365 // When significantDigits == maxSignificantDigits, we can stop. |
| 366 // when output == end, we have filed the string. |
| 367 // Note: denormalized numbers will not have the same number of |
| 368 // significantDigits, but do not need them to round-trip. |
286 } | 369 } |
287 // SkStrAppendFloat might still use scientific notation, so use snprintf | 370 SkASSERT(output <= end); |
288 // directly.. | 371 *output = '\0'; |
289 static const int kFloat_MaxSize = 19; | 372 return output - result; |
290 char buffer[kFloat_MaxSize]; | |
291 int len = SNPRINTF(buffer, kFloat_MaxSize, "%#.8f", value); | |
292 // %f always prints trailing 0s, so strip them. | |
293 for (; buffer[len - 1] == '0' && len > 0; len--) { | |
294 buffer[len - 1] = '\0'; | |
295 } | |
296 if (buffer[len - 1] == '.') { | |
297 buffer[len - 1] = '\0'; | |
298 } | |
299 stream->writeText(buffer); | |
300 return; | |
301 #endif // SK_ALLOW_LARGE_PDF_SCALARS | |
302 } | 373 } |
303 | 374 |
304 SkString SkPDFUtils::FormatString(const char* cin, size_t len) { | 375 SkString SkPDFUtils::FormatString(const char* cin, size_t len) { |
305 SkDEBUGCODE(static const size_t kMaxLen = 65535;) | 376 SkDEBUGCODE(static const size_t kMaxLen = 65535;) |
306 SkASSERT(len <= kMaxLen); | 377 SkASSERT(len <= kMaxLen); |
307 | 378 |
308 // 7-bit clean is a heuristic to decide what string format to use; | 379 // 7-bit clean is a heuristic to decide what string format to use; |
309 // a 7-bit clean string should require little escaping. | 380 // a 7-bit clean string should require little escaping. |
310 bool sevenBitClean = true; | 381 bool sevenBitClean = true; |
311 size_t characterCount = 2 + len; | 382 size_t characterCount = 2 + len; |
(...skipping 25 matching lines...) Expand all Loading... |
337 for (size_t i = 0; i < len; i++) { | 408 for (size_t i = 0; i < len; i++) { |
338 uint8_t c = static_cast<uint8_t>(cin[i]); | 409 uint8_t c = static_cast<uint8_t>(cin[i]); |
339 static const char gHex[] = "0123456789ABCDEF"; | 410 static const char gHex[] = "0123456789ABCDEF"; |
340 *str++ = gHex[(c >> 4) & 0xF]; | 411 *str++ = gHex[(c >> 4) & 0xF]; |
341 *str++ = gHex[(c ) & 0xF]; | 412 *str++ = gHex[(c ) & 0xF]; |
342 } | 413 } |
343 *str++ = '>'; | 414 *str++ = '>'; |
344 } | 415 } |
345 return result; | 416 return result; |
346 } | 417 } |
OLD | NEW |