< prev index next >

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

 ``` `````` 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 *

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 *

307 * A scaling 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 *

320 * A shearing transformation, sometimes called a skew, effectively 321 * rotates one axis so that the x and y axes are no longer perpendicular. 322 *

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 *

Bounding Rectangles

328 *

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 *

4339 * Since 3D bounds cannot be converted with {@code rootScene} set to {@code true}, trying to convert 3D bounds will yield {@code null}. 4340 *

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 accessibleRoleProperty() { 9793 if (accessibleRole == null) { 9794 accessibleRole = new SimpleObjectProperty(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 *

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 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 *

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 *

307 * A scaling 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 *

320 * A shearing transformation, sometimes called a skew, effectively 321 * rotates one axis so that the x and y axes are no longer perpendicular. 322 *

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 *

Bounding Rectangles

328 *

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 *

4344 * Since 3D bounds cannot be converted with {@code rootScene} set to {@code true}, trying to convert 3D bounds will yield {@code null}. 4345 *

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 accessibleRoleProperty() { 9803 if (accessibleRole == null) { 9804 accessibleRole = new SimpleObjectProperty(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 *

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 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 >