1 /*
   2  * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.javafx.scene;
  27 
  28 import com.sun.glass.ui.Accessible;
  29 import com.sun.javafx.geom.BaseBounds;
  30 import com.sun.javafx.geom.PickRay;
  31 import com.sun.javafx.geom.transform.BaseTransform;
  32 import com.sun.javafx.jmx.MXNodeAlgorithm;
  33 import com.sun.javafx.jmx.MXNodeAlgorithmContext;
  34 import com.sun.javafx.scene.input.PickResultChooser;
  35 import com.sun.javafx.scene.traversal.Direction;
  36 import com.sun.javafx.sg.prism.NGNode;
  37 import com.sun.javafx.util.Utils;
  38 import java.util.List;
  39 import java.util.Map;
  40 import javafx.beans.binding.BooleanExpression;
  41 import javafx.beans.property.BooleanProperty;
  42 import javafx.css.CssMetaData;
  43 import javafx.css.Style;
  44 import javafx.css.Styleable;
  45 import javafx.css.StyleableProperty;
  46 import javafx.geometry.Bounds;
  47 import javafx.scene.Node;
  48 import javafx.scene.SubScene;
  49 
  50 /**
  51  * Used to access internal methods of Node.
  52  */
  53 public abstract class NodeHelper {
  54     private static NodeAccessor nodeAccessor;
  55 
  56     static {
  57         Utils.forceInit(Node.class);
  58     }
  59 
  60     protected NodeHelper() {
  61     }
  62 
  63     protected static NodeHelper getHelper(Node node) {
  64         return nodeAccessor.getHelper(node);
  65     }
  66 
  67     protected static void setHelper(Node node, NodeHelper nodeHelper) {
  68         nodeAccessor.setHelper(node, nodeHelper);
  69     }
  70 
  71     /*
  72      * Static helper methods for cases where the implementation is done in an
  73      * instance method that is overridden by subclasses.
  74      * These methods exist in the base class only.
  75      */
  76 
  77     public static NGNode createPeer(Node node) {
  78         return getHelper(node).createPeerImpl(node);
  79     }
  80 
  81     public static void markDirty(Node node, DirtyBits dirtyBit) {
  82         getHelper(node).markDirtyImpl(node, dirtyBit);
  83     }
  84 
  85     public static void updatePeer(Node node) {
  86         getHelper(node).updatePeerImpl(node);
  87     }
  88 
  89     public static Bounds computeLayoutBounds(Node node) {
  90         return getHelper(node).computeLayoutBoundsImpl(node);
  91     }
  92 
  93     /*
  94      * Computes the geometric bounds for this Node. This method is abstract
  95      * and must be implemented by each Node subclass.
  96      */
  97     public static BaseBounds computeGeomBounds(Node node,
  98             BaseBounds bounds, BaseTransform tx) {
  99         return getHelper(node).computeGeomBoundsImpl(node, bounds, tx);
 100     }
 101 
 102     public static void transformsChanged(Node node) {
 103         getHelper(node).transformsChangedImpl(node);
 104     }
 105 
 106     public static boolean computeContains(Node node, double localX, double localY) {
 107         return getHelper(node).computeContainsImpl(node, localX, localY);
 108     }
 109 
 110     public static void pickNodeLocal(Node node, PickRay localPickRay,
 111             PickResultChooser result) {
 112         getHelper(node).pickNodeLocalImpl(node, localPickRay, result);
 113     }
 114 
 115     public static boolean computeIntersects(Node node, PickRay pickRay,
 116             PickResultChooser pickResult) {
 117         return getHelper(node).computeIntersectsImpl(node, pickRay, pickResult);
 118     }
 119 
 120     public static void geomChanged(Node node) {
 121         getHelper(node).geomChangedImpl(node);
 122     }
 123 
 124     public static void notifyLayoutBoundsChanged(Node node) {
 125         getHelper(node).notifyLayoutBoundsChangedImpl(node);
 126     }
 127 
 128     public static void processCSS(Node node) {
 129         getHelper(node).processCSSImpl(node);
 130     }
 131 
 132     /*
 133      * This method is used by Scene-graph JMX bean to obtain the Scene-graph structure.
 134      *
 135      * @param alg current algorithm to process this node
 136      * @param ctx current context
 137      * @return the algorithm specific result for this node
 138      */
 139     public static Object processMXNode(Node node, MXNodeAlgorithm alg, MXNodeAlgorithmContext ctx) {
 140         return getHelper(node).processMXNodeImpl(node, alg, ctx);
 141     }
 142 
 143     /*
 144      * Methods that will be overridden by subclasses
 145      */
 146 
 147     protected abstract NGNode createPeerImpl(Node node);
 148     protected abstract boolean computeContainsImpl(Node node, double localX, double localY);
 149     protected abstract BaseBounds computeGeomBoundsImpl(Node node,
 150             BaseBounds bounds, BaseTransform tx);
 151     protected abstract Object processMXNodeImpl(Node node, MXNodeAlgorithm alg, MXNodeAlgorithmContext ctx);
 152 
 153     protected void markDirtyImpl(Node node, DirtyBits dirtyBit) {
 154         nodeAccessor.doMarkDirty(node, dirtyBit);
 155     }
 156 
 157     protected void updatePeerImpl(Node node) {
 158         nodeAccessor.doUpdatePeer(node);
 159     }
 160 
 161     protected Bounds computeLayoutBoundsImpl(Node node) {
 162         return nodeAccessor.doComputeLayoutBounds(node);
 163     }
 164 
 165     protected void transformsChangedImpl(Node node) {
 166         nodeAccessor.doTransformsChanged(node);
 167     }
 168 
 169     protected void pickNodeLocalImpl(Node node, PickRay localPickRay,
 170             PickResultChooser result) {
 171         nodeAccessor.doPickNodeLocal(node, localPickRay, result);
 172     }
 173 
 174     protected boolean computeIntersectsImpl(Node node, PickRay pickRay,
 175             PickResultChooser pickResult) {
 176         return nodeAccessor.doComputeIntersects(node, pickRay, pickResult);
 177     }
 178 
 179     protected void geomChangedImpl(Node node) {
 180         nodeAccessor.doGeomChanged(node);
 181     }
 182 
 183     protected void notifyLayoutBoundsChangedImpl(Node node) {
 184         nodeAccessor.doNotifyLayoutBoundsChanged(node);
 185     }
 186 
 187     protected void processCSSImpl(Node node) {
 188         nodeAccessor.doProcessCSS(node);
 189     }
 190 
 191     /*
 192      * Methods used by Node (base) class only
 193      */
 194 
 195     public static boolean isDirty(Node node, DirtyBits dirtyBit) {
 196         return nodeAccessor.isDirty(node, dirtyBit);
 197     }
 198 
 199     public static boolean isDirtyEmpty(Node node) {
 200         return nodeAccessor.isDirtyEmpty(node);
 201     }
 202 
 203     public static void syncPeer(Node node) {
 204         nodeAccessor.syncPeer(node);
 205     }
 206 
 207     public static <P extends NGNode> P getPeer(Node node) {
 208         return nodeAccessor.getPeer(node);
 209     }
 210 
 211     public static BaseTransform getLeafTransform(Node node) {
 212         return nodeAccessor.getLeafTransform(node);
 213     }
 214 
 215     public static void layoutBoundsChanged(Node node) {
 216         nodeAccessor.layoutBoundsChanged(node);
 217     }
 218 
 219     public static void setShowMnemonics(Node node, boolean value) {
 220         nodeAccessor.setShowMnemonics(node, value);
 221     }
 222 
 223     public static boolean isShowMnemonics(Node node) {
 224         return nodeAccessor.isShowMnemonics(node);
 225     }
 226 
 227     public static BooleanProperty showMnemonicsProperty(Node node) {
 228         return nodeAccessor.showMnemonicsProperty(node);
 229     }
 230 
 231     public static boolean traverse(Node node, Direction direction) {
 232         return nodeAccessor.traverse(node, direction);
 233     }
 234 
 235     public static double getPivotX(Node node) {
 236         return nodeAccessor.getPivotX(node);
 237     }
 238 
 239     public static double getPivotY(Node node) {
 240         return nodeAccessor.getPivotY(node);
 241     }
 242 
 243     public static double getPivotZ(Node node) {
 244         return nodeAccessor.getPivotZ(node);
 245     }
 246 
 247     public static void pickNode(Node node, PickRay pickRay,
 248             PickResultChooser result) {
 249         nodeAccessor.pickNode(node, pickRay, result);
 250     }
 251 
 252     public static boolean intersects(Node node, PickRay pickRay,
 253             PickResultChooser pickResult) {
 254         return nodeAccessor.intersects(node, pickRay, pickResult);
 255     }
 256 
 257     public static double intersectsBounds(Node node, PickRay pickRay) {
 258         return nodeAccessor.intersectsBounds(node, pickRay);
 259     }
 260 
 261     public static void layoutNodeForPrinting(Node node) {
 262         nodeAccessor.layoutNodeForPrinting(node);
 263     }
 264 
 265     public static boolean isDerivedDepthTest(Node node) {
 266         return nodeAccessor.isDerivedDepthTest(node);
 267     }
 268 
 269     public static SubScene getSubScene(Node node) {
 270         return nodeAccessor.getSubScene(node);
 271     }
 272 
 273     public static Accessible getAccessible(Node node) {
 274         return nodeAccessor.getAccessible(node);
 275     }
 276 
 277     public static void reapplyCSS(Node node) {
 278         nodeAccessor.reapplyCSS(node);
 279     }
 280 
 281     public static boolean isTreeVisible(Node node) {
 282         return nodeAccessor.isTreeVisible(node);
 283     }
 284 
 285     public static BooleanExpression treeVisibleProperty(Node node) {
 286         return nodeAccessor.treeVisibleProperty(node);
 287     }
 288 
 289     public static List<Style> getMatchingStyles(CssMetaData cssMetaData, Styleable styleable) {
 290         return getMatchingStyles(cssMetaData, styleable);
 291     }
 292 
 293     public static Map<StyleableProperty<?>,List<Style>> findStyles(Node node, Map<StyleableProperty<?>,List<Style>> styleMap) {
 294         return nodeAccessor.findStyles(node, styleMap);
 295     }
 296 
 297     public static void setNodeAccessor(final NodeAccessor newAccessor) {
 298         if (nodeAccessor != null) {
 299             throw new IllegalStateException();
 300         }
 301 
 302         nodeAccessor = newAccessor;
 303     }
 304 
 305     public static NodeAccessor getNodeAccessor() {
 306         if (nodeAccessor == null) {
 307             throw new IllegalStateException();
 308         }
 309 
 310         return nodeAccessor;
 311     }
 312 
 313     public interface NodeAccessor {
 314         NodeHelper getHelper(Node node);
 315         void setHelper(Node node, NodeHelper nodeHelper);
 316         void doMarkDirty(Node node, DirtyBits dirtyBit);
 317         void doUpdatePeer(Node node);
 318         BaseTransform getLeafTransform(Node node);
 319         Bounds doComputeLayoutBounds(Node node);
 320         void doTransformsChanged(Node node);
 321         void doPickNodeLocal(Node node, PickRay localPickRay,
 322             PickResultChooser result);
 323         boolean doComputeIntersects(Node node, PickRay pickRay,
 324             PickResultChooser pickResult);
 325         void doGeomChanged(Node node);
 326         void doNotifyLayoutBoundsChanged(Node node);
 327         void doProcessCSS(Node node);
 328         boolean isDirty(Node node, DirtyBits dirtyBit);
 329         boolean isDirtyEmpty(Node node);
 330         void syncPeer(Node node);
 331         <P extends NGNode> P getPeer(Node node);
 332         void layoutBoundsChanged(Node node);
 333         void setShowMnemonics(Node node, boolean value);
 334         boolean isShowMnemonics(Node node);
 335         BooleanProperty showMnemonicsProperty(Node node);
 336         boolean traverse(Node node, Direction direction);
 337         double getPivotX(Node node);
 338         double getPivotY(Node node);
 339         double getPivotZ(Node node);
 340         void pickNode(Node node, PickRay pickRay, PickResultChooser result);
 341         boolean intersects(Node node, PickRay pickRay, PickResultChooser pickResult);
 342         double intersectsBounds(Node node, PickRay pickRay);
 343         void layoutNodeForPrinting(Node node);
 344         boolean isDerivedDepthTest(Node node);
 345         SubScene getSubScene(Node node);
 346         void setLabeledBy(Node node, Node labeledBy);
 347         Accessible getAccessible(Node node);
 348         void reapplyCSS(Node node);
 349         boolean isTreeVisible(Node node);
 350         BooleanExpression treeVisibleProperty(Node node);
 351         List<Style> getMatchingStyles(CssMetaData cssMetaData, Styleable styleable);
 352         Map<StyleableProperty<?>,List<Style>> findStyles(Node node,
 353                 Map<StyleableProperty<?>,List<Style>> styleMap);
 354     }
 355 
 356 }