001: /*
002: * Copyright 2005 Sun Microsystems, Inc. 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. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.java2d.pipe;
027:
028: import java.awt.AlphaComposite;
029: import java.awt.Composite;
030: import java.awt.Paint;
031: import java.awt.geom.AffineTransform;
032: import sun.java2d.InvalidPipeException;
033: import sun.java2d.SunGraphics2D;
034: import sun.java2d.SurfaceData;
035: import sun.java2d.loops.XORComposite;
036: import static sun.java2d.pipe.BufferedOpCodes.*;
037: import static sun.java2d.pipe.BufferedRenderPipe.BYTES_PER_SPAN;
038:
039: /**
040: * Base context class for managing state in a single-threaded rendering
041: * environment. Each state-setting operation (e.g. SET_COLOR) is added to
042: * the provided RenderQueue, which will be processed at a later time by a
043: * single thread. Note that the RenderQueue lock must be acquired before
044: * calling the validate() method (or any other method in this class). See
045: * the RenderQueue class comments for a sample usage scenario.
046: */
047: public class BufferedContext {
048:
049: /*
050: * The following flags help the internals of validate() determine
051: * the appropriate (meaning correct, or optimal) code path when
052: * setting up the current context. The flags can be bitwise OR'd
053: * together as needed.
054: */
055:
056: /**
057: * Indicates that no flags are needed; take all default code paths.
058: */
059: public static final int NO_CONTEXT_FLAGS = (0 << 0);
060: /**
061: * Indicates that the source surface (or color value, if it is a simple
062: * rendering operation) is opaque (has an alpha value of 1.0). If this
063: * flag is present, it allows us to disable blending in certain
064: * situations in order to improve performance.
065: */
066: public static final int SRC_IS_OPAQUE = (1 << 0);
067: /**
068: * Indicates that the operation uses an alpha mask, which may determine
069: * the code path that is used when setting up the current paint state.
070: */
071: public static final int USE_MASK = (1 << 1);
072:
073: protected RenderQueue rq;
074: protected RenderBuffer buf;
075:
076: /**
077: * This is a reference to the most recently validated BufferedContext. If
078: * this value is null, it means that there is no current context. It is
079: * provided here so that validate() only needs to do a quick reference
080: * check to see if the BufferedContext passed to that method is the same
081: * as the one we've cached here.
082: */
083: protected static BufferedContext currentContext;
084:
085: private SurfaceData validatedSrcData;
086: private SurfaceData validatedDstData;
087: private Region validatedClip;
088: private Composite validatedComp;
089: private Paint validatedPaint;
090: private int validatedFlags;
091: private boolean xformInUse;
092:
093: protected BufferedContext(RenderQueue rq) {
094: this .rq = rq;
095: this .buf = rq.getBuffer();
096: }
097:
098: /**
099: * Validates the given parameters against the current state for this
100: * context. If this context is not current, it will be made current
101: * for the given source and destination surfaces, and the viewport will
102: * be updated. Then each part of the context state (clip, composite,
103: * etc.) is checked against the previous value. If the value has changed
104: * since the last call to validate(), it will be updated accordingly.
105: *
106: * Note that the SunGraphics2D parameter is only used for the purposes
107: * of validating a (non-null) Paint parameter. In all other cases it
108: * is safe to pass a null SunGraphics2D and it will be ignored.
109: */
110: public void validate(SurfaceData srcData, SurfaceData dstData,
111: Region clip, Composite comp, AffineTransform xform,
112: Paint paint, SunGraphics2D sg2d, int flags) {
113: // assert rq.lock.isHeldByCurrentThread();
114:
115: boolean updateClip = (clip != validatedClip);
116: boolean updatePaint = (paint != validatedPaint);
117:
118: if (!dstData.isValid()) {
119: throw new InvalidPipeException("bounds changed");
120: }
121:
122: if ((currentContext != this ) || (srcData != validatedSrcData)
123: || (dstData != validatedDstData)) {
124: if (dstData != validatedDstData) {
125: // the clip is dependent on the destination surface, so we
126: // need to update it if we have a new destination surface
127: updateClip = true;
128: }
129:
130: if (paint == null) {
131: // make sure we update the color state (otherwise, it might
132: // not be updated if this is the first time the context
133: // is being validated)
134: updatePaint = true;
135: }
136:
137: // update the current source and destination surfaces
138: setSurfaces(srcData, dstData);
139:
140: currentContext = this ;
141: validatedSrcData = srcData;
142: validatedDstData = dstData;
143: }
144:
145: // validate clip
146: if (updateClip) {
147: if (clip != null) {
148: setClip(clip);
149: } else {
150: resetClip();
151: }
152: validatedClip = clip;
153: }
154:
155: // validate composite (note that a change in the context flags
156: // may require us to update the composite state, even if the
157: // composite has not changed)
158: if ((comp != validatedComp) || (flags != validatedFlags)) {
159: if (comp != null) {
160: setComposite(comp, flags);
161: } else {
162: resetComposite();
163: }
164: // the paint state is dependent on the composite state, so make
165: // sure we update the color below
166: updatePaint = true;
167: validatedComp = comp;
168: validatedFlags = flags;
169: }
170:
171: // validate transform
172: if (xform == null) {
173: if (xformInUse) {
174: resetTransform();
175: xformInUse = false;
176: }
177: } else {
178: setTransform(xform);
179: xformInUse = true;
180: }
181:
182: // validate paint
183: if (updatePaint) {
184: if (paint != null) {
185: BufferedPaints.setPaint(rq, sg2d, paint, flags);
186: } else {
187: BufferedPaints.resetPaint(rq);
188: }
189: validatedPaint = paint;
190: }
191:
192: // mark dstData dirty
193: dstData.markDirty();
194: }
195:
196: /**
197: * Invalidates the surfaces associated with this context. This is
198: * useful when the context is no longer needed, and we want to break
199: * the chain caused by these surface references.
200: */
201: public void invalidateSurfaces() {
202: validatedSrcData = null;
203: validatedDstData = null;
204: }
205:
206: private void setSurfaces(SurfaceData srcData, SurfaceData dstData) {
207: // assert rq.lock.isHeldByCurrentThread();
208: rq.ensureCapacityAndAlignment(20, 4);
209: buf.putInt(SET_SURFACES);
210: buf.putLong(srcData.getNativeOps());
211: buf.putLong(dstData.getNativeOps());
212: }
213:
214: private void resetClip() {
215: // assert rq.lock.isHeldByCurrentThread();
216: rq.ensureCapacity(4);
217: buf.putInt(RESET_CLIP);
218: }
219:
220: private void setClip(Region clip) {
221: // assert rq.lock.isHeldByCurrentThread();
222: if (clip.isRectangular()) {
223: rq.ensureCapacity(20);
224: buf.putInt(SET_RECT_CLIP);
225: buf.putInt(clip.getLoX()).putInt(clip.getLoY());
226: buf.putInt(clip.getHiX()).putInt(clip.getHiY());
227: } else {
228: rq.ensureCapacity(28); // so that we have room for at least a span
229: buf.putInt(BEGIN_SHAPE_CLIP);
230: buf.putInt(SET_SHAPE_CLIP_SPANS);
231: // include a placeholder for the span count
232: int countIndex = buf.position();
233: buf.putInt(0);
234: int spanCount = 0;
235: int remainingSpans = buf.remaining() / BYTES_PER_SPAN;
236: int span[] = new int[4];
237: SpanIterator si = clip.getSpanIterator();
238: while (si.nextSpan(span)) {
239: if (remainingSpans == 0) {
240: buf.putInt(countIndex, spanCount);
241: rq.flushNow();
242: buf.putInt(SET_SHAPE_CLIP_SPANS);
243: countIndex = buf.position();
244: buf.putInt(0);
245: spanCount = 0;
246: remainingSpans = buf.remaining() / BYTES_PER_SPAN;
247: }
248: buf.putInt(span[0]); // x1
249: buf.putInt(span[1]); // y1
250: buf.putInt(span[2]); // x2
251: buf.putInt(span[3]); // y2
252: spanCount++;
253: remainingSpans--;
254: }
255: buf.putInt(countIndex, spanCount);
256: rq.ensureCapacity(4);
257: buf.putInt(END_SHAPE_CLIP);
258: }
259: }
260:
261: private void resetComposite() {
262: // assert rq.lock.isHeldByCurrentThread();
263: rq.ensureCapacity(4);
264: buf.putInt(RESET_COMPOSITE);
265: }
266:
267: private void setComposite(Composite comp, int flags) {
268: // assert rq.lock.isHeldByCurrentThread();
269: if (comp instanceof AlphaComposite) {
270: AlphaComposite ac = (AlphaComposite) comp;
271: rq.ensureCapacity(16);
272: buf.putInt(SET_ALPHA_COMPOSITE);
273: buf.putInt(ac.getRule());
274: buf.putFloat(ac.getAlpha());
275: buf.putInt(flags);
276: } else if (comp instanceof XORComposite) {
277: int xorPixel = ((XORComposite) comp).getXorPixel();
278: rq.ensureCapacity(8);
279: buf.putInt(SET_XOR_COMPOSITE);
280: buf.putInt(xorPixel);
281: } else {
282: throw new InternalError("not yet implemented");
283: }
284: }
285:
286: private void resetTransform() {
287: // assert rq.lock.isHeldByCurrentThread();
288: rq.ensureCapacity(4);
289: buf.putInt(RESET_TRANSFORM);
290: }
291:
292: private void setTransform(AffineTransform xform) {
293: // assert rq.lock.isHeldByCurrentThread();
294: rq.ensureCapacityAndAlignment(52, 4);
295: buf.putInt(SET_TRANSFORM);
296: buf.putDouble(xform.getScaleX());
297: buf.putDouble(xform.getShearY());
298: buf.putDouble(xform.getShearX());
299: buf.putDouble(xform.getScaleY());
300: buf.putDouble(xform.getTranslateX());
301: buf.putDouble(xform.getTranslateY());
302: }
303: }
|