8186364: RFE: API for java.awt.geom.Path2D storage trimming
authorlbourges
Fri, 18 Aug 2017 10:12:50 -0700
changeset 47181 ae2a6a1c45b1
parent 47180 8bd272c413d1
child 47182 be143f7fe40a
8186364: RFE: API for java.awt.geom.Path2D storage trimming Reviewed-by: prr, flar
jdk/src/java.desktop/share/classes/java/awt/geom/Path2D.java
jdk/test/java/awt/geom/Path2D/Path2DCopyConstructor.java
--- a/jdk/src/java.desktop/share/classes/java/awt/geom/Path2D.java	Thu Aug 17 19:24:58 2017 -0700
+++ b/jdk/src/java.desktop/share/classes/java/awt/geom/Path2D.java	Fri Aug 18 10:12:50 2017 -0700
@@ -276,6 +276,17 @@
         }
 
         @Override
+        public final void trimToSize() {
+            // trim arrays:
+            if (numTypes < pointTypes.length) {
+                this.pointTypes = Arrays.copyOf(pointTypes, numTypes);
+            }
+            if (numCoords < floatCoords.length) {
+                this.floatCoords = Arrays.copyOf(floatCoords, numCoords);
+            }
+        }
+
+        @Override
         float[] cloneCoordsFloat(AffineTransform at) {
             // trim arrays:
             float ret[];
@@ -1151,6 +1162,17 @@
         }
 
         @Override
+        public final void trimToSize() {
+            // trim arrays:
+            if (numTypes < pointTypes.length) {
+                this.pointTypes = Arrays.copyOf(pointTypes, numTypes);
+            }
+            if (numCoords < doubleCoords.length) {
+                this.doubleCoords = Arrays.copyOf(doubleCoords, numCoords);
+            }
+        }
+
+        @Override
         float[] cloneCoordsFloat(AffineTransform at) {
             // trim arrays:
             float ret[] = new float[numCoords];
@@ -2481,6 +2503,15 @@
         // compatibility so we cannot restrict it further.
         // REMIND: Can we do both somehow?
 
+    /**
+     * Trims the capacity of this Path2D instance to its current
+     * size. An application can use this operation to minimize the
+     * storage of a path.
+     *
+     * @since 10
+     */
+    public abstract void trimToSize();
+
     /*
      * Support fields and methods for serializing the subclasses.
      */
--- a/jdk/test/java/awt/geom/Path2D/Path2DCopyConstructor.java	Thu Aug 17 19:24:58 2017 -0700
+++ b/jdk/test/java/awt/geom/Path2D/Path2DCopyConstructor.java	Fri Aug 18 10:12:50 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,9 +34,10 @@
 
 /**
  * @test
- * @bug 8076419
+ * @bug 8076419 8078192 8186364
  * @summary Check Path2D copy constructor (trims arrays)
  *          and constructor with zero capacity
+ *          and Path2D.trimToSize()
  * @run main Path2DCopyConstructor
  */
 public class Path2DCopyConstructor {
@@ -179,58 +180,232 @@
     }
 
     static void test(Path2D p2d, boolean isEmpty) {
-        testEqual(new Path2D.Float(p2d), p2d);
-        testEqual(new Path2D.Double(p2d), p2d);
-        testEqual(new GeneralPath(p2d), p2d);
+        Path2D c;
+        Path2D.Float pf;
+        Path2D.Double pd;
+        GeneralPath gp;
 
-        testIterator(new Path2D.Float(p2d), p2d);
-        testIterator(new Path2D.Double(p2d), p2d);
-        testIterator((Path2D) p2d.clone(), p2d);
+        pf = new Path2D.Float(p2d);
+        testEqual(pf, p2d);
+        pf.trimToSize();
+        testEqual(pf, p2d);
+        pd = new Path2D.Double(p2d);
+        testEqual(pd, p2d);
+        pd.trimToSize();
+        testEqual(pd, p2d);
+        c = (Path2D)p2d.clone();
+        testEqual(c, p2d);
+        c.trimToSize();
+        testEqual(c, p2d);
+        gp = new GeneralPath(p2d);
+        testEqual(gp, p2d);
+        gp.trimToSize();
+        testEqual(gp, p2d);
 
-        testFlattening(new Path2D.Float(p2d), p2d);
-        testFlattening(new Path2D.Double(p2d), p2d);
-        testFlattening((Path2D) p2d.clone(), p2d);
+        pf = new Path2D.Float(p2d);
+        testIterator(pf, p2d);
+        pf.trimToSize();
+        testIterator(pf, p2d);
+        pd = new Path2D.Double(p2d);
+        testIterator(pd, p2d);
+        pd.trimToSize();
+        testIterator(pd, p2d);
+        c = (Path2D)p2d.clone();
+        testIterator(c, p2d);
+        c.trimToSize();
+        testIterator(c, p2d);
+        gp = new GeneralPath(p2d);
+        testIterator(gp, p2d);
+        gp.trimToSize();
+        testIterator(gp, p2d);
 
-        testAddMove(new Path2D.Float(p2d));
-        testAddMove(new Path2D.Double(p2d));
-        testAddMove((Path2D) p2d.clone());
+        pf = new Path2D.Float(p2d);
+        testFlattening(pf, p2d);
+        pf.trimToSize();
+        testFlattening(pf, p2d);
+        pd = new Path2D.Double(p2d);
+        testFlattening(pd, p2d);
+        pd.trimToSize();
+        testFlattening(pd, p2d);
+        c = (Path2D)p2d.clone();
+        testFlattening(c, p2d);
+        c.trimToSize();
+        testFlattening(c, p2d);
+        gp = new GeneralPath(p2d);
+        testFlattening(gp, p2d);
+        gp.trimToSize();
+        testFlattening(gp, p2d);
+
+        pf = new Path2D.Float(p2d);
+        testAddMove(pf);
+        pf.trimToSize();
+        testAddMove(pf);
+        pd = new Path2D.Double(p2d);
+        testAddMove(pd);
+        pd.trimToSize();
+        testAddMove(pd);
+        c = (Path2D)p2d.clone();
+        testAddMove(c);
+        c.trimToSize();
+        testAddMove(c);
+        gp = new GeneralPath(p2d);
+        testAddMove(gp);
+        gp.trimToSize();
+        testAddMove(gp);
 
         // These should expect exception if empty
-        testAddLine(new Path2D.Float(p2d), isEmpty);
-        testAddLine(new Path2D.Double(p2d), isEmpty);
-        testAddLine((Path2D) p2d.clone(), isEmpty);
+        pf = new Path2D.Float(p2d);
+        testAddLine(pf, isEmpty);
+        pf.trimToSize();
+        testAddLine(pf, isEmpty);
+        pd = new Path2D.Double(p2d);
+        testAddLine(pd, isEmpty);
+        pd.trimToSize();
+        testAddLine(pd, isEmpty);
+        c = (Path2D)p2d.clone();
+        testAddLine(c, isEmpty);
+        c.trimToSize();
+        testAddLine(c, isEmpty);
+        gp = new GeneralPath(p2d);
+        testAddLine(gp, isEmpty);
+        gp.trimToSize();
+        testAddLine(gp, isEmpty);
 
-        testAddQuad(new Path2D.Float(p2d), isEmpty);
-        testAddQuad(new Path2D.Double(p2d), isEmpty);
-        testAddQuad((Path2D) p2d.clone(), isEmpty);
+        pf = new Path2D.Float(p2d);
+        testAddQuad(pf, isEmpty);
+        pf.trimToSize();
+        testAddQuad(pf, isEmpty);
+        pd = new Path2D.Double(p2d);
+        testAddQuad(pd, isEmpty);
+        pd.trimToSize();
+        testAddQuad(pd, isEmpty);
+        c = (Path2D)p2d.clone();
+        testAddQuad(c, isEmpty);
+        c.trimToSize();
+        testAddQuad(c, isEmpty);
+        gp = new GeneralPath(p2d);
+        testAddQuad(gp, isEmpty);
+        gp.trimToSize();
+        testAddQuad(gp, isEmpty);
 
-        testAddCubic(new Path2D.Float(p2d), isEmpty);
-        testAddCubic(new Path2D.Double(p2d), isEmpty);
-        testAddCubic((Path2D) p2d.clone(), isEmpty);
+        pf = new Path2D.Float(p2d);
+        testAddCubic(pf, isEmpty);
+        pf.trimToSize();
+        testAddCubic(pf, isEmpty);
+        pd = new Path2D.Double(p2d);
+        testAddCubic(pd, isEmpty);
+        pd.trimToSize();
+        testAddCubic(pd, isEmpty);
+        c = (Path2D)p2d.clone();
+        testAddCubic(c, isEmpty);
+        c.trimToSize();
+        testAddCubic(c, isEmpty);
+        gp = new GeneralPath(p2d);
+        testAddCubic(gp, isEmpty);
+        gp.trimToSize();
+        testAddCubic(gp, isEmpty);
 
-        testAddClose(new Path2D.Float(p2d), isEmpty);
-        testAddClose(new Path2D.Double(p2d), isEmpty);
-        testAddClose((Path2D) p2d.clone(), isEmpty);
+        pf = new Path2D.Float(p2d);
+        testAddClose(pf, isEmpty);
+        pf.trimToSize();
+        testAddClose(pf, isEmpty);
+        pd = new Path2D.Double(p2d);
+        testAddClose(pd, isEmpty);
+        pd.trimToSize();
+        testAddClose(pd, isEmpty);
+        c = (Path2D)p2d.clone();
+        testAddClose(c, isEmpty);
+        c.trimToSize();
+        testAddClose(c, isEmpty);
+        gp = new GeneralPath(p2d);
+        testAddClose(gp, isEmpty);
+        gp.trimToSize();
+        testAddClose(gp, isEmpty);
 
-        testGetBounds(new Path2D.Float(p2d), p2d);
-        testGetBounds(new Path2D.Double(p2d), p2d);
-        testGetBounds((Path2D) p2d.clone(), p2d);
+        pf = new Path2D.Float(p2d);
+        testGetBounds(pf, p2d);
+        pf.trimToSize();
+        testGetBounds(pf, p2d);
+        pd = new Path2D.Double(p2d);
+        testGetBounds(pd, p2d);
+        pd.trimToSize();
+        testGetBounds(pd, p2d);
+        c = (Path2D)p2d.clone();
+        testGetBounds(c, p2d);
+        c.trimToSize();
+        testGetBounds(c, p2d);
+        gp = new GeneralPath(p2d);
+        testGetBounds(gp, p2d);
+        gp.trimToSize();
+        testGetBounds(gp, p2d);
 
-        testTransform(new Path2D.Float(p2d));
-        testTransform(new Path2D.Double(p2d));
-        testTransform((Path2D) p2d.clone());
+        pf = new Path2D.Float(p2d);
+        testTransform(pf);
+        pf.trimToSize();
+        testTransform(pf);
+        pd = new Path2D.Double(p2d);
+        testTransform(pd);
+        pd.trimToSize();
+        testTransform(pd);
+        c = (Path2D)p2d.clone();
+        testTransform(c);
+        c.trimToSize();
+        testTransform(c);
+        gp = new GeneralPath(p2d);
+        testTransform(gp);
+        gp.trimToSize();
+        testTransform(gp);
 
-        testIntersect(new Path2D.Float(p2d), p2d);
-        testIntersect(new Path2D.Double(p2d), p2d);
-        testIntersect((Path2D) p2d.clone(), p2d);
+        pf = new Path2D.Float(p2d);
+        testIntersect(pf, p2d);
+        pf.trimToSize();
+        testIntersect(pf, p2d);
+        pd = new Path2D.Double(p2d);
+        testIntersect(pd, p2d);
+        pd.trimToSize();
+        testIntersect(pd, p2d);
+        c = (Path2D)p2d.clone();
+        testIntersect(c, p2d);
+        c.trimToSize();
+        testIntersect(c, p2d);
+        gp = new GeneralPath(p2d);
+        testIntersect(gp, p2d);
+        gp.trimToSize();
+        testIntersect(gp, p2d);
 
-        testContains(new Path2D.Float(p2d), p2d);
-        testContains(new Path2D.Double(p2d), p2d);
-        testContains((Path2D) p2d.clone(), p2d);
+        pf = new Path2D.Float(p2d);
+        testContains(pf, p2d);
+        pf.trimToSize();
+        testContains(pf, p2d);
+        pd = new Path2D.Double(p2d);
+        testContains(pd, p2d);
+        pd.trimToSize();
+        testContains(pd, p2d);
+        c = (Path2D)p2d.clone();
+        testContains(c, p2d);
+        c.trimToSize();
+        testContains(c, p2d);
+        gp = new GeneralPath(p2d);
+        testContains(gp, p2d);
+        gp.trimToSize();
+        testContains(gp, p2d);
 
-        testGetCurrentPoint(new Path2D.Float(p2d), p2d);
-        testGetCurrentPoint(new Path2D.Double(p2d), p2d);
-        testGetCurrentPoint((Path2D) p2d.clone(), p2d);
+        pf = new Path2D.Float(p2d);
+        testGetCurrentPoint(pf, p2d);
+        pf.trimToSize();
+        testGetCurrentPoint(pf, p2d);
+        pd = new Path2D.Double(p2d);
+        testGetCurrentPoint(pd, p2d);
+        pd.trimToSize();
+        testGetCurrentPoint(pd, p2d);
+        c = (Path2D)p2d.clone();
+        testGetCurrentPoint(c, p2d);
+        c.trimToSize();
+        testGetCurrentPoint(c, p2d);
+        gp = new GeneralPath(p2d);
+        testGetCurrentPoint(gp, p2d);
+        gp.trimToSize();
+        testGetCurrentPoint(gp, p2d);
     }
 
     static void testEqual(Path2D pathA, Path2D pathB) {