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 "SkFixed.h" | 10 #include "SkFixed.h" |
(...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
275 return j + 1; | 275 return j + 1; |
276 } | 276 } |
277 | 277 |
278 void SkPDFUtils::AppendScalar(SkScalar value, SkWStream* stream) { | 278 void SkPDFUtils::AppendScalar(SkScalar value, SkWStream* stream) { |
279 char result[kMaximumFloatDecimalLength]; | 279 char result[kMaximumFloatDecimalLength]; |
280 size_t len = SkPDFUtils::FloatToDecimal(SkScalarToFloat(value), result); | 280 size_t len = SkPDFUtils::FloatToDecimal(SkScalarToFloat(value), result); |
281 SkASSERT(len < kMaximumFloatDecimalLength); | 281 SkASSERT(len < kMaximumFloatDecimalLength); |
282 stream->write(result, len); | 282 stream->write(result, len); |
283 } | 283 } |
284 | 284 |
| 285 // Return pow(10.0, e), optimized for common cases. |
| 286 inline double pow10(int e) { |
| 287 switch (e) { |
| 288 case 0: return 1.0; // common cases |
| 289 case 1: return 10.0; |
| 290 case 2: return 100.0; |
| 291 case 3: return 1e+03; |
| 292 case 4: return 1e+04; |
| 293 case 5: return 1e+05; |
| 294 case 6: return 1e+06; |
| 295 case 7: return 1e+07; |
| 296 case 8: return 1e+08; |
| 297 case 9: return 1e+09; |
| 298 case 10: return 1e+10; |
| 299 case 11: return 1e+11; |
| 300 case 12: return 1e+12; |
| 301 case 13: return 1e+13; |
| 302 case 14: return 1e+14; |
| 303 case 15: return 1e+15; |
| 304 default: |
| 305 if (e > 15) { |
| 306 double value = 1e+15; |
| 307 while (e-- > 15) { value *= 10.0; } |
| 308 return value; |
| 309 } else { |
| 310 SkASSERT(e < 0); |
| 311 double value = 1.0; |
| 312 while (e++ < 0) { value /= 10.0; } |
| 313 return value; |
| 314 } |
| 315 } |
| 316 } |
| 317 |
285 /** Write a string into result, includeing a terminating '\0' (for | 318 /** Write a string into result, includeing a terminating '\0' (for |
286 unit testing). Return strlen(result) (for SkWStream::write) The | 319 unit testing). Return strlen(result) (for SkWStream::write) The |
287 resulting string will be in the form /[-]?([0-9]*.)?[0-9]+/ and | 320 resulting string will be in the form /[-]?([0-9]*.)?[0-9]+/ and |
288 sscanf(result, "%f", &x) will return the original value iff the | 321 sscanf(result, "%f", &x) will return the original value iff the |
289 value is finite. This function accepts all possible input values. | 322 value is finite. This function accepts all possible input values. |
290 | 323 |
291 Motivation: "PDF does not support [numbers] in exponential format | 324 Motivation: "PDF does not support [numbers] in exponential format |
292 (such as 6.02e23)." Otherwise, this function would rely on a | 325 (such as 6.02e23)." Otherwise, this function would rely on a |
293 sprintf-type function from the standard library. */ | 326 sprintf-type function from the standard library. */ |
294 size_t SkPDFUtils::FloatToDecimal(float value, | 327 size_t SkPDFUtils::FloatToDecimal(float value, |
(...skipping 25 matching lines...) Expand all Loading... |
320 if (value == SK_FloatNegativeInfinity) { | 353 if (value == SK_FloatNegativeInfinity) { |
321 value = -FLT_MAX; // nearest finite float. | 354 value = -FLT_MAX; // nearest finite float. |
322 } | 355 } |
323 if (!std::isfinite(value) || value == 0.0f) { | 356 if (!std::isfinite(value) || value == 0.0f) { |
324 // NAN is unsupported in PDF. Always output a valid number. | 357 // NAN is unsupported in PDF. Always output a valid number. |
325 // Also catch zero here, as a special case. | 358 // Also catch zero here, as a special case. |
326 *output++ = '0'; | 359 *output++ = '0'; |
327 *output = '\0'; | 360 *output = '\0'; |
328 return output - result; | 361 return output - result; |
329 } | 362 } |
330 // Inspired by: | |
331 // http://www.exploringbinary.com/quick-and-dirty-floating-point-to-decimal-
conversion/ | |
332 | |
333 if (value < 0.0) { | 363 if (value < 0.0) { |
334 *output++ = '-'; | 364 *output++ = '-'; |
335 value = -value; | 365 value = -value; |
336 } | 366 } |
337 SkASSERT(value >= 0.0f); | 367 SkASSERT(value >= 0.0f); |
338 | 368 |
339 // Must use double math to keep precision right. | 369 int binaryExponent; |
340 double intPart; | 370 (void)std::frexp(value, &binaryExponent); |
341 double fracPart = std::modf(static_cast<double>(value), &intPart); | 371 static const double kLog2 = 0.3010299956639812; // log10(2.0); |
342 SkASSERT(intPart + fracPart == static_cast<double>(value)); | 372 int decimalExponent = static_cast<int>(std::floor(kLog2 * binaryExponent)); |
343 size_t significantDigits = 0; | 373 int decimalShift = decimalExponent - 8; |
344 const size_t maxSignificantDigits = 9; | 374 double power = pow10(-decimalShift); |
345 // Any fewer significant digits loses precision. The unit test | 375 int32_t d = static_cast<int32_t>(value * power + 0.5); |
346 // checks round-trip correctness. | 376 // SkASSERT(value == (float)(d * pow(10.0, decimalShift))); |
347 SkASSERT(intPart >= 0.0 && fracPart >= 0.0); // negative handled already. | 377 SkASSERT(d <= 999999999); |
348 SkASSERT(intPart > 0.0 || fracPart > 0.0); // zero already caught. | 378 if (d > 167772159) { // floor(pow(10,1+log10(1<<24))) |
349 if (intPart > 0.0) { | 379 // need one fewer decimal digits for 24-bit precision. |
350 // put the intPart digits onto a stack for later reversal. | 380 decimalShift = decimalExponent - 7; |
351 char reversed[1 + FLT_MAX_10_EXP]; // 39 == 1 + FLT_MAX_10_EXP | 381 // SkASSERT(power * 0.1 = pow10(-decimalShift)); |
352 // the largest integer part is FLT_MAX; it has 39 decimal digits. | 382 // recalculate to get rounding right. |
353 size_t reversedIndex = 0; | 383 d = static_cast<int32_t>(value * (power * 0.1) + 0.5); |
| 384 SkASSERT(d <= 99999999); |
| 385 } |
| 386 while (d % 10 == 0) { |
| 387 d /= 10; |
| 388 ++decimalShift; |
| 389 } |
| 390 SkASSERT(d > 0); |
| 391 // SkASSERT(value == (float)(d * pow(10.0, decimalShift))); |
| 392 uint8_t buffer[9]; // decimal value buffer. |
| 393 int bufferIndex = 0; |
| 394 do { |
| 395 buffer[bufferIndex++] = d % 10; |
| 396 d /= 10; |
| 397 } while (d != 0); |
| 398 SkASSERT(bufferIndex <= (int)sizeof(buffer) && bufferIndex > 0); |
| 399 if (decimalShift >= 0) { |
354 do { | 400 do { |
355 SkASSERT(reversedIndex < sizeof(reversed)); | 401 --bufferIndex; |
356 int digit = static_cast<int>(std::fmod(intPart, 10.0)); | 402 *output++ = '0' + buffer[bufferIndex]; |
357 SkASSERT(digit >= 0 && digit <= 9); | 403 } while (bufferIndex); |
358 reversed[reversedIndex++] = '0' + digit; | 404 for (int i = 0; i < decimalShift; ++i) { |
359 intPart = std::floor(intPart / 10.0); | 405 *output++ = '0'; |
360 } while (intPart > 0.0); | |
361 significantDigits = reversedIndex; | |
362 SkASSERT(reversedIndex <= sizeof(reversed)); | |
363 SkASSERT(output + reversedIndex <= end); | |
364 while (reversedIndex-- > 0) { // pop from stack, append to result | |
365 *output++ = reversed[reversedIndex]; | |
366 } | 406 } |
367 } | 407 } else { |
368 if (fracPart > 0 && significantDigits < maxSignificantDigits) { | 408 int placesBeforeDecimal = bufferIndex + decimalShift; |
369 *output++ = '.'; | 409 if (placesBeforeDecimal > 0) { |
370 SkASSERT(output <= end); | 410 while (placesBeforeDecimal-- > 0) { |
371 do { | 411 --bufferIndex; |
372 fracPart = std::modf(fracPart * 10.0, &intPart); | 412 *output++ = '0' + buffer[bufferIndex]; |
373 int digit = static_cast<int>(intPart); | |
374 SkASSERT(digit >= 0 && digit <= 9); | |
375 *output++ = '0' + digit; | |
376 SkASSERT(output <= end); | |
377 if (digit > 0 || significantDigits > 0) { | |
378 // start counting significantDigits after first non-zero digit. | |
379 ++significantDigits; | |
380 } | 413 } |
381 } while (fracPart > 0.0 | 414 *output++ = '.'; |
382 && significantDigits < maxSignificantDigits | 415 } else { |
383 && output < end); | 416 *output++ = '.'; |
384 // When fracPart == 0, additional digits will be zero. | 417 int placesAfterDecimal = -placesBeforeDecimal; |
385 // When significantDigits == maxSignificantDigits, we can stop. | 418 while (placesAfterDecimal-- > 0) { |
386 // when output == end, we have filed the string. | 419 *output++ = '0'; |
387 // Note: denormalized numbers will not have the same number of | 420 } |
388 // significantDigits, but do not need them to round-trip. | 421 } |
| 422 while (bufferIndex > 0) { |
| 423 --bufferIndex; |
| 424 *output++ = '0' + buffer[bufferIndex]; |
| 425 if (output == end) { |
| 426 break; // denormalized: don't need extra precision. |
| 427 // Note: denormalized numbers will not have the same number of |
| 428 // significantDigits, but do not need them to round-trip. |
| 429 } |
| 430 } |
389 } | 431 } |
390 SkASSERT(output <= end); | 432 SkASSERT(output <= end); |
391 *output = '\0'; | 433 *output = '\0'; |
392 return output - result; | 434 return output - result; |
393 } | 435 } |
394 | 436 |
395 void SkPDFUtils::WriteString(SkWStream* wStream, const char* cin, size_t len) { | 437 void SkPDFUtils::WriteString(SkWStream* wStream, const char* cin, size_t len) { |
396 SkDEBUGCODE(static const size_t kMaxLen = 65535;) | 438 SkDEBUGCODE(static const size_t kMaxLen = 65535;) |
397 SkASSERT(len <= kMaxLen); | 439 SkASSERT(len <= kMaxLen); |
398 | 440 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
430 uint8_t c = static_cast<uint8_t>(cin[i]); | 472 uint8_t c = static_cast<uint8_t>(cin[i]); |
431 static const char gHex[] = "0123456789ABCDEF"; | 473 static const char gHex[] = "0123456789ABCDEF"; |
432 char hexValue[2]; | 474 char hexValue[2]; |
433 hexValue[0] = gHex[(c >> 4) & 0xF]; | 475 hexValue[0] = gHex[(c >> 4) & 0xF]; |
434 hexValue[1] = gHex[ c & 0xF]; | 476 hexValue[1] = gHex[ c & 0xF]; |
435 wStream->write(hexValue, 2); | 477 wStream->write(hexValue, 2); |
436 } | 478 } |
437 wStream->writeText(">"); | 479 wStream->writeText(">"); |
438 } | 480 } |
439 } | 481 } |
OLD | NEW |