1 /* 2 * Copyright (c) 2012, 2014, 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 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 */ 24 25 package javafx.scene.layout; 26 27 import javafx.scene.Group; 28 import javafx.scene.Scene; 29 import javafx.scene.paint.Color; 30 import javafx.scene.paint.Paint; 31 import javafx.stage.Stage; 32 import java.util.ArrayList; 33 import java.util.LinkedList; 34 import java.util.List; 35 import java.util.concurrent.atomic.AtomicReference; 36 import testharness.VisualTestBase; 37 38 /** 39 */ 40 public abstract class RegionUITestBase extends VisualTestBase { 41 static final int WIDTH = 400; 42 static final int HEIGHT = 300; 43 static final int REGION_TOP = 50; 44 static final int REGION_LEFT = 50; 45 static final int REGION_RIGHT = 350; 46 static final int REGION_BOTTOM = 250; 47 static final int REGION_WIDTH = 300; 48 static final int REGION_HEIGHT = 200; 49 static final Color SCENE_FILL = Color.WHITE; 50 51 protected Stage stage; 52 protected Scene scene; 53 protected Group root; 54 protected Region region; 55 56 @Override 57 public void doSetup() { 58 super.doSetup(); 59 runAndWait(() -> { 60 stage = getStage(); 61 region = new Region(); 62 region.setPrefSize(REGION_WIDTH, REGION_HEIGHT); 63 region.relocate(REGION_LEFT, REGION_TOP); 64 scene = new Scene(root = new Group(region), WIDTH, HEIGHT); 65 scene.setFill(SCENE_FILL); 66 stage.setScene(scene); 67 stage.show(); 68 }); 69 } 70 71 protected void setStyle(final String style) { 72 runAndWait(() -> region.setStyle(style)); 73 waitFirstFrame(); 74 } 75 76 static final double TOLERANCE = 0.07; 77 78 protected void assertColorEquals(Color expected, int x, int y, double tolerance) { 79 Color actual = getColorThreadSafe(x, y); 80 try { 81 assertColorEquals(expected, actual, tolerance); 82 } catch (AssertionError error) { 83 throw new AssertionError(error.getMessage() + " at position x=" + x + ", y=" + y); 84 } 85 } 86 87 protected void assertColorDoesNotEqual(Color notExpected, int x, int y, double tolerance) { 88 Color actual = getColorThreadSafe(x, y); 89 assertColorDoesNotEqual(notExpected, actual, tolerance); 90 } 91 92 private Color getColorThreadSafe(int x, int y) { 93 AtomicReference<Color> color = new AtomicReference<>(); 94 runAndWait(() -> color.set(getColor(scene, x, y))); 95 return color.get(); 96 } 97 98 /** 99 * Using the information available in Background and Border for the region, 100 * this method will check that the scene color is used for those places that 101 * are outside the region boundary (including the empty part of a rounded corner) 102 * and that the expected color is used for the interior of the region. If the 103 * given expected color is null, then this test will just make sure that 104 * the color IS NOT the scene background. For example, when doing a gradient fill 105 * or image fill it might not be possible to really know the expected color, but 106 * at least we can make sure we're not seeing the scene background color. 107 */ 108 protected void checkRegionCornersAndBoundariesForFills() { 109 Background background = region.getBackground(); 110 Border border = region.getBorder(); 111 if (border != null) { 112 throw new AssertionError("No implementation of this method for borders yet"); 113 } 114 115 if (region.getShape() != null) { 116 throw new AssertionError("No implementation of this method for regions with a shape yet"); 117 } 118 119 Paint lastFill = SCENE_FILL; 120 for (BackgroundFill fill : background.getFills()) { 121 checkRegionCornersAndBoundariesOfBackgroundFill(fill, lastFill); 122 lastFill = fill.getFill(); 123 } 124 } 125 126 protected void checkRegionLeftBoundary(BackgroundFill fill, Paint outsideFill) { 127 checkRegionLeftBoundary(fill, fill.getFill(), outsideFill); 128 } 129 130 protected void checkRegionLeftBoundary(BackgroundFill fill, Paint insideFill, Paint outsideFill) { 131 checkRegionLeftBoundary(fill, insideFill, outsideFill, 1, TOLERANCE); 132 } 133 134 protected void checkRegionLeftBoundary(BackgroundFill fill, Paint insideFill, Paint outsideFill, int distance, double tolerance) { 135 checkRegionLeftBoundary(fill.getInsets().getLeft(), insideFill, outsideFill, distance, tolerance); 136 } 137 138 protected void checkRegionLeftBoundary(Paint outsideFill) { 139 checkRegionLeftBoundary(0, null, outsideFill, 1, TOLERANCE); 140 } 141 142 protected void checkRegionLeftBoundary(double leftInset, Paint insideFill, Paint outsideFill, int distance, double tolerance) { 143 List<TestParameters> params = new ArrayList<>(); 144 final int x1 = (int) (region.getLayoutX() + leftInset); 145 final int midY = HEIGHT / 2; 146 params.add(new TestParameters(outsideFill, insideFill, x1 - 1 - distance, midY, tolerance)); // left outside 147 params.add(new TestParameters(insideFill, outsideFill, x1 + distance, midY, tolerance)); // left inside 148 runTests(params); 149 } 150 151 protected void checkRegionTopBoundary(BackgroundFill fill, Paint outsideFill) { 152 checkRegionTopBoundary(fill, fill.getFill(), outsideFill); 153 } 154 155 protected void checkRegionTopBoundary(BackgroundFill fill, Paint insideFill, Paint outsideFill) { 156 checkRegionTopBoundary(fill, insideFill, outsideFill, 1, TOLERANCE); 157 } 158 159 protected void checkRegionTopBoundary(BackgroundFill fill, Paint insideFill, Paint outsideFill, int distance, double tolerance) { 160 double outermostTop = fill.getInsets().getTop(); 161 checkRegionTopBoundary(outermostTop, insideFill, outsideFill, distance, tolerance); 162 } 163 164 protected void checkRegionTopBoundary(Paint outsideFill) { 165 checkRegionTopBoundary(0, null, outsideFill, 1, TOLERANCE); 166 } 167 168 protected void checkRegionTopBoundary(double topInset, Paint insideFill, Paint outsideFill, int distance, double tolerance) { 169 List<TestParameters> params = new LinkedList<>(); 170 final int y1 = (int) (region.getLayoutY() + topInset); 171 final int midX = WIDTH / 2; 172 params.add(new TestParameters(outsideFill, insideFill, midX, y1 - 1 - distance, tolerance)); // top outside 173 params.add(new TestParameters(insideFill, outsideFill, midX, y1 + distance, tolerance)); // top inside 174 runTests(params); 175 } 176 177 protected void checkRegionRightBoundary(BackgroundFill fill, Paint outsideFill) { 178 checkRegionRightBoundary(fill, fill.getFill(), outsideFill); 179 } 180 181 protected void checkRegionRightBoundary(BackgroundFill fill, Paint insideFill, Paint outsideFill) { 182 checkRegionRightBoundary(fill, insideFill, outsideFill, 1, TOLERANCE); 183 } 184 185 protected void checkRegionRightBoundary(BackgroundFill fill, Paint insideFill, Paint outsideFill, int distance, double tolerance) { 186 double outermostRight = fill.getInsets().getRight(); 187 checkRegionRightBoundary(outermostRight, insideFill, outsideFill, distance, tolerance); 188 } 189 190 protected void checkRegionRightBoundary(Paint outsideFill) { 191 checkRegionRightBoundary(0, null, outsideFill, 1, TOLERANCE); 192 } 193 194 protected void checkRegionRightBoundary(double rightInset, Paint insideFill, Paint outsideFill, int distance, double tolerance) { 195 List<TestParameters> params = new LinkedList<>(); 196 final int x2 = (int) Math.ceil(region.getLayoutX() + region.getWidth() - rightInset); 197 final int midY = HEIGHT / 2; 198 params.add(new TestParameters(outsideFill, insideFill, x2 + distance, midY, tolerance)); // right outside 199 params.add(new TestParameters(insideFill, outsideFill, x2 - 1 - distance, midY, tolerance)); // right inside 200 runTests(params); 201 } 202 203 protected void checkRegionBottomBoundary(BackgroundFill fill, Paint outsideFill) { 204 checkRegionBottomBoundary(fill, fill.getFill(), outsideFill); 205 } 206 207 protected void checkRegionBottomBoundary(BackgroundFill fill, Paint insideFill, Paint outsideFill) { 208 checkRegionBottomBoundary(fill, insideFill, outsideFill, 1, TOLERANCE); 209 } 210 211 protected void checkRegionBottomBoundary(BackgroundFill fill, Paint insideFill, Paint outsideFill, int distance, double tolerance) { 212 double outermostBottom = fill.getInsets().getBottom(); 213 checkRegionBottomBoundary(outermostBottom, insideFill, outsideFill, distance, tolerance); 214 } 215 216 protected void checkRegionBottomBoundary(Paint outsideFill) { 217 checkRegionBottomBoundary(0, null, outsideFill, 0, TOLERANCE); 218 } 219 220 protected void checkRegionBottomBoundary(double bottomInset, Paint insideFill, Paint outsideFill, int distance, double tolerance) { 221 List<TestParameters> params = new LinkedList<>(); 222 final int y2 = (int) Math.ceil(region.getLayoutY() + region.getHeight() - bottomInset); 223 final int midX = WIDTH / 2; 224 params.add(new TestParameters(outsideFill, insideFill, midX, y2 + distance, tolerance)); // bottom outside 225 params.add(new TestParameters(insideFill, outsideFill, midX, y2 - 1 - distance, tolerance)); // bottom inside 226 runTests(params); 227 } 228 229 // .5 * 1/Math.sqrt(2). If you multiply this value by the diameter of the 230 // circle, then you will get half the length of the side of the square which 231 // is inscribed within the circle. This will tell me the point of the arc where 232 // I want to do my testing. 233 static final float HALF_SQRT_HALF = .35355339059327f; 234 235 protected void checkRegionTopLeftCorner(BackgroundFill fill, Paint outsideFill) { 236 checkRegionTopLeftCorner(fill, fill.getFill(), outsideFill); 237 } 238 239 protected void checkRegionTopLeftCorner(BackgroundFill fill, Paint insideFill, Paint outsideFill) { 240 checkRegionTopLeftCorner(fill, insideFill, outsideFill, 1, TOLERANCE); 241 } 242 243 protected void checkRegionTopLeftCorner(BackgroundFill fill, Paint insideFill, Paint outsideFill, int distance, double tolerance) { 244 List<TestParameters> params = new LinkedList<>(); 245 246 // Now check the corners of each side. Each corner is a quarter-ellipse. What needs to be done is, 247 // for each background fill, figure out the x,y that constitutes the center of the arc (45 degrees) 248 // and then, for each point, find the one that is closest to the corner of the window. That point 249 // will be the one that constitutes the edge of the arc, and we can then test just outside that point 250 // and just inside that point. 251 252 final CornerRadii radii = fill.getRadii(); 253 double hr = radii.getTopLeftHorizontalRadius(); 254 double h = radii.isTopLeftHorizontalRadiusAsPercentage() ? hr * region.getWidth() : hr; 255 double vr = radii.getTopLeftVerticalRadius(); 256 double v = radii.isTopLeftVerticalRadiusAsPercentage() ? vr * region.getHeight() : vr; 257 double topLeftX = region.getLayoutX() + (fill.getInsets().getLeft() + (h - h * 2 * HALF_SQRT_HALF)); 258 double topLeftY = region.getLayoutY() + (fill.getInsets().getTop() + (v - v * 2 * HALF_SQRT_HALF)); 259 params.add(new TestParameters(outsideFill, insideFill, (int) topLeftX - 1 - distance, (int) topLeftY - 1 - distance, tolerance)); // outside 260 params.add(new TestParameters(insideFill, outsideFill, (int) topLeftX + distance, (int) topLeftY + distance, tolerance)); // inside 261 runTests(params); 262 } 263 264 protected void checkRegionTopRightCorner(BackgroundFill fill, Paint outsideFill) { 265 checkRegionTopRightCorner(fill, fill.getFill(), outsideFill); 266 } 267 268 protected void checkRegionTopRightCorner(BackgroundFill fill, Paint insideFill, Paint outsideFill) { 269 checkRegionTopRightCorner(fill, insideFill, outsideFill, 1, TOLERANCE); 270 } 271 272 protected void checkRegionTopRightCorner(BackgroundFill fill, Paint insideFill, Paint outsideFill, int distance, double tolerance) { 273 List<TestParameters> params = new LinkedList<>(); 274 final CornerRadii radii = fill.getRadii(); 275 double hr = radii.getTopRightHorizontalRadius(); 276 double h = radii.isTopRightHorizontalRadiusAsPercentage() ? hr * region.getWidth() : hr; 277 double vr = radii.getTopRightVerticalRadius(); 278 double v = radii.isTopRightVerticalRadiusAsPercentage() ? vr * region.getHeight() : vr; 279 double topRightX = region.getLayoutX() + region.getWidth() - (fill.getInsets().getRight() + (h - h * 2 * HALF_SQRT_HALF)); 280 double topRightY = region.getLayoutY() + (fill.getInsets().getTop() + (v - v * 2 * HALF_SQRT_HALF)); 281 params.add(new TestParameters(outsideFill, insideFill, (int) Math.ceil(topRightX + distance), (int) topRightY - 1 - distance, tolerance)); // outside 282 params.add(new TestParameters(insideFill, outsideFill, (int) Math.ceil(topRightX - distance) - 1, (int) topRightY + distance, tolerance)); // inside 283 runTests(params); 284 } 285 286 protected void checkRegionBottomRightCorner(BackgroundFill fill, Paint outsideFill) { 287 checkRegionBottomRightCorner(fill, fill.getFill(), outsideFill); 288 } 289 290 protected void checkRegionBottomRightCorner(BackgroundFill fill, Paint insideFill, Paint outsideFill) { 291 checkRegionBottomRightCorner(fill, insideFill, outsideFill, 1, TOLERANCE); 292 } 293 294 protected void checkRegionBottomRightCorner(BackgroundFill fill, Paint insideFill, Paint outsideFill, int distance, double tolerance) { 295 List<TestParameters> params = new LinkedList<>(); 296 final CornerRadii radii = fill.getRadii(); 297 double hr = radii.getBottomRightHorizontalRadius(); 298 double h = radii.isBottomRightHorizontalRadiusAsPercentage() ? hr * region.getWidth() : hr; 299 double vr = radii.getBottomRightVerticalRadius(); 300 double v = radii.isBottomRightVerticalRadiusAsPercentage() ? vr * region.getHeight() : vr; 301 double bottomRightX = region.getLayoutX() + region.getWidth() - (fill.getInsets().getRight() + (h - h * 2 * HALF_SQRT_HALF)); 302 double bottomRightY = region.getLayoutY() + region.getHeight() - (fill.getInsets().getBottom() + (v - v * 2 * HALF_SQRT_HALF)); 303 params.add(new TestParameters(outsideFill, insideFill, (int) Math.ceil(bottomRightX + distance), (int) Math.ceil(bottomRightY + distance), tolerance)); // outside 304 params.add(new TestParameters(insideFill, outsideFill, (int) Math.ceil(bottomRightX - distance) - 1, (int) Math.ceil(bottomRightY - distance) - 1, tolerance)); // inside 305 runTests(params); 306 } 307 308 protected void checkRegionBottomLeftCorner(BackgroundFill fill, Paint outsideFill) { 309 checkRegionBottomLeftCorner(fill, fill.getFill(), outsideFill); 310 } 311 312 protected void checkRegionBottomLeftCorner(BackgroundFill fill, Paint insideFill, Paint outsideFill) { 313 checkRegionBottomLeftCorner(fill, insideFill, outsideFill, 1, TOLERANCE); 314 } 315 316 protected void checkRegionBottomLeftCorner(BackgroundFill fill, Paint insideFill, Paint outsideFill, int distance, double tolerance) { 317 List<TestParameters> params = new LinkedList<>(); 318 final CornerRadii radii = fill.getRadii(); 319 double hr = radii.getBottomLeftHorizontalRadius(); 320 double h = radii.isBottomLeftHorizontalRadiusAsPercentage() ? hr * region.getWidth() : hr; 321 double vr = radii.getBottomLeftVerticalRadius(); 322 double v = radii.isBottomLeftVerticalRadiusAsPercentage() ? vr * region.getHeight() : vr; 323 double bottomLeftX = region.getLayoutX() + (fill.getInsets().getLeft() + (h - h * 2 * HALF_SQRT_HALF)); 324 double bottomLeftY = region.getLayoutY() + region.getHeight() - (fill.getInsets().getBottom() + (v - v * 2 * HALF_SQRT_HALF)); 325 params.add(new TestParameters(outsideFill, insideFill, (int) bottomLeftX - 1 - distance, (int) Math.ceil(bottomLeftY + distance), tolerance)); // outside 326 params.add(new TestParameters(insideFill, outsideFill, (int) bottomLeftX + distance, (int) Math.ceil(bottomLeftY - 1 - distance), tolerance)); // inside 327 runTests(params); 328 } 329 330 protected void checkRegionCornersAndBoundariesOfBackgroundFill(BackgroundFill fill, Paint outsideFill) { 331 checkRegionCornersAndBoundariesOfBackgroundFill(fill, fill.getFill(), outsideFill); 332 } 333 334 protected void checkRegionCornersAndBoundariesOfBackgroundFill(BackgroundFill fill, Paint insideFill, Paint lastFill) { 335 checkRegionCornersAndBoundariesOfBackgroundFill(fill, insideFill, lastFill, 1, TOLERANCE); 336 } 337 338 protected void checkRegionCornersAndBoundariesOfBackgroundFill(BackgroundFill fill, Paint insideFill, Paint lastFill, int distance, double tolerance) { 339 checkRegionLeftBoundary(fill, insideFill, lastFill, distance, tolerance); 340 checkRegionTopLeftCorner(fill, insideFill, lastFill, distance, tolerance); 341 checkRegionTopBoundary(fill, insideFill, lastFill, distance, tolerance); 342 checkRegionTopRightCorner(fill, insideFill, lastFill, distance, tolerance); 343 checkRegionRightBoundary(fill, insideFill, lastFill, distance, tolerance); 344 checkRegionBottomRightCorner(fill, insideFill, lastFill, distance, tolerance); 345 checkRegionBottomBoundary(fill, insideFill, lastFill, distance, tolerance); 346 checkRegionBottomLeftCorner(fill, insideFill, lastFill, distance, tolerance); 347 } 348 349 private void runTests(List<TestParameters> params) { 350 for (TestParameters p : params) { 351 boolean exactMatch = p.expected instanceof Color; 352 if (exactMatch) { 353 assertColorEquals((Color) p.expected, p.x, p.y, p.tolerance); 354 } else { 355 if (!(p.notExpected instanceof Color) || 356 p.expected == p.notExpected || 357 (p.expected != null && p.expected.equals(p.notExpected))) { 358 // I won't be able to distinguish, so just have to skip 359 System.err.println("WARNING: Had to skip RegionUITest case because there was not an easy " + 360 "way to distinguish pass vs. fail"); 361 continue; 362 } 363 assertColorDoesNotEqual((Color) p.notExpected, p.x, p.y, p.tolerance); 364 } 365 } 366 } 367 368 private static final class TestParameters { 369 Paint expected; 370 Paint notExpected; 371 int x, y; 372 double tolerance; 373 374 TestParameters(Paint expected, Paint notExpected, int x, int y, double tolerance) { 375 this.expected = expected; 376 this.notExpected = notExpected; 377 this.x = x; 378 this.y = y; 379 this.tolerance = tolerance; 380 } 381 } 382 }