diff -r 179b696beb69 javafx-ui-common/src/javafx/scene/layout/FlowPane.java
--- a/javafx-ui-common/src/javafx/scene/layout/FlowPane.java	Wed Aug 29 20:17:08 2012 -0700
+++ b/javafx-ui-common/src/javafx/scene/layout/FlowPane.java	Thu Sep 06 09:58:38 2012 +0200
@@ -29,9 +29,7 @@
 import static javafx.geometry.Orientation.HORIZONTAL;
 import static javafx.geometry.Orientation.VERTICAL;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
+import java.util.*;
 
 import javafx.beans.property.DoubleProperty;
 import javafx.beans.property.DoublePropertyBase;
@@ -49,7 +47,6 @@
 import com.sun.javafx.css.StyleableProperty;
 import com.sun.javafx.css.converters.EnumConverter;
 import com.sun.javafx.css.converters.SizeConverter;
-import javafx.beans.property.Property;
 
 /**
  * FlowPane lays out its children in a flow that wraps at the flowpane's boundary.
@@ -150,6 +147,10 @@
  */
 public class FlowPane extends Pane {
 
+    private static final double EPSILON = 1e-12;
+
+    private static enum Command {NONE, TRANSLATE_ONLY, RECALCULATE_LAYOUT};
+
     /********************************************************************
      *  BEGIN static methods
      ********************************************************************/
@@ -570,94 +571,117 @@
     }
 
     private List<Run> runs = null;
+    private Map<Node, LayoutRect> layoutRects = new HashMap();
     private double lastMaxRunLength = -1;
     boolean computingRuns = false;
+    boolean currentToggle = false;
+    
+    private List<Run> getRuns(double maxRunLength) {
+        if (runs == null || Math.abs(maxRunLength - lastMaxRunLength) > EPSILON) {
+            try {
+                computingRuns = true;
+                lastMaxRunLength = maxRunLength;
+                runs = new ArrayList();
+                final boolean horizontal = getOrientation() == HORIZONTAL;
+                final VPos vPos = getRowValignment();
+                final double currentVGap = snapSpace(this.getVgap());
+                final double currentHGap = snapSpace(this.getHgap());
+                int index = 0;
+                double runOffset = 0;
+                double runLength = 0;
+                Run run = new Run(index);
 
-    private List<Run> getRuns(double maxRunLength) {
-        if (runs == null || maxRunLength != lastMaxRunLength) {
-            computingRuns = true;
-            lastMaxRunLength = maxRunLength;
-            runs = new ArrayList();
-            double runLength = 0;
-            double runOffset = 0;
-            Run run = new Run();
-            double vgap = snapSpace(this.getVgap());
-            double hgap = snapSpace(this.getHgap());
+                final List<Node> managedChildren = getManagedChildren();
+                currentToggle = !currentToggle;
+                for (final Node child : managedChildren) {
+                    final Insets margin = getMargin(child);
+                    final double width = computeChildPrefAreaWidth(child, margin);
+                    final double height = computeChildPrefAreaHeight(child, margin);
+                    final double alignedHeight = (horizontal && vPos == VPos.BASELINE)? computeChildPrefAreaHeight(child, margin, vPos) : height;
+                    final double size = horizontal? width : height;
+                    if (runLength + size > maxRunLength && runLength > 0) {
+                        // wrap to next run *unless* its the only node in the run
+                        normalizeRun(run, runLength, horizontal, currentHGap, currentVGap, vPos);
+                        runOffset += horizontal? run.height + currentVGap : run.width + currentHGap;
+                        runLength = 0;
+                        run = new Run(index);
+                    }
+                    LayoutRect layoutRect = layoutRects.get(child);
+                    if (layoutRect == null) {
+                        layoutRect = new LayoutRect();
+                        layoutRects.put(child, layoutRect);
+                    }
+                    layoutRect.toggle = currentToggle;
+                    if (horizontal) {
+                        if (Double.isNaN(layoutRect.width) || Math.abs(layoutRect.width - width) > EPSILON) {
+                            layoutRect.width = width;
+                            layoutRect.command = Command.RECALCULATE_LAYOUT;
+                        } else {
+                            layoutRect.command = (Math.abs(layoutRect.x - runLength) > EPSILON || Math.abs(layoutRect.y - runOffset) > EPSILON)?
+                                    Command.TRANSLATE_ONLY : Command.NONE;
+                        }
+                        layoutRect.x = runLength;
+                        layoutRect.y = runOffset;
+                        runLength += width + currentHGap;
+                        run.height = Math.max(run.height, alignedHeight);
+                        if (vPos == VPos.BASELINE) {
+                            run.baselineOffset = Math.max(run.baselineOffset, (margin != null? margin.getTop() : 0)  + child.getBaselineOffset());
+                        }
+                    } else {
+                        if (Double.isNaN(layoutRect.height) || Math.abs(layoutRect.height - height) > EPSILON) {
+                            layoutRect.height = height;
+                            layoutRect.command = Command.RECALCULATE_LAYOUT;
+                        } else {
+                            layoutRect.command = (Math.abs(layoutRect.x - runOffset) > EPSILON || Math.abs(layoutRect.y - runLength) > EPSILON)?
+                                    Command.TRANSLATE_ONLY : Command.NONE;
+                        }
+                        layoutRect.x = runOffset;
+                        layoutRect.y = runLength;
+                        runLength += height + currentVGap;
+                        run.width = Math.max(run.width, width);
+                    }
+                    index++; 
+                }
+                // insert last run
+                normalizeRun(run, runLength, horizontal, currentHGap, currentVGap, vPos);
 
-            final List<Node> children = getChildren();
-            for (int i=0, size=children.size(); i<size; i++) {
-                Node child = children.get(i);
-                if (child.isManaged()) {
-                    LayoutRect nodeRect = new LayoutRect();
-                    nodeRect.node = child;
-                    Insets margin = getMargin(child);
-                    nodeRect.width = computeChildPrefAreaWidth(child, margin);
-                    nodeRect.height = computeChildPrefAreaHeight(child, margin);
-                    double nodeLength = getOrientation() == HORIZONTAL ? nodeRect.width : nodeRect.height;
-                    if (runLength + nodeLength > maxRunLength && runLength > 0) {
-                        // wrap to next run *unless* its the only node in the run
-                        normalizeRun(run, runOffset);
-                        if (getOrientation() == HORIZONTAL) {
-                            // horizontal
-                            runOffset += run.height + vgap;
-                        } else {
-                            // vertical
-                            runOffset += run.width + hgap;
-                        }
-                        runs.add(run);
-                        runLength = 0;
-                        run = new Run();
+                for (Iterator<LayoutRect> iterator = layoutRects.values().iterator(); iterator.hasNext(); ) {
+                    final LayoutRect rect = iterator.next();
+                    if (rect.toggle != currentToggle) {
+                        iterator.remove();
                     }
-                    if (getOrientation() == HORIZONTAL) {
-                        // horizontal
-                        nodeRect.x = runLength;
-                        runLength += nodeRect.width + hgap;
-                    } else {
-                        // vertical
-                        nodeRect.y = runLength;
-                        runLength += nodeRect.height + vgap;
-                    }
-                    run.rects.add(nodeRect);
                 }
-
+            } finally {
+                computingRuns = false;
             }
-            // insert last run
-            normalizeRun(run, runOffset);
-            runs.add(run);
-            computingRuns = false;
         }
         return runs;
     }
 
-    private void normalizeRun(Run run, double runOffset) {
-        if (getOrientation() == HORIZONTAL) {
-            // horizontal
-            ArrayList<Node> rownodes = new ArrayList();
-            run.width = (run.rects.size()-1)*snapSpace(getHgap());
-            Insets margins[] = new Insets[run.rects.size()];
-            for (int i=0, max=run.rects.size(); i<max; i++) {
-                LayoutRect lrect = run.rects.get(i);
-                margins[i] = getMargin(lrect.node);
-                rownodes.add(lrect.node);
-                run.width += lrect.width;
-                lrect.y = runOffset;
+    private void normalizeRun(Run run, double runLength, boolean horizontal, double currentHGap, double currentVGap, VPos vPos) {
+        if (horizontal) {
+            run.width = runLength - currentHGap;
+            if (vPos != VPos.BASELINE) {
+                run.baselineOffset = run.height;
             }
-            run.height = computeMaxPrefAreaHeight(rownodes, margins, getRowValignment());
-            run.baselineOffset = getRowValignment() == VPos.BASELINE? getMaxAreaBaselineOffset(rownodes, margins) : run.height;
+        } else {
+            run.height = runLength - currentVGap;
+            run.baselineOffset = run.height;
+        }
+        runs.add(run);
+    }
 
+    // MH: Move to Region once Richard pushed his changes
+    double computeChildPrefAreaHeight(Node child, Insets margin, VPos valignment) {
+        if (valignment == VPos.BASELINE) {
+            final double baseline = child.getBaselineOffset();
+            final double top = margin != null? snapSpace(margin.getTop()) : 0;
+            final double bottom = margin != null? snapSpace(margin.getBottom()) : 0;
+            final double above = baseline + top;
+            final double below = snapSpace(snapSize(child.prefHeight(-1)) - baseline + bottom);
+            return above + below;
         } else {
-            // vertical
-            run.height = (run.rects.size()-1)*snapSpace(getVgap());
-            double maxw = 0;
-            for (int i=0, max=run.rects.size(); i<max; i++) {
-                LayoutRect lrect = run.rects.get(i);
-                run.height += lrect.height;
-                lrect.x = runOffset;
-                maxw = Math.max(maxw, lrect.width);
-            }
-
-            run.width = maxw;
-            run.baselineOffset = run.height;
+            return computeChildPrefAreaHeight(child, margin);
         }
     }
 
@@ -699,31 +723,62 @@
         final double right = insets.getRight();
         final double insideWidth = width - left - right;
         final double insideHeight = height - top - bottom;
+        final List<Node> managedChildren = getManagedChildren();
+        final boolean horizontal = getOrientation() == HORIZONTAL;
+        final Pos currentAlignment = getAlignment();
+        final HPos hPos = currentAlignment.getHpos();
+        final VPos vPos = currentAlignment.getVpos();
+        final VPos rowAlignment = getRowValignment();
 
         //REMIND(aim): need to figure out how to cache the runs to avoid over-calculation
-        final List<Run> runs = getRuns(getOrientation() == HORIZONTAL ? insideWidth : insideHeight);
+        final List<Run> runs = getRuns(horizontal? insideWidth : insideHeight);
+        final double contentSize = horizontal? computeContentHeight(runs) : computeContentWidth(runs);
 
         // Now that the nodes are broken into runs, figure out alignments
         for (int i=0, max=runs.size(); i<max; i++) {
             final Run run = runs.get(i);
+            final int n = (i+1 == max)? managedChildren.size() : runs.get(i+1).index;
             final double xoffset = left + computeXOffset(insideWidth,
-                                     getOrientation() == HORIZONTAL ? run.width : computeContentWidth(runs),
-                                     getAlignment().getHpos());
+                                     horizontal? run.width : contentSize,
+                                     hPos);
             final double yoffset = top + computeYOffset(insideHeight,
-                                    getOrientation() == VERTICAL ? run.height : computeContentHeight(runs),
-                                    getAlignment().getVpos());
-            for (int j = 0; j < run.rects.size(); j++) {
-                final LayoutRect lrect = run.rects.get(j);
+                    !horizontal ? run.height : contentSize,
+                    vPos);
+            for (final Node node : managedChildren.subList(run.index, n)) {
 //              System.out.println("flowpane.layout: run="+i+" "+run.width+"x"+run.height+" xoffset="+xoffset+" yoffset="+yoffset+" lrect="+lrect);
-                final double x = xoffset + lrect.x;
-                final double y = yoffset + lrect.y;
-                layoutInArea(lrect.node, x, y,
-                           getOrientation() == HORIZONTAL? lrect.width : run.width,
-                           getOrientation() == VERTICAL? lrect.height : run.height,
-                           run.baselineOffset, getMargin(lrect.node),
-                           // only fill height if we don't have baseline alignment
-                           true, getOrientation() == VERTICAL || getRowValignment() != VPos.BASELINE,
-                           getColumnHalignment(), getRowValignment());
+                final LayoutRect rect = layoutRects.get(node);
+                assert rect != null;
+                if (horizontal) {
+                    if (Double.isNaN(rect.height) || Math.abs(rect.height - run.height) > EPSILON) {
+                        rect.height = run.height;
+                        rect.command = Command.RECALCULATE_LAYOUT;
+                    }
+                } else {
+                    if (Double.isNaN(rect.width) || Math.abs(rect.width - run.width) > EPSILON) {
+                        rect.width = run.width;
+                        rect.command = Command.RECALCULATE_LAYOUT;
+                    }
+                }
+                switch (rect.command) {
+                    case RECALCULATE_LAYOUT:
+                        layoutInArea(node, 
+                                xoffset + rect.x, yoffset + rect.y,
+                                rect.width, rect.height,
+                                run.baselineOffset, getMargin(node),
+                                // only fill height if we don't have baseline alignment
+                                true, !horizontal || rowAlignment != VPos.BASELINE,
+                                getColumnHalignment(), rowAlignment);
+                        break;
+                    case TRANSLATE_ONLY:
+                        // TODO: Check if child itself has changed
+                        positionInArea(node, 
+                                xoffset + rect.x, yoffset + rect.y, 
+                                rect.width, rect.height, 
+                                run.baselineOffset, getMargin(node), 
+                                getColumnHalignment(), rowAlignment, 
+                                isSnapToPixel());
+                        break;
+                }
             }
         }
     }
@@ -883,23 +938,23 @@
         return impl_CSS_STYLEABLES();
     }
 
-    //REMIND(aim); replace when we get mutable rects
     private static class LayoutRect {
-        public Node node;
-        double x;
-        double y;
+        double x = Double.NaN;
+        double y = Double.NaN;
+        double width = Double.NaN;
+        double height = Double.NaN;
+        boolean toggle;
+        Command command;
+    }
+
+    private static class Run {
+        final int index;
         double width;
         double height;
-
-        @Override public String toString() {
-            return "LayoutRect node id="+node.getId()+" "+x+","+y+" "+width+"x"+height;
+        double baselineOffset;
+        Run(int index) {
+            this.index = index;
         }
     }
 
-    private static class Run {
-        ArrayList<LayoutRect> rects = new ArrayList();
-        double width;
-        double height;
-        double baselineOffset;
-    }
 }
