1 /* 2 * Copyright (c) 2010, 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 * 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.shape; 27 28 import com.sun.javafx.scene.DirtyBits; 29 import com.sun.javafx.sg.prism.NGNode; 30 import com.sun.javafx.sg.prism.NGShape; 31 import javafx.beans.value.WritableValue; 32 import javafx.collections.FXCollections; 33 import javafx.collections.ListChangeListener; 34 import javafx.collections.ObservableList; 35 import javafx.css.CssMetaData; 36 import javafx.css.Styleable; 37 import javafx.css.StyleableProperty; 38 import javafx.scene.Group; 39 import javafx.scene.NodeTest; 40 import javafx.scene.Scene; 41 import javafx.scene.paint.Color; 42 import org.junit.Assert; 43 import org.junit.Test; 44 45 import java.util.ArrayList; 46 import java.util.Collections; 47 import java.util.List; 48 49 import static org.junit.Assert.*; 50 51 public class ShapeTest { 52 53 @Test public void testBoundPropertySync_StrokeType() throws Exception { 54 NodeTest.assertObjectProperty_AsStringSynced( 55 new StubShape(), 56 "strokeType", "strokeType", StrokeType.CENTERED); 57 } 58 59 @Test public void testBoundPropertySync_StrokeLineCap() throws Exception { 60 NodeTest.assertObjectProperty_AsStringSynced( 61 new StubShape(), 62 "strokeLineCap", "strokeLineCap", StrokeLineCap.SQUARE); 63 } 64 65 @Test public void testBoundPropertySync_StrokeLineJoin() throws Exception { 66 NodeTest.assertObjectProperty_AsStringSynced( 67 new StubShape(), 68 "strokeLineJoin", "strokeLineJoin", StrokeLineJoin.MITER); 69 } 70 71 @Test public void testBoundPropertySync_StrokeWidth() throws Exception { 72 NodeTest.assertDoublePropertySynced( 73 new StubShape(), 74 "strokeWidth", "strokeWidth", 2.0); 75 } 76 77 @Test public void testBoundPropertySync_StrokeMiterLimit() throws Exception { 78 NodeTest.assertDoublePropertySynced( 79 new StubShape(), 80 "strokeMiterLimit", "strokeMiterLimit", 3.0); 81 } 82 83 @Test public void testBoundPropertySync_DashOffset() throws Exception { 84 NodeTest.assertDoublePropertySynced( 85 new StubShape(), 86 "strokeDashOffset", "strokeDashOffset", 15.0); 87 } 88 89 @Test public void testBoundPropertySync_Stroke() throws Exception { 90 final Shape shape = new StubShape(); 91 shape.setStroke(Color.RED); 92 NodeTest.assertObjectProperty_AsStringSynced( 93 shape, "stroke", "stroke", Color.GREEN); 94 } 95 96 @Test public void testBoundPropertySync_Fill() throws Exception { 97 final Shape shape = new StubShape(); 98 shape.setFill(Color.BLUE); 99 NodeTest.assertObjectProperty_AsStringSynced( 100 shape, "fill", "fill", Color.RED); 101 } 102 103 @Test public void testBoundPropertySync_Smooth() throws Exception { 104 final Shape shape = new StubShape(); 105 shape.setSmooth(true); 106 NodeTest.assertBooleanPropertySynced( 107 shape, "smooth", "smooth", false); 108 } 109 110 boolean listChangeCalled = false; 111 @Test public void testStrokeDashArray() { 112 // there is no strokeDashArrayProperty or this test 113 // would be in Shape_properties_Test 114 final ObservableList<Double> expected = 115 FXCollections.observableArrayList(Double.valueOf(1), 116 Double.valueOf(2), 117 Double.valueOf(3)); 118 final Shape shape = new StubShape(); 119 ObservableList<Double> actual = shape.getStrokeDashArray(); 120 assertNotNull(actual); 121 assertTrue(actual.isEmpty()); 122 123 actual.addListener((ListChangeListener<Double>) c -> { 124 listChangeCalled = true; 125 assertTrue(c.next()); 126 Assert.assertEquals(expected, c.getAddedSubList()); 127 }); 128 129 shape.getStrokeDashArray().addAll(expected); 130 actual = shape.getStrokeDashArray(); 131 assertEquals(expected, actual); 132 133 assertTrue(listChangeCalled); 134 } 135 136 @Test public void testGetStrokeDashArrayViaCSSPropertyIsNotNull() { 137 final Shape shape = new StubShape(); 138 Double[] actual = null; 139 List<CssMetaData<? extends Styleable, ?>> styleables = shape.getCssMetaData(); 140 for (CssMetaData styleable : styleables) { 141 if ("-fx-stroke-dash-array".equals(styleable.getProperty())) { 142 WritableValue writable = styleable.getStyleableProperty(shape); 143 actual = (Double[])writable.getValue(); 144 break; 145 } 146 } 147 assertNotNull(actual); 148 } 149 150 @Test public void testGetStrokeDashArrayViaCSSPropertyIsSame() { 151 final Shape shape = new StubShape(); 152 shape.getStrokeDashArray().addAll(5d, 7d, 1d, 3d); 153 Double[] actuals = null; 154 List<CssMetaData<? extends Styleable, ?>> styleables = shape.getCssMetaData(); 155 156 for (CssMetaData styleable : styleables) { 157 if ("-fx-stroke-dash-array".equals(styleable.getProperty())) { 158 WritableValue writable = styleable.getStyleableProperty(shape); 159 actuals = (Double[])writable.getValue(); 160 } 161 } 162 163 final Double[] expecteds = new Double[] {5d, 7d, 1d, 3d}; 164 Assert.assertArrayEquals(expecteds, actuals); 165 } 166 167 @Test public void testSetStrokeDashArrayViaCSSPropertyIsSame() { 168 final Shape shape = new StubShape(); 169 List<Double> actual = null; 170 List<CssMetaData<? extends Styleable, ?>> styleables = shape.getCssMetaData(); 171 172 for (CssMetaData styleable : styleables) { 173 if ("-fx-stroke-dash-array".equals(styleable.getProperty())) { 174 StyleableProperty styleableProperty = styleable.getStyleableProperty(shape); 175 styleableProperty.applyStyle(null, new Double[] {5d, 7d, 1d, 3d}); 176 actual = shape.getStrokeDashArray(); 177 } 178 } 179 180 final List<Double> expected = new ArrayList(); 181 Collections.addAll(expected, 5d, 7d, 1d, 3d); 182 assertEquals(expected, actual); 183 } 184 185 // RT-18647: ClassCastException: [Ljava.lang.Double; cannot be cast to javafx.collections.ObservableList 186 @Test public void testRT_18647() { 187 final Scene scene = new Scene(new Group(), 500, 500); 188 189 final Shape shape = new StubShape(); 190 shape.setStyle("-fx-stroke-dash-array: 5 7 1 3;"); 191 192 ((Group)scene.getRoot()).getChildren().add(shape); 193 shape.applyCss(); 194 195 final List<Double> expected = new ArrayList(); 196 Collections.addAll(expected, 5d, 7d, 1d, 3d); 197 198 List<Double> actual = shape.getStrokeDashArray(); 199 assertEquals(expected, actual); 200 201 } 202 203 boolean listenerCalled = false; 204 // make sure shapeChangeListener doesn't hold reference to runnable. 205 @Test public void testShapeChangeListenerLeakTest() { 206 207 Shape shape = new StubShape(); 208 209 Runnable listener = () -> { 210 listenerCalled = true; 211 }; 212 213 shape.impl_setShapeChangeListener(listener); 214 215 // sync peer to clear out dirty bits 216 shape.impl_syncPeer(); 217 218 // should trigger listener 219 shape.setFill(Color.GREEN); 220 221 assert(listenerCalled); 222 223 listener = null; 224 System.gc(); 225 226 // sync peer to clear out dirty bits 227 shape.impl_syncPeer(); 228 229 // this flag should remain false (listener should not be called) 230 listenerCalled = false; 231 232 shape.setFill(Color.RED); 233 234 assert(!listenerCalled); 235 } 236 237 public class StubShape extends Shape { 238 239 public StubShape() { 240 setStroke(Color.BLACK); 241 } 242 243 @Override 244 protected NGNode impl_createPeer() { 245 return new StubNGShape(); 246 } 247 248 @Override public com.sun.javafx.geom.Shape impl_configShape() { 249 return new com.sun.javafx.geom.RoundRectangle2D(0, 0, 10, 10, 4, 4); 250 } 251 } 252 253 public class StubNGShape extends NGShape { 254 private StrokeType pgStrokeType; 255 private StrokeLineCap pgStrokeLineCap; 256 private StrokeLineJoin pgStrokeLineJoin; 257 private float strokeWidth; 258 private float strokeMiterLimit; 259 private float[] strokeDashArray; 260 private float strokeDashOffset; 261 private Object stroke; 262 private Mode mode; 263 private boolean smooth; 264 private Object fill; 265 266 public Object getFill() { return fill; } 267 public boolean isSmooth() { return smooth; } 268 public Mode getMode() { return mode; } 269 public Object getStroke() { return stroke; } 270 public float getStrokeDashOffset() { return strokeDashOffset; } 271 public float getStrokeMiterLimit() { return strokeMiterLimit; } 272 public float getStrokeWidth() { return strokeWidth; } 273 public StrokeType getStrokeType() { return pgStrokeType; } 274 public StrokeLineCap getStrokeLineCap() { return pgStrokeLineCap; } 275 public StrokeLineJoin getStrokeLineJoin() { return pgStrokeLineJoin; } 276 public void setMode(Mode mode) { this.mode = mode; } 277 @Override public void setSmooth(boolean smooth) { this.smooth = smooth; } 278 @Override public void setFillPaint(Object fillPaint) { this.fill = fillPaint; } 279 @Override public void setDrawPaint(Object drawPaint) { this.stroke = drawPaint; } 280 @Override public void setDrawStroke(float strokeWidth, 281 StrokeType type, 282 StrokeLineCap lineCap, 283 StrokeLineJoin lineJoin, 284 float strokeMiterLimit, 285 float[] strokeDashArray, 286 float strokeDashOffset) { 287 this.pgStrokeType = type; 288 this.pgStrokeLineCap = lineCap; 289 this.pgStrokeLineJoin = lineJoin; 290 this.strokeWidth = strokeWidth; 291 this.strokeMiterLimit = strokeMiterLimit; 292 this.strokeDashOffset = strokeDashOffset; 293 this.strokeDashArray = new float[strokeDashArray == null ? 0 : strokeDashArray.length]; 294 System.arraycopy(strokeDashArray, 0, this.strokeDashArray, 0, this.strokeDashArray.length); 295 } 296 297 @Override 298 public com.sun.javafx.geom.Shape getShape() { 299 return null; 300 } 301 } 302 }