changeset 1628:69bec44a5f3a

RT-31045 GridPane may take an abnormally long time to be rendered Backported growOrShrinkRowHeights & growOrShrinkColumnWidths methods from GridPane in 8.0
author Martin Sladecek <martin.sladecek@oracle.com>
date Thu, 13 Jun 2013 08:58:28 +0200
parents 6b5ccbc93d06
children e1b2ee95cb11 6dd9f40e495c
files javafx-ui-common/src/javafx/scene/layout/GridPane.java
diffstat 1 files changed, 63 insertions(+), 57 deletions(-) [+]
line wrap: on
line diff
--- a/javafx-ui-common/src/javafx/scene/layout/GridPane.java	Wed Jun 05 13:23:09 2013 -0700
+++ b/javafx-ui-common/src/javafx/scene/layout/GridPane.java	Thu Jun 13 08:58:28 2013 +0200
@@ -53,6 +53,7 @@
 import com.sun.javafx.css.converters.BooleanConverter;
 import com.sun.javafx.css.converters.EnumConverter;
 import com.sun.javafx.css.converters.SizeConverter;
+import java.util.Iterator;
 import javafx.collections.ListChangeListener;
 import javafx.geometry.Orientation;
 
@@ -593,7 +594,7 @@
             setConstraints(nodes[i], columnIndex, rowIndex + i);
         }
     }
-    
+
     static int getNodeRowIndex(Node node) {
         Integer rowIndex = getRowIndex(node);
         return rowIndex != null? rowIndex : 0;
@@ -926,7 +927,7 @@
                 int end = getNodeColumnEnd(child);
                 columnIndex = Math.max(columnIndex, (end != REMAINING? end : index) + 1);
             }
-        }        
+        }
         createRow(rowIndex, columnIndex, children);
         getChildren().addAll(children);
     }
@@ -951,7 +952,7 @@
                 int end = getNodeRowEnd(child);
                 rowIndex = Math.max(rowIndex, (end != REMAINING? end : index) + 1);
             }
-        }        
+        }
         createColumn(columnIndex, rowIndex, children);
         getChildren().addAll(children);
     }
@@ -983,7 +984,7 @@
     // This is set to true while in layoutChildren and set false on the conclusion.
     // It is used to decide whether to update metricsDirty in requestLayout().
     private boolean performingLayout = false;
-    
+
     @Override protected double computeMinWidth(double height) {
         computeGridMetrics();
         if (getContentBias() == Orientation.VERTICAL) {
@@ -1194,7 +1195,7 @@
             if (computeMin || computeMax || computePref || computeGrow || rowVPos == VPos.BASELINE) {
                 // compute from content
                 for (int j = 0; j < endNodes.size(); j++) {
-                    Node child = endNodes.get(j);                    
+                    Node child = endNodes.get(j);
                     Insets margin = getMargin(child);
                     double top = margin != null? margin.getTop() : 0;
                     int rowIndex = getNodeRowIndex(child);
@@ -1316,7 +1317,7 @@
                     columnPercentWidth[i] = constraints.getPercentWidth();
                     computeGrow = false;
                 } else {
-                    double w = constraints.getPrefWidth();          
+                    double w = constraints.getPrefWidth();
                     if (w != USE_COMPUTED_SIZE) {
                         columnPrefWidth[i] = w;
                         computePref = false;
@@ -1339,7 +1340,7 @@
             }
 
             if (computeMin || computeMax || computePref || computeGrow) {
-                // compute from content                
+                // compute from content
                 for (int j = 0; j < endNodes.size(); j++) {
                     Node child = endNodes.get(j);
                     Insets margin = getMargin(child);
@@ -1392,18 +1393,18 @@
 
             if (columnMinWidth[i] == USE_PREF_SIZE) {
                 //RT-20573 Use the bounded size if the pref has not been set
-                columnMinWidth[i] = columnPrefWidth[i] == 0 ? 
-                    boundedSize(columnPrefWidth[i], columnMinWidth[i], columnMaxWidth[i]) == USE_PREF_SIZE ? 
-                        0 : boundedSize(columnPrefWidth[i], columnMinWidth[i], columnMaxWidth[i]) : 
+                columnMinWidth[i] = columnPrefWidth[i] == 0 ?
+                    boundedSize(columnPrefWidth[i], columnMinWidth[i], columnMaxWidth[i]) == USE_PREF_SIZE ?
+                        0 : boundedSize(columnPrefWidth[i], columnMinWidth[i], columnMaxWidth[i]) :
                     columnPrefWidth[i];
             }
             if (columnMaxWidth[i] == USE_PREF_SIZE) {
-                columnMaxWidth[i] = columnPrefWidth[i] == 0 ? 
-                    boundedSize(columnPrefWidth[i], columnMinWidth[i], columnMaxWidth[i]) == USE_PREF_SIZE ? 
-                        0 : boundedSize(columnPrefWidth[i], columnMinWidth[i], columnMaxWidth[i]) : 
+                columnMaxWidth[i] = columnPrefWidth[i] == 0 ?
+                    boundedSize(columnPrefWidth[i], columnMinWidth[i], columnMaxWidth[i]) == USE_PREF_SIZE ?
+                        0 : boundedSize(columnPrefWidth[i], columnMinWidth[i], columnMaxWidth[i]) :
                     columnPrefWidth[i];
-            }                        
-            columnPrefWidth[i] = boundedSize(columnPrefWidth[i], columnMinWidth[i], columnMaxWidth[i]);            
+            }
+            columnPrefWidth[i] = boundedSize(columnPrefWidth[i], columnMinWidth[i], columnMaxWidth[i]);
             //System.out.println("column "+i+": h="+columnWidths[i]+" percent="+columnPercentWidth[i]+" min="+columnMinWidth[i]+" pref="+columnPrefWidth[i]+" max="+columnMaxWidth[i]+" grow="+columnGrow[i]);
         }
         // if percentages sum is bigger than 100, treat them as weights
@@ -1475,7 +1476,7 @@
         double rowTotal = 0;
         computeGridMetrics();
 
-        Orientation contentBias = getContentBias();        
+        Orientation contentBias = getContentBias();
         if (contentBias == null) {
             rowTotal = adjustRowHeights(rowPrefHeight, height);
             columnTotal = adjustColumnWidths(columnPrefWidth, width);
@@ -1580,7 +1581,6 @@
     private double growOrShrinkRowHeights(Priority priority, double extraHeight) {
         final boolean shrinking = extraHeight < 0;
         List<Integer> adjusting = new ArrayList<Integer>();
-        List<Integer> adjusted = new ArrayList<Integer>();
 
         for (int i = 0; i < rowGrow.length; i++) {
             if (rowPercentHeight[i] < 0 && (shrinking || rowGrow[i] == priority)) {
@@ -1590,32 +1590,37 @@
 
         double available = extraHeight; // will be negative in shrinking case
         boolean handleRemainder = false;
-        int portion = 0;
-        while (available != 0 && adjusting.size() > 0) {
+        double portion = 0;
+
+        // RT-25684: We have to be careful that when subtracting change
+        // that we don't jump right past 0 - this leads to an infinite
+        // loop
+        final boolean wasPositive = available >= 0.0;
+        boolean isPositive = wasPositive;
+
+        double[] limitSize = shrinking? rowMinHeight : rowMaxHeight;
+        while (available != 0 && wasPositive == isPositive && adjusting.size() > 0) {
             if (!handleRemainder) {
-                portion = (int)available / adjusting.size(); // negative in shrinking case
+                portion = available > 0 ? Math.floor(available / adjusting.size()) :
+                        Math.ceil(available / adjusting.size()); // negative in shrinking case
             }
             if (portion != 0) {
-                for (int i = 0; i < adjusting.size(); i++) {
-                    final int index = adjusting.get(i);
-                    final double limit = (shrinking? rowMinHeight[index] : rowMaxHeight[index])
+                for (Iterator<Integer> i = adjusting.iterator(); i.hasNext() && available != 0;) {
+                    final int index = i.next();
+                    final double limit = snapSpace(limitSize[index])
                             - rowHeights[index]; // negative in shrinking case
                     final double change = Math.abs(limit) <= Math.abs(portion)? limit : portion;
-                    //System.out.println("row "+index+": height="+rowHeights[index]+" extra="+extraHeight+"portion="+portion+" row mpm="+rowMinHeight[index]+"/"+rowPrefHeight[index]+"/"+rowMaxHeight[index]+" limit="+limit+" change="+change);
-                    rowHeights[index] += change;                
+                    rowHeights[index] += change;
                     available -= change;
+                    isPositive = available >= 0.0;
                     if (Math.abs(change) < Math.abs(portion)) {
-                        adjusted.add(index);
+                        i.remove();
                     }
                     if (available == 0) {
                         break;
                     }
                 }
-                for (int i = 0; i < adjusted.size(); i++) {
-                    adjusting.remove(adjusted.get(i));
-                }
-                adjusted.clear();
-            } else {
+             } else {
                 // Handle the remainder
                 portion = (int)(available) % adjusting.size();
                 if (portion == 0) {
@@ -1627,10 +1632,7 @@
                 }
             }
         }
-                        
-        for (int i = 0; i < rowHeights.length; i++) {
-            rowHeights[i] = snapSpace(rowHeights[i]);            
-        }
+
         return available; // might be negative in shrinking case
     }
 
@@ -1672,44 +1674,51 @@
     }
 
     private double growOrShrinkColumnWidths(Priority priority, double extraWidth) {
+        if (extraWidth == 0) {
+            return 0;
+        }
         final boolean shrinking = extraWidth < 0;
-
         List<Integer> adjusting = new ArrayList<Integer>();
-        List<Integer> adjusted = new ArrayList<Integer>();
 
         for (int i = 0; i < columnGrow.length; i++) {
             if (columnPercentWidth[i] < 0 && (shrinking || columnGrow[i] == priority)) {
                 adjusting.add(i);
             }
         }
-        
+
         double available = extraWidth; // will be negative in shrinking case
         boolean handleRemainder = false;
-        int portion = 0;
-        while (available != 0 && adjusting.size() > 0) {            
+        double portion = 0;
+
+        // RT-25684: We have to be careful that when subtracting change
+        // that we don't jump right past 0 - this leads to an infinite
+        // loop
+        final boolean wasPositive = available >= 0.0;
+        boolean isPositive = wasPositive;
+
+        double[] limitSize = shrinking? columnMinWidth :
+                            columnMaxWidth;
+        while (available != 0 && wasPositive == isPositive && adjusting.size() > 0) {
             if (!handleRemainder) {
-                portion = (int)available / adjusting.size(); // negative in shrinking case
+                portion = available > 0 ? Math.floor(available / adjusting.size()) :
+                        Math.ceil(available / adjusting.size()); // negative in shrinking case
             }
             if (portion != 0) {
-                for (int i = 0; i < adjusting.size(); i++) {
-                    final int index = adjusting.get(i);
-                    final double limit = (shrinking? columnMinWidth[index] : columnMaxWidth[index])
+                for (Iterator<Integer> i = adjusting.iterator(); i.hasNext() && available != 0;) {
+                    final int index = i.next();
+                    final double limit = snapSpace(limitSize[index])
                             - columnWidths[index]; // negative in shrinking case
                     final double change = Math.abs(limit) <= Math.abs(portion)? limit : portion;
-                    columnWidths[index] += change;                
-                    //if (node.id.startsWith("debug.")) println("{if (shrinking) "vshrink" else "vgrow"}: {node.id} portion({portion})=available({available})/({sizeof adjusting}) change={change}");
+                    columnWidths[index] += change;
                     available -= change;
+                    isPositive = available >= 0.0;
                     if (Math.abs(change) < Math.abs(portion)) {
-                        adjusted.add(index);
+                        i.remove();
                     }
-                    if (available == 0) {                        
+                    if (available == 0) {
                         break;
-                    }                    
+                    }
                 }
-                for (int i = 0; i < adjusted.size(); i++) {
-                    adjusting.remove(adjusted.get(i));
-                }
-                adjusted.clear();
             } else {
                 // Handle the remainder
                 portion = (int)(available) % adjusting.size();
@@ -1722,10 +1731,7 @@
                 }
             }
         }
-               
-        for (int i = 0; i < columnWidths.length; i++) {
-            columnWidths[i] = snapSpace(columnWidths[i]);
-        }
+
         return available; // might be negative in shrinking case
     }