1 /*
   2  * Copyright (c) 2013, 2018, 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.scene.input.PickResultChooser;
  33 import com.sun.javafx.scene.traversal.Direction;
  34 import com.sun.javafx.sg.prism.NGNode;
  35 import com.sun.javafx.util.Utils;
  36 import java.util.List;
  37 import java.util.Map;
  38 import javafx.beans.binding.BooleanExpression;
  39 import javafx.beans.property.BooleanProperty;
  40 import javafx.css.CssMetaData;
  41 import javafx.css.Style;
  42 import javafx.css.Styleable;
  43 import javafx.css.StyleableProperty;
  44 import javafx.geometry.Bounds;
  45 import javafx.scene.Node;
  46 import javafx.scene.SubScene;
  47 import javafx.scene.shape.Shape;
  48 import javafx.scene.shape.Shape3D;
  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 
  65         NodeHelper helper = nodeAccessor.getHelper(node);
  66         if (helper == null) {
  67             String nodeType;
  68             if (node instanceof Shape) {
  69                 nodeType = "Shape";
  70             } else if (node instanceof Shape3D) {
  71                 nodeType = "Shape3D";
  72             } else {
  73                 nodeType = "Node";
  74             }
  75 
  76             throw new UnsupportedOperationException(
  77                     "Applications should not extend the "
  78                     + nodeType + " class directly.");
  79         }
  80         return helper;
  81     }
  82 
  83     protected static void setHelper(Node node, NodeHelper nodeHelper) {
  84         nodeAccessor.setHelper(node, nodeHelper);
  85     }
  86 
  87     /*
  88      * Static helper methods for cases where the implementation is done in an
  89      * instance method that is overridden by subclasses.
  90      * These methods exist in the base class only.
  91      */
  92 
  93     public static NGNode createPeer(Node node) {
  94         return getHelper(node).createPeerImpl(node);
  95     }
  96 
  97     public static void markDirty(Node node, DirtyBits dirtyBit) {
  98         getHelper(node).markDirtyImpl(node, dirtyBit);
  99     }
 100 
 101     public static void updatePeer(Node node) {
 102         getHelper(node).updatePeerImpl(node);
 103     }
 104 
 105     public static Bounds computeLayoutBounds(Node node) {
 106         return getHelper(node).computeLayoutBoundsImpl(node);
 107     }
 108 
 109     /*
 110      * Computes the geometric bounds for this Node. This method is abstract
 111      * and must be implemented by each Node subclass.
 112      */
 113     public static BaseBounds computeGeomBounds(Node node,
 114             BaseBounds bounds, BaseTransform tx) {
 115         return getHelper(node).computeGeomBoundsImpl(node, bounds, tx);
 116     }
 117 
 118     public static void transformsChanged(Node node) {
 119         getHelper(node).transformsChangedImpl(node);
 120     }
 121 
 122     public static boolean computeContains(Node node, double localX, double localY) {
 123         return getHelper(node).computeContainsImpl(node, localX, localY);
 124     }
 125 
 126     public static void pickNodeLocal(Node node, PickRay localPickRay,
 127             PickResultChooser result) {
 128         getHelper(node).pickNodeLocalImpl(node, localPickRay, result);
 129     }
 130 
 131     public static boolean computeIntersects(Node node, PickRay pickRay,
 132             PickResultChooser pickResult) {
 133         return getHelper(node).computeIntersectsImpl(node, pickRay, pickResult);
 134     }
 135 
 136     public static void geomChanged(Node node) {
 137         getHelper(node).geomChangedImpl(node);
 138     }
 139 
 140     public static void notifyLayoutBoundsChanged(Node node) {
 141         getHelper(node).notifyLayoutBoundsChangedImpl(node);
 142     }
 143 
 144     public static void processCSS(Node node) {
 145         getHelper(node).processCSSImpl(node);
 146     }
 147 
 148     /*
 149      * Methods that will be overridden by subclasses
 150      */
 151 
 152     protected abstract NGNode createPeerImpl(Node node);
 153     protected abstract boolean computeContainsImpl(Node node, double localX, double localY);
 154     protected abstract BaseBounds computeGeomBoundsImpl(Node node,
 155             BaseBounds bounds, BaseTransform tx);
 156 
 157     protected void markDirtyImpl(Node node, DirtyBits dirtyBit) {
 158         nodeAccessor.doMarkDirty(node, dirtyBit);
 159     }
 160 
 161     protected void updatePeerImpl(Node node) {
 162         nodeAccessor.doUpdatePeer(node);
 163     }
 164 
 165     protected Bounds computeLayoutBoundsImpl(Node node) {
 166         return nodeAccessor.doComputeLayoutBounds(node);
 167     }
 168 
 169     protected void transformsChangedImpl(Node node) {
 170         nodeAccessor.doTransformsChanged(node);
 171     }
 172 
 173     protected void pickNodeLocalImpl(Node node, PickRay localPickRay,
 174             PickResultChooser result) {
 175         nodeAccessor.doPickNodeLocal(node, localPickRay, result);
 176     }
 177 
 178     protected boolean computeIntersectsImpl(Node node, PickRay pickRay,
 179             PickResultChooser pickResult) {
 180         return nodeAccessor.doComputeIntersects(node, pickRay, pickResult);
 181     }
 182 
 183     protected void geomChangedImpl(Node node) {
 184         nodeAccessor.doGeomChanged(node);
 185     }
 186 
 187     protected void notifyLayoutBoundsChangedImpl(Node node) {
 188         nodeAccessor.doNotifyLayoutBoundsChanged(node);
 189     }
 190 
 191     protected void processCSSImpl(Node node) {
 192         nodeAccessor.doProcessCSS(node);
 193     }
 194 
 195     /*
 196      * Methods used by Node (base) class only
 197      */
 198 
 199     public static boolean isDirty(Node node, DirtyBits dirtyBit) {
 200         return nodeAccessor.isDirty(node, dirtyBit);
 201     }
 202 
 203     public static boolean isDirtyEmpty(Node node) {
 204         return nodeAccessor.isDirtyEmpty(node);
 205     }
 206 
 207     public static void syncPeer(Node node) {
 208         nodeAccessor.syncPeer(node);
 209     }
 210 
 211     public static <P extends NGNode> P getPeer(Node node) {
 212         return nodeAccessor.getPeer(node);
 213     }
 214 
 215     public static BaseTransform getLeafTransform(Node node) {
 216         return nodeAccessor.getLeafTransform(node);
 217     }
 218 
 219     public static void layoutBoundsChanged(Node node) {
 220         nodeAccessor.layoutBoundsChanged(node);
 221     }
 222 
 223     public static void setShowMnemonics(Node node, boolean value) {
 224         nodeAccessor.setShowMnemonics(node, value);
 225     }
 226 
 227     public static boolean isShowMnemonics(Node node) {
 228         return nodeAccessor.isShowMnemonics(node);
 229     }
 230 
 231     public static BooleanProperty showMnemonicsProperty(Node node) {
 232         return nodeAccessor.showMnemonicsProperty(node);
 233     }
 234 
 235     public static boolean traverse(Node node, Direction direction) {
 236         return nodeAccessor.traverse(node, direction);
 237     }
 238 
 239     public static double getPivotX(Node node) {
 240         return nodeAccessor.getPivotX(node);
 241     }
 242 
 243     public static double getPivotY(Node node) {
 244         return nodeAccessor.getPivotY(node);
 245     }
 246 
 247     public static double getPivotZ(Node node) {
 248         return nodeAccessor.getPivotZ(node);
 249     }
 250 
 251     public static void pickNode(Node node, PickRay pickRay,
 252             PickResultChooser result) {
 253         nodeAccessor.pickNode(node, pickRay, result);
 254     }
 255 
 256     public static boolean intersects(Node node, PickRay pickRay,
 257             PickResultChooser pickResult) {
 258         return nodeAccessor.intersects(node, pickRay, pickResult);
 259     }
 260 
 261     public static double intersectsBounds(Node node, PickRay pickRay) {
 262         return nodeAccessor.intersectsBounds(node, pickRay);
 263     }
 264 
 265     public static void layoutNodeForPrinting(Node node) {
 266         nodeAccessor.layoutNodeForPrinting(node);
 267     }
 268 
 269     public static boolean isDerivedDepthTest(Node node) {
 270         return nodeAccessor.isDerivedDepthTest(node);
 271     }
 272 
 273     public static SubScene getSubScene(Node node) {
 274         return nodeAccessor.getSubScene(node);
 275     }
 276 
 277     public static Accessible getAccessible(Node node) {
 278         return nodeAccessor.getAccessible(node);
 279     }
 280 
 281     public static void reapplyCSS(Node node) {
 282         nodeAccessor.reapplyCSS(node);
 283     }
 284 
 285     public static boolean isTreeVisible(Node node) {
 286         return nodeAccessor.isTreeVisible(node);
 287     }
 288 
 289     public static BooleanExpression treeVisibleProperty(Node node) {
 290         return nodeAccessor.treeVisibleProperty(node);
 291     }
 292 
 293     public static boolean isTreeShowing(Node node) {
 294         return nodeAccessor.isTreeShowing(node);
 295     }
 296 
 297     public static BooleanExpression treeShowingProperty(Node node) {
 298         return nodeAccessor.treeShowingProperty(node);
 299     }
 300 
 301     public static List<Style> getMatchingStyles(CssMetaData cssMetaData, Styleable styleable) {
 302         return nodeAccessor.getMatchingStyles(cssMetaData, styleable);
 303     }
 304 
 305     public static Map<StyleableProperty<?>,List<Style>> findStyles(Node node, Map<StyleableProperty<?>,List<Style>> styleMap) {
 306         return nodeAccessor.findStyles(node, styleMap);
 307     }
 308 
 309     public static void setNodeAccessor(final NodeAccessor newAccessor) {
 310         if (nodeAccessor != null) {
 311             throw new IllegalStateException();
 312         }
 313 
 314         nodeAccessor = newAccessor;
 315     }
 316 
 317     public static NodeAccessor getNodeAccessor() {
 318         if (nodeAccessor == null) {
 319             throw new IllegalStateException();
 320         }
 321 
 322         return nodeAccessor;
 323     }
 324 
 325     public interface NodeAccessor {
 326         NodeHelper getHelper(Node node);
 327         void setHelper(Node node, NodeHelper nodeHelper);
 328         void doMarkDirty(Node node, DirtyBits dirtyBit);
 329         void doUpdatePeer(Node node);
 330         BaseTransform getLeafTransform(Node node);
 331         Bounds doComputeLayoutBounds(Node node);
 332         void doTransformsChanged(Node node);
 333         void doPickNodeLocal(Node node, PickRay localPickRay,
 334                 PickResultChooser result);
 335         boolean doComputeIntersects(Node node, PickRay pickRay,
 336                 PickResultChooser pickResult);
 337         void doGeomChanged(Node node);
 338         void doNotifyLayoutBoundsChanged(Node node);
 339         void doProcessCSS(Node node);
 340         boolean isDirty(Node node, DirtyBits dirtyBit);
 341         boolean isDirtyEmpty(Node node);
 342         void syncPeer(Node node);
 343         <P extends NGNode> P getPeer(Node node);
 344         void layoutBoundsChanged(Node node);
 345         void setShowMnemonics(Node node, boolean value);
 346         boolean isShowMnemonics(Node node);
 347         BooleanProperty showMnemonicsProperty(Node node);
 348         boolean traverse(Node node, Direction direction);
 349         double getPivotX(Node node);
 350         double getPivotY(Node node);
 351         double getPivotZ(Node node);
 352         void pickNode(Node node, PickRay pickRay, PickResultChooser result);
 353         boolean intersects(Node node, PickRay pickRay, PickResultChooser pickResult);
 354         double intersectsBounds(Node node, PickRay pickRay);
 355         void layoutNodeForPrinting(Node node);
 356         boolean isDerivedDepthTest(Node node);
 357         SubScene getSubScene(Node node);
 358         void setLabeledBy(Node node, Node labeledBy);
 359         Accessible getAccessible(Node node);
 360         void reapplyCSS(Node node);
 361         boolean isTreeVisible(Node node);
 362         BooleanExpression treeVisibleProperty(Node node);
 363         boolean isTreeShowing(Node node);
 364         BooleanExpression treeShowingProperty(Node node);
 365         List<Style> getMatchingStyles(CssMetaData cssMetaData, Styleable styleable);
 366         Map<StyleableProperty<?>,List<Style>> findStyles(Node node,
 367                 Map<StyleableProperty<?>,List<Style>> styleMap);
 368     }
 369 
 370 }