# HG changeset patch # Parent 9d38b97a2595c84954b84a4e9e59e67c263d72ee diff -r 9d38b97a2595 javafx-ui-common/src/com/sun/javafx/css/SimpleSelector.java --- a/javafx-ui-common/src/com/sun/javafx/css/SimpleSelector.java Tue Feb 21 21:44:27 2012 -0800 +++ b/javafx-ui-common/src/com/sun/javafx/css/SimpleSelector.java Thu Feb 23 07:54:27 2012 -0800 @@ -47,11 +47,7 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; import javafx.scene.Node; import javafx.scene.Scene; @@ -62,7 +58,7 @@ */ final public class SimpleSelector extends Selector { static final private Object MAX_CLASS_DEPTH = 255; - + /** * If specified in the CSS file, the name of the java class to which * this selector is applied. For example, if the CSS file had: @@ -79,8 +75,8 @@ return name; } - final private List styleClasses; + /** * @return Immutable List<String> of style-classes of the selector */ @@ -131,7 +127,7 @@ ? Collections.unmodifiableList(styleClasses) : Collections.EMPTY_LIST; this.matchOnStyleClass = (this.styleClasses.size() > 0); - + this.pseudoclasses = (pseudoclasses != null) ? Collections.unmodifiableList(pseudoclasses) @@ -180,8 +176,7 @@ } @Override - public boolean applies(final Node node) - { + public boolean applies(final Node node) { // if the selector has an id, // then bail if it doesn't match the node's id // (do this first since it is potentially the cheapest check) @@ -216,16 +211,13 @@ @Override boolean stateMatches(final Node node, long states) { - return ((pclassMask & states) == pclassMask); - } /* * Optimized className.equals(name) || className.endsWith(".".concat(name)). */ - private boolean nameMatchesAtEnd(final String className) - { + private boolean nameMatchesAtEnd(final String className) { // if name is null or empty, why bother? if (!matchOnName) return false; @@ -241,7 +233,6 @@ return className.regionMatches(dotPos+1, this.name, 0, nameLen); } return false; - } // Are the Selector's style classes a subset of the Node's style classes? @@ -270,7 +261,6 @@ * in seq1 are contained in seq2 */ boolean isSubsetOf(final List seq1, final List seq2) { - // if one or the other is null, then they are a subset if both are null if (seq1 == null || seq2 == null) return seq1 == null && seq2 == null; diff -r 9d38b97a2595 javafx-ui-common/src/javafx/scene/Parent.java --- a/javafx-ui-common/src/javafx/scene/Parent.java Tue Feb 21 21:44:27 2012 -0800 +++ b/javafx-ui-common/src/javafx/scene/Parent.java Thu Feb 23 07:54:27 2012 -0800 @@ -797,6 +797,8 @@ private double prefWidthCache = -1; private double prefHeightCache = -1; + private double minWidthCache = -1; + private double minHeightCache = -1; /** * Requests a layout pass to be performed before the next scene is @@ -808,14 +810,18 @@ * will be invoked on its parent. */ public void requestLayout() { + prefWidthCache = -1; + prefHeightCache = -1; + minWidthCache = -1; + minHeightCache = -1; + if (!isNeedsLayout()) { - prefWidthCache = -1; - prefHeightCache = -1; - setNeedsLayout(true); PlatformLogger logger = Logging.getLayoutLogger(); if (logger.isLoggable(PlatformLogger.FINER)) { logger.finer(this.toString()); } + + setNeedsLayout(true); if (isLayoutRoot()) { if (getScene() != null) { if (logger.isLoggable(PlatformLogger.FINER)) { @@ -826,18 +832,6 @@ } else if (getParent() != null) { getParent().requestLayout(); } - } else { - clearPrefSizeCache(); - } - } - - void clearPrefSizeCache() { - prefWidthCache = -1; - prefHeightCache = -1; - if (!isLayoutRoot()) { - if (getParent() != null) { - getParent().clearPrefSizeCache(); - } } } @@ -863,6 +857,28 @@ } } + @Override public double minWidth(double height) { + if (height == -1) { + if (minWidthCache == -1) { + minWidthCache = computeMinWidth(-1); + } + return minWidthCache; + } else { + return computeMinWidth(height); + } + } + + @Override public double minHeight(double width) { + if (width == -1) { + if (minHeightCache == -1) { + minHeightCache = computeMinHeight(-1); + } + return minHeightCache; + } else { + return computeMinHeight(width); + } + } + // PENDING_DOC_REVIEW /** * Calculates the preferred width of this {@code Parent}. The default @@ -914,6 +930,31 @@ } /** + * Calculates the minimum width of this {@code Parent}. The default + * implementation simply returns the pref width. + * + * @param height the height that should be used if min width depends + * on it + * @return the calculated min width + */ + protected double computeMinWidth(double height) { + return super.prefWidth(height); + } + + // PENDING_DOC_REVIEW + /** + * Calculates the min height of this {@code Parent}. The default + * implementation simply returns the pref height; + * + * @param width the width that should be used if min height depends + * on it + * @return the calculated min height + */ + protected double computeMinHeight(double width) { + return super.prefHeight(width); + } + + /** * Calculates the baseline offset based on the first managed child. If there * is no such child, returns {@link Node#getBaselineOffset()}. * diff -r 9d38b97a2595 javafx-ui-common/src/javafx/scene/layout/Region.java --- a/javafx-ui-common/src/javafx/scene/layout/Region.java Tue Feb 21 21:44:27 2012 -0800 +++ b/javafx-ui-common/src/javafx/scene/layout/Region.java Thu Feb 23 07:54:27 2012 -0800 @@ -1327,7 +1327,7 @@ @Override public final double minWidth(double height) { double override = getMinWidth(); if (override == USE_COMPUTED_SIZE) { - return computeMinWidth(height); + return super.minWidth(height); } else if (override == USE_PREF_SIZE) { return prefWidth(height); } @@ -1345,7 +1345,7 @@ @Override public final double minHeight(double width) { double override = getMinHeight(); if (override == USE_COMPUTED_SIZE) { - return computeMinHeight(width); + return super.minHeight(width); } else if (override == USE_PREF_SIZE) { return prefHeight(width); } diff -r 9d38b97a2595 javafx-ui-controls/src/javafx/scene/control/Control.java --- a/javafx-ui-controls/src/javafx/scene/control/Control.java Tue Feb 21 21:44:27 2012 -0800 +++ b/javafx-ui-controls/src/javafx/scene/control/Control.java Thu Feb 23 07:54:27 2012 -0800 @@ -625,7 +625,7 @@ @Override public final double minWidth(double height) { double override = getMinWidth(); if (override == USE_COMPUTED_SIZE) { - return computeMinWidth(height); + return super.minWidth(height); } else if (override == USE_PREF_SIZE) { return prefWidth(height); } @@ -643,7 +643,7 @@ @Override public final double minHeight(double width) { double override = getMinHeight(); if (override == USE_COMPUTED_SIZE) { - return computeMinHeight(width); + return super.minHeight(width); } else if (override == USE_PREF_SIZE) { return prefHeight(width); } @@ -747,7 +747,7 @@ * the minimum width. * @return A double representing the minimum width of this control. */ - protected double computeMinWidth(double height) { + @Override protected double computeMinWidth(double height) { return getSkinNode() == null ? 0 : getSkinNode().minWidth(height); } /** @@ -760,7 +760,7 @@ * the minimum height. * @return A double representing the minimum height of this control. */ - protected double computeMinHeight(double width) { + @Override protected double computeMinHeight(double width) { return getSkinNode() == null ? 0 : getSkinNode().minHeight(width); } /** diff -r 9d38b97a2595 javafx-ui-controls/src/javafx/scene/control/PopupControl.java --- a/javafx-ui-controls/src/javafx/scene/control/PopupControl.java Tue Feb 21 21:44:27 2012 -0800 +++ b/javafx-ui-controls/src/javafx/scene/control/PopupControl.java Thu Feb 23 07:54:27 2012 -0800 @@ -114,6 +114,12 @@ // given to match the popup window's width & height. } + // TODO we should have some interface which has id, styleClass, style, etc + // which is in common between PopupControl and Node. + + // TODO we should have some interface for minWidth, maxWidth, etc which are + // both here and on Node. + /** * The id of this {@code Node}. This simple string identifier is useful for * finding a specific Node within the scene graph. While the id of a Node @@ -137,6 +143,8 @@ * @defaultValue null */ private final ObservableList styleClass = new TrackableObservableList() { + // TODO we can save one class if we factor this into a StyleClassList, and reuse it between + // here and in Node. @Override protected void onChanged(Change c) { // Push the change along to the bridge group bridge.getStyleClass().setAll(styleClass); @@ -189,13 +197,6 @@ skinProperty().set(value); } @Override public final Skin getSkin() { - if (getScene() != null && getScene().getRoot() != null) { - // RT-14094, RT-16754: We need the skins of the popup - // and it children before the stage is visible so we - // can calculate the popup position based on content - // size. - getScene().getRoot().impl_processCSS(true); - } return skinProperty().getValue(); } @@ -477,6 +478,20 @@ } /** + * Cached prefWidth, prefHeight, minWidth, minHeight. These + * results are repeatedly sought during the layout pass, + * and caching the results leads to a significant decrease + * in overhead. + */ + private double prefWidthCache = -1; + private double prefHeightCache = -1; + private double minWidthCache = -1; + private double minHeightCache = -1; + private double maxWidthCache = -1; + private double maxHeightCache = -1; + private boolean skinSizeComputed = false; + + /** * Called during layout to determine the minimum width for this node. * Returns the value from minWidth(forHeight) unless * the application overrode the minimum width by setting the minWidth property. @@ -488,7 +503,8 @@ public final double minWidth(double height) { double override = getMinWidth(); if (override == USE_COMPUTED_SIZE) { - return recalculateMinWidth(height); + if (minWidthCache == -1) minWidthCache = recalculateMinWidth(height); + return minWidthCache; } else if (override == USE_PREF_SIZE) { return prefWidth(height); } @@ -507,7 +523,8 @@ public final double minHeight(double width) { double override = getMinHeight(); if (override == USE_COMPUTED_SIZE) { - return recalculateMinHeight(width); + if (minHeightCache == -1) minHeightCache = recalculateMinHeight(width); + return minHeightCache; } else if (override == USE_PREF_SIZE) { return prefHeight(width); } @@ -527,7 +544,8 @@ public final double prefWidth(double height) { double override = getPrefWidth(); if (override == USE_COMPUTED_SIZE) { - return recalculatePrefWidth(height); + if (prefWidthCache == -1) prefWidthCache = recalculatePrefWidth(height); + return prefWidthCache; } else if (override == USE_PREF_SIZE) { return prefWidth(height); } @@ -546,7 +564,8 @@ public final double prefHeight(double width) { double override = getPrefHeight(); if (override == USE_COMPUTED_SIZE) { - return recalculatePrefHeight(width); + if (prefHeightCache == -1) prefHeightCache = recalculatePrefHeight(width); + return prefHeightCache; } else if (override == USE_PREF_SIZE) { return prefHeight(width); } @@ -565,7 +584,8 @@ public final double maxWidth(double height) { double override = getMaxWidth(); if (override == USE_COMPUTED_SIZE) { - return recalculateMaxWidth(height); + if (maxWidthCache == -1) maxWidthCache = recalculateMaxWidth(height); + return maxWidthCache; } else if (override == USE_PREF_SIZE) { return prefWidth(height); } @@ -584,7 +604,8 @@ public final double maxHeight(double width) { double override = getMaxHeight(); if (override == USE_COMPUTED_SIZE) { - return recalculateMaxHeight(width); + if (maxHeightCache == -1) maxHeightCache = recalculateMaxHeight(width); + return maxHeightCache; } else if (override == USE_PREF_SIZE) { return prefHeight(width); } @@ -597,23 +618,40 @@ // we simply return 0 for all the values since a Control without a Skin // doesn't render private double recalculateMinWidth(double height) { + recomputeSkinSize(); return getSkinNode() == null ? 0 : getSkinNode().minWidth(height); } private double recalculateMinHeight(double width) { + recomputeSkinSize(); return getSkinNode() == null ? 0 : getSkinNode().minHeight(width); } private double recalculateMaxWidth(double height) { + recomputeSkinSize(); return getSkinNode() == null ? 0 : getSkinNode().maxWidth(height); } private double recalculateMaxHeight(double width) { + recomputeSkinSize(); return getSkinNode() == null ? 0 : getSkinNode().maxHeight(width); } private double recalculatePrefWidth(double height) { + recomputeSkinSize(); return getSkinNode() == null? 0 : getSkinNode().prefWidth(height); } private double recalculatePrefHeight(double width) { + recomputeSkinSize(); return getSkinNode() == null? 0 : getSkinNode().prefHeight(width); } + + private void recomputeSkinSize() { + if (!skinSizeComputed && getScene() != null && getScene().getRoot() != null) { + // RT-14094, RT-16754: We need the skins of the popup + // and it children before the stage is visible so we + // can calculate the popup position based on content + // size. + getScene().getRoot().impl_processCSS(true); + skinSizeComputed = true; + } + } // public double getBaselineOffset() { return getSkinNode() == null? 0 : getSkinNode().getBaselineOffset(); } /** @@ -622,6 +660,13 @@ * the skin changes, or the skin.node changes). */ private void updateChildren() { + prefWidthCache = -1; + prefHeightCache = -1; + minWidthCache = -1; + minHeightCache = -1; + maxWidthCache = -1; + maxHeightCache = -1; + skinSizeComputed = false; final Node n = getSkinNode(); if (n != null) bridge.getChildren().setAll(n); else bridge.getChildren().clear(); @@ -696,7 +741,6 @@ * @deprecated This is an experimental API that is not intended for general use and is subject to change in future versions */ public Styleable impl_getStyleable() { - if (styleable == null) { styleable = new Styleable() { @@ -746,6 +790,26 @@ } /** + * Requests a layout pass to be performed before the next scene is + * rendered. This is batched up asynchronously to happen once per + * "pulse", or frame of animation. + *

+ * If this parent is either a layout root or unmanaged, then it will be + * added directly to the scene's dirty layout list, otherwise requestLayout + * will be invoked on its parent. + */ + @Override public void requestLayout() { + prefWidthCache = -1; + prefHeightCache = -1; + minWidthCache = -1; + minHeightCache = -1; + maxWidthCache = -1; + maxHeightCache = -1; + skinSizeComputed = false; + super.requestLayout(); + } + + /** * Skin is responsible for rendering this {@code PopupControl}. From the * perspective of the {@code PopupControl}, the {@code Skin} is a black box. * It listens and responds to changes in state in a {@code PopupControl}.