< prev index next >

modules/javafx.graphics/src/main/java/javafx/scene/Node.java

Print this page




 290  * the node about a specified "pivot" point, causing the node to appear rotated.
 291  * For example, if you create a {@link javafx.scene.shape.Rectangle} which is
 292  * drawn at the origin (x=0, y=0) and has a width of 100 and height of 30 and
 293  * you apply a {@link javafx.scene.transform.Rotate} with a 90 degree rotation
 294  * (angle=90) and a pivot at the origin (pivotX=0, pivotY=0), then
 295  * the rectangle will be drawn as if its x and y were zero but its height was
 296  * 100 and its width -30. That is, it is as if a pin is being stuck at the top
 297  * left corner and the rectangle is rotating 90 degrees clockwise around that
 298  * pin. If the pivot point is instead placed in the center of the rectangle
 299  * (at point x=50, y=15) then the rectangle will instead appear to rotate about
 300  * its center.
 301  * <p>
 302  * Note that as with all transformations, the x, y, width, and height variables
 303  * of the rectangle (which remain relative to the local coordinate space) have
 304  * not changed, but rather the transformation alters the entire coordinate space
 305  * of the rectangle.
 306  * <p>
 307  * A <b>scaling</b> transformation causes a node to either appear larger or
 308  * smaller depending on the scaling factor. Scaling alters the coordinate space
 309  * of the node such that each unit of distance along the axis in local
 310  * coordinates is multipled by the scale factor. As with rotation
 311  * transformations, scaling transformations are applied about a "pivot" point.
 312  * You can think of this as the point in the Node around which you "zoom".  For
 313  * example, if you create a {@link javafx.scene.shape.Rectangle} with a
 314  * {@code strokeWidth} of 5, and a width and height of 50, and you apply a
 315  * {@link javafx.scene.transform.Scale} with scale factors (x=2.0, y=2.0) and
 316  * a pivot at the origin (pivotX=0, pivotY=0), the entire rectangle
 317  * (including the stroke) will double in size, growing to the right and
 318  * downwards from the origin.
 319  * <p>
 320  * A <b>shearing</b> transformation, sometimes called a skew, effectively
 321  * rotates one axis so that the x and y axes are no longer perpendicular.
 322  * <p>
 323  * Multiple transformations may be applied to a node by specifying an ordered
 324  * chain of transforms.  The order in which the transforms are applied is
 325  * defined by the ObservableList specified in the {@link #getTransforms transforms} variable.
 326  *
 327  * <h3>Bounding Rectangles</h3>
 328  * <p>
 329  * Since every {@code Node} has transformations, every Node's geometric
 330  * bounding rectangle can be described differently depending on whether


2054         node.syncPeer();
2055         if (node instanceof Parent) {
2056             Parent p = (Parent) node;
2057             final int childrenCount = p.getChildren().size();
2058 
2059             for (int i = 0; i < childrenCount; i++) {
2060                 Node n = p.getChildren().get(i);
2061                 if (n != null) {
2062                     syncAll(n);
2063                 }
2064             }
2065         }
2066         if (node.getClip() != null) {
2067             syncAll(node.getClip());
2068         }
2069     }
2070 
2071     private void doLayoutPass() {
2072         if (this instanceof Parent) {
2073             // TODO: As an optimization we only need to layout those dirty
2074             // roots that are descendents of this node
2075             Parent p = (Parent)this;
2076             for (int i = 0; i < 3; i++) {
2077                 p.layout();
2078             }
2079         }
2080     }
2081 
2082     private void doCSSLayoutSyncForSnapshot() {
2083         doCSSPass();
2084         doLayoutPass();
2085         updateBounds();
2086         Scene.setAllowPGAccess(true);
2087         syncAll(this);
2088         Scene.setAllowPGAccess(false);
2089     }
2090 
2091     private WritableImage doSnapshot(SnapshotParameters params, WritableImage img) {
2092         if (getScene() != null) {
2093             getScene().doCSSLayoutSyncForSnapshot(this);
2094         } else {


3228             return getLayoutBounds().getHeight();
3229         }
3230     }
3231 
3232     /**
3233      * Returns the area of this {@code Node} projected onto the
3234      * physical screen in pixel units.
3235      * @return the area of this {@code Node} projected onto the physical screen
3236      * @since JavaFX 8.0
3237      */
3238     public double computeAreaInScreen() {
3239         return doComputeAreaInScreen();
3240     }
3241 
3242     /*
3243      * Help application or utility to implement LOD support by returning the
3244      * projected area of a Node in pixel unit. The projected area is not clipped.
3245      *
3246      * For perspective camera, this method first exams node's bounds against
3247      * camera's clipping plane to cut off those out of viewing frustrum. After
3248      * computing areaInScreen, it applys a tight viewing frustrum check using
3249      * canonical view volume.
3250      *
3251      * The result of areaInScreen comes from the product of
3252      * (projViewTx x localToSceneTransform x localBounds).
3253      *
3254      * Returns 0 for those fall outside viewing frustrum.
3255      */
3256     private double doComputeAreaInScreen() {
3257         Scene tmpScene = getScene();
3258         if (tmpScene != null) {
3259             Bounds bounds = getBoundsInLocal();
3260             Camera camera = tmpScene.getEffectiveCamera();
3261             boolean isPerspective = camera instanceof PerspectiveCamera ? true : false;
3262             Transform localToSceneTx = getLocalToSceneTransform();
3263             Affine3D tempTx = TempState.getInstance().tempTx;
3264             BaseBounds localBounds = new BoxBounds((float) bounds.getMinX(),
3265                                                    (float) bounds.getMinY(),
3266                                                    (float) bounds.getMinZ(),
3267                                                    (float) bounds.getMaxX(),
3268                                                    (float) bounds.getMaxY(),


3315                         maxZ = nodeInSceneBounds.getMaxZ();
3316                     }
3317 
3318                     if (minZ > camera.getFarClipInScene()
3319                             || maxZ < camera.getNearClipInScene()) {
3320                         return 0;
3321                     }
3322 
3323                 } else {
3324                     BaseBounds nodeInCameraBounds = new BoxBounds();
3325 
3326                     // We need to set tempTx to identity since it is a recycled transform.
3327                     // This is because TransformHelper.apply() is a matrix concatenation operation.
3328                     tempTx.setToIdentity();
3329                     TransformHelper.apply(localToSceneTx, tempTx);
3330 
3331                     // Convert node from local coordinate to camera coordinate
3332                     tempTx.preConcatenate(camera.getSceneToLocalTransform());
3333                     tempTx.transform(localBounds, nodeInCameraBounds);
3334 
3335                     // Compare in camera coornidate
3336                     if (nodeInCameraBounds.getMinZ() > camera.getFarClip()
3337                             || nodeInCameraBounds.getMaxZ() < camera.getNearClip()) {
3338                         return 0;
3339                     }
3340                 }
3341             }
3342 
3343             GeneralTransform3D projViewTx = TempState.getInstance().projViewTx;
3344             projViewTx.set(camera.getProjViewTransform());
3345 
3346             // We need to set tempTx to identity since it is a recycled transform.
3347             // This is because TransformHelper.apply() is a matrix concatenation operation.
3348             tempTx.setToIdentity();
3349             TransformHelper.apply(localToSceneTx, tempTx);
3350 
3351             // The product of projViewTx * localToSceneTransform
3352             GeneralTransform3D tx = projViewTx.mul(tempTx);
3353 
3354             // Transform localBounds to projected bounds
3355             localBounds = tx.transform(localBounds, localBounds);


3751             if (!tx.isIdentity()) {
3752                 double translateX = tx.getMxt();
3753                 double translateY = tx.getMyt();
3754                 double translateZ = tx.getMzt();
3755                 bounds = bounds.deriveWithNewBounds((float) (bounds.getMinX() + translateX),
3756                         (float) (bounds.getMinY() + translateY),
3757                         (float) (bounds.getMinZ() + translateZ),
3758                         (float) (bounds.getMaxX() + translateX),
3759                         (float) (bounds.getMaxY() + translateY),
3760                         (float) (bounds.getMaxZ() + translateZ));
3761             }
3762             return bounds;
3763         } else if (tx.is2D()
3764                 && (tx.getType()
3765                 & ~(BaseTransform.TYPE_UNIFORM_SCALE | BaseTransform.TYPE_TRANSLATION
3766                 | BaseTransform.TYPE_FLIP | BaseTransform.TYPE_QUADRANT_ROTATION)) != 0) {
3767             // this is a non-uniform scale / non-quadrant rotate / skew transform
3768             return computeLocalBounds(bounds, tx);
3769         } else {
3770             // 3D transformations and
3771             // selected 2D transformations (unifrom transform, flip, quadrant rotation).
3772             // These 2D transformation will yield tight bounds when applied on the pre-computed
3773             // geomBounds
3774             // Note: Transforming the local bounds into a 3D space will yield a bounds
3775             // that isn't as tight as transforming its geometry and compute it bounds.
3776             updateLocalBounds();
3777             return tx.transform(localBounds, bounds);
3778         }
3779     }
3780 
3781     /**
3782      * Loads the given bounds object with the geometric bounds relative to,
3783      * and based on, the given transform.
3784      *
3785      * We *never* pass null in as a bounds. This method will
3786      * NOT take a null bounds object. The returned value may be
3787      * the same bounds object passed in, or it may be a new object.
3788      * The reason for this object promotion is in the case of needing
3789      * to promote from a RectBounds to a BoxBounds (3D).
3790      */
3791     BaseBounds getGeomBounds(BaseBounds bounds, BaseTransform tx) {


4261      * {@link javafx.stage.Screen} into the local coordinate space of this
4262      * {@code Node}. Returns reasonable result only in 2D space.
4263      * @param screenBounds bounds on a Screen
4264      * @return bounds in the local Node'space or null if Node is not in a {@link Window}.
4265      * Null is also returned if the transformation from local to Scene is not invertible.
4266      * @since JavaFX 8.0
4267      */
4268     public Bounds screenToLocal(Bounds screenBounds) {
4269         final Point2D p1 = screenToLocal(screenBounds.getMinX(), screenBounds.getMinY());
4270         final Point2D p2 = screenToLocal(screenBounds.getMinX(), screenBounds.getMaxY());
4271         final Point2D p3 = screenToLocal(screenBounds.getMaxX(), screenBounds.getMinY());
4272         final Point2D p4 = screenToLocal(screenBounds.getMaxX(), screenBounds.getMaxY());
4273 
4274         return BoundsUtils.createBoundingBox(p1, p2, p3, p4);
4275     }
4276 
4277 
4278     /**
4279      * Transforms a point from the coordinate space of the scene
4280      * into the local coordinate space of this {@code Node}.
4281      * If the Node does not have any {@link SubScene} or {@code rootScene} is set to true, the arguments are in {@link Scene} coordinates
4282      * of the Node returned by {@link #getScene()}. Othwerwise, the subscene coordinates are used, which is equivalent to calling
4283      * {@link #sceneToLocal(double, double)}


4284      * @param x the x coordinate
4285      * @param y the y coordinate
4286      * @param rootScene whether Scene coordinates should be used even if the Node is in a SubScene
4287      * @return local coordinates of the point
4288      * @since JavaFX 8u40
4289      */
4290     public Point2D sceneToLocal(double x, double y, boolean rootScene) {
4291         if (!rootScene) {
4292             return sceneToLocal(x, y);
4293         }
4294         final com.sun.javafx.geom.Point2D tempPt =
4295                 TempState.getInstance().point;
4296 
4297         tempPt.setLocation((float)(x), (float)y);
4298 
4299         final SubScene subScene = getSubScene();
4300         if (subScene != null) {
4301             final Point2D ssCoord = SceneUtils.sceneToSubScenePlane(subScene,
4302                     new Point2D(tempPt.x, tempPt.y));
4303             if (ssCoord == null) {
4304                 return null;
4305             }
4306             tempPt.setLocation((float) ssCoord.getX(), (float) ssCoord.getY());
4307         }
4308 
4309         try {
4310             sceneToLocal(tempPt);
4311             return new Point2D(tempPt.x, tempPt.y);
4312         } catch (NoninvertibleTransformException e) {
4313             return null;
4314         }
4315     }
4316 
4317     /**
4318      * Transforms a point from the coordinate space of the scene
4319      * into the local coordinate space of this {@code Node}.
4320      * If the Node does not have any {@link SubScene} or {@code rootScene} is set to true, the arguments are in {@link Scene} coordinates
4321      * of the Node returned by {@link #getScene()}. Othwerwise, the subscene coordinates are used, which is equivalent to calling
4322      * {@link #sceneToLocal(javafx.geometry.Point2D)}


4323      * @param point the point
4324      * @param rootScene whether Scene coordinates should be used even if the Node is in a SubScene
4325      * @return local coordinates of the point
4326      * @since JavaFX 8u40
4327      */
4328     public Point2D sceneToLocal(Point2D point, boolean rootScene) {
4329         return sceneToLocal(point.getX(), point.getY(), rootScene);
4330     }
4331 
4332     /**
4333      * Transforms a bounds from the coordinate space of the scene
4334      * into the local coordinate space of this {@code Node}.
4335      * If the Node does not have any {@link SubScene} or {@code rootScene} is set to true, the arguments are in {@link Scene} coordinates
4336      * of the Node returned by {@link #getScene()}. Othwerwise, the subscene coordinates are used, which is equivalent to calling

4337      * {@link #sceneToLocal(javafx.geometry.Bounds)}.
4338      * <p>
4339      *     Since 3D bounds cannot be converted with {@code rootScene} set to {@code true}, trying to convert 3D bounds will yield {@code null}.
4340      * </p>
4341      * @param bounds the bounds
4342      * @param rootScene whether Scene coordinates should be used even if the Node is in a SubScene
4343      * @return local coordinates of the bounds
4344      * @since JavaFX 8u40
4345      */
4346     public Bounds sceneToLocal(Bounds bounds, boolean rootScene) {
4347         if (!rootScene) {
4348             return sceneToLocal(bounds);
4349         }
4350         if (bounds.getMinZ() != 0 || bounds.getMaxZ() != 0) {
4351             return null;
4352         }
4353         final Point2D p1 = sceneToLocal(bounds.getMinX(), bounds.getMinY(), true);
4354         final Point2D p2 = sceneToLocal(bounds.getMinX(), bounds.getMaxY(), true);
4355         final Point2D p3 = sceneToLocal(bounds.getMaxX(), bounds.getMinY(), true);
4356         final Point2D p4 = sceneToLocal(bounds.getMaxX(), bounds.getMaxY(), true);


4615      * Note that if this node is in a {@link SubScene}, the result is in the subscene coordinates,
4616      * not that of {@link javafx.scene.Scene}.
4617      * @param x the x coordinate of a point in Node's space
4618      * @param y the y coordinate of a point in Node's space
4619      * @param z the z coordinate of a point in Node's space
4620      * @return the transformed 3D point in Scene's space
4621      * @see #localToScene(double, double, double, boolean)
4622      * @since JavaFX 8.0
4623      */
4624     public Point3D localToScene(double x, double y, double z) {
4625         final com.sun.javafx.geom.Vec3d tempV3D =
4626                 TempState.getInstance().vec3d;
4627         tempV3D.set(x, y, z);
4628         localToScene(tempV3D);
4629         return new Point3D(tempV3D.x, tempV3D.y, tempV3D.z);
4630     }
4631 
4632     /**
4633      * Transforms a point from the local coordinate space of this {@code Node}
4634      * into the coordinate space of its scene.
4635      * If the Node does not have any {@link SubScene} or {@code rootScene} is set to true, the result point is in {@link Scene} coordinates
4636      * of the Node returned by {@link #getScene()}. Othwerwise, the subscene coordinates are used, which is equivalent to calling
4637      * {@link #localToScene(javafx.geometry.Point3D)}

4638      *
4639      * @param localPoint the point in local coordinates
4640      * @param rootScene whether Scene coordinates should be used even if the Node is in a SubScene
4641      * @return transformed point
4642      *
4643      * @see #localToScene(javafx.geometry.Point3D)
4644      * @since JavaFX 8u40
4645      */
4646     public Point3D localToScene(Point3D localPoint, boolean rootScene) {
4647         Point3D pt = localToScene(localPoint);
4648         if (rootScene) {
4649             final SubScene subScene = getSubScene();
4650             if (subScene != null) {
4651                 pt = SceneUtils.subSceneToScene(subScene, pt);
4652             }
4653         }
4654         return pt;
4655     }
4656 
4657     /**
4658      * Transforms a point from the local coordinate space of this {@code Node}
4659      * into the coordinate space of its scene.
4660      * If the Node does not have any {@link SubScene} or {@code rootScene} is set to true, the result point is in {@link Scene} coordinates
4661      * of the Node returned by {@link #getScene()}. Othwerwise, the subscene coordinates are used, which is equivalent to calling
4662      * {@link #localToScene(double, double, double)}

4663      *
4664      * @param x the x coordinate of the point in local coordinates
4665      * @param y the y coordinate of the point in local coordinates
4666      * @param z the z coordinate of the point in local coordinates
4667      * @param rootScene whether Scene coordinates should be used even if the Node is in a SubScene
4668      * @return transformed point
4669      *
4670      * @see #localToScene(double, double, double)
4671      * @since JavaFX 8u40
4672      */
4673     public Point3D localToScene(double x, double y, double z, boolean rootScene) {
4674         return localToScene(new Point3D(x, y, z), rootScene);
4675     }
4676 
4677     /**
4678      * Transforms a point from the local coordinate space of this {@code Node}
4679      * into the coordinate space of its scene.
4680      * If the Node does not have any {@link SubScene} or {@code rootScene} is set to true, the result point is in {@link Scene} coordinates
4681      * of the Node returned by {@link #getScene()}. Othwerwise, the subscene coordinates are used, which is equivalent to calling
4682      * {@link #localToScene(javafx.geometry.Point2D)}

4683      *
4684      * @param localPoint the point in local coordinates
4685      * @param rootScene whether Scene coordinates should be used even if the Node is in a SubScene
4686      * @return transformed point
4687      *
4688      * @see #localToScene(javafx.geometry.Point2D)
4689      * @since JavaFX 8u40
4690      */
4691     public Point2D localToScene(Point2D localPoint, boolean rootScene) {
4692         if (!rootScene) {
4693             return localToScene(localPoint);
4694         }
4695         Point3D pt = localToScene(localPoint.getX(), localPoint.getY(), 0, rootScene);
4696         return new Point2D(pt.getX(), pt.getY());
4697     }
4698 
4699     /**
4700      * Transforms a point from the local coordinate space of this {@code Node}
4701      * into the coordinate space of its scene.
4702      * If the Node does not have any {@link SubScene} or {@code rootScene} is set to true, the result point is in {@link Scene} coordinates
4703      * of the Node returned by {@link #getScene()}. Othwerwise, the subscene coordinates are used, which is equivalent to calling
4704      * {@link #localToScene(double, double)}

4705      *
4706      * @param x the x coordinate of the point in local coordinates
4707      * @param y the y coordinate of the point in local coordinates
4708      * @param rootScene whether Scene coordinates should be used even if the Node is in a SubScene
4709      * @return transformed point
4710      *
4711      * @see #localToScene(double, double)
4712      * @since JavaFX 8u40
4713      */
4714     public Point2D localToScene(double x, double y, boolean rootScene) {
4715         return localToScene(new Point2D(x, y), rootScene);
4716     }
4717 
4718     /**
4719      * Transforms a bounds from the local coordinate space of this {@code Node}
4720      * into the coordinate space of its scene.
4721      * If the Node does not have any {@link SubScene} or {@code rootScene} is set to true, the result bounds are in {@link Scene} coordinates
4722      * of the Node returned by {@link #getScene()}. Othwerwise, the subscene coordinates are used, which is equivalent to calling
4723      * {@link #localToScene(javafx.geometry.Bounds)}

4724      *
4725      * @param localBounds the bounds in local coordinates
4726      * @param rootScene whether Scene coordinates should be used even if the Node is in a SubScene
4727      * @return transformed bounds
4728      *
4729      * @see #localToScene(javafx.geometry.Bounds)
4730      * @since JavaFX 8u40
4731      */
4732     public Bounds localToScene(Bounds localBounds, boolean rootScene) {
4733         if (!rootScene) {
4734             return localToScene(localBounds);
4735         }
4736         Point3D p1 = localToScene(localBounds.getMinX(), localBounds.getMinY(), localBounds.getMinZ(), true);
4737         Point3D p2 = localToScene(localBounds.getMinX(), localBounds.getMinY(), localBounds.getMaxZ(), true);
4738         Point3D p3 = localToScene(localBounds.getMinX(), localBounds.getMaxY(), localBounds.getMinZ(), true);
4739         Point3D p4 = localToScene(localBounds.getMinX(), localBounds.getMaxY(), localBounds.getMaxZ(), true);
4740         Point3D p5 = localToScene(localBounds.getMaxX(), localBounds.getMaxY(), localBounds.getMinZ(), true);
4741         Point3D p6 = localToScene(localBounds.getMaxX(), localBounds.getMaxY(), localBounds.getMaxZ(), true);
4742         Point3D p7 = localToScene(localBounds.getMaxX(), localBounds.getMinY(), localBounds.getMinZ(), true);
4743         Point3D p8 = localToScene(localBounds.getMaxX(), localBounds.getMinY(), localBounds.getMaxZ(), true);


7113 
7114                     @Override
7115                     protected void invalidated() {
7116                         Effect _effect = get();
7117                         if (oldEffect != null) {
7118                             EffectHelper.effectDirtyProperty(oldEffect).removeListener(
7119                                     effectChangeListener.getWeakListener());
7120                         }
7121                         oldEffect = _effect;
7122                         if (_effect != null) {
7123                             EffectHelper.effectDirtyProperty(_effect)
7124                                    .addListener(
7125                                        effectChangeListener.getWeakListener());
7126                             if (EffectHelper.isEffectDirty(_effect)) {
7127                                 NodeHelper.markDirty(Node.this, DirtyBits.EFFECT_EFFECT);
7128                             }
7129                             oldBits = EffectHelper.effectDirtyProperty(_effect).get();
7130                         }
7131 
7132                         NodeHelper.markDirty(Node.this, DirtyBits.NODE_EFFECT);
7133                         // bounds may have changed regardeless whether
7134                         // the dirty flag on efffect is set
7135                         localBoundsChanged();
7136                     }
7137 
7138                     @Override
7139                     public CssMetaData getCssMetaData() {
7140                         return StyleableProperties.EFFECT;
7141                     }
7142 
7143                     @Override
7144                     public Object getBean() {
7145                         return Node.this;
7146                     }
7147 
7148                     @Override
7149                     public String getName() {
7150                         return "effect";
7151                     }
7152                 };
7153             }
7154             return effect;


8455                 ExpressionHelper.fireValueChangedEvent(helper);
8456             }
8457         }
8458 
8459         @Override
8460         public boolean get() {
8461             valid = true;
8462             return Node.this.treeShowing;
8463         }
8464 
8465     }
8466 
8467     private void updateTreeVisible(boolean parentChanged) {
8468         boolean isTreeVisible = isVisible();
8469         final Node parentNode = getParent() != null ? getParent() :
8470                     clipParent != null ? clipParent :
8471                     getSubScene() != null ? getSubScene() : null;
8472         if (isTreeVisible) {
8473             isTreeVisible = parentNode == null || parentNode.isTreeVisible();
8474         }
8475         // When the parent has changed to visible and we have unsynchornized visibility,
8476         // we have to synchronize, because the rendering will now pass throught the newly-visible parent
8477         // Otherwise an invisible Node might get rendered
8478         if (parentChanged && parentNode != null && parentNode.isTreeVisible()
8479                 && isDirty(DirtyBits.NODE_VISIBLE)) {
8480             addToSceneDirtyList();
8481         }
8482         setTreeVisible(isTreeVisible);
8483 
8484         updateTreeShowing();
8485     }
8486 
8487     private boolean treeVisible;
8488     private TreeVisiblePropertyReadOnly treeVisibleRO;
8489 
8490     final void setTreeVisible(boolean value) {
8491         if (treeVisible != value) {
8492             treeVisible = value;
8493             updateCanReceiveFocus();
8494             focusSetDirty(getScene());
8495             if (getClip() != null) {
8496                 getClip().updateTreeVisible(true);


9356         return FXCollections.unmodifiableObservableSet(pseudoClassStates);
9357 
9358     }
9359 
9360     // Walks up the tree telling each parent that the pseudo class state of
9361     // this node has changed.
9362     final void notifyParentsOfInvalidatedCSS() {
9363         SubScene subScene = getSubScene();
9364         Parent root = (subScene != null) ?
9365                 subScene.getRoot() : getScene().getRoot();
9366 
9367         if (!root.isDirty(DirtyBits.NODE_CSS)) {
9368             // Ensure that Scene.root is marked as dirty. If the scene isn't
9369             // dirty, nothing will get repainted. This bit is cleared from
9370             // Scene in doCSSPass().
9371             NodeHelper.markDirty(root, DirtyBits.NODE_CSS);
9372             if (subScene != null) {
9373                 // If the node is part of a subscene, then we must ensure that
9374                 // the we not only mark subScene.root dirty, but continue and
9375                 // call subScene.notifyParentsOfInvalidatedCSS() until
9376                 // Scene.root gets marked dirty, via the recurisve call:
9377                 subScene.cssFlag = CssFlags.UPDATE;
9378                 subScene.notifyParentsOfInvalidatedCSS();
9379             }
9380         }
9381         Parent _parent = getParent();
9382         while (_parent != null) {
9383             if (_parent.cssFlag == CssFlags.CLEAN) {
9384                 _parent.cssFlag = CssFlags.DIRTY_BRANCH;
9385                 _parent = _parent.getParent();
9386             } else {
9387                 _parent = null;
9388             }
9389         }
9390     }
9391 
9392     final void reapplyCSS() {
9393 
9394         if (getScene() == null) return;
9395 
9396         if (cssFlag == CssFlags.REAPPLY) return;


9792     public final ObjectProperty<AccessibleRole> accessibleRoleProperty() {
9793         if (accessibleRole == null) {
9794             accessibleRole = new SimpleObjectProperty<AccessibleRole>(this, "accessibleRole", AccessibleRole.NODE);
9795         }
9796         return accessibleRole;
9797     }
9798 
9799     public final void setAccessibleRoleDescription(String value) {
9800         accessibleRoleDescriptionProperty().set(value);
9801     }
9802 
9803     public final String getAccessibleRoleDescription() {
9804         if (accessibilityProperties == null) return null;
9805         if (accessibilityProperties.accessibleRoleDescription == null) return null;
9806         return accessibleRoleDescriptionProperty().get();
9807     }
9808 
9809     /**
9810      * The role description of this {@code Node}.
9811      * <p>
9812      * Noramlly, when a role is provided for a node, the screen reader
9813      * speaks the role as well as the contents of the node.  When this
9814      * value is set, it is possbile to override the default.  This is
9815      * useful because the set of roles is predefined.  For example,
9816      * it is possible to set the role of a node to be a button, but
9817      * have the role description be arbitrary text.
9818      *
9819      * @return the role description of this {@code Node}.
9820      * @defaultValue null
9821      *
9822      * @since JavaFX 8u40
9823      */
9824     public final ObjectProperty<String> accessibleRoleDescriptionProperty() {
9825         return getAccessibilityProperties().getAccessibleRoleDescription();
9826     }
9827 
9828     public final void setAccessibleText(String value) {
9829         accessibleTextProperty().set(value);
9830     }
9831 
9832     public final String getAccessibleText() {
9833         if (accessibilityProperties == null) return null;
9834         if (accessibilityProperties.accessibleText == null) return null;




 290  * the node about a specified "pivot" point, causing the node to appear rotated.
 291  * For example, if you create a {@link javafx.scene.shape.Rectangle} which is
 292  * drawn at the origin (x=0, y=0) and has a width of 100 and height of 30 and
 293  * you apply a {@link javafx.scene.transform.Rotate} with a 90 degree rotation
 294  * (angle=90) and a pivot at the origin (pivotX=0, pivotY=0), then
 295  * the rectangle will be drawn as if its x and y were zero but its height was
 296  * 100 and its width -30. That is, it is as if a pin is being stuck at the top
 297  * left corner and the rectangle is rotating 90 degrees clockwise around that
 298  * pin. If the pivot point is instead placed in the center of the rectangle
 299  * (at point x=50, y=15) then the rectangle will instead appear to rotate about
 300  * its center.
 301  * <p>
 302  * Note that as with all transformations, the x, y, width, and height variables
 303  * of the rectangle (which remain relative to the local coordinate space) have
 304  * not changed, but rather the transformation alters the entire coordinate space
 305  * of the rectangle.
 306  * <p>
 307  * A <b>scaling</b> transformation causes a node to either appear larger or
 308  * smaller depending on the scaling factor. Scaling alters the coordinate space
 309  * of the node such that each unit of distance along the axis in local
 310  * coordinates is multiplied by the scale factor. As with rotation
 311  * transformations, scaling transformations are applied about a "pivot" point.
 312  * You can think of this as the point in the Node around which you "zoom".  For
 313  * example, if you create a {@link javafx.scene.shape.Rectangle} with a
 314  * {@code strokeWidth} of 5, and a width and height of 50, and you apply a
 315  * {@link javafx.scene.transform.Scale} with scale factors (x=2.0, y=2.0) and
 316  * a pivot at the origin (pivotX=0, pivotY=0), the entire rectangle
 317  * (including the stroke) will double in size, growing to the right and
 318  * downwards from the origin.
 319  * <p>
 320  * A <b>shearing</b> transformation, sometimes called a skew, effectively
 321  * rotates one axis so that the x and y axes are no longer perpendicular.
 322  * <p>
 323  * Multiple transformations may be applied to a node by specifying an ordered
 324  * chain of transforms.  The order in which the transforms are applied is
 325  * defined by the ObservableList specified in the {@link #getTransforms transforms} variable.
 326  *
 327  * <h3>Bounding Rectangles</h3>
 328  * <p>
 329  * Since every {@code Node} has transformations, every Node's geometric
 330  * bounding rectangle can be described differently depending on whether


2054         node.syncPeer();
2055         if (node instanceof Parent) {
2056             Parent p = (Parent) node;
2057             final int childrenCount = p.getChildren().size();
2058 
2059             for (int i = 0; i < childrenCount; i++) {
2060                 Node n = p.getChildren().get(i);
2061                 if (n != null) {
2062                     syncAll(n);
2063                 }
2064             }
2065         }
2066         if (node.getClip() != null) {
2067             syncAll(node.getClip());
2068         }
2069     }
2070 
2071     private void doLayoutPass() {
2072         if (this instanceof Parent) {
2073             // TODO: As an optimization we only need to layout those dirty
2074             // roots that are descendants of this node
2075             Parent p = (Parent)this;
2076             for (int i = 0; i < 3; i++) {
2077                 p.layout();
2078             }
2079         }
2080     }
2081 
2082     private void doCSSLayoutSyncForSnapshot() {
2083         doCSSPass();
2084         doLayoutPass();
2085         updateBounds();
2086         Scene.setAllowPGAccess(true);
2087         syncAll(this);
2088         Scene.setAllowPGAccess(false);
2089     }
2090 
2091     private WritableImage doSnapshot(SnapshotParameters params, WritableImage img) {
2092         if (getScene() != null) {
2093             getScene().doCSSLayoutSyncForSnapshot(this);
2094         } else {


3228             return getLayoutBounds().getHeight();
3229         }
3230     }
3231 
3232     /**
3233      * Returns the area of this {@code Node} projected onto the
3234      * physical screen in pixel units.
3235      * @return the area of this {@code Node} projected onto the physical screen
3236      * @since JavaFX 8.0
3237      */
3238     public double computeAreaInScreen() {
3239         return doComputeAreaInScreen();
3240     }
3241 
3242     /*
3243      * Help application or utility to implement LOD support by returning the
3244      * projected area of a Node in pixel unit. The projected area is not clipped.
3245      *
3246      * For perspective camera, this method first exams node's bounds against
3247      * camera's clipping plane to cut off those out of viewing frustrum. After
3248      * computing areaInScreen, it applies a tight viewing frustrum check using
3249      * canonical view volume.
3250      *
3251      * The result of areaInScreen comes from the product of
3252      * (projViewTx x localToSceneTransform x localBounds).
3253      *
3254      * Returns 0 for those fall outside viewing frustrum.
3255      */
3256     private double doComputeAreaInScreen() {
3257         Scene tmpScene = getScene();
3258         if (tmpScene != null) {
3259             Bounds bounds = getBoundsInLocal();
3260             Camera camera = tmpScene.getEffectiveCamera();
3261             boolean isPerspective = camera instanceof PerspectiveCamera ? true : false;
3262             Transform localToSceneTx = getLocalToSceneTransform();
3263             Affine3D tempTx = TempState.getInstance().tempTx;
3264             BaseBounds localBounds = new BoxBounds((float) bounds.getMinX(),
3265                                                    (float) bounds.getMinY(),
3266                                                    (float) bounds.getMinZ(),
3267                                                    (float) bounds.getMaxX(),
3268                                                    (float) bounds.getMaxY(),


3315                         maxZ = nodeInSceneBounds.getMaxZ();
3316                     }
3317 
3318                     if (minZ > camera.getFarClipInScene()
3319                             || maxZ < camera.getNearClipInScene()) {
3320                         return 0;
3321                     }
3322 
3323                 } else {
3324                     BaseBounds nodeInCameraBounds = new BoxBounds();
3325 
3326                     // We need to set tempTx to identity since it is a recycled transform.
3327                     // This is because TransformHelper.apply() is a matrix concatenation operation.
3328                     tempTx.setToIdentity();
3329                     TransformHelper.apply(localToSceneTx, tempTx);
3330 
3331                     // Convert node from local coordinate to camera coordinate
3332                     tempTx.preConcatenate(camera.getSceneToLocalTransform());
3333                     tempTx.transform(localBounds, nodeInCameraBounds);
3334 
3335                     // Compare in camera coordinate
3336                     if (nodeInCameraBounds.getMinZ() > camera.getFarClip()
3337                             || nodeInCameraBounds.getMaxZ() < camera.getNearClip()) {
3338                         return 0;
3339                     }
3340                 }
3341             }
3342 
3343             GeneralTransform3D projViewTx = TempState.getInstance().projViewTx;
3344             projViewTx.set(camera.getProjViewTransform());
3345 
3346             // We need to set tempTx to identity since it is a recycled transform.
3347             // This is because TransformHelper.apply() is a matrix concatenation operation.
3348             tempTx.setToIdentity();
3349             TransformHelper.apply(localToSceneTx, tempTx);
3350 
3351             // The product of projViewTx * localToSceneTransform
3352             GeneralTransform3D tx = projViewTx.mul(tempTx);
3353 
3354             // Transform localBounds to projected bounds
3355             localBounds = tx.transform(localBounds, localBounds);


3751             if (!tx.isIdentity()) {
3752                 double translateX = tx.getMxt();
3753                 double translateY = tx.getMyt();
3754                 double translateZ = tx.getMzt();
3755                 bounds = bounds.deriveWithNewBounds((float) (bounds.getMinX() + translateX),
3756                         (float) (bounds.getMinY() + translateY),
3757                         (float) (bounds.getMinZ() + translateZ),
3758                         (float) (bounds.getMaxX() + translateX),
3759                         (float) (bounds.getMaxY() + translateY),
3760                         (float) (bounds.getMaxZ() + translateZ));
3761             }
3762             return bounds;
3763         } else if (tx.is2D()
3764                 && (tx.getType()
3765                 & ~(BaseTransform.TYPE_UNIFORM_SCALE | BaseTransform.TYPE_TRANSLATION
3766                 | BaseTransform.TYPE_FLIP | BaseTransform.TYPE_QUADRANT_ROTATION)) != 0) {
3767             // this is a non-uniform scale / non-quadrant rotate / skew transform
3768             return computeLocalBounds(bounds, tx);
3769         } else {
3770             // 3D transformations and
3771             // selected 2D transformations (uniform transform, flip, quadrant rotation).
3772             // These 2D transformation will yield tight bounds when applied on the pre-computed
3773             // geomBounds
3774             // Note: Transforming the local bounds into a 3D space will yield a bounds
3775             // that isn't as tight as transforming its geometry and compute it bounds.
3776             updateLocalBounds();
3777             return tx.transform(localBounds, bounds);
3778         }
3779     }
3780 
3781     /**
3782      * Loads the given bounds object with the geometric bounds relative to,
3783      * and based on, the given transform.
3784      *
3785      * We *never* pass null in as a bounds. This method will
3786      * NOT take a null bounds object. The returned value may be
3787      * the same bounds object passed in, or it may be a new object.
3788      * The reason for this object promotion is in the case of needing
3789      * to promote from a RectBounds to a BoxBounds (3D).
3790      */
3791     BaseBounds getGeomBounds(BaseBounds bounds, BaseTransform tx) {


4261      * {@link javafx.stage.Screen} into the local coordinate space of this
4262      * {@code Node}. Returns reasonable result only in 2D space.
4263      * @param screenBounds bounds on a Screen
4264      * @return bounds in the local Node'space or null if Node is not in a {@link Window}.
4265      * Null is also returned if the transformation from local to Scene is not invertible.
4266      * @since JavaFX 8.0
4267      */
4268     public Bounds screenToLocal(Bounds screenBounds) {
4269         final Point2D p1 = screenToLocal(screenBounds.getMinX(), screenBounds.getMinY());
4270         final Point2D p2 = screenToLocal(screenBounds.getMinX(), screenBounds.getMaxY());
4271         final Point2D p3 = screenToLocal(screenBounds.getMaxX(), screenBounds.getMinY());
4272         final Point2D p4 = screenToLocal(screenBounds.getMaxX(), screenBounds.getMaxY());
4273 
4274         return BoundsUtils.createBoundingBox(p1, p2, p3, p4);
4275     }
4276 
4277 
4278     /**
4279      * Transforms a point from the coordinate space of the scene
4280      * into the local coordinate space of this {@code Node}.
4281      * If the Node does not have any {@link SubScene} or {@code rootScene} is set to true, the
4282      * arguments are in {@link Scene} coordinates of the Node returned by {@link #getScene()}.
4283      * Otherwise, the subscene coordinates are used, which is equivalent to calling
4284      * {@link #sceneToLocal(double, double)}.
4285      *
4286      * @param x the x coordinate
4287      * @param y the y coordinate
4288      * @param rootScene whether Scene coordinates should be used even if the Node is in a SubScene
4289      * @return local coordinates of the point
4290      * @since JavaFX 8u40
4291      */
4292     public Point2D sceneToLocal(double x, double y, boolean rootScene) {
4293         if (!rootScene) {
4294             return sceneToLocal(x, y);
4295         }
4296         final com.sun.javafx.geom.Point2D tempPt =
4297                 TempState.getInstance().point;
4298 
4299         tempPt.setLocation((float)(x), (float)y);
4300 
4301         final SubScene subScene = getSubScene();
4302         if (subScene != null) {
4303             final Point2D ssCoord = SceneUtils.sceneToSubScenePlane(subScene,
4304                     new Point2D(tempPt.x, tempPt.y));
4305             if (ssCoord == null) {
4306                 return null;
4307             }
4308             tempPt.setLocation((float) ssCoord.getX(), (float) ssCoord.getY());
4309         }
4310 
4311         try {
4312             sceneToLocal(tempPt);
4313             return new Point2D(tempPt.x, tempPt.y);
4314         } catch (NoninvertibleTransformException e) {
4315             return null;
4316         }
4317     }
4318 
4319     /**
4320      * Transforms a point from the coordinate space of the scene
4321      * into the local coordinate space of this {@code Node}.
4322      * If the Node does not have any {@link SubScene} or {@code rootScene} is set to true, the
4323      * arguments are in {@link Scene} coordinates of the Node returned by {@link #getScene()}.
4324      * Otherwise, the subscene coordinates are used, which is equivalent to calling
4325      * {@link #sceneToLocal(javafx.geometry.Point2D)}.
4326      *
4327      * @param point the point
4328      * @param rootScene whether Scene coordinates should be used even if the Node is in a SubScene
4329      * @return local coordinates of the point
4330      * @since JavaFX 8u40
4331      */
4332     public Point2D sceneToLocal(Point2D point, boolean rootScene) {
4333         return sceneToLocal(point.getX(), point.getY(), rootScene);
4334     }
4335 
4336     /**
4337      * Transforms a bounds from the coordinate space of the scene
4338      * into the local coordinate space of this {@code Node}.
4339      * If the Node does not have any {@link SubScene} or {@code rootScene} is set to true, the
4340      * arguments are in {@link Scene} coordinates of the Node returned by {@link #getScene()}.
4341      * Otherwise, the subscene coordinates are used, which is equivalent to calling
4342      * {@link #sceneToLocal(javafx.geometry.Bounds)}.
4343      * <p>
4344      *     Since 3D bounds cannot be converted with {@code rootScene} set to {@code true}, trying to convert 3D bounds will yield {@code null}.
4345      * </p>
4346      * @param bounds the bounds
4347      * @param rootScene whether Scene coordinates should be used even if the Node is in a SubScene
4348      * @return local coordinates of the bounds
4349      * @since JavaFX 8u40
4350      */
4351     public Bounds sceneToLocal(Bounds bounds, boolean rootScene) {
4352         if (!rootScene) {
4353             return sceneToLocal(bounds);
4354         }
4355         if (bounds.getMinZ() != 0 || bounds.getMaxZ() != 0) {
4356             return null;
4357         }
4358         final Point2D p1 = sceneToLocal(bounds.getMinX(), bounds.getMinY(), true);
4359         final Point2D p2 = sceneToLocal(bounds.getMinX(), bounds.getMaxY(), true);
4360         final Point2D p3 = sceneToLocal(bounds.getMaxX(), bounds.getMinY(), true);
4361         final Point2D p4 = sceneToLocal(bounds.getMaxX(), bounds.getMaxY(), true);


4620      * Note that if this node is in a {@link SubScene}, the result is in the subscene coordinates,
4621      * not that of {@link javafx.scene.Scene}.
4622      * @param x the x coordinate of a point in Node's space
4623      * @param y the y coordinate of a point in Node's space
4624      * @param z the z coordinate of a point in Node's space
4625      * @return the transformed 3D point in Scene's space
4626      * @see #localToScene(double, double, double, boolean)
4627      * @since JavaFX 8.0
4628      */
4629     public Point3D localToScene(double x, double y, double z) {
4630         final com.sun.javafx.geom.Vec3d tempV3D =
4631                 TempState.getInstance().vec3d;
4632         tempV3D.set(x, y, z);
4633         localToScene(tempV3D);
4634         return new Point3D(tempV3D.x, tempV3D.y, tempV3D.z);
4635     }
4636 
4637     /**
4638      * Transforms a point from the local coordinate space of this {@code Node}
4639      * into the coordinate space of its scene.
4640      * If the Node does not have any {@link SubScene} or {@code rootScene} is set to true, the
4641      * result point is in {@link Scene} coordinates of the Node returned by {@link #getScene()}.
4642      * Otherwise, the subscene coordinates are used, which is equivalent to calling
4643      * {@link #localToScene(javafx.geometry.Point3D)}.
4644      *
4645      * @param localPoint the point in local coordinates
4646      * @param rootScene whether Scene coordinates should be used even if the Node is in a SubScene
4647      * @return transformed point
4648      *
4649      * @see #localToScene(javafx.geometry.Point3D)
4650      * @since JavaFX 8u40
4651      */
4652     public Point3D localToScene(Point3D localPoint, boolean rootScene) {
4653         Point3D pt = localToScene(localPoint);
4654         if (rootScene) {
4655             final SubScene subScene = getSubScene();
4656             if (subScene != null) {
4657                 pt = SceneUtils.subSceneToScene(subScene, pt);
4658             }
4659         }
4660         return pt;
4661     }
4662 
4663     /**
4664      * Transforms a point from the local coordinate space of this {@code Node}
4665      * into the coordinate space of its scene.
4666      * If the Node does not have any {@link SubScene} or {@code rootScene} is set to true, the
4667      * result point is in {@link Scene} coordinates of the Node returned by {@link #getScene()}.
4668      * Otherwise, the subscene coordinates are used, which is equivalent to calling
4669      * {@link #localToScene(double, double, double)}.
4670      *
4671      * @param x the x coordinate of the point in local coordinates
4672      * @param y the y coordinate of the point in local coordinates
4673      * @param z the z coordinate of the point in local coordinates
4674      * @param rootScene whether Scene coordinates should be used even if the Node is in a SubScene
4675      * @return transformed point
4676      *
4677      * @see #localToScene(double, double, double)
4678      * @since JavaFX 8u40
4679      */
4680     public Point3D localToScene(double x, double y, double z, boolean rootScene) {
4681         return localToScene(new Point3D(x, y, z), rootScene);
4682     }
4683 
4684     /**
4685      * Transforms a point from the local coordinate space of this {@code Node}
4686      * into the coordinate space of its scene.
4687      * If the Node does not have any {@link SubScene} or {@code rootScene} is set to true, the
4688      * result point is in {@link Scene} coordinates of the Node returned by {@link #getScene()}.
4689      * Otherwise, the subscene coordinates are used, which is equivalent to calling
4690      * {@link #localToScene(javafx.geometry.Point2D)}.
4691      *
4692      * @param localPoint the point in local coordinates
4693      * @param rootScene whether Scene coordinates should be used even if the Node is in a SubScene
4694      * @return transformed point
4695      *
4696      * @see #localToScene(javafx.geometry.Point2D)
4697      * @since JavaFX 8u40
4698      */
4699     public Point2D localToScene(Point2D localPoint, boolean rootScene) {
4700         if (!rootScene) {
4701             return localToScene(localPoint);
4702         }
4703         Point3D pt = localToScene(localPoint.getX(), localPoint.getY(), 0, rootScene);
4704         return new Point2D(pt.getX(), pt.getY());
4705     }
4706 
4707     /**
4708      * Transforms a point from the local coordinate space of this {@code Node}
4709      * into the coordinate space of its scene.
4710      * If the Node does not have any {@link SubScene} or {@code rootScene} is set to true, the
4711      * result point is in {@link Scene} coordinates of the Node returned by {@link #getScene()}.
4712      * Otherwise, the subscene coordinates are used, which is equivalent to calling
4713      * {@link #localToScene(double, double)}.
4714      *
4715      * @param x the x coordinate of the point in local coordinates
4716      * @param y the y coordinate of the point in local coordinates
4717      * @param rootScene whether Scene coordinates should be used even if the Node is in a SubScene
4718      * @return transformed point
4719      *
4720      * @see #localToScene(double, double)
4721      * @since JavaFX 8u40
4722      */
4723     public Point2D localToScene(double x, double y, boolean rootScene) {
4724         return localToScene(new Point2D(x, y), rootScene);
4725     }
4726 
4727     /**
4728      * Transforms a bounds from the local coordinate space of this {@code Node}
4729      * into the coordinate space of its scene.
4730      * If the Node does not have any {@link SubScene} or {@code rootScene} is set to true, the
4731      * result bounds are in {@link Scene} coordinates of the Node returned by {@link #getScene()}.
4732      * Otherwise, the subscene coordinates are used, which is equivalent to calling
4733      * {@link #localToScene(javafx.geometry.Bounds)}.
4734      *
4735      * @param localBounds the bounds in local coordinates
4736      * @param rootScene whether Scene coordinates should be used even if the Node is in a SubScene
4737      * @return transformed bounds
4738      *
4739      * @see #localToScene(javafx.geometry.Bounds)
4740      * @since JavaFX 8u40
4741      */
4742     public Bounds localToScene(Bounds localBounds, boolean rootScene) {
4743         if (!rootScene) {
4744             return localToScene(localBounds);
4745         }
4746         Point3D p1 = localToScene(localBounds.getMinX(), localBounds.getMinY(), localBounds.getMinZ(), true);
4747         Point3D p2 = localToScene(localBounds.getMinX(), localBounds.getMinY(), localBounds.getMaxZ(), true);
4748         Point3D p3 = localToScene(localBounds.getMinX(), localBounds.getMaxY(), localBounds.getMinZ(), true);
4749         Point3D p4 = localToScene(localBounds.getMinX(), localBounds.getMaxY(), localBounds.getMaxZ(), true);
4750         Point3D p5 = localToScene(localBounds.getMaxX(), localBounds.getMaxY(), localBounds.getMinZ(), true);
4751         Point3D p6 = localToScene(localBounds.getMaxX(), localBounds.getMaxY(), localBounds.getMaxZ(), true);
4752         Point3D p7 = localToScene(localBounds.getMaxX(), localBounds.getMinY(), localBounds.getMinZ(), true);
4753         Point3D p8 = localToScene(localBounds.getMaxX(), localBounds.getMinY(), localBounds.getMaxZ(), true);


7123 
7124                     @Override
7125                     protected void invalidated() {
7126                         Effect _effect = get();
7127                         if (oldEffect != null) {
7128                             EffectHelper.effectDirtyProperty(oldEffect).removeListener(
7129                                     effectChangeListener.getWeakListener());
7130                         }
7131                         oldEffect = _effect;
7132                         if (_effect != null) {
7133                             EffectHelper.effectDirtyProperty(_effect)
7134                                    .addListener(
7135                                        effectChangeListener.getWeakListener());
7136                             if (EffectHelper.isEffectDirty(_effect)) {
7137                                 NodeHelper.markDirty(Node.this, DirtyBits.EFFECT_EFFECT);
7138                             }
7139                             oldBits = EffectHelper.effectDirtyProperty(_effect).get();
7140                         }
7141 
7142                         NodeHelper.markDirty(Node.this, DirtyBits.NODE_EFFECT);
7143                         // bounds may have changed regardless whether
7144                         // the dirty flag on effect is set
7145                         localBoundsChanged();
7146                     }
7147 
7148                     @Override
7149                     public CssMetaData getCssMetaData() {
7150                         return StyleableProperties.EFFECT;
7151                     }
7152 
7153                     @Override
7154                     public Object getBean() {
7155                         return Node.this;
7156                     }
7157 
7158                     @Override
7159                     public String getName() {
7160                         return "effect";
7161                     }
7162                 };
7163             }
7164             return effect;


8465                 ExpressionHelper.fireValueChangedEvent(helper);
8466             }
8467         }
8468 
8469         @Override
8470         public boolean get() {
8471             valid = true;
8472             return Node.this.treeShowing;
8473         }
8474 
8475     }
8476 
8477     private void updateTreeVisible(boolean parentChanged) {
8478         boolean isTreeVisible = isVisible();
8479         final Node parentNode = getParent() != null ? getParent() :
8480                     clipParent != null ? clipParent :
8481                     getSubScene() != null ? getSubScene() : null;
8482         if (isTreeVisible) {
8483             isTreeVisible = parentNode == null || parentNode.isTreeVisible();
8484         }
8485         // When the parent has changed to visible and we have unsynchronized visibility,
8486         // we have to synchronize, because the rendering will now pass through the newly-visible parent
8487         // Otherwise an invisible Node might get rendered
8488         if (parentChanged && parentNode != null && parentNode.isTreeVisible()
8489                 && isDirty(DirtyBits.NODE_VISIBLE)) {
8490             addToSceneDirtyList();
8491         }
8492         setTreeVisible(isTreeVisible);
8493 
8494         updateTreeShowing();
8495     }
8496 
8497     private boolean treeVisible;
8498     private TreeVisiblePropertyReadOnly treeVisibleRO;
8499 
8500     final void setTreeVisible(boolean value) {
8501         if (treeVisible != value) {
8502             treeVisible = value;
8503             updateCanReceiveFocus();
8504             focusSetDirty(getScene());
8505             if (getClip() != null) {
8506                 getClip().updateTreeVisible(true);


9366         return FXCollections.unmodifiableObservableSet(pseudoClassStates);
9367 
9368     }
9369 
9370     // Walks up the tree telling each parent that the pseudo class state of
9371     // this node has changed.
9372     final void notifyParentsOfInvalidatedCSS() {
9373         SubScene subScene = getSubScene();
9374         Parent root = (subScene != null) ?
9375                 subScene.getRoot() : getScene().getRoot();
9376 
9377         if (!root.isDirty(DirtyBits.NODE_CSS)) {
9378             // Ensure that Scene.root is marked as dirty. If the scene isn't
9379             // dirty, nothing will get repainted. This bit is cleared from
9380             // Scene in doCSSPass().
9381             NodeHelper.markDirty(root, DirtyBits.NODE_CSS);
9382             if (subScene != null) {
9383                 // If the node is part of a subscene, then we must ensure that
9384                 // the we not only mark subScene.root dirty, but continue and
9385                 // call subScene.notifyParentsOfInvalidatedCSS() until
9386                 // Scene.root gets marked dirty, via the recursive call:
9387                 subScene.cssFlag = CssFlags.UPDATE;
9388                 subScene.notifyParentsOfInvalidatedCSS();
9389             }
9390         }
9391         Parent _parent = getParent();
9392         while (_parent != null) {
9393             if (_parent.cssFlag == CssFlags.CLEAN) {
9394                 _parent.cssFlag = CssFlags.DIRTY_BRANCH;
9395                 _parent = _parent.getParent();
9396             } else {
9397                 _parent = null;
9398             }
9399         }
9400     }
9401 
9402     final void reapplyCSS() {
9403 
9404         if (getScene() == null) return;
9405 
9406         if (cssFlag == CssFlags.REAPPLY) return;


9802     public final ObjectProperty<AccessibleRole> accessibleRoleProperty() {
9803         if (accessibleRole == null) {
9804             accessibleRole = new SimpleObjectProperty<AccessibleRole>(this, "accessibleRole", AccessibleRole.NODE);
9805         }
9806         return accessibleRole;
9807     }
9808 
9809     public final void setAccessibleRoleDescription(String value) {
9810         accessibleRoleDescriptionProperty().set(value);
9811     }
9812 
9813     public final String getAccessibleRoleDescription() {
9814         if (accessibilityProperties == null) return null;
9815         if (accessibilityProperties.accessibleRoleDescription == null) return null;
9816         return accessibleRoleDescriptionProperty().get();
9817     }
9818 
9819     /**
9820      * The role description of this {@code Node}.
9821      * <p>
9822      * Normally, when a role is provided for a node, the screen reader
9823      * speaks the role as well as the contents of the node.  When this
9824      * value is set, it is possible to override the default.  This is
9825      * useful because the set of roles is predefined.  For example,
9826      * it is possible to set the role of a node to be a button, but
9827      * have the role description be arbitrary text.
9828      *
9829      * @return the role description of this {@code Node}.
9830      * @defaultValue null
9831      *
9832      * @since JavaFX 8u40
9833      */
9834     public final ObjectProperty<String> accessibleRoleDescriptionProperty() {
9835         return getAccessibilityProperties().getAccessibleRoleDescription();
9836     }
9837 
9838     public final void setAccessibleText(String value) {
9839         accessibleTextProperty().set(value);
9840     }
9841 
9842     public final String getAccessibleText() {
9843         if (accessibilityProperties == null) return null;
9844         if (accessibilityProperties.accessibleText == null) return null;


< prev index next >