1 /*
   2  * Copyright (c) 2011, 2013, 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.layout;
  27 
  28 import java.util.EnumSet;
  29 import javafx.geometry.Insets;
  30 import javafx.scene.paint.Color;
  31 import javafx.scene.shape.Circle;
  32 import org.junit.Before;
  33 import org.junit.Test;
  34 
  35 import static org.junit.Assert.*;
  36 
  37 /**
  38  * Tests for Region picking. By default, Region has pickOnBounds set to true, so picking
  39  * anything within the bounds of the region will return true, anything outside the bounds
  40  * false. However, due to RT-25066, the bounds of a region defined by a shape will be 0x0,
  41  * in which case it will never be picked.
  42  *
  43  * If pickOnBounds is false, then an entire different code path is executed. We don't care
  44  * whether a fill is transparent or not (transparent fills can still cause the region to
  45  * pick), but we do care about picking within the "shape" and picking within the rounded
  46  * rectangle which is created as a result of background fills / background images.
  47  *
  48  * In the case of background images, we don't care about whether we are picking a transparent
  49  * pixel or not, but just based on the insets etc (since we don't have a good means for testing
  50  * the image pixel value).
  51  */
  52 public class RegionPickTest {
  53     private static final double X = 0;
  54     private static final double Y = 0;
  55     private static final double WIDTH = 100;
  56     private static final double HEIGHT = 100;
  57     private static final double CENTER_X = X + (WIDTH / 2.0);
  58     private static final double CENTER_Y = Y + (HEIGHT / 2.0);
  59     private static final double LEFT_OF = X - 10;
  60     private static final double ABOVE = Y - 10;
  61     private static final double RIGHT_OF = X + WIDTH + 10;
  62     private static final double BELOW = Y + HEIGHT + 10;
  63 
  64     private Region region;
  65 
  66     @Before public void setup() {
  67         region = new Region();
  68         region.resizeRelocate(X, Y, WIDTH, HEIGHT);
  69         region.setPickOnBounds(false);
  70     }
  71 
  72     /**************************************************************************
  73      *                                                                        *
  74      * Set of tests to ensure that picking within / without a region with     *
  75      * pickOnBounds set to true (the normal default) results in expected      *
  76      * behavior (pick when within bounds, not when without bounds)            *
  77      *                                                                        *
  78      *************************************************************************/
  79 
  80     @Test public void pickingNormalRegion() {
  81         region.setPickOnBounds(true);
  82         assertFalse(region.contains(LEFT_OF, CENTER_Y));
  83         assertFalse(region.contains(CENTER_X, ABOVE));
  84         assertFalse(region.contains(RIGHT_OF, CENTER_Y));
  85         assertFalse(region.contains(CENTER_X, BELOW));
  86         assertTrue(region.contains(CENTER_X, CENTER_Y));
  87     }
  88 
  89     /**************************************************************************
  90      *                                                                        *
  91      * Test for a Region which has no fills of any kind, but has              *
  92      * pickOnBounds set to false. Such a Region should never pick.            *
  93      *                                                                        *
  94      *************************************************************************/
  95 
  96     @Test public void pickingEmptyRegionDoesNotWork() {
  97         assertFalse(region.contains(LEFT_OF, CENTER_Y));
  98         assertFalse(region.contains(CENTER_X, ABOVE));
  99         assertFalse(region.contains(RIGHT_OF, CENTER_Y));
 100         assertFalse(region.contains(CENTER_X, BELOW));
 101         assertFalse(region.contains(CENTER_X, CENTER_Y));
 102     }
 103 
 104     /**************************************************************************
 105      *                                                                        *
 106      * Test behavior when picking a region with fills, but no shape or border *
 107      * or images.                                                             *
 108      *                                                                        *
 109      *************************************************************************/
 110 
 111     @Test public void pickingRectangularFillWorks() {
 112         region.setBackground(new Background(new BackgroundFill(Color.RED, CornerRadii.EMPTY, Insets.EMPTY)));
 113         assertFalse(region.contains(LEFT_OF, CENTER_Y));
 114         assertFalse(region.contains(CENTER_X, ABOVE));
 115         assertFalse(region.contains(RIGHT_OF, CENTER_Y));
 116         assertFalse(region.contains(CENTER_X, BELOW));
 117         assertTrue(region.contains(CENTER_X, CENTER_Y));
 118     }
 119 
 120     @Test public void pickingRectangularFillWithInsetsWorks() {
 121         // With insets of 10, we ought to not pick inside the region until we get to position 10
 122         region.setBackground(new Background(new BackgroundFill(Color.RED, CornerRadii.EMPTY, new Insets(10))));
 123         assertFalse(region.contains(X + 9, CENTER_Y));
 124         assertFalse(region.contains(CENTER_X, Y + 9));
 125         assertFalse(region.contains(X + WIDTH - 9, CENTER_Y));
 126         assertFalse(region.contains(CENTER_X, Y + HEIGHT - 9));
 127         assertTrue(region.contains(X + 10, CENTER_Y));
 128         assertTrue(region.contains(CENTER_X, Y + 10));
 129         assertTrue(region.contains(X + WIDTH - 10, CENTER_Y));
 130         assertTrue(region.contains(CENTER_X, Y + HEIGHT - 10));
 131         assertTrue(region.contains(CENTER_X, CENTER_Y));
 132     }
 133 
 134     @Test public void pickingRectangularFillWithUniformRadiusWorks() {
 135         region.setBackground(new Background(new BackgroundFill(Color.RED, new CornerRadii(10), Insets.EMPTY)));
 136         // Check points in the top-left corner area
 137         assertTrue(region.contains(X, Y + 10));
 138         assertTrue(region.contains(X + 10, Y));
 139         assertTrue(region.contains(X + 10 - (10 * Math.cos(45)), Y + 10 - (10 * Math.sin(45))));
 140         assertTrue(region.contains(X + 10 - (9 * Math.cos(45)), Y + 10 - (9 * Math.sin(45))));
 141         assertFalse(region.contains(X + 10 - (11 * Math.cos(45)), Y + 10 - (11 * Math.sin(45))));
 142         // Check points in the top-right corner area
 143         assertTrue(region.contains(X + WIDTH, Y + 10));
 144         assertTrue(region.contains(X + WIDTH - 10, Y));
 145         assertTrue(region.contains(X + WIDTH - 10 + (10 * Math.cos(45)), Y + 10 - (10 * Math.sin(45))));
 146         assertTrue(region.contains(X + WIDTH - 10 + (9 * Math.cos(45)), Y + 10 - (9 * Math.sin(45))));
 147         assertFalse(region.contains(X + WIDTH - 10 + (11 * Math.cos(45)), Y + 10 - (11 * Math.sin(45))));
 148         // Check points in the bottom-right corner area
 149         assertTrue(region.contains(X + WIDTH, Y + HEIGHT - 10));
 150         assertTrue(region.contains(X + WIDTH - 10, Y + HEIGHT));
 151         assertTrue(region.contains(X + WIDTH - 10 + (10 * Math.cos(45)), Y + HEIGHT - 10 + (10 * Math.sin(45))));
 152         assertTrue(region.contains(X + WIDTH - 10 + (9 * Math.cos(45)), Y + HEIGHT - 10 + (9 * Math.sin(45))));
 153         assertFalse(region.contains(X + WIDTH - 10 + (11 * Math.cos(45)), Y + HEIGHT - 10 + (11 * Math.sin(45))));
 154         // Check points in the bottom-left corner area
 155         assertTrue(region.contains(X, Y + HEIGHT - 10));
 156         assertTrue(region.contains(X + 10, Y + HEIGHT));
 157         assertTrue(region.contains(X + 10 - (10 * Math.cos(45)), Y + HEIGHT - 10 + (10 * Math.sin(45))));
 158         assertTrue(region.contains(X + 10 - (9 * Math.cos(45)), Y + HEIGHT - 10 + (9 * Math.sin(45))));
 159         assertFalse(region.contains(X + 10 - (11 * Math.cos(45)), Y + HEIGHT - 10 + (11 * Math.sin(45))));
 160         // Check the center
 161         assertTrue(region.contains(CENTER_X, CENTER_Y));
 162     }
 163 
 164     @Test public void pickingRectangularFillWithUniformRadiusWithInsetsWorks() {
 165         region.setBackground(new Background(new BackgroundFill(Color.RED, new CornerRadii(10), new Insets(10))));
 166         // Check points in the top-left corner area
 167         assertTrue(region.contains(X + 10, Y + 20));
 168         assertTrue(region.contains(X + 20, Y + 10));
 169         assertTrue(region.contains(X + 20 - (10 * Math.cos(45)), Y + 20 - (10 * Math.sin(45))));
 170         assertTrue(region.contains(X + 20 - (9 * Math.cos(45)), Y + 20 - (9 * Math.sin(45))));
 171         assertFalse(region.contains(X + 20 - (11 * Math.cos(45)), Y + 20 - (11 * Math.sin(45))));
 172         // Check points in the top-right corner area
 173         assertTrue(region.contains(X + WIDTH - 10, Y + 20));
 174         assertTrue(region.contains(X + WIDTH - 20, Y + 10));
 175         assertTrue(region.contains(X + WIDTH - 20 + (10 * Math.cos(45)), Y + 20 - (10 * Math.sin(45))));
 176         assertTrue(region.contains(X + WIDTH - 20 + (9 * Math.cos(45)), Y + 20 - (9 * Math.sin(45))));
 177         assertFalse(region.contains(X + WIDTH - 20 + (11 * Math.cos(45)), Y + 20 - (11 * Math.sin(45))));
 178         // Check points in the bottom-right corner area
 179         assertTrue(region.contains(X + WIDTH - 10, Y + HEIGHT - 20));
 180         assertTrue(region.contains(X + WIDTH - 20, Y + HEIGHT - 10));
 181         assertTrue(region.contains(X + WIDTH - 20 + (10 * Math.cos(45)), Y + HEIGHT - 20 + (10 * Math.sin(45))));
 182         assertTrue(region.contains(X + WIDTH - 20 + (9 * Math.cos(45)), Y + HEIGHT - 20 + (9 * Math.sin(45))));
 183         assertFalse(region.contains(X + WIDTH - 20 + (11 * Math.cos(45)), Y + HEIGHT - 20 + (11 * Math.sin(45))));
 184         // Check points in the bottom-left corner area
 185         assertTrue(region.contains(X + 10, Y + HEIGHT - 20));
 186         assertTrue(region.contains(X + 20, Y + HEIGHT - 10));
 187         assertTrue(region.contains(X + 20 - (10 * Math.cos(45)), Y + HEIGHT - 20 + (10 * Math.sin(45))));
 188         assertTrue(region.contains(X + 20 - (9 * Math.cos(45)), Y + HEIGHT - 20 + (9 * Math.sin(45))));
 189         assertFalse(region.contains(X + 20 - (11 * Math.cos(45)), Y + HEIGHT - 20 + (11 * Math.sin(45))));
 190         // Check the center
 191         assertTrue(region.contains(CENTER_X, CENTER_Y));
 192     }
 193 
 194     // test with really really large corner radius
 195     @Test public void pickingRectangularFillWithUniformVERYLARGERadiusWorks() {
 196         region.setBackground(new Background(new BackgroundFill(Color.RED, new CornerRadii(10000000), Insets.EMPTY)));
 197         // This produces an effective radius of 50 due to my width/height being 100x100
 198         // Check points in the top-left corner area
 199         assertTrue(region.contains(X, Y + 50));
 200         assertTrue(region.contains(X + 50, Y));
 201         assertTrue(region.contains(X + 50 - (50 * Math.cos(45)), Y + 50 - (50 * Math.sin(45))));
 202         assertTrue(region.contains(X + 50 - (49 * Math.cos(45)), Y + 50 - (49 * Math.sin(45))));
 203         assertFalse(region.contains(X + 50 - (51 * Math.cos(45)), Y + 50 - (51 * Math.sin(45))));
 204         // Check points in the top-right corner area
 205         assertTrue(region.contains(X + WIDTH, Y + 50));
 206         assertTrue(region.contains(X + WIDTH - 50, Y));
 207         assertTrue(region.contains(X + WIDTH - 50 + (50 * Math.cos(45)), Y + 50 - (50 * Math.sin(45))));
 208         assertTrue(region.contains(X + WIDTH - 50 + (49 * Math.cos(45)), Y + 50 - (49 * Math.sin(45))));
 209         assertFalse(region.contains(X + WIDTH - 50 + (51 * Math.cos(45)), Y + 50 - (51 * Math.sin(45))));
 210         // Check points in the bottom-right corner area
 211         assertTrue(region.contains(X + WIDTH, Y + HEIGHT - 50));
 212         assertTrue(region.contains(X + WIDTH - 50, Y + HEIGHT));
 213         assertTrue(region.contains(X + WIDTH - 50 + (50 * Math.cos(45)), Y + HEIGHT - 50 + (50 * Math.sin(45))));
 214         assertTrue(region.contains(X + WIDTH - 50 + (49 * Math.cos(45)), Y + HEIGHT - 50 + (49 * Math.sin(45))));
 215         assertFalse(region.contains(X + WIDTH - 50 + (51 * Math.cos(45)), Y + HEIGHT - 50 + (51 * Math.sin(45))));
 216         // Check points in the bottom-left corner area
 217         assertTrue(region.contains(X, Y + HEIGHT - 50));
 218         assertTrue(region.contains(X + 50, Y + HEIGHT));
 219         assertTrue(region.contains(X + 50 - (50 * Math.cos(45)), Y + HEIGHT - 50 + (50 * Math.sin(45))));
 220         assertTrue(region.contains(X + 50 - (49 * Math.cos(45)), Y + HEIGHT - 50 + (49 * Math.sin(45))));
 221         assertFalse(region.contains(X + 50 - (51 * Math.cos(45)), Y + HEIGHT - 50 + (51 * Math.sin(45))));
 222         // Check the center
 223         assertTrue(region.contains(CENTER_X, CENTER_Y));
 224     }
 225 
 226     @Test public void pickingRectangularFillWithIndependentRadiusWorks() {
 227         region.setBackground(new Background(new BackgroundFill(Color.RED, new CornerRadii(1, 2, 3, 4, false),
 228                                                                Insets.EMPTY)));
 229         // Check points in the top-left corner area
 230         assertTrue(region.contains(X, Y + 1));
 231         assertTrue(region.contains(X + 1, Y));
 232         assertTrue(region.contains(X + 1 - (1 * Math.cos(45)), Y + 1 - (1 * Math.sin(45))));
 233         assertTrue(region.contains(X + 1 - (.5 * Math.cos(45)), Y + 1 - (.5 * Math.sin(45))));
 234         assertFalse(region.contains(X + 1 - (2 * Math.cos(45)), Y + 1 - (2 * Math.sin(45))));
 235         // Check points in the top-right corner area
 236         assertTrue(region.contains(X + WIDTH, Y + 2));
 237         assertTrue(region.contains(X + WIDTH - 2, Y));
 238         assertTrue(region.contains(X + WIDTH - 2 + (2 * Math.cos(45)), Y + 2 - (2 * Math.sin(45))));
 239         assertTrue(region.contains(X + WIDTH - 2 + (1 * Math.cos(45)), Y + 2 - (1 * Math.sin(45))));
 240         assertFalse(region.contains(X + WIDTH - 2 + (3 * Math.cos(45)), Y + 2 - (3 * Math.sin(45))));
 241         // Check points in the bottom-right corner area
 242         assertTrue(region.contains(X + WIDTH, Y + HEIGHT - 3));
 243         assertTrue(region.contains(X + WIDTH - 3, Y + HEIGHT));
 244         assertTrue(region.contains(X + WIDTH - 3 + (3 * Math.cos(45)), Y + HEIGHT - 3 + (3 * Math.sin(45))));
 245         assertTrue(region.contains(X + WIDTH - 3 + (2 * Math.cos(45)), Y + HEIGHT - 3 + (2 * Math.sin(45))));
 246         assertFalse(region.contains(X + WIDTH - 3 + (4 * Math.cos(45)), Y + HEIGHT - 3 + (4 * Math.sin(45))));
 247         // Check points in the bottom-left corner area
 248         assertTrue(region.contains(X, Y + HEIGHT - 4));
 249         assertTrue(region.contains(X + 4, Y + HEIGHT));
 250         assertTrue(region.contains(X + 4 - (4 * Math.cos(45)), Y + HEIGHT - 4 + (4 * Math.sin(45))));
 251         assertTrue(region.contains(X + 4 - (3 * Math.cos(45)), Y + HEIGHT - 4 + (3 * Math.sin(45))));
 252         assertFalse(region.contains(X + 4 - (5 * Math.cos(45)), Y + HEIGHT - 4 + (5 * Math.sin(45))));
 253         // Check the center
 254         assertTrue(region.contains(CENTER_X, CENTER_Y));
 255     }
 256 
 257     @Test public void pickingRectangularFillWithIndependentRadiusWorks2() {
 258         region.setBackground(new Background(new BackgroundFill(Color.RED,
 259             new CornerRadii(1, 2, 3, 4, 5, 6, 7, 8, false, false, false, false, false, false, false, false),
 260             Insets.EMPTY)));
 261         // Check points in the top-left corner area
 262         assertTrue(region.contains(X, Y + 2));
 263         assertTrue(region.contains(X + 1, Y));
 264         assertTrue(region.contains(X + 1 - (1 * Math.cos(45)), Y + 2 - (2 * Math.sin(45))));
 265         assertTrue(region.contains(X + 1 - (.5 * Math.cos(45)), Y + 2 - (1 * Math.sin(45))));
 266         assertFalse(region.contains(X + 1 - (2 * Math.cos(45)), Y + 2 - (3 * Math.sin(45))));
 267         // Check points in the top-right corner area
 268         assertTrue(region.contains(X + WIDTH, Y + 3));
 269         assertTrue(region.contains(X + WIDTH - 4, Y));
 270         assertTrue(region.contains(X + WIDTH - 4 + (4 * Math.cos(45)), Y + 3 - (3 * Math.sin(45))));
 271         assertTrue(region.contains(X + WIDTH - 4 + (3 * Math.cos(45)), Y + 3 - (2 * Math.sin(45))));
 272         assertFalse(region.contains(X + WIDTH - 4 + (5 * Math.cos(45)), Y + 3 - (4 * Math.sin(45))));
 273         // Check points in the bottom-right corner area
 274         assertTrue(region.contains(X + WIDTH, Y + HEIGHT - 6));
 275         assertTrue(region.contains(X + WIDTH - 5, Y + HEIGHT));
 276         assertTrue(region.contains(X + WIDTH - 5 + (5 * Math.cos(45)), Y + HEIGHT - 6 + (6 * Math.sin(45))));
 277         assertTrue(region.contains(X + WIDTH - 5 + (4 * Math.cos(45)), Y + HEIGHT - 6 + (5 * Math.sin(45))));
 278         assertFalse(region.contains(X + WIDTH - 5 + (6 * Math.cos(45)), Y + HEIGHT - 6 + (7 * Math.sin(45))));
 279         // Check points in the bottom-left corner area
 280         assertTrue(region.contains(X, Y + HEIGHT - 7));
 281         assertTrue(region.contains(X + 8, Y + HEIGHT));
 282         assertTrue(region.contains(X + 8 - (8 * Math.cos(45)), Y + HEIGHT - 7 + (7 * Math.sin(45))));
 283         assertTrue(region.contains(X + 8 - (7 * Math.cos(45)), Y + HEIGHT - 7 + (6 * Math.sin(45))));
 284         assertFalse(region.contains(X + 8 - (9 * Math.cos(45)), Y + HEIGHT - 7 + (8 * Math.sin(45))));
 285         // Check the center
 286         assertTrue(region.contains(CENTER_X, CENTER_Y));
 287     }
 288 
 289     @Test public void pickingRectangularFillWithIndependentRadiusWithInsetsWorks() {
 290         region.setBackground(new Background(new BackgroundFill(Color.RED,
 291             new CornerRadii(1, 2, 3, 4, 5, 6, 7, 8, false, false, false, false, false, false, false, false),
 292             new Insets(4, 3, 2, 1))));
 293         // Check points in the top-left corner area
 294         assertTrue(region.contains(X + 1, Y + 2 + 4));
 295         assertTrue(region.contains(X + 1 + 1, Y + 4));
 296         assertTrue(region.contains(X + 1 + 1 - (1 * Math.cos(45)), Y + 2 + 4 - (2 * Math.sin(45))));
 297         assertTrue(region.contains(X + 1 + 1 - (.5 * Math.cos(45)), Y + 2 + 4 - (1 * Math.sin(45))));
 298         assertFalse(region.contains(X + 1 + 1 - (2 * Math.cos(45)), Y + 2 + 4 - (3 * Math.sin(45))));
 299         // Check points in the top-right corner area
 300         assertTrue(region.contains(X + WIDTH - 3, Y + 3 + 4));
 301         assertTrue(region.contains(X + WIDTH - 4 - 3, Y + 4));
 302         assertTrue(region.contains(X + WIDTH - 4 - 3 + (4 * Math.cos(45)), Y + 4 + 3 - (3 * Math.sin(45))));
 303         assertTrue(region.contains(X + WIDTH - 4 - 3 + (3 * Math.cos(45)), Y + 4 + 3 - (2 * Math.sin(45))));
 304         assertFalse(region.contains(X + WIDTH - 4 - 3 + (5 * Math.cos(45)), Y + 4 + 3 - (4 * Math.sin(45))));
 305         // Check points in the bottom-right corner area
 306         assertTrue(region.contains(X + WIDTH - 3, Y + HEIGHT - 2 - 6));
 307         assertTrue(region.contains(X + WIDTH - 3 - 5, Y + HEIGHT - 2));
 308         assertTrue(region.contains(X + WIDTH - 3 - 5 + (5 * Math.cos(45)), Y + HEIGHT - 2 - 6 + (6 * Math.sin(45))));
 309         assertTrue(region.contains(X + WIDTH - 3 - 5 + (4 * Math.cos(45)), Y + HEIGHT - 2 - 6 + (5 * Math.sin(45))));
 310         assertFalse(region.contains(X + WIDTH - 3 - 5 + (6 * Math.cos(45)), Y + HEIGHT - 2 - 6 + (7 * Math.sin(45))));
 311         // Check points in the bottom-left corner area
 312         assertTrue(region.contains(X + 1, Y + HEIGHT - 2 - 7));
 313         assertTrue(region.contains(X + 1 + 8, Y + HEIGHT - 2));
 314         assertTrue(region.contains(X + 1 + 8 - (8 * Math.cos(45)), Y + HEIGHT - 2 - 7 + (7 * Math.sin(45))));
 315         assertTrue(region.contains(X + 1 + 8 - (7 * Math.cos(45)), Y + HEIGHT - 2 - 7 + (6 * Math.sin(45))));
 316         assertFalse(region.contains(X + 1 + 8 - (9 * Math.cos(45)), Y + HEIGHT - 2 - 7 + (8 * Math.sin(45))));
 317         // Check the center
 318         assertTrue(region.contains(CENTER_X, CENTER_Y));
 319     }
 320 
 321     // TODO test with really really large corner radius
 322 
 323     /**************************************************************************
 324      *                                                                        *
 325      * Test behavior when picking a region with borders, but no shape or      *
 326      * or images.                                                             *
 327      *                                                                        *
 328      *************************************************************************/
 329 
 330     @Test public void pickingRectangularBorderWorks() {
 331         region.setBorder(new Border(new BorderStroke(Color.GREEN, BorderStrokeStyle.SOLID, CornerRadii.EMPTY,
 332                                                      new BorderWidths(1))));
 333         assertFalse(region.contains(LEFT_OF, CENTER_Y));
 334         assertFalse(region.contains(CENTER_X, ABOVE));
 335         assertFalse(region.contains(RIGHT_OF, CENTER_Y));
 336         assertFalse(region.contains(CENTER_X, BELOW));
 337         // Note that the center is empty and should not be picked
 338         assertFalse(region.contains(CENTER_X, CENTER_Y));
 339     }
 340 
 341     @Test public void pickingRectangularBorderWithThickBorder() {
 342         region.setBorder(new Border(new BorderStroke(Color.GREEN, BorderStrokeStyle.SOLID, CornerRadii.EMPTY,
 343                                                      new BorderWidths(10))));
 344         assertFalse(region.contains(LEFT_OF, CENTER_Y));
 345         assertFalse(region.contains(CENTER_X, ABOVE));
 346         assertFalse(region.contains(RIGHT_OF, CENTER_Y));
 347         assertFalse(region.contains(CENTER_X, BELOW));
 348         assertFalse(region.contains(CENTER_X, CENTER_Y));
 349 
 350         assertTrue(region.contains(X, Y));
 351         assertTrue(region.contains(X+5, Y+5));
 352         assertFalse(region.contains(X+10, Y+10));
 353     }
 354 
 355     @Test public void pickingRectangularBorderWithIndependentBorderWidths() {
 356         region.setBorder(new Border(new BorderStroke(Color.GREEN, BorderStrokeStyle.SOLID, CornerRadii.EMPTY,
 357                                                      new BorderWidths(5, 10, 15, 20))));
 358         assertFalse(region.contains(LEFT_OF, CENTER_Y));
 359         assertFalse(region.contains(CENTER_X, ABOVE));
 360         assertFalse(region.contains(RIGHT_OF, CENTER_Y));
 361         assertFalse(region.contains(CENTER_X, BELOW));
 362         assertFalse(region.contains(CENTER_X, CENTER_Y));
 363 
 364         // Top. Test first and last pixels, and one-past
 365         assertTrue(region.contains(CENTER_X, Y));
 366         assertTrue(region.contains(CENTER_X, Y + 4));
 367         assertFalse(region.contains(CENTER_X, Y + 5));
 368 
 369         // Right. Test first and last pixels, and one-past
 370         assertTrue(region.contains(WIDTH, CENTER_Y));
 371         assertTrue(region.contains(WIDTH - 9, CENTER_Y));
 372         assertFalse(region.contains(WIDTH - 10, CENTER_Y));
 373 
 374         // Bottom. Test first and last pixels, and one-past
 375         assertTrue(region.contains(CENTER_X, HEIGHT));
 376         assertTrue(region.contains(CENTER_X, HEIGHT - 14));
 377         assertFalse(region.contains(CENTER_X, HEIGHT - 15));
 378 
 379         // Left. Test first and last pixels, and one-past
 380         assertTrue(region.contains(X, CENTER_Y));
 381         assertTrue(region.contains(X + 19, CENTER_Y));
 382         assertFalse(region.contains(X + 20, CENTER_Y));
 383     }
 384 
 385     @Test public void pickingRectangularBorderWithIndependentPercentageBorderWidths() {
 386         region.setBorder(new Border(new BorderStroke(Color.GREEN, BorderStrokeStyle.SOLID, CornerRadii.EMPTY,
 387                                                      new BorderWidths(.05, .10, .15, .20, true, true, true, true))));
 388         assertFalse(region.contains(LEFT_OF, CENTER_Y));
 389         assertFalse(region.contains(CENTER_X, ABOVE));
 390         assertFalse(region.contains(RIGHT_OF, CENTER_Y));
 391         assertFalse(region.contains(CENTER_X, BELOW));
 392         assertFalse(region.contains(CENTER_X, CENTER_Y));
 393 
 394         // Top. Test first and last pixels, and one-past
 395         assertTrue(region.contains(CENTER_X, Y));
 396         assertTrue(region.contains(CENTER_X, Y + 4));
 397         assertFalse(region.contains(CENTER_X, Y + 5));
 398 
 399         // Right. Test first and last pixels, and one-past
 400         assertTrue(region.contains(WIDTH, CENTER_Y));
 401         assertTrue(region.contains(WIDTH - 9, CENTER_Y));
 402         assertFalse(region.contains(WIDTH - 10, CENTER_Y));
 403 
 404         // Bottom. Test first and last pixels, and one-past
 405         assertTrue(region.contains(CENTER_X, HEIGHT));
 406         assertTrue(region.contains(CENTER_X, HEIGHT - 14));
 407         assertFalse(region.contains(CENTER_X, HEIGHT - 15));
 408 
 409         // Left. Test first and last pixels, and one-past
 410         assertTrue(region.contains(X, CENTER_Y));
 411         assertTrue(region.contains(X + 19, CENTER_Y));
 412         assertFalse(region.contains(X + 20, CENTER_Y));
 413     }
 414 
 415     @Test public void pickingRectangularBorderWithIndependentBorderWidthsAndInsets() {
 416         region.setBorder(new Border(new BorderStroke(Color.GREEN, BorderStrokeStyle.SOLID, CornerRadii.EMPTY,
 417                                                      new BorderWidths(5, 10, 15, 20), new Insets(1, 2, 3, 4))));
 418         // Top. Test first and last pixels, and one-past
 419         assertFalse(region.contains(CENTER_X, Y));
 420         assertTrue(region.contains(CENTER_X, Y+1));
 421         assertTrue(region.contains(CENTER_X, Y+1 + 4));
 422         assertFalse(region.contains(CENTER_X, Y+1 + 5));
 423 
 424         // Right. Test first and last pixels, and one-past
 425         assertFalse(region.contains(WIDTH-1, CENTER_Y));
 426         assertTrue(region.contains(WIDTH-2, CENTER_Y));
 427         assertTrue(region.contains(WIDTH-2 - 9, CENTER_Y));
 428         assertFalse(region.contains(WIDTH-2 - 10, CENTER_Y));
 429 
 430         // Bottom. Test first and last pixels, and one-past
 431         assertFalse(region.contains(CENTER_X, HEIGHT-2));
 432         assertTrue(region.contains(CENTER_X, HEIGHT-3));
 433         assertTrue(region.contains(CENTER_X, HEIGHT-3 - 14));
 434         assertFalse(region.contains(CENTER_X, HEIGHT-3 - 15));
 435 
 436         // Left. Test first and last pixels, and one-past
 437         assertFalse(region.contains(X+3, CENTER_Y));
 438         assertTrue(region.contains(X+4, CENTER_Y));
 439         assertTrue(region.contains(X+4 + 19, CENTER_Y));
 440         assertFalse(region.contains(X+4 + 20, CENTER_Y));
 441     }
 442 
 443     @Test public void pickingRectangularBorderWithIndependentRadiusWithInsetsWorks() {
 444         region.setBorder(new Border(new BorderStroke(Color.RED, BorderStrokeStyle.SOLID,
 445             new CornerRadii(1, 2, 3, 4, 5, 6, 7, 8, false, false, false, false, false, false, false, false),
 446             new BorderWidths(5, 10, 15, 20), new Insets(4, 3, 2, 1))));
 447         // Check points in the top-left corner area
 448         assertTrue(region.contains(X + 1, Y + 2 + 4));
 449         assertTrue(region.contains(X + 1 + 1, Y + 4));
 450         assertTrue(region.contains(X + 1 + 1 - (1 * Math.cos(45)), Y + 2 + 4 - (2 * Math.sin(45))));
 451         assertTrue(region.contains(X + 1 + 1 - (.5 * Math.cos(45)), Y + 2 + 4 - (1 * Math.sin(45))));
 452         assertFalse(region.contains(X + 1 + 1 - (2 * Math.cos(45)), Y + 2 + 4 - (3 * Math.sin(45))));
 453         // Check points in the top-right corner area
 454         assertTrue(region.contains(X + WIDTH - 3, Y + 3 + 4));
 455         assertTrue(region.contains(X + WIDTH - 4 - 3, Y + 4));
 456         assertTrue(region.contains(X + WIDTH - 4 - 3 + (4 * Math.cos(45)), Y + 4 + 3 - (3 * Math.sin(45))));
 457         assertTrue(region.contains(X + WIDTH - 4 - 3 + (3 * Math.cos(45)), Y + 4 + 3 - (2 * Math.sin(45))));
 458         assertFalse(region.contains(X + WIDTH - 4 - 3 + (5 * Math.cos(45)), Y + 4 + 3 - (4 * Math.sin(45))));
 459         // Check points in the bottom-right corner area
 460         assertTrue(region.contains(X + WIDTH - 3, Y + HEIGHT - 2 - 6));
 461         assertTrue(region.contains(X + WIDTH - 3 - 5, Y + HEIGHT - 2));
 462         assertTrue(region.contains(X + WIDTH - 3 - 5 + (5 * Math.cos(45)), Y + HEIGHT - 2 - 6 + (6 * Math.sin(45))));
 463         assertTrue(region.contains(X + WIDTH - 3 - 5 + (4 * Math.cos(45)), Y + HEIGHT - 2 - 6 + (5 * Math.sin(45))));
 464         assertFalse(region.contains(X + WIDTH - 3 - 5 + (6 * Math.cos(45)), Y + HEIGHT - 2 - 6 + (7 * Math.sin(45))));
 465         // Check points in the bottom-left corner area
 466         assertTrue(region.contains(X + 1, Y + HEIGHT - 2 - 7));
 467         assertTrue(region.contains(X + 1 + 8, Y + HEIGHT - 2));
 468         assertTrue(region.contains(X + 1 + 8 - (8 * Math.cos(45)), Y + HEIGHT - 2 - 7 + (7 * Math.sin(45))));
 469         assertTrue(region.contains(X + 1 + 8 - (7 * Math.cos(45)), Y + HEIGHT - 2 - 7 + (6 * Math.sin(45))));
 470         assertFalse(region.contains(X + 1 + 8 - (9 * Math.cos(45)), Y + HEIGHT - 2 - 7 + (8 * Math.sin(45))));
 471         // Check the center
 472         assertFalse(region.contains(CENTER_X, CENTER_Y));
 473         // TODO Could stand to have more tests testing the inside hit edge
 474     }
 475 
 476     @Test public void pickingRectangularBorderWithIndependentPercentageRadiusWithInsetsWorks() {
 477         region.setBorder(new Border(new BorderStroke(Color.RED, BorderStrokeStyle.SOLID,
 478             new CornerRadii(.01, .02, .03, .04, .05, .06, .07, .08, true, true, true, true, true, true, true, true),
 479             new BorderWidths(5, 10, 15, 20), new Insets(4, 3, 2, 1))));
 480         // Check points in the top-left corner area
 481         assertTrue(region.contains(X + 1, Y + 2 + 4));
 482         assertTrue(region.contains(X + 1 + 1, Y + 4));
 483         assertTrue(region.contains(X + 1 + 1 - (1 * Math.cos(45)), Y + 2 + 4 - (2 * Math.sin(45))));
 484         assertTrue(region.contains(X + 1 + 1 - (.5 * Math.cos(45)), Y + 2 + 4 - (1 * Math.sin(45))));
 485         assertFalse(region.contains(X + 1 + 1 - (2 * Math.cos(45)), Y + 2 + 4 - (3 * Math.sin(45))));
 486         // Check points in the top-right corner area
 487         assertTrue(region.contains(X + WIDTH - 3, Y + 3 + 4));
 488         assertTrue(region.contains(X + WIDTH - 4 - 3, Y + 4));
 489         assertTrue(region.contains(X + WIDTH - 4 - 3 + (4 * Math.cos(45)), Y + 4 + 3 - (3 * Math.sin(45))));
 490         assertTrue(region.contains(X + WIDTH - 4 - 3 + (3 * Math.cos(45)), Y + 4 + 3 - (2 * Math.sin(45))));
 491         assertFalse(region.contains(X + WIDTH - 4 - 3 + (5 * Math.cos(45)), Y + 4 + 3 - (4 * Math.sin(45))));
 492         // Check points in the bottom-right corner area
 493         assertTrue(region.contains(X + WIDTH - 3, Y + HEIGHT - 2 - 6));
 494         assertTrue(region.contains(X + WIDTH - 3 - 5, Y + HEIGHT - 2));
 495         assertTrue(region.contains(X + WIDTH - 3 - 5 + (5 * Math.cos(45)), Y + HEIGHT - 2 - 6 + (6 * Math.sin(45))));
 496         assertTrue(region.contains(X + WIDTH - 3 - 5 + (4 * Math.cos(45)), Y + HEIGHT - 2 - 6 + (5 * Math.sin(45))));
 497         assertFalse(region.contains(X + WIDTH - 3 - 5 + (6 * Math.cos(45)), Y + HEIGHT - 2 - 6 + (7 * Math.sin(45))));
 498         // Check points in the bottom-left corner area
 499         assertTrue(region.contains(X + 1, Y + HEIGHT - 2 - 7));
 500         assertTrue(region.contains(X + 1 + 8, Y + HEIGHT - 2));
 501         assertTrue(region.contains(X + 1 + 8 - (8 * Math.cos(45)), Y + HEIGHT - 2 - 7 + (7 * Math.sin(45))));
 502         assertTrue(region.contains(X + 1 + 8 - (7 * Math.cos(45)), Y + HEIGHT - 2 - 7 + (6 * Math.sin(45))));
 503         assertFalse(region.contains(X + 1 + 8 - (9 * Math.cos(45)), Y + HEIGHT - 2 - 7 + (8 * Math.sin(45))));
 504         // Check the center
 505         assertFalse(region.contains(CENTER_X, CENTER_Y));
 506         // TODO Could stand to have more tests testing the inside hit edge
 507     }
 508 
 509     /**************************************************************************
 510      *                                                                        *
 511      * Test behavior when picking a shaped region. We have to test all the    *
 512      * positionShape / scaleShape variants to make sure we are always picking *
 513      * based on the perceived (rendered) shape                                *
 514      *                                                                        *
 515      *************************************************************************/
 516 
 517     
 518     private void setupRegionShapeWith(double finalShapeSize, double insets, double centerPos) {
 519         region.setShape(new Circle(centerPos, centerPos, finalShapeSize + insets));
 520         region.setBackground(new Background(new BackgroundFill(Color.RED, CornerRadii.EMPTY, 
 521                 new Insets(insets))));
 522         
 523     }
 524     
 525     
 526     @Test public void pickingSimpleShape() {
 527         region.setPickOnBounds(false);
 528         region.setScaleShape(false);
 529         region.setCenterShape(false);
 530         
 531         double variants[][] = new double[][]{new double[]{30, 0, 50}, new double[]{30, 10, 50}};
 532 
 533         for (double[] v : variants) {
 534             setupRegionShapeWith(v[0], v[1], v[2]);
 535 
 536             assertFalse(region.contains(X + 50, Y + 81));
 537             assertFalse(region.contains(X + 50, Y + 19));
 538             assertFalse(region.contains(X + 81, Y + 50));
 539             assertFalse(region.contains(X + 19, Y + 50));
 540             assertTrue(region.contains(X + 50, Y + 79));
 541             assertTrue(region.contains(X + 50, Y + 21));
 542             assertTrue(region.contains(X + 79, Y + 50));
 543             assertTrue(region.contains(X + 21, Y + 50));
 544         }
 545         
 546     }
 547     
 548     @Test public void pickingCenteredShape() {
 549         region.setPickOnBounds(false);
 550         region.setScaleShape(false);
 551         region.setCenterShape(true);
 552 
 553         double variants[][] = new double[][]{new double[]{30, 0, 50}, new double[]{30, 10, 50},
 554         new double[] {30, 0, 0}, new double[] { 30, 10, 0}};
 555 
 556         for (double[] v : variants) {
 557             setupRegionShapeWith(v[0], v[1], v[2]);
 558 
 559             assertFalse(region.contains(X + 50, Y + 81));
 560             assertFalse(region.contains(X + 50, Y + 19));
 561             assertFalse(region.contains(X + 81, Y + 50));
 562             assertFalse(region.contains(X + 19, Y + 50));
 563             assertTrue(region.contains(X + 50, Y + 79));
 564             assertTrue(region.contains(X + 50, Y + 21));
 565             assertTrue(region.contains(X + 79, Y + 50));
 566             assertTrue(region.contains(X + 21, Y + 50));
 567         }
 568         
 569     }
 570     
 571     @Test public void pickingScaledShape() {
 572         region.setPickOnBounds(false);
 573         region.setScaleShape(true);
 574         region.setCenterShape(false);
 575 
 576         double variants[][] = new double[][]{new double[]{30, 0, 0}, new double[]{30, 10, 0}};
 577 
 578         for (double[] v : variants) {
 579             setupRegionShapeWith(v[0], v[1], v[2]);
 580             
 581              // insets are still valid after scale
 582             double shapeWidth = WIDTH - 2* v[1];
 583             double shapeHeight = HEIGHT - 2 * v[1];
 584             //Shape is moved by insets
 585             double shapeX = X + v[1];
 586             double shapeY = Y + v[1];
 587 
 588             assertFalse(region.contains(shapeX, shapeY + shapeHeight / 2 + 1));
 589             assertFalse(region.contains(shapeX, shapeY - shapeHeight / 2 - 1));
 590             assertFalse(region.contains(shapeX + shapeWidth / 2 + 1, shapeY));
 591             assertFalse(region.contains(shapeX - shapeWidth / 2 - 1, shapeY));
 592 
 593             assertTrue(region.contains(shapeX + 1, shapeY + shapeHeight / 2 - 1));
 594             assertTrue(region.contains(shapeX + shapeWidth / 2 - 1, shapeY));
 595 
 596             // Even though the shape is there, these points are outside of region's bounds, so it wouldn't be really picked.
 597             assertFalse(region.contains(shapeX + 1, shapeY - shapeHeight / 2 + 1));
 598             assertFalse(region.contains(shapeX - shapeWidth / 2 + 1, shapeY));
 599         }
 600         
 601     }
 602     
 603     @Test public void pickingScaledAndCenteredShape() {
 604         region.setPickOnBounds(false);
 605         region.setScaleShape(true);
 606         region.setCenterShape(true);
 607 
 608         double variants[][] = new double[][]{new double[]{30, 0, 50}, new double[]{30, 10, 50},
 609         new double[] {30, 0, 0}, new double[] { 30, 10, 0}};
 610 
 611         for (double[] v : variants) {
 612             setupRegionShapeWith(v[0], v[1], v[2]);
 613             
 614             // insets are still valid after scale
 615             double shapeWidth = WIDTH - 2* v[1];
 616             double shapeHeight = HEIGHT - 2 * v[1];
 617            
 618             double shapeX = X + v[1];
 619             double shapeY = Y + v[1];
 620 
 621             assertFalse(region.contains(X + WIDTH / 2, shapeY + shapeHeight + 1));
 622             assertFalse(region.contains(X + WIDTH / 2, shapeY - 1));
 623             assertFalse(region.contains(shapeX + shapeWidth + 1, Y + HEIGHT / 2));
 624             assertFalse(region.contains(shapeX - 1, Y + HEIGHT / 2));
 625 
 626             assertTrue(region.contains(X + WIDTH / 2, shapeY + shapeHeight - 1));
 627             assertTrue(region.contains(X + WIDTH / 2, shapeY + 1));
 628             assertTrue(region.contains(shapeX + shapeWidth - 1, Y + HEIGHT / 2));
 629             assertTrue(region.contains(shapeX + 1, Y + HEIGHT / 2));
 630         }
 631     }
 632     
 633 }