Spec-Zone .ru
спецификации, руководства, описания, API
|
001/* 002 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. Oracle designates this 008 * particular file as subject to the "Classpath" exception as provided 009 * by Oracle in the LICENSE file that accompanied this code. 010 * 011 * This code is distributed in the hope that it will be useful, but WITHOUT 012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 014 * version 2 for more details (a copy is included in the LICENSE file that 015 * accompanied this code). 016 * 017 * You should have received a copy of the GNU General Public License version 018 * 2 along with this work; if not, write to the Free Software Foundation, 019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 020 * 021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 022 * or visit www.oracle.com if you need additional information or have any 023 * questions. 024 */ 025 026package javafx.scene.effect; 027 028import javafx.beans.Observable; 029import javafx.beans.property.IntegerProperty; 030import javafx.beans.property.ObjectPropertyBase; 031import javafx.beans.property.SimpleIntegerProperty; 032import javafx.scene.Node; 033 034import com.sun.javafx.effect.EffectDirtyBits; 035import com.sun.javafx.geom.BaseBounds; 036import com.sun.javafx.geom.transform.BaseTransform; 037import com.sun.javafx.scene.BoundsAccessor; 038 039/** 040 * The abstract base class for all effect implementations. 041 * An effect is a graphical algorithm that produces an image, typically 042 * as a modification of a source image. 043 * An effect can be associated with a scene graph {@code Node} by setting 044 * the {@link javafx.scene.Node#effectProperty Node.effect} attribute. 045 * Some effects change the color properties of the source pixels 046 * (such as {@link ColorAdjust}), 047 * others combine multiple images together (such as {@link Blend}), 048 * while still others warp or move the pixels of the source image around 049 * (such as {@link DisplacementMap} or {@link PerspectiveTransform}). 050 * All effects have at least one input defined and the input can be set 051 * to another effect to chain the effects together and combine their 052 * results, or it can be left unspecified in which case the effect will 053 * operate on a graphical rendering of the node it is attached to. 054 * <p> 055 * Note: this is a conditional feature. See 056 * {@link javafx.application.ConditionalFeature#EFFECT ConditionalFeature.EFFECT} 057 * for more information. 058 */ 059public abstract class Effect { 060 /** 061 * Creates a new Effect. 062 */ 063 protected Effect() { 064 markDirty(EffectDirtyBits.EFFECT_DIRTY); 065 } 066 067 void effectBoundsChanged() { 068 toggleDirty(EffectDirtyBits.BOUNDS_CHANGED); 069 } 070 071 private com.sun.scenario.effect.Effect peer; 072 abstract com.sun.scenario.effect.Effect impl_createImpl(); 073 074 /** 075 * @treatAsPrivate implementation detail 076 * @deprecated This is an internal API that is not intended for use and will be removed in the next version 077 */ 078 @Deprecated 079 public com.sun.scenario.effect.Effect impl_getImpl() { 080 if (peer == null) { 081 peer = impl_createImpl(); 082 } 083 return peer; 084 } 085 086 // effect is marked dirty in the constructor, so we don't need to be lazy here 087 private IntegerProperty effectDirty = 088 new SimpleIntegerProperty(this, "effectDirty"); 089 090 private void setEffectDirty(int value) { 091 impl_effectDirtyProperty().set(value); 092 } 093 094 /** 095 * @treatAsPrivate implementation detail 096 * @deprecated This is an internal API that is not intended for use and will be removed in the next version 097 */ 098 @Deprecated 099 public final IntegerProperty impl_effectDirtyProperty() { 100 return effectDirty; 101 } 102 103 /** 104 * @treatAsPrivate implementation detail 105 * @deprecated This is an internal API that is not intended for use and will be removed in the next version 106 */ 107 @Deprecated 108 public final boolean impl_isEffectDirty() { 109 return isEffectDirty(EffectDirtyBits.EFFECT_DIRTY); 110 } 111 112 /** 113 * Set the specified dirty bit 114 */ 115 final void markDirty(EffectDirtyBits dirtyBit) { 116 setEffectDirty(effectDirty.get() | dirtyBit.getMask()); 117 } 118 119 /** 120 * Toggle the specified dirty bit 121 */ 122 private void toggleDirty(EffectDirtyBits dirtyBit) { 123 setEffectDirty(effectDirty.get() ^ dirtyBit.getMask()); 124 } 125 126 /** 127 * Test the specified dirty bit 128 */ 129 private boolean isEffectDirty(EffectDirtyBits dirtyBit) { 130 return ((effectDirty.get() & dirtyBit.getMask()) != 0); 131 } 132 133 /** 134 * Clear the specified dirty bit 135 */ 136 private void clearEffectDirty(EffectDirtyBits dirtyBit) { 137 setEffectDirty(effectDirty.get() & ~dirtyBit.getMask()); 138 } 139 140 /** 141 * @treatAsPrivate implementation detail 142 * @deprecated This is an internal API that is not intended for use and will be removed in the next version 143 */ 144 @Deprecated 145 public final void impl_sync() { 146 if (isEffectDirty(EffectDirtyBits.EFFECT_DIRTY)) { 147 impl_update(); 148 clearEffectDirty(EffectDirtyBits.EFFECT_DIRTY); 149 } 150 } 151 152 abstract void impl_update(); 153 154 abstract boolean impl_checkChainContains(Effect e); 155 156 boolean impl_containsCycles(Effect value) { 157 if (value != null 158 && (value == this || value.impl_checkChainContains(this))) { 159 return true; 160 } 161 return false; 162 } 163 164 class EffectInputChangeListener extends EffectChangeListener { 165 private int oldBits; 166 167 public void register(Effect value) { 168 super.register(value == null? null: value.impl_effectDirtyProperty()); 169 if (value != null) { 170 oldBits = value.impl_effectDirtyProperty().get(); 171 } 172 } 173 174 @Override 175 public void invalidated(Observable valueModel) { 176 int newBits = ((IntegerProperty)valueModel).get(); 177 int dirtyBits = newBits ^ oldBits; 178 oldBits = newBits; 179 if (EffectDirtyBits.isSet(dirtyBits, EffectDirtyBits.EFFECT_DIRTY) 180 && EffectDirtyBits.isSet(newBits, EffectDirtyBits.EFFECT_DIRTY)) { 181 markDirty(EffectDirtyBits.EFFECT_DIRTY); 182 } 183 if (EffectDirtyBits.isSet(dirtyBits, EffectDirtyBits.BOUNDS_CHANGED)) { 184 toggleDirty(EffectDirtyBits.BOUNDS_CHANGED); 185 } 186 } 187 } 188 189 class EffectInputProperty extends ObjectPropertyBase<Effect> { 190 private final String propertyName; 191 192 private Effect validInput = null; 193 194 private final EffectInputChangeListener effectChangeListener = 195 new EffectInputChangeListener(); 196 197 public EffectInputProperty(final String propertyName) { 198 this.propertyName = propertyName; 199 } 200 201 @Override 202 public void invalidated() { 203 final Effect newInput = super.get(); 204 if (impl_containsCycles(newInput)) { 205 if (isBound()) { 206 unbind(); 207 set(validInput); 208 throw new IllegalArgumentException("Cycle in effect chain " 209 + "detected, binding was set to incorrect value, " 210 + "unbinding the input property"); 211 } else { 212 set(validInput); 213 throw new IllegalArgumentException("Cycle in effect chain detected"); 214 } 215 } 216 validInput = newInput; 217 effectChangeListener.register(newInput); 218 markDirty(EffectDirtyBits.EFFECT_DIRTY); 219 220 // we toggle dirty flag for bounds on this effect to notify 221 // "consumers" of this effect that bounds have changed 222 // 223 // bounds of this effect might change 224 // even if bounds of chained effect are not dirty 225 effectBoundsChanged(); 226 } 227 228 @Override 229 public Object getBean() { 230 return Effect.this; 231 } 232 233 @Override 234 public String getName() { 235 return propertyName; 236 } 237 } 238 239 /** 240 * Returns bounds of given node with applied effect. 241 * 242 * We *never* pass null in as a bounds. This method will 243 * NOT take a null bounds object. The returned value may be 244 * the same bounds object passed in, or it may be a new object. 245 * 246 * @treatAsPrivate implementation detail 247 * @deprecated This is an internal API that is not intended for use and will be removed in the next version 248 */ 249 @Deprecated 250 public abstract BaseBounds impl_getBounds(BaseBounds bounds, 251 BaseTransform tx, 252 Node node, 253 BoundsAccessor boundsAccessor); 254 /** 255 * 256 * @treatAsPrivate implementation detail 257 * @deprecated This is an internal API that is not intended for use and will be removed in the next version 258 */ 259 @Deprecated 260 public abstract Effect impl_copy(); 261 262}