Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(150)

Side by Side Diff: src/pdf/SkPDFUtils.cpp

Issue 2146103004: SkPDF: re-work SkPDFUtils::FloatToDecimal (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: 2016-07-25 (Monday) 15:22:36 EDT Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | tests/PDFPrimitivesTest.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | tests/PDFPrimitivesTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698