]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
PDFNumber.doubleOut() rewritten using java.text.DecimalFormat.
authorJeremias Maerki <jeremias@apache.org>
Thu, 1 Sep 2005 10:06:53 +0000 (10:06 +0000)
committerJeremias Maerki <jeremias@apache.org>
Thu, 1 Sep 2005 10:06:53 +0000 (10:06 +0000)
This fixes a bug of doubleOut() not recognizing the scientific format sometimes returned by Double.toString(double).
This change may result in slightly different value being written to the PDF stream. The former doubleOut contained specific code to do special rounding where the new method using DecimalFormat implicitly uses the BigDecimal.ROUND_HALF_EVEN strategy when rounding. These different values hopefully won't make a big visual difference. They don't in my tests.

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@265688 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/fop/pdf/PDFNumber.java
test/java/org/apache/fop/UtilityCodeTestSuite.java
test/java/org/apache/fop/util/PDFNumberTestCase.java [new file with mode: 0644]

index d624dd621fd7d15d0ad32220921b7eab89e82a2f..b235663dfe59e698132842c7078e98245ab7074d 100644 (file)
  
 package org.apache.fop.pdf;
 
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.util.Locale;
+
+import com.sun.corba.se.internal.orbutil.Lock;
+
 /**
  * This class represents a simple number object. It also contains contains some 
  * utility methods for outputing numbers to PDF.
@@ -53,41 +59,20 @@ public class PDFNumber extends PDFObject {
     }
 
     /**
-     * Output a double value to a string suitable for PDF.
+     * Output a double value to a string suitable for PDF (6 decimal digits).
      *
      * @param doubleDown the double value
      * @return the value as a string
      */
     public static String doubleOut(double doubleDown) {
-        StringBuffer p = new StringBuffer();
-        if (doubleDown < 0) {
-            doubleDown = -doubleDown;
-            p.append("-");
-        }
-        double trouble = doubleDown % 1;
-
-        if (trouble > 0.950) {
-            p.append((int)doubleDown + 1);
-        } else if (trouble < 0.050) {
-            p.append((int)doubleDown);
-        } else {
-            String doubleString = new String(doubleDown + "");
-            int decimal = doubleString.indexOf(".");
-            if (decimal != -1) {
-                p.append(doubleString.substring(0, decimal));
-
-                if ((doubleString.length() - decimal) > 6) {
-                    p.append(doubleString.substring(decimal, decimal + 6));
-                } else {
-                    p.append(doubleString.substring(decimal));
-                }
-            } else {
-                p.append(doubleString);
-            }
-        }
-        return (p.toString());
+        return doubleOut(doubleDown, 6);
     }
 
+    // Static cache. Possible concurrency implications. See comment in doubleOut(double, int).
+    private static DecimalFormat[] decimalFormatCache = new DecimalFormat[17];
+    
+    private static final String BASE_FORMAT = "0.################";
+    
     /**
      * Output a double value to a string suitable for PDF.
      * In this method it is possible to set the maximum
@@ -98,33 +83,24 @@ public class PDFNumber extends PDFObject {
      * @return the value as a string
      */
     public static String doubleOut(double doubleDown, int dec) {
-        StringBuffer p = new StringBuffer();
-        if (doubleDown < 0) {
-            doubleDown = -doubleDown;
-            p.append("-");
+        if (dec < 0 || dec >= decimalFormatCache.length) {
+            throw new IllegalArgumentException("Parameter dec must be between 1 and " 
+                    + (decimalFormatCache.length + 1));
         }
-        double trouble = doubleDown % 1;
-
-        if (trouble > (1.0 - (5.0 / (Math.pow(10.0, dec))))) {
-            p.append((int)doubleDown + 1);
-        } else if (trouble < (5.0 / (Math.pow(10.0, dec)))) {
-            p.append((int)doubleDown);
-        } else {
-            String doubleString = new String(doubleDown + "");
-            int decimal = doubleString.indexOf(".");
-            if (decimal != -1) {
-                p.append(doubleString.substring(0, decimal));
-
-                if ((doubleString.length() - decimal) > dec) {
-                    p.append(doubleString.substring(decimal, decimal + dec));
-                } else {
-                    p.append(doubleString.substring(decimal));
-                }
-            } else {
-                p.append(doubleString);
+        if (decimalFormatCache[dec] == null) {
+            //We don't care about the rare case where a DecimalFormat might be replaced in
+            //a multi-threaded environment, so we don't synchronize the access to the static
+            //array (mainly for performance reasons). After all, the DecimalFormat instances
+            //read-only objects so it doesn't matter which instance is used as long as one
+            //is available.
+            String s = "0";
+            if (dec > 0) {
+                s = BASE_FORMAT.substring(0, dec + 2);
             }
+            DecimalFormat df = new DecimalFormat(s, new DecimalFormatSymbols(Locale.US));
+            decimalFormatCache[dec] = df;
         }
-        return (p.toString());
+        return decimalFormatCache[dec].format(doubleDown);
     }
 
     /**
index 7253e7669231eee30d66ad3fac79e5a819d2793d..719ffa6550835200cc466e58cb2e6ba8b8c4fbc5 100644 (file)
@@ -20,6 +20,7 @@ package org.apache.fop;
 
 import org.apache.fop.util.ASCII85InputStreamTestCase;
 import org.apache.fop.util.ASCII85OutputStreamTestCase;
+import org.apache.fop.util.PDFNumberTestCase;
 
 import junit.framework.Test;
 import junit.framework.TestSuite;
@@ -39,6 +40,7 @@ public class UtilityCodeTestSuite {
         //$JUnit-BEGIN$
         suite.addTest(new TestSuite(ASCII85OutputStreamTestCase.class));
         suite.addTest(new TestSuite(ASCII85InputStreamTestCase.class));
+        suite.addTest(new TestSuite(PDFNumberTestCase.class));
         //$JUnit-END$
         return suite;
     }
diff --git a/test/java/org/apache/fop/util/PDFNumberTestCase.java b/test/java/org/apache/fop/util/PDFNumberTestCase.java
new file mode 100644 (file)
index 0000000..3c32d48
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id$ */
+
+package org.apache.fop.util;
+
+import org.apache.fop.pdf.PDFNumber;
+
+import junit.framework.TestCase;
+
+/**
+ * This test tests PDFNumber's doubleOut() methods.
+ */
+public class PDFNumberTestCase extends TestCase {
+
+    /**
+     * Tests PDFNumber.doubleOut().
+     * @throws Exception if the test fails
+     */
+    public void testDoubleOut1() throws Exception {
+        //Default is 6 decimal digits
+        assertEquals("0", PDFNumber.doubleOut(0.0f));
+        assertEquals("0", PDFNumber.doubleOut(0.0000000000000000000123f));
+        assertEquals("0.1", PDFNumber.doubleOut(0.1f));
+        assertEquals("100", PDFNumber.doubleOut(100.0f));
+        assertEquals("100", PDFNumber.doubleOut(99.99999999999999999999999f));
+        
+        //You'd expect 100.123456 here but DecimalFormat uses the BigDecimal.ROUND_HALF_EVEN 
+        //strategy. I don't know if that's a problem. The strange thing testDoubleOut2
+        //seems to return the normally expected value. Weird.
+        assertEquals("100.123459", PDFNumber.doubleOut(100.12345611111111f));
+        assertEquals("-100.123459", PDFNumber.doubleOut(-100.12345611111111f));
+    }
+    
+    /**
+     * Tests PDFNumber.doubleOut().
+     * @throws Exception if the test fails
+     */
+    public void testDoubleOut2() throws Exception {
+        //4 decimal digits in this case
+        assertEquals("0", PDFNumber.doubleOut(0.0f, 4));
+        assertEquals("0", PDFNumber.doubleOut(0.0000000000000000000123f, 4));
+        assertEquals("0.1", PDFNumber.doubleOut(0.1f, 4));
+        assertEquals("100", PDFNumber.doubleOut(100.0f, 4));
+        assertEquals("100", PDFNumber.doubleOut(99.99999999999999999999999f, 4));
+        assertEquals("100.1234", PDFNumber.doubleOut(100.12341111111111f, 4));
+        assertEquals("-100.1234", PDFNumber.doubleOut(-100.12341111111111f, 4));
+    }
+    
+    /**
+     * Tests PDFNumber.doubleOut().
+     * @throws Exception if the test fails
+     */
+    public void testDoubleOut3() throws Exception {
+        //0 decimal digits in this case
+        assertEquals("0", PDFNumber.doubleOut(0.0f, 0));
+        assertEquals("0", PDFNumber.doubleOut(0.1f, 0));
+        assertEquals("1", PDFNumber.doubleOut(0.6f, 0));
+        assertEquals("100", PDFNumber.doubleOut(100.1234f, 0));
+        assertEquals("-100", PDFNumber.doubleOut(-100.1234f, 0));
+    }
+    
+    /**
+     * Tests PDFNumber.doubleOut(). Special cases (former bugs).
+     * @throws Exception if the test fails
+     */
+    public void testDoubleOut4() throws Exception {
+        double d = Double.parseDouble("5.7220458984375E-6");
+        assertEquals("0.000006", PDFNumber.doubleOut(d));
+        assertEquals("0", PDFNumber.doubleOut(d, 4));
+        assertEquals("0.00000572", PDFNumber.doubleOut(d, 8));
+    }
+    
+    /**
+     * Tests PDFNumber.doubleOut(). Tests for wrong parameters.
+     * @throws Exception if the test fails
+     */
+    public void testDoubleOutWrongParameters() throws Exception {
+        try {
+            PDFNumber.doubleOut(0.1f, -1);
+            fail("IllegalArgument expected!");
+        } catch (IllegalArgumentException iae) {
+            //we want that
+        }
+        try {
+            PDFNumber.doubleOut(0.1f, 17); //We support max 16 decimal digits
+            fail("IllegalArgument expected!");
+        } catch (IllegalArgumentException iae) {
+            //we want that
+        }
+        try {
+            PDFNumber.doubleOut(0.1f, 98274659);
+            fail("IllegalArgument expected!");
+        } catch (IllegalArgumentException iae) {
+            //we want that
+        }
+    }
+    
+}