1 /*
   2  * Copyright (c) 2012, 2015, 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 javafx.scene.control;
  27 
  28 import com.sun.javafx.scene.control.LambdaMultiplePropertyChangeListenerHandler;
  29 import com.sun.javafx.scene.control.behavior.BehaviorBase;
  30 import javafx.application.ConditionalFeature;
  31 import javafx.application.Platform;
  32 import javafx.beans.value.ObservableValue;
  33 import javafx.css.CssMetaData;
  34 import javafx.css.PseudoClass;
  35 import java.util.Collections;
  36 import java.util.List;
  37 import java.util.function.Consumer;
  38 
  39 import javafx.collections.ObservableList;
  40 import javafx.css.Styleable;
  41 import javafx.event.EventHandler;
  42 import javafx.geometry.HPos;
  43 import javafx.geometry.Insets;
  44 import javafx.geometry.VPos;
  45 import javafx.scene.AccessibleAction;
  46 import javafx.scene.AccessibleAttribute;
  47 import javafx.scene.Node;
  48 import javafx.scene.input.MouseEvent;
  49 import javafx.scene.layout.Region;
  50 
  51 /**
  52  * Base implementation class for defining the visual representation of user
  53  * interface controls by defining a scene graph of nodes to represent the
  54  * {@link Skin skin}.
  55  * A user interface control is abstracted behind the {@link Skinnable} interface.
  56  *
  57  * @since JavaFX 8.0
  58  */
  59 public abstract class SkinBase<C extends Control> implements Skin<C> {
  60 
  61     /***************************************************************************
  62      *                                                                         *
  63      * Private fields                                                          *
  64      *                                                                         *
  65      **************************************************************************/
  66 
  67     /**
  68      * The {@code Control} that is referencing this Skin. There is a
  69      * one-to-one relationship between a {@code Skin} and a {@code Control}.
  70      * When a {@code Skin} is set on a {@code Control}, this variable is
  71      * automatically updated.
  72      */
  73     private C control;
  74     
  75     /**
  76      * A local field that directly refers to the children list inside the Control.
  77      */
  78     private ObservableList<Node> children;
  79 
  80     /**
  81      * This is part of the workaround introduced during delomboking. We probably will
  82      * want to adjust the way listeners are added rather than continuing to use this
  83      * map (although it doesn't really do much harm).
  84      */
  85     private LambdaMultiplePropertyChangeListenerHandler lambdaChangeListenerHandler;
  86 
  87 
  88     
  89     /***************************************************************************
  90      *                                                                         *
  91      * Event Handlers / Listeners                                              *
  92      *                                                                         *
  93      **************************************************************************/
  94     
  95     /**
  96      * Mouse handler used for consuming all mouse events (preventing them
  97      * from bubbling up to parent)
  98      */
  99     private static final EventHandler<MouseEvent> mouseEventConsumer = event -> {
 100         /*
 101         ** we used to consume mouse wheel rotations here,
 102         ** be we've switched to ScrollEvents, and only consume those which we use.
 103         ** See RT-13995 & RT-14480
 104         */
 105         event.consume();
 106     };
 107     
 108     
 109     
 110     /***************************************************************************
 111      *                                                                         *
 112      * Constructor                                                             *
 113      *                                                                         *
 114      **************************************************************************/
 115 
 116     /**
 117      * Constructor for all SkinBase instances.
 118      * 
 119      * @param control The control for which this Skin should attach to.
 120      */
 121     protected SkinBase(final C control) {
 122         if (control == null) {
 123             throw new IllegalArgumentException("Cannot pass null for control");
 124         }
 125 
 126         // Update the control and behavior
 127         this.control = control;
 128         this.children = control.getControlChildren();
 129         
 130         // Default behavior for controls is to consume all mouse events
 131         consumeMouseEvents(true);
 132     }
 133     
 134     
 135 
 136     /***************************************************************************
 137      *                                                                         *
 138      * Public API (from Skin)                                                  *
 139      *                                                                         *
 140      **************************************************************************/    
 141 
 142     /** {@inheritDoc} */
 143     @Override public final C getSkinnable() {
 144         return control;
 145     }
 146 
 147     /** {@inheritDoc} */
 148     @Override public final Node getNode() {
 149         return control; 
 150     }
 151 
 152     /** {@inheritDoc} */
 153     @Override public void dispose() { 
 154 //        control.removeEventHandler(ContextMenuEvent.CONTEXT_MENU_REQUESTED, contextMenuHandler);
 155 
 156         // unhook listeners
 157         if (lambdaChangeListenerHandler != null) {
 158             lambdaChangeListenerHandler.dispose();
 159         }
 160 
 161         this.control = null;
 162     }
 163     
 164     
 165     
 166     /***************************************************************************
 167      *                                                                         *
 168      * Public API                                                              *
 169      *                                                                         *
 170      **************************************************************************/     
 171     
 172     /**
 173      * Returns the children of the skin.
 174      */
 175     public final ObservableList<Node> getChildren() {
 176         return children;
 177     }
 178     
 179     /**
 180      * Called during the layout pass of the scenegraph. 
 181      */
 182     protected void layoutChildren(final double contentX, final double contentY,
 183             final double contentWidth, final double contentHeight) {
 184         // By default simply sizes all managed children to fit within the space provided
 185         for (int i=0, max=children.size(); i<max; i++) {
 186             Node child = children.get(i);
 187             if (child.isManaged()) {
 188                 layoutInArea(child, contentX, contentY, contentWidth, contentHeight, -1, HPos.CENTER, VPos.CENTER);
 189             }
 190         }
 191     }
 192     
 193     /**
 194      * Determines whether all mouse events should be automatically consumed.
 195      */
 196     protected final void consumeMouseEvents(boolean value) {
 197         if (value) {
 198             control.addEventHandler(MouseEvent.ANY, mouseEventConsumer);
 199         } else {
 200             control.removeEventHandler(MouseEvent.ANY, mouseEventConsumer);
 201         }
 202     }
 203 
 204 
 205     /**
 206      * Subclasses can invoke this method to register that we want to listen to
 207      * property change events for the given property.
 208      */
 209     protected final void registerChangeListener(ObservableValue<?> property, Consumer<ObservableValue<?>> consumer) {
 210         if (lambdaChangeListenerHandler == null) {
 211             lambdaChangeListenerHandler = new LambdaMultiplePropertyChangeListenerHandler();
 212         }
 213         lambdaChangeListenerHandler.registerChangeListener(property, consumer);
 214     }
 215 
 216 
 217     
 218     
 219     /***************************************************************************
 220      *                                                                         *
 221      * Public Layout-related API                                               *
 222      *                                                                         *
 223      **************************************************************************/
 224     
 225     /**
 226      * Computes the minimum allowable width of the Skin, based on the provided
 227      * height.
 228      *
 229      * @param height The height of the Skin, in case this value might dictate
 230      *      the minimum width.
 231      * @param topInset the pixel snapped top inset
 232      * @param rightInset the pixel snapped right inset
 233      * @param bottomInset the pixel snapped bottom inset
 234      * @param leftInset  the pixel snapped left inset
 235      * @return A double representing the minimum width of this Skin.
 236      */
 237     protected double computeMinWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) {
 238 
 239         double minX = 0;
 240         double maxX = 0;
 241         boolean firstManagedChild = true;
 242         for (int i = 0; i < children.size(); i++) {
 243             Node node = children.get(i);
 244             if (node.isManaged()) {
 245                 final double x = node.getLayoutBounds().getMinX() + node.getLayoutX();
 246                 if (!firstManagedChild) {  // branch prediction favors most often used condition
 247                     minX = Math.min(minX, x);
 248                     maxX = Math.max(maxX, x + node.minWidth(-1));
 249                 } else {
 250                     minX = x;
 251                     maxX = x + node.minWidth(-1);
 252                     firstManagedChild = false;
 253                 }
 254             }
 255         }
 256         double minWidth = maxX - minX;
 257         return leftInset + minWidth + rightInset;
 258     }
 259 
 260     /**
 261      * Computes the minimum allowable height of the Skin, based on the provided
 262      * width.
 263      *
 264      * @param width The width of the Skin, in case this value might dictate
 265      *      the minimum height.
 266      * @param topInset the pixel snapped top inset
 267      * @param rightInset the pixel snapped right inset
 268      * @param bottomInset the pixel snapped bottom inset
 269      * @param leftInset  the pixel snapped left inset
 270      * @return A double representing the minimum height of this Skin.
 271      */
 272     protected double computeMinHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {
 273 
 274         double minY = 0;
 275         double maxY = 0;
 276         boolean firstManagedChild = true;
 277         for (int i = 0; i < children.size(); i++) {
 278             Node node = children.get(i);
 279             if (node.isManaged()) {
 280                 final double y = node.getLayoutBounds().getMinY() + node.getLayoutY();
 281                 if (!firstManagedChild) {  // branch prediction favors most often used condition
 282                     minY = Math.min(minY, y);
 283                     maxY = Math.max(maxY, y + node.minHeight(-1));
 284                 } else {
 285                     minY = y;
 286                     maxY = y + node.minHeight(-1);
 287                     firstManagedChild = false;
 288                 }
 289             }
 290         }
 291         double minHeight = maxY - minY;
 292         return topInset + minHeight + bottomInset;
 293     }
 294 
 295     /**
 296      * Computes the maximum allowable width of the Skin, based on the provided
 297      * height.
 298      *
 299      * @param height The height of the Skin, in case this value might dictate
 300      *      the maximum width.
 301      * @param topInset the pixel snapped top inset
 302      * @param rightInset the pixel snapped right inset
 303      * @param bottomInset the pixel snapped bottom inset
 304      * @param leftInset  the pixel snapped left inset
 305      * @return A double representing the maximum width of this Skin.
 306      */
 307     protected double computeMaxWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) {
 308         return Double.MAX_VALUE;
 309     }
 310     
 311     /**
 312      * Computes the maximum allowable height of the Skin, based on the provided
 313      * width.
 314      *
 315      * @param width The width of the Skin, in case this value might dictate
 316      *      the maximum height.
 317      * @param topInset the pixel snapped top inset
 318      * @param rightInset the pixel snapped right inset
 319      * @param bottomInset the pixel snapped bottom inset
 320      * @param leftInset  the pixel snapped left inset
 321      * @return A double representing the maximum height of this Skin.
 322      */
 323     protected double computeMaxHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {
 324         return Double.MAX_VALUE;
 325     }
 326     
 327     // PENDING_DOC_REVIEW
 328     /**
 329      * Calculates the preferred width of this {@code SkinBase}. The default
 330      * implementation calculates this width as the width of the area occupied
 331      * by its managed children when they are positioned at their
 332      * current positions at their preferred widths.
 333      *
 334      * @param height the height that should be used if preferred width depends on it
 335      * @param topInset the pixel snapped top inset
 336      * @param rightInset the pixel snapped right inset
 337      * @param bottomInset the pixel snapped bottom inset
 338      * @param leftInset  the pixel snapped left inset
 339      * @return the calculated preferred width
 340      */
 341     protected double computePrefWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) {
 342 
 343         double minX = 0;
 344         double maxX = 0;
 345         boolean firstManagedChild = true;
 346         for (int i = 0; i < children.size(); i++) {
 347             Node node = children.get(i);
 348             if (node.isManaged()) {
 349                 final double x = node.getLayoutBounds().getMinX() + node.getLayoutX();
 350                 if (!firstManagedChild) {  // branch prediction favors most often used condition
 351                     minX = Math.min(minX, x);
 352                     maxX = Math.max(maxX, x + node.prefWidth(-1));
 353                 } else {
 354                     minX = x;
 355                     maxX = x + node.prefWidth(-1);
 356                     firstManagedChild = false;
 357                 }
 358             }
 359         }
 360         return maxX - minX;
 361     }
 362     
 363     // PENDING_DOC_REVIEW
 364     /**
 365      * Calculates the preferred height of this {@code SkinBase}. The default
 366      * implementation calculates this height as the height of the area occupied
 367      * by its managed children when they are positioned at their current
 368      * positions at their preferred heights.
 369      *
 370      * @param width the width that should be used if preferred height depends on it
 371      * @param topInset the pixel snapped top inset
 372      * @param rightInset the pixel snapped right inset
 373      * @param bottomInset the pixel snapped bottom inset
 374      * @param leftInset  the pixel snapped left inset
 375      * @return the calculated preferred height
 376      */
 377     protected double computePrefHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {
 378 
 379         double minY = 0;
 380         double maxY = 0;
 381         boolean firstManagedChild = true;
 382         for (int i = 0; i < children.size(); i++) {
 383             Node node = children.get(i);
 384             if (node.isManaged()) {
 385                 final double y = node.getLayoutBounds().getMinY() + node.getLayoutY();
 386                 if (!firstManagedChild) {  // branch prediction favors most often used condition
 387                     minY = Math.min(minY, y);
 388                     maxY = Math.max(maxY, y + node.prefHeight(-1));
 389                 } else {
 390                     minY = y;
 391                     maxY = y + node.prefHeight(-1);
 392                     firstManagedChild = false;
 393                 }
 394             }
 395         }
 396         return maxY - minY;
 397     }
 398     
 399     /**
 400      * Calculates the baseline offset based on the first managed child. If there
 401      * is no such child, returns {@link Node#getBaselineOffset()}.
 402      *
 403      * @param topInset the pixel snapped top inset
 404      * @param rightInset the pixel snapped right inset
 405      * @param bottomInset the pixel snapped bottom inset
 406      * @param leftInset  the pixel snapped left inset
 407      * @return baseline offset
 408      */
 409     protected double computeBaselineOffset(double topInset, double rightInset, double bottomInset, double leftInset) {
 410         int size = children.size();
 411         for (int i = 0; i < size; ++i) {
 412             Node child = children.get(i);
 413             if (child.isManaged()) {
 414                 double offset = child.getBaselineOffset();
 415                 if (offset == Node.BASELINE_OFFSET_SAME_AS_HEIGHT) {
 416                     continue;
 417                 }
 418                 return child.getLayoutBounds().getMinY() + child.getLayoutY() + offset;
 419             }
 420         }
 421         return Node.BASELINE_OFFSET_SAME_AS_HEIGHT;
 422     }
 423 
 424     
 425     /***************************************************************************
 426      *                                                                         *
 427      * (Mostly ugly) Skin -> Control forwarding API                            *
 428      *                                                                         *
 429      **************************************************************************/
 430 
 431     /**
 432      * Utility method to get the top inset which includes padding and border
 433      * inset. Then snapped to whole pixels if getSkinnable().isSnapToPixel() is true.
 434      *
 435      * @return Rounded up insets top
 436      */
 437     protected double snappedTopInset() {
 438         return control.snappedTopInset();
 439     }
 440 
 441     /**
 442      * Utility method to get the bottom inset which includes padding and border
 443      * inset. Then snapped to whole pixels if getSkinnable().isSnapToPixel() is true.
 444      *
 445      * @return Rounded up insets bottom
 446      */
 447     protected double snappedBottomInset() {
 448         return control.snappedBottomInset();
 449     }
 450 
 451     /**
 452      * Utility method to get the left inset which includes padding and border
 453      * inset. Then snapped to whole pixels if getSkinnable().isSnapToPixel() is true.
 454      *
 455      * @return Rounded up insets left
 456      */
 457     protected double snappedLeftInset() {
 458         return control.snappedLeftInset();
 459     }
 460 
 461     /**
 462      * Utility method to get the right inset which includes padding and border
 463      * inset. Then snapped to whole pixels if getSkinnable().isSnapToPixel() is true.
 464      *
 465      * @return Rounded up insets right
 466      */
 467     protected double snappedRightInset() {
 468         return control.snappedRightInset();
 469     }
 470 
 471     /**
 472      * If this region's snapToPixel property is true, returns a value rounded
 473      * to the nearest pixel, else returns the same value.
 474      * @param value the space value to be snapped
 475      * @return value rounded to nearest pixel
 476      */
 477     protected double snapSpace(double value) {
 478         return control.isSnapToPixel() ? Math.round(value) : value;
 479     }
 480     
 481     /**
 482      * If this region's snapToPixel property is true, returns a value ceiled
 483      * to the nearest pixel, else returns the same value.
 484      * @param value the size value to be snapped
 485      * @return value ceiled to nearest pixel
 486      */
 487     protected double snapSize(double value) {
 488         return control.isSnapToPixel() ? Math.ceil(value) : value;
 489     }
 490 
 491     /**
 492      * If this region's snapToPixel property is true, returns a value rounded
 493      * to the nearest pixel, else returns the same value.
 494      * @param value the position value to be snapped
 495      * @return value rounded to nearest pixel
 496      */
 497     protected double snapPosition(double value) {
 498         return control.isSnapToPixel() ? Math.round(value) : value;
 499     }
 500 
 501     /**
 502      * Utility method which positions the child within an area of this
 503      * skin defined by {@code areaX}, {@code areaY}, {@code areaWidth} x {@code areaHeight},
 504      * with a baseline offset relative to that area.
 505      * <p>
 506      * This function does <i>not</i> resize the node and uses the node's layout bounds
 507      * width and height to determine how it should be positioned within the area.
 508      * <p>
 509      * If the vertical alignment is {@code VPos.BASELINE} then it
 510      * will position the node so that its own baseline aligns with the passed in
 511      * {@code baselineOffset}, otherwise the baseline parameter is ignored.
 512      * <p>
 513      * If {@code snapToPixel} is {@code true} for this skin, then the x/y position
 514      * values will be rounded to their nearest pixel boundaries.
 515      *
 516      * @param child the child being positioned within this skin
 517      * @param areaX the horizontal offset of the layout area relative to this skin
 518      * @param areaY the vertical offset of the layout area relative to this skin
 519      * @param areaWidth  the width of the layout area
 520      * @param areaHeight the height of the layout area
 521      * @param areaBaselineOffset the baseline offset to be used if VPos is BASELINE
 522      * @param halignment the horizontal alignment for the child within the area
 523      * @param valignment the vertical alignment for the child within the area
 524      *
 525      */
 526     protected void positionInArea(Node child, double areaX, double areaY, 
 527             double areaWidth, double areaHeight, double areaBaselineOffset, 
 528             HPos halignment, VPos valignment) {
 529         positionInArea(child, areaX, areaY, areaWidth, areaHeight, 
 530                 areaBaselineOffset, Insets.EMPTY, halignment, valignment);
 531     }
 532 
 533     /**
 534      * Utility method which positions the child within an area of this
 535      * skin defined by {@code areaX}, {@code areaY}, {@code areaWidth} x {@code areaHeight},
 536      * with a baseline offset relative to that area.
 537      * <p>
 538      * This function does <i>not</i> resize the node and uses the node's layout bounds
 539      * width and height to determine how it should be positioned within the area.
 540      * <p>
 541      * If the vertical alignment is {@code VPos.BASELINE} then it
 542      * will position the node so that its own baseline aligns with the passed in
 543      * {@code baselineOffset},  otherwise the baseline parameter is ignored.
 544      * <p>
 545      * If {@code snapToPixel} is {@code true} for this skin, then the x/y position
 546      * values will be rounded to their nearest pixel boundaries.
 547      * <p>
 548      * If {@code margin} is non-null, then that space will be allocated around the
 549      * child within the layout area.  margin may be null.
 550      *
 551      * @param child the child being positioned within this skin
 552      * @param areaX the horizontal offset of the layout area relative to this skin
 553      * @param areaY the vertical offset of the layout area relative to this skin
 554      * @param areaWidth  the width of the layout area
 555      * @param areaHeight the height of the layout area
 556      * @param areaBaselineOffset the baseline offset to be used if VPos is BASELINE
 557      * @param margin the margin of space to be allocated around the child
 558      * @param halignment the horizontal alignment for the child within the area
 559      * @param valignment the vertical alignment for the child within the area
 560      *
 561      * @since JavaFX 8.0
 562      */
 563     protected void positionInArea(Node child, double areaX, double areaY,
 564             double areaWidth, double areaHeight, double areaBaselineOffset, 
 565             Insets margin, HPos halignment, VPos valignment) {
 566         Region.positionInArea(child, areaX, areaY, areaWidth, areaHeight, 
 567                 areaBaselineOffset, margin, halignment, valignment, 
 568                 control.isSnapToPixel());
 569     }
 570 
 571     /**
 572      * Utility method which lays out the child within an area of this
 573      * skin defined by {@code areaX}, {@code areaY}, {@code areaWidth} x {@code areaHeight},
 574      * with a baseline offset relative to that area.
 575      * <p>
 576      * If the child is resizable, this method will resize it to fill the specified
 577      * area unless the node's maximum size prevents it.  If the node's maximum
 578      * size preference is less than the area size, the maximum size will be used.
 579      * If node's maximum is greater than the area size, then the node will be
 580      * resized to fit within the area, unless its minimum size prevents it.
 581      * <p>
 582      * If the child has a non-null contentBias, then this method will use it when
 583      * resizing the child.  If the contentBias is horizontal, it will set its width
 584      * first to the area's width (up to the child's max width limit) and then pass
 585      * that value to compute the child's height.  If child's contentBias is vertical,
 586      * then it will set its height to the area height (up to child's max height limit)
 587      * and pass that height to compute the child's width.  If the child's contentBias
 588      * is null, then it's width and height have no dependencies on each other.
 589      * <p>
 590      * If the child is not resizable (Shape, Group, etc) then it will only be
 591      * positioned and not resized.
 592      * <p>
 593      * If the child's resulting size differs from the area's size (either
 594      * because it was not resizable or it's sizing preferences prevented it), then
 595      * this function will align the node relative to the area using horizontal and
 596      * vertical alignment values.
 597      * If valignment is {@code VPos.BASELINE} then the node's baseline will be aligned
 598      * with the area baseline offset parameter, otherwise the baseline parameter
 599      * is ignored.
 600      * <p>
 601      * If {@code snapToPixel} is {@code true} for this skin, then the resulting x,y
 602      * values will be rounded to their nearest pixel boundaries and the
 603      * width/height values will be ceiled to the next pixel boundary.
 604      *
 605      * @param child the child being positioned within this skin
 606      * @param areaX the horizontal offset of the layout area relative to this skin
 607      * @param areaY the vertical offset of the layout area relative to this skin
 608      * @param areaWidth  the width of the layout area
 609      * @param areaHeight the height of the layout area
 610      * @param areaBaselineOffset the baseline offset to be used if VPos is BASELINE
 611      * @param halignment the horizontal alignment for the child within the area
 612      * @param valignment the vertical alignment for the child within the area
 613      *
 614      */
 615     protected void layoutInArea(Node child, double areaX, double areaY,
 616                                double areaWidth, double areaHeight,
 617                                double areaBaselineOffset,
 618                                HPos halignment, VPos valignment) {
 619         layoutInArea(child, areaX, areaY, areaWidth, areaHeight, areaBaselineOffset, 
 620                 Insets.EMPTY, true, true, halignment, valignment);
 621     }
 622 
 623     /**
 624      * Utility method which lays out the child within an area of this
 625      * skin defined by {@code areaX}, {@code areaY}, {@code areaWidth} x {@code areaHeight},
 626      * with a baseline offset relative to that area.
 627      * <p>
 628      * If the child is resizable, this method will resize it to fill the specified
 629      * area unless the node's maximum size prevents it.  If the node's maximum
 630      * size preference is less than the area size, the maximum size will be used.
 631      * If node's maximum is greater than the area size, then the node will be
 632      * resized to fit within the area, unless its minimum size prevents it.
 633      * <p>
 634      * If the child has a non-null contentBias, then this method will use it when
 635      * resizing the child.  If the contentBias is horizontal, it will set its width
 636      * first to the area's width (up to the child's max width limit) and then pass
 637      * that value to compute the child's height.  If child's contentBias is vertical,
 638      * then it will set its height to the area height (up to child's max height limit)
 639      * and pass that height to compute the child's width.  If the child's contentBias
 640      * is null, then it's width and height have no dependencies on each other.
 641      * <p>
 642      * If the child is not resizable (Shape, Group, etc) then it will only be
 643      * positioned and not resized.
 644      * <p>
 645      * If the child's resulting size differs from the area's size (either
 646      * because it was not resizable or it's sizing preferences prevented it), then
 647      * this function will align the node relative to the area using horizontal and
 648      * vertical alignment values.
 649      * If valignment is {@code VPos.BASELINE} then the node's baseline will be aligned
 650      * with the area baseline offset parameter, otherwise the baseline parameter
 651      * is ignored.
 652      * <p>
 653      * If {@code margin} is non-null, then that space will be allocated around the
 654      * child within the layout area.  margin may be null.
 655      * <p>
 656      * If {@code snapToPixel} is {@code true} for this skin, then the resulting x,y
 657      * values will be rounded to their nearest pixel boundaries and the
 658      * width/height values will be ceiled to the next pixel boundary.
 659      *
 660      * @param child the child being positioned within this skin
 661      * @param areaX the horizontal offset of the layout area relative to this skin
 662      * @param areaY the vertical offset of the layout area relative to this skin
 663      * @param areaWidth  the width of the layout area
 664      * @param areaHeight the height of the layout area
 665      * @param areaBaselineOffset the baseline offset to be used if VPos is BASELINE
 666      * @param margin the margin of space to be allocated around the child
 667      * @param halignment the horizontal alignment for the child within the area
 668      * @param valignment the vertical alignment for the child within the area
 669      */
 670     protected void layoutInArea(Node child, double areaX, double areaY,
 671                                double areaWidth, double areaHeight,
 672                                double areaBaselineOffset,
 673                                Insets margin,
 674                                HPos halignment, VPos valignment) {
 675         layoutInArea(child, areaX, areaY, areaWidth, areaHeight, areaBaselineOffset,
 676                 margin, true, true, halignment, valignment);
 677     }
 678 
 679     /**
 680      * Utility method which lays out the child within an area of this
 681      * skin defined by {@code areaX}, {@code areaY}, {@code areaWidth} x {@code areaHeight},
 682      * with a baseline offset relative to that area.
 683      * <p>
 684      * If the child is resizable, this method will use {@code fillWidth} and {@code fillHeight}
 685      * to determine whether to resize it to fill the area or keep the child at its
 686      * preferred dimension.  If fillWidth/fillHeight are true, then this method
 687      * will only resize the child up to its max size limits.  If the node's maximum
 688      * size preference is less than the area size, the maximum size will be used.
 689      * If node's maximum is greater than the area size, then the node will be
 690      * resized to fit within the area, unless its minimum size prevents it.
 691      * <p>
 692      * If the child has a non-null contentBias, then this method will use it when
 693      * resizing the child.  If the contentBias is horizontal, it will set its width
 694      * first and then pass that value to compute the child's height.  If child's
 695      * contentBias is vertical, then it will set its height first
 696      * and pass that value to compute the child's width.  If the child's contentBias
 697      * is null, then it's width and height have no dependencies on each other.
 698      * <p>
 699      * If the child is not resizable (Shape, Group, etc) then it will only be
 700      * positioned and not resized.
 701      * <p>
 702      * If the child's resulting size differs from the area's size (either
 703      * because it was not resizable or it's sizing preferences prevented it), then
 704      * this function will align the node relative to the area using horizontal and
 705      * vertical alignment values.
 706      * If valignment is {@code VPos.BASELINE} then the node's baseline will be aligned
 707      * with the area baseline offset parameter, otherwise the baseline parameter
 708      * is ignored.
 709      * <p>
 710      * If {@code margin} is non-null, then that space will be allocated around the
 711      * child within the layout area.  margin may be null.
 712      * <p>
 713      * If {@code snapToPixel} is {@code true} for this skin, then the resulting x,y
 714      * values will be rounded to their nearest pixel boundaries and the
 715      * width/height values will be ceiled to the next pixel boundary.
 716      *
 717      * @param child the child being positioned within this skin
 718      * @param areaX the horizontal offset of the layout area relative to this skin
 719      * @param areaY the vertical offset of the layout area relative to this skin
 720      * @param areaWidth  the width of the layout area
 721      * @param areaHeight the height of the layout area
 722      * @param areaBaselineOffset the baseline offset to be used if VPos is BASELINE
 723      * @param margin the margin of space to be allocated around the child
 724      * @param fillWidth whether or not the child should be resized to fill the area width or kept to its preferred width
 725      * @param fillHeight whether or not the child should e resized to fill the area height or kept to its preferred height
 726      * @param halignment the horizontal alignment for the child within the area
 727      * @param valignment the vertical alignment for the child within the area
 728      */
 729     protected void layoutInArea(Node child, double areaX, double areaY,
 730                                double areaWidth, double areaHeight,
 731                                double areaBaselineOffset,
 732                                Insets margin, boolean fillWidth, boolean fillHeight,
 733                                HPos halignment, VPos valignment) {
 734         Region.layoutInArea(child, areaX, areaY, areaWidth, areaHeight, 
 735                 areaBaselineOffset, margin, fillWidth, fillHeight, halignment, 
 736                 valignment, control.isSnapToPixel());
 737     }
 738     
 739     
 740     
 741     /***************************************************************************
 742      *                                                                         *
 743      * Private Implementation                                                  *
 744      *                                                                         *
 745      **************************************************************************/     
 746     
 747     
 748     
 749      /**************************************************************************
 750       *                                                                        *
 751       * Specialization of CSS handling code                                    *
 752       *                                                                        *
 753      **************************************************************************/
 754 
 755     private static class StyleableProperties {
 756         private static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES;
 757 
 758         static {
 759             STYLEABLES = Collections.unmodifiableList(Control.getClassCssMetaData());
 760         }
 761     }
 762 
 763     /** 
 764      * Returns the CssMetaData associated with this class, which may include the
 765      * CssMetaData of its super classes.
 766      */
 767     public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() {
 768         return SkinBase.StyleableProperties.STYLEABLES;
 769     }
 770 
 771     /**
 772      * This method should delegate to {@link Node#getClassCssMetaData()} so that
 773      * a Node's CssMetaData can be accessed without the need for reflection.
 774      * @return The CssMetaData associated with this node, which may include the
 775      * CssMetaData of its super classes.
 776      */
 777     public List<CssMetaData<? extends Styleable, ?>> getCssMetaData() {
 778         return getClassCssMetaData();
 779     }
 780     
 781     /**
 782      * Used to specify that a pseudo-class of this Node has changed. If the
 783      * pseudo-class is used in a CSS selector that matches this Node, CSS will
 784      * be reapplied. Typically, this method is called from the {@code invalidated}
 785      * method of a property that is used as a pseudo-class. For example:
 786      * <code><pre>
 787      *
 788      *     private static final PseudoClass MY_PSEUDO_CLASS_STATE = PseudoClass.getPseudoClass("my-state");
 789      *
 790      *     BooleanProperty myPseudoClassState = new BooleanPropertyBase(false) {
 791      *
 792      *           {@literal @}Override public void invalidated() {
 793      *                pseudoClassStateChanged(MY_PSEUDO_CLASS_STATE, get());
 794      *           }
 795      *
 796      *           {@literal @}Override public Object getBean() {
 797      *               return MyControl.this;
 798      *           }
 799      *
 800      *           {@literal @}Override public String getName() {
 801      *               return "myPseudoClassState";
 802      *           }
 803      *       };
 804      * </pre><code>
 805      *
 806      * @see Node#pseudoClassStateChanged
 807      * @param pseudoClass the pseudo-class that has changed state
 808      * @param active whether or not the state is active
 809      * @since JavaFX 8.0
 810      */
 811     public final void pseudoClassStateChanged(PseudoClass pseudoClass, boolean active) {
 812         Control ctl = getSkinnable();
 813         if (ctl != null) {
 814             ctl.pseudoClassStateChanged(pseudoClass, active);
 815         }
 816     }
 817 
 818 
 819     /***************************************************************************
 820      *                                                                         *
 821      * Accessibility handling                                                  *
 822      *                                                                         *
 823      **************************************************************************/
 824 
 825     /**
 826      * This method is called by the assistive technology to request
 827      * the value for an attribute.
 828      * <p>
 829      * This method is commonly overridden by subclasses to implement
 830      * attributes that are required for a specific role.<br>
 831      * If a particular attribute is not handled, the super class implementation
 832      * must be called.
 833      * </p>
 834      *
 835      * @param attribute the requested attribute
 836      * @param parameters optional list of parameters
 837      * @return the value for the requested attribute
 838      *
 839      * @see AccessibleAttribute
 840      * @see Node#queryAccessibleAttribute
 841      *
 842      * @since JavaFX 8u40
 843      */
 844     protected Object queryAccessibleAttribute(AccessibleAttribute attribute, Object... parameters) {
 845         return null;
 846     }
 847 
 848     /**
 849      * This method is called by the assistive technology to request the action
 850      * indicated by the argument should be executed.
 851      * <p>
 852      * This method is commonly overridden by subclasses to implement
 853      * action that are required for a specific role.<br>
 854      * If a particular action is not handled, the super class implementation
 855      * must be called.
 856      * </p>
 857      *
 858      * @param action the action to execute
 859      * @param parameters optional list of parameters
 860      *
 861      * @see AccessibleAction
 862      * @see Node#executeAccessibleAction
 863      *
 864      * @since JavaFX 8u40
 865      */
 866     protected void executeAccessibleAction(AccessibleAction action, Object... parameters) {
 867     }
 868 
 869     /***************************************************************************
 870      *                                                                         *
 871      * Testing-only API                                                        *
 872      *                                                                         *
 873      **************************************************************************/
 874 
 875 }