SkPDF: re-work SkPDFUtils::FloatToDecimal

  * do a lot less floating-point math by converting to
    an integer as early as possible [faster].
  * round rather than truncate.
  * use 8 significant digits rather than 9 when possible.
  * remove trailing zeros in fractions.

before:
      0.12 !    PDFScalar   nonrendering
after:
      0.07 !    PDFScalar   nonrendering

Accuracy guaranteed by existing unit test.

Example diffs:

    -/Shading <</Function <</C0 [.321568638 .333333343 .321568638]
    +/Shading <</Function <</C0 [.32156864 .33333334 .32156864]

    -/C1 [.258823543 .270588248 .258823543]
    +/C1 [.25882354 .27058825 .25882354]

    -1 0 0 -1 20 120.394500 Tm
    +1 0 0 -1 20 120.394501 Tm

    -1 0 0 -1 20 184.789001 Tm
    +1 0 0 -1 20 184.789 Tm

    -291.503997 0 l
    +291.504 0 l

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2146103004

Review-Url: https://codereview.chromium.org/2146103004
diff --git a/tests/PDFPrimitivesTest.cpp b/tests/PDFPrimitivesTest.cpp
index d816b60..cef1150 100644
--- a/tests/PDFPrimitivesTest.cpp
+++ b/tests/PDFPrimitivesTest.cpp
@@ -27,6 +27,9 @@
 #include "Test.h"
 #include "sk_tool_utils.h"
 
+#include <cstdlib>
+#include <cmath>
+
 #define DUMMY_TEXT "DCT compessed stream."
 
 namespace {
@@ -44,9 +47,8 @@
         catPtr = &catalog;
     }
     obj.emitObject(&buffer, catPtr->numbers, catPtr->substitutes);
-    SkAutoTDelete<SkStreamAsset> asset(buffer.detachAsStream());
-    SkString tmp(asset->getLength());
-    asset->read(tmp.writable_str(), asset->getLength());
+    SkString tmp(buffer.bytesWritten());
+    buffer.copyTo(tmp.writable_str());
     return tmp;
 }
 
@@ -54,42 +56,41 @@
     return len == str.size() && 0 == memcmp(str.c_str(), strPtr, len);
 }
 
-#define ASSERT_EQL(REPORTER, SKSTRING, STRING, LEN)                     \
-    do {                                                                \
-        const char* strptr = STRING;                                    \
-        const SkString& sks = SKSTRING;                                 \
-        if (!eq(sks, strptr, LEN)) {                                    \
-            REPORT_FAILURE(                                             \
-                    REPORTER,                                           \
-                    "",                                                 \
-                    SkStringPrintf("'%s' != '%s'", strptr, sks.c_str()));  \
-        }                                                               \
-    } while (false)
+static void assert_eql(skiatest::Reporter* reporter,
+                       const SkString& skString,
+                       const char* str,
+                       size_t len) {
+    if (!eq(skString, str, len)) {
+        REPORT_FAILURE(reporter, "", SkStringPrintf(
+                "'%*s' != '%s'", len, str, skString.c_str()));
+    }
+}
 
-#define ASSERT_EQ(REPORTER, SKSTRING, STRING)             \
-    do {                                                  \
-        const char* str = STRING;                         \
-        ASSERT_EQL(REPORTER, SKSTRING, str, strlen(str)); \
-    } while (false)
-
-#define ASSERT_EMIT_EQ(REPORTER, OBJECT, STRING)          \
-    do {                                                  \
-        SkString result = emit_to_string(OBJECT);         \
-        ASSERT_EQ(REPORTER, result, STRING);              \
-    } while (false)
+static void assert_eq(skiatest::Reporter* reporter,
+                      const SkString& skString,
+                      const char* str) {
+    assert_eql(reporter, skString, str, strlen(str));
+}
 
 
+template <typename T>
+static void assert_emit_eq(skiatest::Reporter* reporter,
+                           T& object,
+                           const char* string) {
+    SkString result = emit_to_string(object);
+    assert_eq(reporter, result, string);
+}
 
 static void TestPDFStream(skiatest::Reporter* reporter) {
     char streamBytes[] = "Test\nFoo\tBar";
     SkAutoTDelete<SkMemoryStream> streamData(new SkMemoryStream(
         streamBytes, strlen(streamBytes), true));
     sk_sp<SkPDFStream> stream(new SkPDFStream(streamData.get()));
-    ASSERT_EMIT_EQ(reporter,
+    assert_emit_eq(reporter,
                    *stream,
                    "<</Length 12>> stream\nTest\nFoo\tBar\nendstream");
     stream->insertInt("Attribute", 42);
-    ASSERT_EMIT_EQ(reporter,
+    assert_emit_eq(reporter,
                    *stream,
                    "<</Length 12\n/Attribute 42>> stream\n"
                    "Test\nFoo\tBar\nendstream");
@@ -115,7 +116,7 @@
         expected.writeText("\nendstream");
         SkAutoDataUnref expectedResultData2(expected.copyToData());
         SkString result = emit_to_string(*stream);
-        ASSERT_EQL(reporter,
+        assert_eql(reporter,
                    result,
                    (const char*)expectedResultData2->data(),
                    expectedResultData2->size());
@@ -154,7 +155,7 @@
     SkString result = emit_to_string(*a2, &catalog);
     // If appendObjRef misbehaves, then the result would
     // be [[]], not [1 0 R].
-    ASSERT_EQ(reporter, result, "[1 0 R]");
+    assert_eq(reporter, result, "[1 0 R]");
 }
 
 static void TestSubstitute(skiatest::Reporter* reporter) {
@@ -190,91 +191,94 @@
     doc->close();
 }
 
+static void assert_emit_eq_number(skiatest::Reporter* reporter, float number) {
+    SkPDFUnion pdfUnion = SkPDFUnion::Scalar(number);
+    SkString result = emit_to_string(pdfUnion);
+    float value = static_cast<float>(std::atof(result.c_str()));
+    if (value != number) {
+        ERRORF(reporter, "%.9g != %s", number, result.c_str());
+    }
+}
+
+
 static void TestPDFUnion(skiatest::Reporter* reporter) {
     SkPDFUnion boolTrue = SkPDFUnion::Bool(true);
-    ASSERT_EMIT_EQ(reporter, boolTrue, "true");
+    assert_emit_eq(reporter, boolTrue, "true");
 
     SkPDFUnion boolFalse = SkPDFUnion::Bool(false);
-    ASSERT_EMIT_EQ(reporter, boolFalse, "false");
+    assert_emit_eq(reporter, boolFalse, "false");
 
     SkPDFUnion int42 = SkPDFUnion::Int(42);
-    ASSERT_EMIT_EQ(reporter, int42, "42");
+    assert_emit_eq(reporter, int42, "42");
 
-    SkPDFUnion realHalf = SkPDFUnion::Scalar(SK_ScalarHalf);
-    ASSERT_EMIT_EQ(reporter, realHalf, ".5");
-
-    SkPDFUnion bigScalar = SkPDFUnion::Scalar(110999.75f);
-    ASSERT_EMIT_EQ(reporter, bigScalar, "110999.75");
-
-    SkPDFUnion biggerScalar = SkPDFUnion::Scalar(50000000.1f);
-    ASSERT_EMIT_EQ(reporter, biggerScalar, "50000000");
-
-    SkPDFUnion smallestScalar = SkPDFUnion::Scalar(1.0f / 65536);
-    ASSERT_EMIT_EQ(reporter, smallestScalar, ".0000152587890");
+    assert_emit_eq_number(reporter, SK_ScalarHalf);
+    assert_emit_eq_number(reporter, 110999.75f);  // bigScalar
+    assert_emit_eq_number(reporter, 50000000.1f);  // biggerScalar
+    assert_emit_eq_number(reporter, 1.0f / 65536);  // smallScalar
 
     SkPDFUnion stringSimple = SkPDFUnion::String("test ) string ( foo");
-    ASSERT_EMIT_EQ(reporter, stringSimple, "(test \\) string \\( foo)");
+    assert_emit_eq(reporter, stringSimple, "(test \\) string \\( foo)");
 
     SkString stringComplexInput("\ttest ) string ( foo");
     SkPDFUnion stringComplex = SkPDFUnion::String(stringComplexInput);
-    ASSERT_EMIT_EQ(reporter, stringComplex, "(\\011test \\) string \\( foo)");
+    assert_emit_eq(reporter, stringComplex, "(\\011test \\) string \\( foo)");
 
     SkString binaryStringInput("\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17\20");
     SkPDFUnion binaryString = SkPDFUnion::String(binaryStringInput);
-    ASSERT_EMIT_EQ(reporter, binaryString, "<0102030405060708090A0B0C0D0E0F10>");
+    assert_emit_eq(reporter, binaryString, "<0102030405060708090A0B0C0D0E0F10>");
 
     SkString nameInput("Test name\twith#tab");
     SkPDFUnion name = SkPDFUnion::Name(nameInput);
-    ASSERT_EMIT_EQ(reporter, name, "/Test#20name#09with#23tab");
+    assert_emit_eq(reporter, name, "/Test#20name#09with#23tab");
 
     SkString nameInput2("A#/%()<>[]{}B");
     SkPDFUnion name2 = SkPDFUnion::Name(nameInput2);
-    ASSERT_EMIT_EQ(reporter, name2, "/A#23#2F#25#28#29#3C#3E#5B#5D#7B#7DB");
+    assert_emit_eq(reporter, name2, "/A#23#2F#25#28#29#3C#3E#5B#5D#7B#7DB");
 
     SkPDFUnion name3 = SkPDFUnion::Name("SimpleNameWithOnlyPrintableASCII");
-    ASSERT_EMIT_EQ(reporter, name3, "/SimpleNameWithOnlyPrintableASCII");
+    assert_emit_eq(reporter, name3, "/SimpleNameWithOnlyPrintableASCII");
 
     // Test that we correctly handle characters with the high-bit set.
     SkString highBitString("\xDE\xAD" "be\xEF");
     SkPDFUnion highBitName = SkPDFUnion::Name(highBitString);
-    ASSERT_EMIT_EQ(reporter, highBitName, "/#DE#ADbe#EF");
+    assert_emit_eq(reporter, highBitName, "/#DE#ADbe#EF");
 }
 
 static void TestPDFArray(skiatest::Reporter* reporter) {
     sk_sp<SkPDFArray> array(new SkPDFArray);
-    ASSERT_EMIT_EQ(reporter, *array, "[]");
+    assert_emit_eq(reporter, *array, "[]");
 
     array->appendInt(42);
-    ASSERT_EMIT_EQ(reporter, *array, "[42]");
+    assert_emit_eq(reporter, *array, "[42]");
 
     array->appendScalar(SK_ScalarHalf);
-    ASSERT_EMIT_EQ(reporter, *array, "[42 .5]");
+    assert_emit_eq(reporter, *array, "[42 .5]");
 
     array->appendInt(0);
-    ASSERT_EMIT_EQ(reporter, *array, "[42 .5 0]");
+    assert_emit_eq(reporter, *array, "[42 .5 0]");
 
     array->appendBool(true);
-    ASSERT_EMIT_EQ(reporter, *array, "[42 .5 0 true]");
+    assert_emit_eq(reporter, *array, "[42 .5 0 true]");
 
     array->appendName("ThisName");
-    ASSERT_EMIT_EQ(reporter, *array, "[42 .5 0 true /ThisName]");
+    assert_emit_eq(reporter, *array, "[42 .5 0 true /ThisName]");
 
     array->appendName(SkString("AnotherName"));
-    ASSERT_EMIT_EQ(reporter, *array, "[42 .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,
+    assert_emit_eq(reporter, *array,
                    "[42 .5 0 true /ThisName /AnotherName (This String)]");
 
     array->appendString(SkString("Another String"));
-    ASSERT_EMIT_EQ(reporter, *array,
+    assert_emit_eq(reporter, *array,
                    "[42 .5 0 true /ThisName /AnotherName (This String) "
                    "(Another String)]");
 
     sk_sp<SkPDFArray> innerArray(new SkPDFArray);
     innerArray->appendInt(-1);
     array->appendObject(std::move(innerArray));
-    ASSERT_EMIT_EQ(reporter, *array,
+    assert_emit_eq(reporter, *array,
                    "[42 .5 0 true /ThisName /AnotherName (This String) "
                    "(Another String) [-1]]");
 
@@ -286,23 +290,23 @@
     array->appendObjRef(std::move(referencedArray));
 
     SkString result = emit_to_string(*array, &catalog);
-    ASSERT_EQ(reporter, result,
+    assert_eq(reporter, result,
               "[42 .5 0 true /ThisName /AnotherName (This String) "
               "(Another String) [-1] 1 0 R]");
 }
 
 static void TestPDFDict(skiatest::Reporter* reporter) {
     sk_sp<SkPDFDict> dict(new SkPDFDict);
-    ASSERT_EMIT_EQ(reporter, *dict, "<<>>");
+    assert_emit_eq(reporter, *dict, "<<>>");
 
     dict->insertInt("n1", SkToSizeT(42));
-    ASSERT_EMIT_EQ(reporter, *dict, "<</n1 42>>");
+    assert_emit_eq(reporter, *dict, "<</n1 42>>");
 
     dict.reset(new SkPDFDict);
-    ASSERT_EMIT_EQ(reporter, *dict, "<<>>");
+    assert_emit_eq(reporter, *dict, "<<>>");
 
     dict->insertInt("n1", 42);
-    ASSERT_EMIT_EQ(reporter, *dict, "<</n1 42>>");
+    assert_emit_eq(reporter, *dict, "<</n1 42>>");
 
     dict->insertScalar("n2", SK_ScalarHalf);
 
@@ -310,37 +314,37 @@
     sk_sp<SkPDFArray> innerArray(new SkPDFArray);
     innerArray->appendInt(-100);
     dict->insertObject(n3, std::move(innerArray));
-    ASSERT_EMIT_EQ(reporter, *dict, "<</n1 42\n/n2 .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, "<<>>");
+    assert_emit_eq(reporter, *dict, "<<>>");
 
     dict->insertInt("n1", 24);
-    ASSERT_EMIT_EQ(reporter, *dict, "<</n1 24>>");
+    assert_emit_eq(reporter, *dict, "<</n1 24>>");
 
     dict->insertInt("n2", SkToSizeT(99));
-    ASSERT_EMIT_EQ(reporter, *dict, "<</n1 24\n/n2 99>>");
+    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 .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 .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 .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 .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 .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>>");
+    assert_emit_eq(reporter, *dict, "<</Type /DType>>");
 
     sk_sp<SkPDFArray> referencedArray(new SkPDFArray);
     Catalog catalog;
@@ -349,7 +353,7 @@
                             referencedArray.get()) == 1);
     dict->insertObjRef("n1", std::move(referencedArray));
     SkString result = emit_to_string(*dict, &catalog);
-    ASSERT_EQ(reporter, result, "<</Type /DType\n/n1 1 0 R>>");
+    assert_eq(reporter, result, "<</Type /DType\n/n1 1 0 R>>");
 }
 
 DEF_TEST(PDFPrimitives, reporter) {
@@ -465,7 +469,7 @@
         ERRORF(reporter, "unscannable result: %s", floatString);
         return;
     }
-    if (isfinite(inputFloat) && roundTripFloat != inputFloat) {
+    if (std::isfinite(inputFloat) && roundTripFloat != inputFloat) {
         ERRORF(reporter, "roundTripFloat (%.9g) != inputFloat (%.9g)",
                roundTripFloat, inputFloat);
     }