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" |
(...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
251 content->writeText(" scn\n"); | 251 content->writeText(" scn\n"); |
252 } | 252 } |
253 | 253 |
254 void SkPDFUtils::AppendScalar(SkScalar value, SkWStream* stream) { | 254 void SkPDFUtils::AppendScalar(SkScalar value, SkWStream* stream) { |
255 char result[kMaximumFloatDecimalLength]; | 255 char result[kMaximumFloatDecimalLength]; |
256 size_t len = SkPDFUtils::FloatToDecimal(SkScalarToFloat(value), result); | 256 size_t len = SkPDFUtils::FloatToDecimal(SkScalarToFloat(value), result); |
257 SkASSERT(len < kMaximumFloatDecimalLength); | 257 SkASSERT(len < kMaximumFloatDecimalLength); |
258 stream->write(result, len); | 258 stream->write(result, len); |
259 } | 259 } |
260 | 260 |
261 // Return pow(10.0, e), optimized for common cases. | |
tomhudson
2016/07/15 20:45:41
Huh, this is really faster?
hal.canary
2016/07/17 02:33:42
yep.
| |
262 inline double pow10(int e) { | |
263 switch (e) { | |
264 case 0: return 1.0; // common cases | |
265 case 1: return 10.0; | |
266 case 2: return 100.0; | |
267 case 3: return 1e+03; | |
268 case 4: return 1e+04; | |
269 case 5: return 1e+05; | |
270 case 6: return 1e+06; | |
271 case 7: return 1e+07; | |
272 case 8: return 1e+08; | |
273 case 9: return 1e+09; | |
274 case 10: return 1e+10; | |
275 case 11: return 1e+11; | |
276 case 12: return 1e+12; | |
277 case 13: return 1e+13; | |
278 case 14: return 1e+14; | |
279 case 15: return 1e+15; | |
280 default: | |
281 if (e > 15) { | |
282 double value = 1e+15; | |
283 while (e-- > 15) { value *= 10.0; } | |
284 return value; | |
285 } else { | |
286 SkASSERT(e < 0); | |
287 double value = 1.0; | |
288 while (e++ < 0) { value /= 10.0; } | |
289 return value; | |
290 } | |
291 } | |
292 } | |
293 | |
261 /** Write a string into result, includeing a terminating '\0' (for | 294 /** Write a string into result, includeing a terminating '\0' (for |
262 unit testing). Return strlen(result) (for SkWStream::write) The | 295 unit testing). Return strlen(result) (for SkWStream::write) The |
263 resulting string will be in the form /[-]?([0-9]*.)?[0-9]+/ and | 296 resulting string will be in the form /[-]?([0-9]*.)?[0-9]+/ and |
264 sscanf(result, "%f", &x) will return the original value iff the | 297 sscanf(result, "%f", &x) will return the original value iff the |
265 value is finite. This function accepts all possible input values. | 298 value is finite. This function accepts all possible input values. |
266 | 299 |
267 Motivation: "PDF does not support [numbers] in exponential format | 300 Motivation: "PDF does not support [numbers] in exponential format |
268 (such as 6.02e23)." Otherwise, this function would rely on a | 301 (such as 6.02e23)." Otherwise, this function would rely on a |
269 sprintf-type function from the standard library. */ | 302 sprintf-type function from the standard library. */ |
270 size_t SkPDFUtils::FloatToDecimal(float value, | 303 size_t SkPDFUtils::FloatToDecimal(float value, |
(...skipping 25 matching lines...) Expand all Loading... | |
296 if (value == SK_FloatNegativeInfinity) { | 329 if (value == SK_FloatNegativeInfinity) { |
297 value = -FLT_MAX; // nearest finite float. | 330 value = -FLT_MAX; // nearest finite float. |
298 } | 331 } |
299 if (!std::isfinite(value) || value == 0.0f) { | 332 if (!std::isfinite(value) || value == 0.0f) { |
300 // NAN is unsupported in PDF. Always output a valid number. | 333 // NAN is unsupported in PDF. Always output a valid number. |
301 // Also catch zero here, as a special case. | 334 // Also catch zero here, as a special case. |
302 *output++ = '0'; | 335 *output++ = '0'; |
303 *output = '\0'; | 336 *output = '\0'; |
304 return output - result; | 337 return output - result; |
305 } | 338 } |
306 // Inspired by: | |
307 // http://www.exploringbinary.com/quick-and-dirty-floating-point-to-decimal- conversion/ | |
308 | |
309 if (value < 0.0) { | 339 if (value < 0.0) { |
310 *output++ = '-'; | 340 *output++ = '-'; |
311 value = -value; | 341 value = -value; |
312 } | 342 } |
313 SkASSERT(value >= 0.0f); | 343 SkASSERT(value >= 0.0f); |
314 | 344 |
315 // Must use double math to keep precision right. | 345 int binaryExponents; |
tomhudson
2016/07/15 20:45:41
Bikeshed: Why is this name plural?
hal.canary
2016/07/17 02:33:42
Done.
| |
316 double intPart; | 346 (void)frexp(value, &binaryExponents); |
tomhudson
2016/07/15 20:45:41
std::frexp()? Or is that not our style?
hal.canary
2016/07/17 02:33:42
We do it both ways. the C++ish way seems to be ga
| |
317 double fracPart = std::modf(static_cast<double>(value), &intPart); | 347 static const double kLog2 = 0.3010299956639812; // log10(2.0); |
tomhudson
2016/07/15 20:45:41
constexpr?
hal.canary
2016/07/17 02:33:42
std::log10 isn't constexpr.
| |
318 SkASSERT(intPart + fracPart == static_cast<double>(value)); | 348 int decimalExponents = (int)floor(kLog2 * binaryExponents); |
tomhudson
2016/07/15 20:45:41
Bikeshed as above
hal.canary
2016/07/17 02:33:42
Done.
| |
319 size_t significantDigits = 0; | 349 int decShift = decimalExponents - 8; |
320 const size_t maxSignificantDigits = 9; | 350 double power = pow10(-decShift); |
tomhudson
2016/07/15 20:45:41
(OK, convinced myself that in the common case pow1
hal.canary
2016/07/17 02:33:42
Done.
| |
321 // Any fewer significant digits loses precision. The unit test | 351 int32_t d = (int32_t)(value * power + 0.5); |
322 // checks round-trip correctness. | 352 //SkASSERT(value == (float)(d * pow(10.0, decShift))); |
323 SkASSERT(intPart >= 0.0 && fracPart >= 0.0); // negative handled already. | 353 SkASSERT(d <= 999999999); |
324 SkASSERT(intPart > 0.0 || fracPart > 0.0); // zero already caught. | 354 if (d > 167772159) { // floor(pow(10,1+log10(1<<24))) |
325 if (intPart > 0.0) { | 355 // need one fewer decimal digits for 24-bit precision. |
326 // put the intPart digits onto a stack for later reversal. | 356 decShift = decimalExponents - 7; |
327 char reversed[1 + FLT_MAX_10_EXP]; // 39 == 1 + FLT_MAX_10_EXP | 357 //SkASSERT(power * 0.1 = pow10(-decShift)); |
328 // the largest integer part is FLT_MAX; it has 39 decimal digits. | 358 d = (int32_t)(value * (power * 0.1) + 0.5); |
329 size_t reversedIndex = 0; | 359 SkASSERT(d <= 99999999); |
360 } | |
361 while (d % 10 == 0) { | |
362 d /= 10; | |
363 ++decShift; | |
364 } | |
365 SkASSERT(d > 0); | |
366 //SkASSERT(value == (float)(d * pow(10.0, decShift))); | |
367 uint8_t buffer[9]; // decimal value buffer. | |
368 int bufferIndex = 0; | |
369 do { | |
370 buffer[bufferIndex++] = d % 10; | |
371 d /= 10; | |
372 } while (d != 0); | |
373 SkASSERT(bufferIndex <= (int)sizeof(buffer) && bufferIndex > 0); | |
374 if (decShift >= 0) { | |
330 do { | 375 do { |
331 SkASSERT(reversedIndex < sizeof(reversed)); | 376 --bufferIndex; |
332 int digit = static_cast<int>(std::fmod(intPart, 10.0)); | 377 *output++ = '0' + buffer[bufferIndex]; |
333 SkASSERT(digit >= 0 && digit <= 9); | 378 } while (bufferIndex); |
334 reversed[reversedIndex++] = '0' + digit; | 379 for (int i = 0; i < decShift; ++i) { |
335 intPart = std::floor(intPart / 10.0); | 380 *output++ = '0'; |
336 } while (intPart > 0.0); | |
337 significantDigits = reversedIndex; | |
338 SkASSERT(reversedIndex <= sizeof(reversed)); | |
339 SkASSERT(output + reversedIndex <= end); | |
340 while (reversedIndex-- > 0) { // pop from stack, append to result | |
341 *output++ = reversed[reversedIndex]; | |
342 } | 381 } |
343 } | 382 } else { |
344 if (fracPart > 0 && significantDigits < maxSignificantDigits) { | 383 int N = bufferIndex + decShift; |
345 *output++ = '.'; | 384 if (N > 0) { |
346 SkASSERT(output <= end); | 385 for (int i = 0; i < N; ++i) { |
347 do { | 386 --bufferIndex; |
348 fracPart = std::modf(fracPart * 10.0, &intPart); | 387 *output++ = '0' + buffer[bufferIndex]; |
349 int digit = static_cast<int>(intPart); | |
350 SkASSERT(digit >= 0 && digit <= 9); | |
351 *output++ = '0' + digit; | |
352 SkASSERT(output <= end); | |
353 if (digit > 0 || significantDigits > 0) { | |
354 // start counting significantDigits after first non-zero digit. | |
355 ++significantDigits; | |
356 } | 388 } |
357 } while (fracPart > 0.0 | 389 *output++ = '.'; |
358 && significantDigits < maxSignificantDigits | 390 } else { |
359 && output < end); | 391 *output++ = '.'; |
360 // When fracPart == 0, additional digits will be zero. | 392 for (int i = 0; i < -N; ++i) { |
361 // When significantDigits == maxSignificantDigits, we can stop. | 393 *output++ = '0'; |
362 // when output == end, we have filed the string. | 394 } |
363 // Note: denormalized numbers will not have the same number of | 395 } |
364 // significantDigits, but do not need them to round-trip. | 396 while (bufferIndex > 0) { |
397 --bufferIndex; | |
398 *output++ = '0' + buffer[bufferIndex]; | |
399 if (output == end) { | |
400 break; // denormalized: don't need extra precision. | |
401 // Note: denormalized numbers will not have the same number of | |
402 // significantDigits, but do not need them to round-trip. | |
403 } | |
404 } | |
365 } | 405 } |
366 SkASSERT(output <= end); | 406 SkASSERT(output <= end); |
367 *output = '\0'; | 407 *output = '\0'; |
368 return output - result; | 408 return output - result; |
369 } | 409 } |
370 | 410 |
371 void SkPDFUtils::WriteString(SkWStream* wStream, const char* cin, size_t len) { | 411 void SkPDFUtils::WriteString(SkWStream* wStream, const char* cin, size_t len) { |
372 SkDEBUGCODE(static const size_t kMaxLen = 65535;) | 412 SkDEBUGCODE(static const size_t kMaxLen = 65535;) |
373 SkASSERT(len <= kMaxLen); | 413 SkASSERT(len <= kMaxLen); |
374 | 414 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
406 uint8_t c = static_cast<uint8_t>(cin[i]); | 446 uint8_t c = static_cast<uint8_t>(cin[i]); |
407 static const char gHex[] = "0123456789ABCDEF"; | 447 static const char gHex[] = "0123456789ABCDEF"; |
408 char hexValue[2]; | 448 char hexValue[2]; |
409 hexValue[0] = gHex[(c >> 4) & 0xF]; | 449 hexValue[0] = gHex[(c >> 4) & 0xF]; |
410 hexValue[1] = gHex[ c & 0xF]; | 450 hexValue[1] = gHex[ c & 0xF]; |
411 wStream->write(hexValue, 2); | 451 wStream->write(hexValue, 2); |
412 } | 452 } |
413 wStream->writeText(">"); | 453 wStream->writeText(">"); |
414 } | 454 } |
415 } | 455 } |
OLD | NEW |