1 /* 2 * Copyright (c) 2013, 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 com.sun.javafx.sg.prism; 27 28 import javafx.geometry.Insets; 29 import javafx.scene.layout.Background; 30 import javafx.scene.layout.BackgroundFill; 31 import javafx.scene.layout.CornerRadii; 32 import java.lang.reflect.Field; 33 import com.sun.javafx.geom.BaseBounds; 34 import com.sun.javafx.geom.BoxBounds; 35 import com.sun.javafx.geom.DirtyRegionContainer; 36 import com.sun.javafx.geom.DirtyRegionPool; 37 import com.sun.javafx.geom.RectBounds; 38 import com.sun.javafx.geom.transform.BaseTransform; 39 import com.sun.javafx.geom.transform.GeneralTransform3D; 40 import com.sun.prism.Graphics; 41 import com.sun.prism.paint.Color; 42 import com.sun.scenario.effect.Effect; 43 44 /** 45 * Base class for all tests in this package. The tests in this package are all about 46 * testing the NGNode and associated classes. These tests all need to be able to work 47 * directly against the NGNodes and not rely on the upper level scene graph nodes. 48 * However Node and the other classes do manage a lot of tasks (like setting up the bounds 49 * and transforms appropriately) during synchronization. This class contains all of the 50 * useful convenience methods for creating scene graphs of NG nodes and manipulating them 51 * so that we can test the NG nodes. 52 */ 53 public class NGTestBase { 54 55 /** Transforms the given node by the specified transform. */ 56 protected static <N extends NGNode> void transform(N node, BaseTransform tx) { 57 // Concatenate this transform with the one already on the node 58 tx = node.getTransform().copy().deriveWithConcatenation(tx); 59 // Compute & set the new transformed bounds for the node 60 node.setTransformedBounds(node.getEffectBounds(new RectBounds(), tx), false); 61 // Set the transform matrix 62 node.setTransformMatrix(tx); 63 } 64 65 /** Translate the given node by the specified amount */ 66 protected static <N extends NGNode> void translate(N node, double tx, double ty) { 67 transform(node, BaseTransform.getTranslateInstance(tx, ty)); 68 } 69 70 /** Set the given effect on the node. effect must not be null. */ 71 protected static <N extends NGNode> void setEffect(N node, Effect effect) { 72 node.setEffect(null); // so that when we ask for the getEffectBounds, it won't include an old effect 73 BaseBounds effectBounds = new RectBounds(); 74 effectBounds = effectBounds.deriveWithNewBounds(effect.getBounds(BaseTransform.IDENTITY_TRANSFORM, new NodeEffectInput(node))); 75 BaseBounds clippedBounds = node.getEffectBounds(new RectBounds(), BaseTransform.IDENTITY_TRANSFORM); 76 node.setEffect(effect); 77 // The new transformed bounds should be the union of the old effect bounds, new effect bounds, and 78 // then transform those bounds. The reason I'm doing it this way is to expose any bugs in the 79 // getEffectBounds() implementation when an effect is present. 80 effectBounds = effectBounds.deriveWithUnion(clippedBounds); 81 node.setTransformedBounds(node.getTransform().transform(effectBounds, effectBounds), false); 82 } 83 84 public static TestNGRectangle createRectangle(int x, int y, int width, int height) { 85 TestNGRectangle rect = new TestNGRectangle(); 86 rect.updateRectangle(x, y, width, height, 0, 0); 87 final RectBounds bounds = new RectBounds(x, y, x + width, y + height); 88 rect.setContentBounds(bounds); 89 rect.setFillPaint(new Color(0, 0, 0, 1.0f)); 90 rect.setTransformMatrix(BaseTransform.IDENTITY_TRANSFORM); 91 rect.setTransformedBounds(bounds, false); 92 return rect; 93 } 94 95 public static TestNGCircle createCircle(int cx, int cy, int radius) { 96 TestNGCircle c = new TestNGCircle(); 97 c.updateCircle(cx, cy, radius); 98 final RectBounds bounds = new RectBounds(cx - radius, cy - radius, cx + radius, cy + radius); 99 c.setContentBounds(bounds); 100 c.setFillPaint(new Color(0, 0, 0, 1.0f)); 101 c.setTransformMatrix(BaseTransform.IDENTITY_TRANSFORM); 102 c.setTransformedBounds(bounds, false); 103 return c; 104 } 105 106 public static TestNGRegion createOpaqueRegion(int x, int y, int width, int height, NGNode... children) { 107 TestNGRegion r = createTransparentRegion(x, y, width, height, children); 108 r.updateBackground(new Background(new BackgroundFill(javafx.scene.paint.Color.BLACK, null, null))); 109 r.setOpaqueInsets(0, 0, 0, 0); 110 return r; 111 } 112 113 public static TestNGRegion createTransparentRegion(int x, int y, int width, int height, NGNode... children) { 114 TestNGRegion r = new TestNGRegion(); 115 for (NGNode child : children) { 116 r.add(-1, child); 117 } 118 r.setSize(width, height); 119 final RectBounds bounds = new RectBounds(0, 0, width, height); 120 r.setContentBounds(bounds); 121 if (x != 0 || y != 0) { 122 r.setTransformMatrix(BaseTransform.getTranslateInstance(x, y)); 123 r.setTransformedBounds(r.getTransform().transform(bounds, new RectBounds()), true); 124 } else { 125 r.setTransformMatrix(BaseTransform.IDENTITY_TRANSFORM); 126 r.setTransformedBounds(bounds, false); 127 } 128 return r; 129 } 130 131 public static TestNGGroup createGroup(NGNode... children) { 132 TestNGGroup group = new TestNGGroup(); 133 BaseBounds contentBounds = new RectBounds(); 134 for (NGNode child : children) { 135 contentBounds = contentBounds.deriveWithUnion( 136 child.getCompleteBounds( 137 new RectBounds(), BaseTransform.IDENTITY_TRANSFORM)); 138 group.add(-1, child); 139 } 140 group.setContentBounds(contentBounds); 141 group.setTransformMatrix(BaseTransform.IDENTITY_TRANSFORM); 142 group.setTransformedBounds(contentBounds, false); 143 return group; 144 } 145 146 public static TestNGRegion createRegion(int w, int h, NGNode... children) { 147 TestNGRegion region = new TestNGRegion(); 148 BaseBounds contentBounds = new RectBounds(); 149 for (NGNode child : children) { 150 contentBounds = contentBounds.deriveWithUnion( 151 child.getCompleteBounds( 152 new RectBounds(), BaseTransform.IDENTITY_TRANSFORM)); 153 region.add(-1, child); 154 } 155 region.setContentBounds(contentBounds); 156 region.setTransformMatrix(BaseTransform.IDENTITY_TRANSFORM); 157 region.setTransformedBounds(contentBounds, false); 158 region.setSize(w, h); 159 160 // I have to do this nasty reflection trickery because we don't have a Toolkit for creating 161 // the Prism Color that is the platform peer. 162 javafx.scene.paint.Color color = new javafx.scene.paint.Color(0, 0, 0, 1); 163 try { 164 Field platformPaint = color.getClass().getDeclaredField("platformPaint"); 165 platformPaint.setAccessible(true); 166 platformPaint.set(color, new Color(0f, 0f, 0f, 1f)); 167 } catch (Exception e) { 168 e.printStackTrace(); 169 } 170 Background background = new Background(new BackgroundFill[] { 171 new BackgroundFill(color, CornerRadii.EMPTY, Insets.EMPTY)}, null); 172 region.updateBackground(background); 173 region.setOpaqueInsets(0, 0, 0, 0); 174 return region; 175 } 176 177 178 public static final class TestNGGroup extends NGGroup implements TestNGNode { 179 private boolean askedToAccumulateDirtyRegion; 180 private boolean computedDirtyRegion; 181 private boolean rendered; 182 183 @Override 184 protected void renderContent(Graphics g) { 185 super.renderContent(g); 186 rendered = true; 187 } 188 189 @Override public int accumulateDirtyRegions(final RectBounds clip, 190 RectBounds dirtyRegion, DirtyRegionPool pool, DirtyRegionContainer drc, BaseTransform tx, GeneralTransform3D pvTx) { 191 askedToAccumulateDirtyRegion = true; 192 return super.accumulateDirtyRegions(clip, dirtyRegion, pool, drc, tx, pvTx); 193 } 194 @Override protected int accumulateGroupDirtyRegion( 195 final RectBounds clip, RectBounds dirtyRegion, DirtyRegionPool pool, DirtyRegionContainer drc, BaseTransform tx, GeneralTransform3D pvTx) 196 { 197 computedDirtyRegion = true; 198 return super.accumulateGroupDirtyRegion(clip, dirtyRegion, pool, drc, tx, pvTx); 199 } 200 @Override protected int accumulateNodeDirtyRegion( 201 final RectBounds clip, RectBounds dirtyRegion, DirtyRegionContainer drc, BaseTransform tx, GeneralTransform3D pvTx) 202 { 203 computedDirtyRegion = true; 204 return super.accumulateNodeDirtyRegion(clip, dirtyRegion, drc, tx, pvTx); 205 } 206 @Override public boolean askedToAccumulateDirtyRegion() { return askedToAccumulateDirtyRegion; } 207 @Override public boolean computedDirtyRegion() { return computedDirtyRegion; } 208 @Override public boolean rendered() { return rendered; } 209 } 210 211 public static final class TestNGRegion extends NGRegion implements TestNGNode { 212 private boolean askedToAccumulateDirtyRegion; 213 private boolean computedDirtyRegion; 214 private boolean rendered; 215 216 @Override 217 protected void renderContent(Graphics g) { 218 super.renderContent(g); 219 rendered = true; 220 } 221 222 @Override public int accumulateDirtyRegions(final RectBounds clip, 223 RectBounds dirtyRegion, DirtyRegionPool pool, DirtyRegionContainer drc, BaseTransform tx, GeneralTransform3D pvTx) { 224 askedToAccumulateDirtyRegion = true; 225 return super.accumulateDirtyRegions(clip, dirtyRegion, pool, drc, tx, pvTx); 226 } 227 @Override protected int accumulateGroupDirtyRegion( 228 final RectBounds clip, RectBounds dirtyRegion, DirtyRegionPool pool, DirtyRegionContainer drc, BaseTransform tx, GeneralTransform3D pvTx) 229 { 230 computedDirtyRegion = true; 231 return super.accumulateGroupDirtyRegion(clip, dirtyRegion, pool, drc, tx, pvTx); 232 } 233 @Override protected int accumulateNodeDirtyRegion( 234 final RectBounds clip, RectBounds dirtyRegion, DirtyRegionContainer drc, BaseTransform tx, GeneralTransform3D pvTx) 235 { 236 computedDirtyRegion = true; 237 return super.accumulateNodeDirtyRegion(clip, dirtyRegion, drc, tx, pvTx); 238 } 239 @Override public boolean askedToAccumulateDirtyRegion() { return askedToAccumulateDirtyRegion; } 240 @Override public boolean computedDirtyRegion() { return computedDirtyRegion; } 241 @Override public boolean rendered() { return rendered; } 242 } 243 244 public static final class TestNGRectangle extends NGRectangle implements TestNGNode { 245 private boolean askedToAccumulateDirtyRegion; 246 private boolean computedDirtyRegion; 247 private boolean rendered; 248 249 @Override 250 protected void renderContent(Graphics g) { 251 rendered = true; 252 } 253 254 @Override public int accumulateDirtyRegions(final RectBounds clip, 255 RectBounds dirtyRegion, DirtyRegionPool pool, DirtyRegionContainer drc, BaseTransform tx, GeneralTransform3D pvTx) { 256 askedToAccumulateDirtyRegion = true; 257 return super.accumulateDirtyRegions(clip, dirtyRegion, pool, drc, tx, pvTx); 258 } 259 @Override protected int accumulateNodeDirtyRegion( 260 final RectBounds clip, RectBounds dirtyRegion, DirtyRegionContainer drc, BaseTransform tx, GeneralTransform3D pvTx) 261 { 262 computedDirtyRegion = true; 263 return super.accumulateNodeDirtyRegion(clip, dirtyRegion, drc, tx, pvTx); 264 } 265 @Override public boolean askedToAccumulateDirtyRegion() { return askedToAccumulateDirtyRegion; } 266 @Override public boolean computedDirtyRegion() { return computedDirtyRegion; } 267 @Override public boolean rendered() { return rendered; } 268 } 269 270 public static final class TestNGCircle extends NGCircle implements TestNGNode { 271 private boolean askedToAccumulateDirtyRegion; 272 private boolean computedDirtyRegion; 273 private boolean rendered; 274 275 @Override 276 protected void renderContent(Graphics g) { 277 rendered = true; 278 } 279 280 @Override public int accumulateDirtyRegions(final RectBounds clip, 281 RectBounds dirtyRegion, DirtyRegionPool pool, DirtyRegionContainer drc, BaseTransform tx, GeneralTransform3D pvTx) { 282 askedToAccumulateDirtyRegion = true; 283 return super.accumulateDirtyRegions(clip, dirtyRegion, pool, drc, tx, pvTx); 284 } 285 @Override protected int accumulateNodeDirtyRegion( 286 final RectBounds clip, RectBounds dirtyRegion, DirtyRegionContainer drc, BaseTransform tx, GeneralTransform3D pvTx) 287 { 288 computedDirtyRegion = true; 289 return super.accumulateNodeDirtyRegion(clip, dirtyRegion, drc,tx, pvTx); 290 } 291 @Override public boolean askedToAccumulateDirtyRegion() { return askedToAccumulateDirtyRegion; } 292 @Override public boolean computedDirtyRegion() { return computedDirtyRegion; } 293 @Override public boolean rendered() { return rendered; } 294 295 } 296 297 public interface TestNGNode { 298 public boolean askedToAccumulateDirtyRegion(); 299 public boolean computedDirtyRegion(); 300 public boolean rendered(); 301 } 302 303 public static abstract class Creator<N extends NGNode> { 304 public abstract N create(); 305 } 306 307 public static abstract class Polluter { 308 protected BaseTransform tx = BaseTransform.IDENTITY_TRANSFORM; 309 protected abstract void pollute(NGNode node); 310 protected BaseBounds modifiedBounds(NGNode node) { 311 return DirtyRegionTestBase.getWhatTransformedBoundsWouldBe(node, tx); 312 } 313 public RectBounds polluteAndGetExpectedBounds(NGNode node) { 314 BaseBounds originalBounds = node.getCompleteBounds(new RectBounds(), BaseTransform.IDENTITY_TRANSFORM); 315 BaseBounds modifiedBounds = modifiedBounds(node); 316 BaseBounds expected = originalBounds.deriveWithUnion(modifiedBounds); 317 pollute(node); 318 return (RectBounds)expected; 319 } 320 } 321 }