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 java.security.AccessController; 29 import java.security.PrivilegedAction; 30 import java.util.HashSet; 31 import java.util.Iterator; 32 import com.sun.javafx.geom.Rectangle; 33 import com.sun.javafx.geom.transform.BaseTransform; 34 import com.sun.scenario.effect.impl.Renderer; 35 36 /** 37 * A simple container that holds an {@code Image} and the valid source 38 * region thereof. Instances of {@code ImageData} can be used as the input 39 * or output from an {@code EffectPeer}. 40 * 41 * Instances of this class must be validated against the {@code FilterContext} 42 * it intended to be used with using 43 * {@link #validate(com.sun.scenario.effect.FilterContext)} method. 44 */ 45 public class ImageData { 46 47 private static HashSet<ImageData> alldatas; 48 49 static { 50 AccessController.doPrivileged(new PrivilegedAction() { 51 public Object run() { 52 if (System.getProperty("decora.showleaks") != null) { 53 alldatas = new HashSet<ImageData>(); 54 Runtime.getRuntime().addShutdownHook(new Thread() { 55 @Override 56 public void run() { 57 Iterator<ImageData> datas = alldatas.iterator(); 58 while (datas.hasNext()) { 59 ImageData id = datas.next(); 60 Rectangle r = id.getUntransformedBounds(); 61 System.out.println("id["+r.width+"x"+r.height+", refcount="+id.refcount+"] leaked from:"); 62 id.fromwhere.printStackTrace(System.out); 63 } 64 } 65 }); 66 } 67 return null; 68 } 69 }); 70 } 71 72 private ImageData sharedOwner; 73 private FilterContext fctx; 74 private int refcount; 75 private Filterable image; 76 private final Rectangle bounds; 77 private BaseTransform transform; 78 private Throwable fromwhere; 79 private boolean reusable; 80 81 public ImageData(FilterContext fctx, Filterable image, Rectangle bounds) { 82 this(fctx, image, bounds, BaseTransform.IDENTITY_TRANSFORM); 83 } 84 85 public ImageData(FilterContext fctx, Filterable image, Rectangle bounds, 86 BaseTransform transform) 87 { 88 this.fctx = fctx; 89 this.refcount = 1; 90 this.image = image; 91 this.bounds = bounds; 92 this.transform = transform; 93 if (alldatas != null) { 94 alldatas.add(this); 95 this.fromwhere = new Throwable(); 96 } 97 } 98 99 public ImageData transform(BaseTransform concattx) { 100 if (concattx.isIdentity()) { 101 return this; 102 } 103 BaseTransform newtx; 104 if (this.transform.isIdentity()) { 105 newtx = concattx; 106 } else { 107 newtx = concattx.copy().deriveWithConcatenation(this.transform); 108 } 109 return new ImageData(this, newtx, bounds); 110 } 111 112 private ImageData(ImageData original, BaseTransform transform, 113 Rectangle bounds) 114 { 115 this(original.fctx, original.image, bounds, transform); 116 this.sharedOwner = original; 117 } 118 119 public void setReusable(boolean reusable) { 120 if (sharedOwner != null) { 121 throw new InternalError("cannot make a shared ImageData reusable"); 122 } 123 this.reusable = reusable; 124 } 125 126 public FilterContext getFilterContext() { 127 return fctx; 128 } 129 130 public Filterable getUntransformedImage() { 131 return image; 132 } 133 134 public Rectangle getUntransformedBounds() { 135 return bounds; 136 } 137 138 public BaseTransform getTransform() { 139 return transform; 140 } 141 142 public Filterable getTransformedImage(Rectangle clip) { 143 if (image == null || fctx == null) { 144 return null; 145 } 146 if (transform.isIdentity()) { 147 return image; 148 } else { 149 Rectangle txbounds = getTransformedBounds(clip); 150 return Renderer.getRenderer(fctx). 151 transform(fctx, image, transform, bounds, txbounds); 152 } 153 } 154 155 public void releaseTransformedImage(Filterable tximage) { 156 if (fctx != null && tximage != null && tximage != image) { 157 Effect.releaseCompatibleImage(fctx, tximage); 158 } 159 } 160 161 public Rectangle getTransformedBounds(Rectangle clip) { 162 if (transform.isIdentity()) { 163 return bounds; 164 } 165 Rectangle txbounds = new Rectangle(); 166 transform.transform(bounds, txbounds); 167 if (clip != null) { 168 txbounds.intersectWith(clip); 169 } 170 return txbounds; 171 } 172 173 public int getReferenceCount() { 174 return refcount; 175 } 176 177 public boolean addref() { 178 if (reusable && refcount == 0) { 179 if (image != null) { 180 image.lock(); 181 } 182 } 183 ++refcount; 184 return image != null && !image.isLost(); 185 } 186 187 public void unref() { 188 if (--refcount == 0) { 189 if (sharedOwner != null) { 190 sharedOwner.unref(); 191 sharedOwner = null; 192 } else if (fctx != null && image != null) { 193 if (reusable) { 194 image.unlock(); 195 return; 196 } 197 Effect.releaseCompatibleImage(fctx, image); 198 } 199 // Just in case - to prevent releasing it twice 200 fctx = null; 201 image = null; 202 if (alldatas != null) { 203 alldatas.remove(this); 204 } 205 } 206 } 207 208 /** 209 * Validates this image data for the use with the passed 210 * {@link FilterContext}. 211 * 212 * @param fctx context to validate against 213 * @return {@code true} if this object is valid and compatible with 214 * the passed {@code FilterContext}, {@code false} otherwise. 215 */ 216 public boolean validate(FilterContext fctx) { 217 return image != null && 218 Renderer.getRenderer(fctx).isImageDataCompatible(this); 219 } 220 }