changeset 5512:70401ef2c3cd

RT-10604: Caching local bounds, removed double computing of effect bounds. Reviewed-by: Eva Krejcirova
author Pavel Safrata <pavel.safrata@oracle.com>
date Thu, 24 Oct 2013 09:15:02 +0100
parents e3c32ab8f05f
children c81922444345
files modules/graphics/src/main/java/javafx/scene/Node.java
diffstat 1 files changed, 94 insertions(+), 41 deletions(-) [+]
line wrap: on
line diff
--- a/modules/graphics/src/main/java/javafx/scene/Node.java	Thu Oct 24 09:26:59 2013 +0200
+++ b/modules/graphics/src/main/java/javafx/scene/Node.java	Thu Oct 24 09:15:02 2013 +0100
@@ -3290,6 +3290,14 @@
     private BaseBounds geomBounds = new RectBounds();
 
     /**
+     * The cached local bounds (without transforms, with clip and effects).
+     * If there is neither clip nor effect
+     * local bounds are equal to geom bounds, so in this case we don't keep
+     * the extra instance and set null to this variable.
+     */
+    private BaseBounds localBounds = null;
+
+    /**
      * This special flag is used only by Parent to flag whether or not
      * the *parent* has processed the fact that bounds have changed for this
      * child Node. We need some way of flagging this on a per-node basis to
@@ -3413,36 +3421,42 @@
      * to promote from a RectBounds to a BoxBounds (3D).
      */
     BaseBounds getLocalBounds(BaseBounds bounds, BaseTransform tx) {
-        if (getEffect() != null || getClip() != null) {
-            // We either get the bounds of the effect (if it isn't null)
-            // or we get the geom bounds (if effect is null). We will then
-            // intersect this with the clip.
-            if (getEffect() != null) {
-                BaseBounds b = getEffect().impl_getBounds(bounds, tx, this, boundsAccessor);
-                bounds = bounds.deriveWithNewBounds(b);
-            } else {
-                bounds = getGeomBounds(bounds, tx);
-            }
-            // intersect with the clip. Take care with "bounds" as it may
-            // actually be TEMP_BOUNDS, so we save off state
-            if (getClip() != null) {
-                //TODO: For 3D case the intersecting transformed bounds and
-                //      transformed clip will not produce the correct bounds.
-                double x1 = bounds.getMinX();
-                double y1 = bounds.getMinY();
-                double x2 = bounds.getMaxX();
-                double y2 = bounds.getMaxY();
-                double z1 = bounds.getMinZ();
-                double z2 = bounds.getMaxZ();
-                bounds = getClip().getTransformedBounds(bounds, tx);
-                bounds.intersectWith((float)x1, (float)y1, (float)z1,
-                        (float)x2, (float)y2, (float)z2);
-            }
-            // return the bounds
+        if (getEffect() == null && getClip() == null) {
+            return getGeomBounds(bounds, tx);
+        }
+
+        if (tx.isTranslateOrIdentity()) {
+            // we can take a fast path since we know tx is either a simple
+            // translation or is identity
+            updateLocalBounds();
+            bounds = bounds.deriveWithNewBounds(localBounds);
+            if (!tx.isIdentity()) {
+                double translateX = tx.getMxt();
+                double translateY = tx.getMyt();
+                double translateZ = tx.getMzt();
+                bounds = bounds.deriveWithNewBounds((float) (bounds.getMinX() + translateX),
+                        (float) (bounds.getMinY() + translateY),
+                        (float) (bounds.getMinZ() + translateZ),
+                        (float) (bounds.getMaxX() + translateX),
+                        (float) (bounds.getMaxY() + translateY),
+                        (float) (bounds.getMaxZ() + translateZ));
+            }
             return bounds;
+        } else if (tx.is2D()
+                && (tx.getType()
+                & ~(BaseTransform.TYPE_UNIFORM_SCALE | BaseTransform.TYPE_TRANSLATION
+                | BaseTransform.TYPE_FLIP | BaseTransform.TYPE_QUADRANT_ROTATION)) != 0) {
+            // this is a non-uniform scale / non-quadrant rotate / skew transform
+            return computeLocalBounds(bounds, tx);
         } else {
-            // fast path, simply return geom bounds
-            return getGeomBounds(bounds, tx);
+            // 3D transformations and
+            // selected 2D transformations (unifrom transform, flip, quadrant rotation).
+            // These 2D transformation will yield tight bounds when applied on the pre-computed
+            // geomBounds
+            // Note: Transforming the local bounds into a 3D space will yield a bounds
+            // that isn't as tight as transforming its geometry and compute it bounds.
+            updateLocalBounds();
+            return tx.transform(localBounds, bounds);
         }
     }
 
@@ -3502,7 +3516,7 @@
     public abstract BaseBounds impl_computeGeomBounds(BaseBounds bounds, BaseTransform tx);
 
     /**
-     * If necessary, recomputes the cached local bounds. If the bounds are not
+     * If necessary, recomputes the cached geom bounds. If the bounds are not
      * invalid, then this method is a no-op.
      */
     void updateGeomBounds() {
@@ -3513,6 +3527,55 @@
     }
 
     /**
+     * Computes the local bounds of this Node.
+     */
+    private BaseBounds computeLocalBounds(BaseBounds bounds, BaseTransform tx) {
+        // We either get the bounds of the effect (if it isn't null)
+        // or we get the geom bounds (if effect is null). We will then
+        // intersect this with the clip.
+        if (getEffect() != null) {
+            BaseBounds b = getEffect().impl_getBounds(bounds, tx, this, boundsAccessor);
+            bounds = bounds.deriveWithNewBounds(b);
+        } else {
+            bounds = getGeomBounds(bounds, tx);
+        }
+        // intersect with the clip. Take care with "bounds" as it may
+        // actually be TEMP_BOUNDS, so we save off state
+        if (getClip() != null) {
+            //TODO: For 3D case the intersecting transformed bounds and
+            //      transformed clip will not produce the correct bounds.
+            double x1 = bounds.getMinX();
+            double y1 = bounds.getMinY();
+            double x2 = bounds.getMaxX();
+            double y2 = bounds.getMaxY();
+            double z1 = bounds.getMinZ();
+            double z2 = bounds.getMaxZ();
+            bounds = getClip().getTransformedBounds(bounds, tx);
+            bounds.intersectWith((float)x1, (float)y1, (float)z1,
+                    (float)x2, (float)y2, (float)z2);
+        }
+        return bounds;
+    }
+
+
+    /**
+     * If necessary, recomputes the cached local bounds. If the bounds are not
+     * invalid, then this method is a no-op.
+     */
+    private void updateLocalBounds() {
+        if (localBoundsInvalid) {
+            if (getClip() != null || getEffect() != null) {
+                localBounds = computeLocalBounds(
+                        localBounds == null ? new RectBounds() : localBounds,
+                        BaseTransform.IDENTITY_TRANSFORM);
+            } else {
+                localBounds = null;
+            }
+            localBoundsInvalid = false;
+        }
+    }
+
+    /**
      * If necessary, recomputes the cached transformed bounds.
      * If the cached transformed bounds are not invalid, then
      * this method is a no-op.
@@ -3694,6 +3757,7 @@
     }
 
     private boolean geomBoundsInvalid = true;
+    private boolean localBoundsInvalid = true;
     private boolean txBoundsInvalid = true;
 
     /**
@@ -3701,6 +3765,7 @@
      * and notifying this node that its transformed bounds have changed.
      */
     void localBoundsChanged() {
+        localBoundsInvalid = true;
         invalidateBoundsInLocal();
         transformedBoundsChanged();
     }
@@ -3824,18 +3889,6 @@
                     return false;
                 }
             }
-            // if there is an effect, then we need to check the effect
-            // for containment as well.
-            if (getEffect() != null) {
-                tempBounds = getEffect().impl_getBounds(
-                                    tempBounds,
-                                    BaseTransform.IDENTITY_TRANSFORM,
-                                    this, boundsAccessor);
-
-                if (!tempBounds.contains((float)localX, (float)localY)) {
-                    return false;
-                }
-            }
             return true;
         }
         return false;