1 /* 2 * Copyright (c) 2008, 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 com.sun.scenario.effect; 27 28 import com.sun.javafx.geom.BaseBounds; 29 import com.sun.javafx.geom.DirtyRegionContainer; 30 import com.sun.javafx.geom.DirtyRegionPool; 31 import com.sun.javafx.geom.RectBounds; 32 import com.sun.javafx.geom.Rectangle; 33 import com.sun.javafx.geom.transform.BaseTransform; 34 35 /** 36 * An effect that returns a mask that is the inverse of the input (i.e., 37 * opaque areas of the input become transparent and vice versa) with a 38 * given offset and padding. 39 */ 40 public class InvertMask extends CoreEffect { 41 42 private int pad; 43 private int xoff; 44 private int yoff; 45 46 /** 47 * Constructs a new {@code InvertMask} effect with the default pad (10), 48 * using the default input for source data. 49 * This is a shorthand equivalent to: 50 * <pre> 51 * new InvertMask(10, DefaultInput) 52 * </pre> 53 */ 54 public InvertMask() { 55 this(10); 56 } 57 58 /** 59 * Constructs a new {@code InvertMask} effect with the default pad (10), 60 * using the given {@code Effect} as the input. 61 * This is a shorthand equivalent to: 62 * <pre> 63 * new InvertMask(10, input) 64 * </pre> 65 * 66 * @param input the single input {@code Effect} 67 */ 68 public InvertMask(Effect input) { 69 this(10, input); 70 } 71 72 /** 73 * Constructs a new {@code InvertMask} effect with the given pad value 74 * using the default input for source data. 75 * 76 * @param pad the amount of padding on each side of the resulting image 77 * @throws IllegalArgumentException if {@code pad} is negative 78 */ 79 public InvertMask(int pad) { 80 this(pad, DefaultInput); 81 } 82 83 /** 84 * Constructs a new {@code InvertMask} effect with the given pad value 85 * and effect input. 86 * 87 * @param pad the amount of padding on each side of the resulting image 88 * @param input the single input {@code Effect} 89 * @throws IllegalArgumentException if {@code pad} is negative 90 */ 91 public InvertMask(int pad, Effect input) { 92 super(input); 93 setPad(pad); 94 updatePeerKey("InvertMask"); 95 } 96 97 /** 98 * Returns the input for this {@code Effect}. 99 * 100 * @return the input for this {@code Effect} 101 */ 102 public final Effect getInput() { 103 return getInputs().get(0); 104 } 105 106 /** 107 * Sets the input for this {@code Effect} to a specific 108 * {@code Effect} or to the default input if {@code input} is 109 * {@code null}. 110 * 111 * @param input the input for this {@code Effect} 112 */ 113 public void setInput(Effect input) { 114 setInput(0, input); 115 } 116 117 /** 118 * Returns the amount of padding added to each side of the resulting 119 * image, in pixels. 120 * 121 * @return the amount of padding, in pixels 122 */ 123 public int getPad() { 124 return pad; 125 } 126 127 /** 128 * Sets the amount of padding added to each side of the resulting 129 * image, in pixels. 130 * <pre> 131 * Min: 0 132 * Max: Integer.MAX_VALUE 133 * Default: 0 134 * Identity: 0 135 * </pre> 136 * 137 * @param pad the amount of padding, in pixels 138 * @throws IllegalArgumentException if {@code pad} is negative 139 */ 140 public void setPad(int pad) { 141 if (pad < 0) { 142 throw new IllegalArgumentException("Pad value must be non-negative"); 143 } 144 int old = this.pad; 145 this.pad = pad; 146 } 147 148 /** 149 * Returns the offset in the x direction, in pixels. 150 * 151 * @return the offset in the x direction, in pixels. 152 */ 153 public int getOffsetX() { 154 return xoff; 155 } 156 157 /** 158 * Sets the offset in the x direction, in pixels. 159 * <pre> 160 * Min: Integer.MIN_VALUE 161 * Max: Integer.MAX_VALUE 162 * Default: 0 163 * Identity: 0 164 * </pre> 165 * 166 * @param xoff the offset in the x direction, in pixels 167 */ 168 public void setOffsetX(int xoff) { 169 int old = this.xoff; 170 this.xoff = xoff; 171 } 172 173 /** 174 * Returns the offset in the y direction, in pixels. 175 * 176 * @return the offset in the y direction, in pixels. 177 */ 178 public int getOffsetY() { 179 return yoff; 180 } 181 182 /** 183 * Sets the offset in the y direction, in pixels. 184 * <pre> 185 * Min: Integer.MIN_VALUE 186 * Max: Integer.MAX_VALUE 187 * Default: 0 188 * Identity: 0 189 * </pre> 190 * 191 * @param yoff the offset in the y direction, in pixels 192 */ 193 public void setOffsetY(int yoff) { 194 float old = this.yoff; 195 this.yoff = yoff; 196 } 197 198 @Override 199 public BaseBounds getBounds(BaseTransform transform, Effect defaultInput) { 200 BaseBounds bounds = super.getBounds(BaseTransform.IDENTITY_TRANSFORM, defaultInput); 201 BaseBounds ret = new RectBounds(bounds.getMinX(), bounds.getMinY(), 202 bounds.getMaxX(), bounds.getMaxY()); 203 ((RectBounds) ret).grow(pad, pad); 204 if (!transform.isIdentity()) { 205 ret = transformBounds(transform, ret); 206 } 207 return ret; 208 } 209 210 @Override 211 public Rectangle getResultBounds(BaseTransform transform, 212 Rectangle outputClip, 213 ImageData... inputDatas) 214 { 215 Rectangle r = super.getResultBounds(transform, outputClip, inputDatas); 216 Rectangle ret = new Rectangle(r); 217 ret.grow(pad, pad); 218 return ret; 219 } 220 221 @Override 222 protected Rectangle getInputClip(int inputIndex, 223 BaseTransform transform, 224 Rectangle outputClip) 225 { 226 // Typically the mask gets padded by synthetic opaque mask data 227 // that is computed from the lack of input pixels in the padded 228 // area. But in the case where a clip has cut down on the 229 // amount of data we are generating then the padding for this 230 // particular (clipped) operation may not be synthetic, rather it 231 // may actually represent inversions of real input pixels. Thus, 232 // the clip for the input needs to make sure it includes any 233 // valid input pixels that may appear not just in the output 234 // clip, but also in its padded fringe. 235 if (outputClip != null) { 236 if (pad != 0) { 237 outputClip = new Rectangle(outputClip); 238 outputClip.grow(pad, pad); 239 } 240 } 241 return outputClip; 242 } 243 244 @Override 245 public boolean reducesOpaquePixels() { 246 return true; 247 } 248 249 @Override 250 public DirtyRegionContainer getDirtyRegions(Effect defaultInput, DirtyRegionPool regionPool) { 251 Effect di = getDefaultedInput(0, defaultInput); 252 DirtyRegionContainer drc = di.getDirtyRegions(defaultInput, regionPool); 253 254 if (xoff != 0 || yoff != 0) { 255 for (int i = 0; i < drc.size(); i++) { 256 drc.getDirtyRegion(i).translate(xoff, yoff, 0); 257 } 258 } 259 260 return drc; 261 } 262 }