SkPDF: fix scalar serialization

BUG=skia:4868
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1720863003

Review URL: https://codereview.chromium.org/1720863003
diff --git a/tests/PDFPrimitivesTest.cpp b/tests/PDFPrimitivesTest.cpp
index 9ca1bd6..f618e6f 100644
--- a/tests/PDFPrimitivesTest.cpp
+++ b/tests/PDFPrimitivesTest.cpp
@@ -18,6 +18,7 @@
 #include "SkPDFFont.h"
 #include "SkPDFStream.h"
 #include "SkPDFTypes.h"
+#include "SkPDFUtils.h"
 #include "SkReadBuffer.h"
 #include "SkScalar.h"
 #include "SkStream.h"
@@ -199,20 +200,16 @@
     ASSERT_EMIT_EQ(reporter, int42, "42");
 
     SkPDFUnion realHalf = SkPDFUnion::Scalar(SK_ScalarHalf);
-    ASSERT_EMIT_EQ(reporter, realHalf, "0.5");
+    ASSERT_EMIT_EQ(reporter, realHalf, ".5");
 
     SkPDFUnion bigScalar = SkPDFUnion::Scalar(110999.75f);
-#if !defined(SK_ALLOW_LARGE_PDF_SCALARS)
-    ASSERT_EMIT_EQ(reporter, bigScalar, "111000");
-#else
     ASSERT_EMIT_EQ(reporter, bigScalar, "110999.75");
 
-    SkPDFUnion biggerScalar = SkPDFUnion::Scalar(50000000.1);
+    SkPDFUnion biggerScalar = SkPDFUnion::Scalar(50000000.1f);
     ASSERT_EMIT_EQ(reporter, biggerScalar, "50000000");
 
-    SkPDFUnion smallestScalar = SkPDFUnion::Scalar(1.0 / 65536);
-    ASSERT_EMIT_EQ(reporter, smallestScalar, "0.00001526");
-#endif
+    SkPDFUnion smallestScalar = SkPDFUnion::Scalar(1.0f / 65536);
+    ASSERT_EMIT_EQ(reporter, smallestScalar, ".0000152587890");
 
     SkPDFUnion stringSimple = SkPDFUnion::String("test ) string ( foo");
     ASSERT_EMIT_EQ(reporter, stringSimple, "(test \\) string \\( foo)");
@@ -248,34 +245,34 @@
     ASSERT_EMIT_EQ(reporter, *array, "[42]");
 
     array->appendScalar(SK_ScalarHalf);
-    ASSERT_EMIT_EQ(reporter, *array, "[42 0.5]");
+    ASSERT_EMIT_EQ(reporter, *array, "[42 .5]");
 
     array->appendInt(0);
-    ASSERT_EMIT_EQ(reporter, *array, "[42 0.5 0]");
+    ASSERT_EMIT_EQ(reporter, *array, "[42 .5 0]");
 
     array->appendBool(true);
-    ASSERT_EMIT_EQ(reporter, *array, "[42 0.5 0 true]");
+    ASSERT_EMIT_EQ(reporter, *array, "[42 .5 0 true]");
 
     array->appendName("ThisName");
-    ASSERT_EMIT_EQ(reporter, *array, "[42 0.5 0 true /ThisName]");
+    ASSERT_EMIT_EQ(reporter, *array, "[42 .5 0 true /ThisName]");
 
     array->appendName(SkString("AnotherName"));
-    ASSERT_EMIT_EQ(reporter, *array, "[42 0.5 0 true /ThisName /AnotherName]");
+    ASSERT_EMIT_EQ(reporter, *array, "[42 .5 0 true /ThisName /AnotherName]");
 
     array->appendString("This String");
     ASSERT_EMIT_EQ(reporter, *array,
-                   "[42 0.5 0 true /ThisName /AnotherName (This String)]");
+                   "[42 .5 0 true /ThisName /AnotherName (This String)]");
 
     array->appendString(SkString("Another String"));
     ASSERT_EMIT_EQ(reporter, *array,
-                   "[42 0.5 0 true /ThisName /AnotherName (This String) "
+                   "[42 .5 0 true /ThisName /AnotherName (This String) "
                    "(Another String)]");
 
     SkAutoTUnref<SkPDFArray> innerArray(new SkPDFArray);
     innerArray->appendInt(-1);
     array->appendObject(innerArray.detach());
     ASSERT_EMIT_EQ(reporter, *array,
-                   "[42 0.5 0 true /ThisName /AnotherName (This String) "
+                   "[42 .5 0 true /ThisName /AnotherName (This String) "
                    "(Another String) [-1]]");
 
     SkAutoTUnref<SkPDFArray> referencedArray(new SkPDFArray);
@@ -287,7 +284,7 @@
 
     SkString result = emit_to_string(*array, &catalog);
     ASSERT_EQ(reporter, result,
-              "[42 0.5 0 true /ThisName /AnotherName (This String) "
+              "[42 .5 0 true /ThisName /AnotherName (This String) "
               "(Another String) [-1] 1 0 R]");
 }
 
@@ -310,7 +307,7 @@
     SkAutoTUnref<SkPDFArray> innerArray(new SkPDFArray);
     innerArray->appendInt(-100);
     dict->insertObject(n3, innerArray.detach());
-    ASSERT_EMIT_EQ(reporter, *dict, "<</n1 42\n/n2 0.5\n/n3 [-100]>>");
+    ASSERT_EMIT_EQ(reporter, *dict, "<</n1 42\n/n2 .5\n/n3 [-100]>>");
 
     dict.reset(new SkPDFDict);
     ASSERT_EMIT_EQ(reporter, *dict, "<<>>");
@@ -322,26 +319,26 @@
     ASSERT_EMIT_EQ(reporter, *dict, "<</n1 24\n/n2 99>>");
 
     dict->insertScalar("n3", SK_ScalarHalf);
-    ASSERT_EMIT_EQ(reporter, *dict, "<</n1 24\n/n2 99\n/n3 0.5>>");
+    ASSERT_EMIT_EQ(reporter, *dict, "<</n1 24\n/n2 99\n/n3 .5>>");
 
     dict->insertName("n4", "AName");
-    ASSERT_EMIT_EQ(reporter, *dict, "<</n1 24\n/n2 99\n/n3 0.5\n/n4 /AName>>");
+    ASSERT_EMIT_EQ(reporter, *dict, "<</n1 24\n/n2 99\n/n3 .5\n/n4 /AName>>");
 
     dict->insertName("n5", SkString("AnotherName"));
-    ASSERT_EMIT_EQ(reporter, *dict, "<</n1 24\n/n2 99\n/n3 0.5\n/n4 /AName\n"
+    ASSERT_EMIT_EQ(reporter, *dict, "<</n1 24\n/n2 99\n/n3 .5\n/n4 /AName\n"
                    "/n5 /AnotherName>>");
 
     dict->insertString("n6", "A String");
-    ASSERT_EMIT_EQ(reporter, *dict, "<</n1 24\n/n2 99\n/n3 0.5\n/n4 /AName\n"
+    ASSERT_EMIT_EQ(reporter, *dict, "<</n1 24\n/n2 99\n/n3 .5\n/n4 /AName\n"
                    "/n5 /AnotherName\n/n6 (A String)>>");
 
     dict->insertString("n7", SkString("Another String"));
-    ASSERT_EMIT_EQ(reporter, *dict, "<</n1 24\n/n2 99\n/n3 0.5\n/n4 /AName\n"
+    ASSERT_EMIT_EQ(reporter, *dict, "<</n1 24\n/n2 99\n/n3 .5\n/n4 /AName\n"
                    "/n5 /AnotherName\n/n6 (A String)\n/n7 (Another String)>>");
 
     dict.reset(new SkPDFDict("DType"));
     ASSERT_EMIT_EQ(reporter, *dict, "<</Type /DType>>");
-    
+
     SkAutoTUnref<SkPDFArray> referencedArray(new SkPDFArray);
     Catalog catalog;
     catalog.numbers.addObject(referencedArray.get());
@@ -435,3 +432,52 @@
     REPORTER_ASSERT(reporter,
                     SkPDFFont::CanEmbedTypeface(portableTypeface, &canon));
 }
+
+
+// test to see that all finite scalars round trip via scanf().
+static void check_pdf_scalar_serialization(
+        skiatest::Reporter* reporter, float inputFloat) {
+    char floatString[SkPDFUtils::kMaximumFloatDecimalLength];
+    size_t len = SkPDFUtils::FloatToDecimal(inputFloat, floatString);
+    if (len >= sizeof(floatString)) {
+        ERRORF(reporter, "string too long: %u", (unsigned)len);
+        return;
+    }
+    if (floatString[len] != '\0' || strlen(floatString) != len) {
+        ERRORF(reporter, "terminator misplaced.");
+        return;  // The terminator is needed for sscanf().
+    }
+    if (reporter->verbose()) {
+        SkDebugf("%15.9g = \"%s\"\n", inputFloat, floatString);
+    }
+    float roundTripFloat;
+    if (1 != sscanf(floatString, "%f", &roundTripFloat)) {
+        ERRORF(reporter, "unscannable result: %s", floatString);
+        return;
+    }
+    if (isfinite(inputFloat) && roundTripFloat != inputFloat) {
+        ERRORF(reporter, "roundTripFloat (%.9g) != inputFloat (%.9g)",
+               roundTripFloat, inputFloat);
+    }
+}
+
+// Test SkPDFUtils::AppendScalar for accuracy.
+DEF_TEST(PDFPrimitives_Scalar, reporter) {
+    SkRandom random(0x5EED);
+    int iterationCount = 512;
+    while (iterationCount-- > 0) {
+        union { uint32_t u; float f; };
+        u = random.nextU();
+        static_assert(sizeof(float) == sizeof(uint32_t), "");
+        check_pdf_scalar_serialization(reporter, f);
+    }
+    float alwaysCheck[] = {
+        0.0f, -0.0f, 1.0f, -1.0f, SK_ScalarPI, 0.1f, FLT_MIN, FLT_MAX,
+        -FLT_MIN, -FLT_MAX, FLT_MIN / 16.0f, -FLT_MIN / 16.0f,
+        SK_FloatNaN, SK_FloatInfinity, SK_FloatNegativeInfinity,
+        -FLT_MIN / 8388608.0
+    };
+    for (float inputFloat: alwaysCheck) {
+        check_pdf_scalar_serialization(reporter, inputFloat);
+    }
+}