Index: src/pdf/SkPDFUtils.cpp |
diff --git a/src/pdf/SkPDFUtils.cpp b/src/pdf/SkPDFUtils.cpp |
index 108f2c10abd56e6d0ae94b263c89c5c9a5d34dd4..2ebbec5779fd2e2880900ceb939525c06bb38e14 100644 |
--- a/src/pdf/SkPDFUtils.cpp |
+++ b/src/pdf/SkPDFUtils.cpp |
@@ -16,6 +16,8 @@ |
#include "SkString.h" |
#include "SkPDFTypes.h" |
+#include <cmath> |
+ |
//static |
SkPDFArray* SkPDFUtils::RectToArray(const SkRect& rect) { |
SkPDFArray* result = new SkPDFArray(); |
@@ -253,52 +255,70 @@ void SkPDFUtils::ApplyPattern(int objectIndex, SkWStream* content) { |
content->writeText(" scn\n"); |
} |
-void SkPDFUtils::AppendScalar(SkScalar value, SkWStream* stream) { |
- // The range of reals in PDF/A is the same as SkFixed: +/- 32,767 and |
- // +/- 1/65,536 (though integers can range from 2^31 - 1 to -2^31). |
- // When using floats that are outside the whole value range, we can use |
- // integers instead. |
- |
-#if !defined(SK_ALLOW_LARGE_PDF_SCALARS) |
- if (value > 32767 || value < -32767) { |
- stream->writeDecAsText(SkScalarRoundToInt(value)); |
- return; |
+void SkPDFUtils::AppendScalar(SkScalar v, SkWStream* stream) { |
+ if (v == SK_FloatInfinity) { |
+ v = FLT_MAX; // nearest finite float. |
} |
- |
- char buffer[SkStrAppendScalar_MaxSize]; |
- char* end = SkStrAppendFixed(buffer, SkScalarToFixed(value)); |
- stream->write(buffer, end - buffer); |
- return; |
-#endif // !SK_ALLOW_LARGE_PDF_SCALARS |
- |
-#if defined(SK_ALLOW_LARGE_PDF_SCALARS) |
- // Floats have 24bits of significance, so anything outside that range is |
- // no more precise than an int. (Plus PDF doesn't support scientific |
- // notation, so this clamps to SK_Max/MinS32). |
- if (value > (1 << 24) || value < -(1 << 24)) { |
- stream->writeDecAsText(value); |
+ if (v == SK_FloatNegativeInfinity) { |
+ v = -FLT_MAX; // nearest finite float. |
+ } |
+ if (!isfinite(v)) { |
+ stream->writeText("0"); // Unsupported number in PDF |
return; |
} |
- // Continue to enforce the PDF limits for small floats. |
- if (value < 1.0f/65536 && value > -1.0f/65536) { |
- stream->writeDecAsText(0); |
+ // "PDF does not support [numbers] in exponential format (such as 6.02e23)" |
+ // Inspired by: |
+ // http://www.exploringbinary.com/quick-and-dirty-floating-point-to-decimal-conversion/ |
+ // Must use double math to keep precision right. |
+ double value = static_cast<double>(v); |
+ char result[1076]; |
+ size_t resultIndex = 0; |
+ if (value < 0.0) { |
+ result[resultIndex++] = '-'; |
+ value = -value; |
+ } |
+ double intPart; |
+ double fracPart = std::modf(value, &intPart); |
+ size_t significantDigits = 0; |
+ const size_t maxSignificantDigits = 9; // any less loses precision |
tomhudson
2016/02/22 20:13:46
With a 32b signed fixed, can't we have 10 signific
hal.canary
2016/02/22 22:45:38
Ah, but we don't have a fixed-point input. SkScal
|
+ SkASSERT(intPart >= 0.0 && fracPart >= 0.0); |
tomhudson
2016/02/22 20:13:46
What happened to negative numbers? std::modf() "[D
hal.canary
2016/02/22 22:45:38
I already dealt with negative number.
tomhudson
2016/02/24 20:10:56
Acknowledged.
|
+ if (intPart == 0.0 && fracPart == 0.0) { |
+ stream->writeText("0"); // Unsupported number in PDF |
tomhudson
2016/02/22 20:13:46
Why is 0 unsupported?
hal.canary
2016/02/22 22:45:38
cut-and-paste error.
|
return; |
} |
- // SkStrAppendFloat might still use scientific notation, so use snprintf |
- // directly.. |
- static const int kFloat_MaxSize = 19; |
- char buffer[kFloat_MaxSize]; |
- int len = SNPRINTF(buffer, kFloat_MaxSize, "%#.8f", value); |
- // %f always prints trailing 0s, so strip them. |
- for (; buffer[len - 1] == '0' && len > 0; len--) { |
- buffer[len - 1] = '\0'; |
+ if (intPart > 0.0) { |
tomhudson
2016/02/22 20:13:46
This code looks like it was hard to write; it shou
|
+ char reversed[311]; |
tomhudson
2016/02/22 20:13:46
What's with the magic number 311? No idea how you
hal.canary
2016/02/22 22:45:38
that's a holdover from the double code. I did som
|
+ size_t reveredIndex = 0; |
tomhudson
2016/02/22 20:13:46
Why is this index holy or particularly esteemed? (
hal.canary
2016/02/22 22:45:38
done
|
+ while (intPart > 0.0) { |
+ SkASSERT(reveredIndex < sizeof(reversed)); |
+ int digit = static_cast<int>(std::fmod(intPart, 10.0)); |
+ SkASSERT(digit >= 0 && digit <= 9); |
+ reversed[reveredIndex++] = '0' + digit; |
+ intPart = std::floor(intPart / 10.0); |
+ } |
+ significantDigits = reveredIndex; |
+ while (reveredIndex-- > 0) { |
+ result[resultIndex++] = reversed[reveredIndex]; |
+ SkASSERT(resultIndex <= sizeof(result)); |
+ } |
} |
- if (buffer[len - 1] == '.') { |
- buffer[len - 1] = '\0'; |
+ if (fracPart > 0 && significantDigits < maxSignificantDigits) { |
+ result[resultIndex++] = '.'; |
+ SkASSERT(resultIndex <= sizeof(result)); |
+ do { |
+ fracPart *= 10.0; |
+ fracPart = std::modf(fracPart, &intPart); |
+ int digit = static_cast<int>(intPart); |
+ result[resultIndex++] = '0' + digit; |
+ SkASSERT(digit >= 0 && digit <= 9); |
+ SkASSERT(resultIndex <= sizeof(result)); |
+ if (digit > 0 || significantDigits > 0) { |
+ ++significantDigits; |
+ } |
+ } while (fracPart > 0 && significantDigits < maxSignificantDigits); |
+ |
} |
- stream->writeText(buffer); |
- return; |
-#endif // SK_ALLOW_LARGE_PDF_SCALARS |
+ stream->write(result, resultIndex); |
} |
SkString SkPDFUtils::FormatString(const char* cin, size_t len) { |