You are viewing a plain text version of this content. The canonical link for it is here.
Posted to fop-commits@xmlgraphics.apache.org by je...@apache.org on 2005/09/01 12:07:08 UTC

svn commit: r265688 - in /xmlgraphics/fop/trunk: src/java/org/apache/fop/pdf/PDFNumber.java test/java/org/apache/fop/UtilityCodeTestSuite.java test/java/org/apache/fop/util/PDFNumberTestCase.java

Author: jeremias
Date: Thu Sep  1 03:06:53 2005
New Revision: 265688

URL: http://svn.apache.org/viewcvs?rev=265688&view=rev
Log:
PDFNumber.doubleOut() rewritten using java.text.DecimalFormat.
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.

Added:
    xmlgraphics/fop/trunk/test/java/org/apache/fop/util/PDFNumberTestCase.java   (with props)
Modified:
    xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFNumber.java
    xmlgraphics/fop/trunk/test/java/org/apache/fop/UtilityCodeTestSuite.java

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFNumber.java
URL: http://svn.apache.org/viewcvs/xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFNumber.java?rev=265688&r1=265687&r2=265688&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFNumber.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/PDFNumber.java Thu Sep  1 03:06:53 2005
@@ -18,6 +18,12 @@
  
 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 @@
     }
 
     /**
-     * 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 @@
      * @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);
     }
 
     /**

Modified: xmlgraphics/fop/trunk/test/java/org/apache/fop/UtilityCodeTestSuite.java
URL: http://svn.apache.org/viewcvs/xmlgraphics/fop/trunk/test/java/org/apache/fop/UtilityCodeTestSuite.java?rev=265688&r1=265687&r2=265688&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/test/java/org/apache/fop/UtilityCodeTestSuite.java (original)
+++ xmlgraphics/fop/trunk/test/java/org/apache/fop/UtilityCodeTestSuite.java Thu Sep  1 03:06:53 2005
@@ -20,6 +20,7 @@
 
 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 @@
         //$JUnit-BEGIN$
         suite.addTest(new TestSuite(ASCII85OutputStreamTestCase.class));
         suite.addTest(new TestSuite(ASCII85InputStreamTestCase.class));
+        suite.addTest(new TestSuite(PDFNumberTestCase.class));
         //$JUnit-END$
         return suite;
     }

Added: xmlgraphics/fop/trunk/test/java/org/apache/fop/util/PDFNumberTestCase.java
URL: http://svn.apache.org/viewcvs/xmlgraphics/fop/trunk/test/java/org/apache/fop/util/PDFNumberTestCase.java?rev=265688&view=auto
==============================================================================
--- xmlgraphics/fop/trunk/test/java/org/apache/fop/util/PDFNumberTestCase.java (added)
+++ xmlgraphics/fop/trunk/test/java/org/apache/fop/util/PDFNumberTestCase.java Thu Sep  1 03:06:53 2005
@@ -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
+        }
+    }
+    
+}

Propchange: xmlgraphics/fop/trunk/test/java/org/apache/fop/util/PDFNumberTestCase.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: xmlgraphics/fop/trunk/test/java/org/apache/fop/util/PDFNumberTestCase.java
------------------------------------------------------------------------------
    svn:keywords = Id



---------------------------------------------------------------------
To unsubscribe, e-mail: fop-commits-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: fop-commits-help@xmlgraphics.apache.org