1 /*
   2  * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 /**
  26  * @test
  27  * @bug 7047069
  28  * @summary Array can dynamically change size when assigned to an object field
  29  *
  30  * @modules java.desktop
  31  * @run main/othervm -Xbatch Test7047069
  32  */
  33 
  34 import java.util.*;
  35 import java.awt.geom.*;
  36 
  37 public class Test7047069 {
  38     static boolean verbose;
  39 
  40     static final int GROW_SIZE = 24;    // Multiple of cubic & quad curve size
  41 
  42     float squareflat;           // Square of the flatness parameter
  43                     // for testing against squared lengths
  44 
  45     int limit;              // Maximum number of recursion levels
  46 
  47     float hold[] = new float[14];   // The cache of interpolated coords
  48                     // Note that this must be long enough
  49                     // to store a full cubic segment and
  50                     // a relative cubic segment to avoid
  51                     // aliasing when copying the coords
  52                     // of a curve to the end of the array.
  53                     // This is also serendipitously equal
  54                     // to the size of a full quad segment
  55                     // and 2 relative quad segments.
  56 
  57     int holdEnd;            // The index of the last curve segment
  58                     // being held for interpolation
  59 
  60     int holdIndex;          // The index of the curve segment
  61                     // that was last interpolated.  This
  62                     // is the curve segment ready to be
  63                     // returned in the next call to
  64                     // currentSegment().
  65 
  66     int levels[];           // The recursion level at which
  67                     // each curve being held in storage
  68                     // was generated.
  69 
  70     int levelIndex;         // The index of the entry in the
  71                     // levels array of the curve segment
  72                     // at the holdIndex
  73 
  74     public static void subdivide(float src[], int srcoff,
  75                                  float left[], int leftoff,
  76                                  float right[], int rightoff)
  77     {
  78         float x1 = src[srcoff + 0];
  79         float y1 = src[srcoff + 1];
  80         float ctrlx = src[srcoff + 2];
  81         float ctrly = src[srcoff + 3];
  82         float x2 = src[srcoff + 4];
  83         float y2 = src[srcoff + 5];
  84         if (left != null) {
  85             left[leftoff + 0] = x1;
  86             left[leftoff + 1] = y1;
  87         }
  88         if (right != null) {
  89             right[rightoff + 4] = x2;
  90             right[rightoff + 5] = y2;
  91         }
  92         x1 = (x1 + ctrlx) / 2f;
  93         y1 = (y1 + ctrly) / 2f;
  94         x2 = (x2 + ctrlx) / 2f;
  95         y2 = (y2 + ctrly) / 2f;
  96         ctrlx = (x1 + x2) / 2f;
  97         ctrly = (y1 + y2) / 2f;
  98         if (left != null) {
  99             left[leftoff + 2] = x1;
 100             left[leftoff + 3] = y1;
 101             left[leftoff + 4] = ctrlx;
 102             left[leftoff + 5] = ctrly;
 103         }
 104         if (right != null) {
 105             right[rightoff + 0] = ctrlx;
 106             right[rightoff + 1] = ctrly;
 107             right[rightoff + 2] = x2;
 108             right[rightoff + 3] = y2;
 109         }
 110     }
 111 
 112     public static double getFlatnessSq(float coords[], int offset) {
 113         return Line2D.ptSegDistSq(coords[offset + 0], coords[offset + 1],
 114                                   coords[offset + 4], coords[offset + 5],
 115                                   coords[offset + 2], coords[offset + 3]);
 116     }
 117 
 118     public Test7047069() {
 119         this.squareflat = .0001f * .0001f;
 120         holdIndex = hold.length - 6;
 121         holdEnd = hold.length - 2;
 122         hold[holdIndex + 0] = (float) (Math.random() * 100);
 123         hold[holdIndex + 1] = (float) (Math.random() * 100);
 124         hold[holdIndex + 2] = (float) (Math.random() * 100);
 125         hold[holdIndex + 3] = (float) (Math.random() * 100);
 126         hold[holdIndex + 4] = (float) (Math.random() * 100);
 127         hold[holdIndex + 5] = (float) (Math.random() * 100);
 128         levelIndex = 0;
 129         this.limit = 10;
 130         this.levels = new int[limit + 1];
 131     }
 132 
 133     /*
 134      * Ensures that the hold array can hold up to (want) more values.
 135      * It is currently holding (hold.length - holdIndex) values.
 136      */
 137     void ensureHoldCapacity(int want) {
 138         if (holdIndex - want < 0) {
 139             int have = hold.length - holdIndex;
 140             int newsize = hold.length + GROW_SIZE;
 141             float newhold[] = new float[newsize];
 142             System.arraycopy(hold, holdIndex,
 143                      newhold, holdIndex + GROW_SIZE,
 144                      have);
 145             if (verbose) System.err.println("old hold = "+hold+"["+hold.length+"]");
 146             if (verbose) System.err.println("replacement hold = "+newhold+"["+newhold.length+"]");
 147             hold = newhold;
 148             if (verbose) System.err.println("new hold = "+hold+"["+hold.length+"]");
 149             if (verbose) System.err.println("replacement hold still = "+newhold+"["+newhold.length+"]");
 150             holdIndex += GROW_SIZE;
 151             holdEnd += GROW_SIZE;
 152         }
 153     }
 154 
 155     private boolean next() {
 156         if (holdIndex >= holdEnd) {
 157             return false;
 158         }
 159 
 160         int level = levels[levelIndex];
 161         while (level < limit) {
 162             if (getFlatnessSq(hold, holdIndex) < squareflat) {
 163                 break;
 164             }
 165 
 166             ensureHoldCapacity(4);
 167             subdivide(hold, holdIndex,
 168                       hold, holdIndex - 4,
 169                       hold, holdIndex);
 170             holdIndex -= 4;
 171 
 172             // Now that we have subdivided, we have constructed
 173             // two curves of one depth lower than the original
 174             // curve.  One of those curves is in the place of
 175             // the former curve and one of them is in the next
 176             // set of held coordinate slots.  We now set both
 177             // curves level values to the next higher level.
 178             level++;
 179             levels[levelIndex] = level;
 180             levelIndex++;
 181             levels[levelIndex] = level;
 182         }
 183 
 184         // This curve segment is flat enough, or it is too deep
 185         // in recursion levels to try to flatten any more.  The
 186         // two coordinates at holdIndex+4 and holdIndex+5 now
 187         // contain the endpoint of the curve which can be the
 188         // endpoint of an approximating line segment.
 189         holdIndex += 4;
 190         levelIndex--;
 191         return true;
 192     }
 193 
 194     public static void main(String argv[]) {
 195         verbose = (argv.length > 0);
 196         for (int i = 0; i < 100000; i++) {
 197             Test7047069 st = new Test7047069();
 198             while (st.next()) {}
 199         }
 200     }
 201 }