|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.java2d.pipe; |
|
|
|
import java.awt.AlphaComposite; |
|
import java.awt.Color; |
|
import java.awt.Composite; |
|
import java.awt.Paint; |
|
import java.awt.geom.AffineTransform; |
|
import sun.java2d.pipe.hw.AccelSurface; |
|
import sun.java2d.InvalidPipeException; |
|
import sun.java2d.SunGraphics2D; |
|
import sun.java2d.loops.XORComposite; |
|
import static sun.java2d.pipe.BufferedOpCodes.*; |
|
import static sun.java2d.pipe.BufferedRenderPipe.BYTES_PER_SPAN; |
|
|
|
import java.lang.annotation.Native; |
|
import java.lang.ref.Reference; |
|
import java.lang.ref.WeakReference; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public abstract class BufferedContext { |
|
|
|
/* |
|
* The following flags help the internals of validate() determine |
|
* the appropriate (meaning correct, or optimal) code path when |
|
* setting up the current context. The flags can be bitwise OR'd |
|
* together as needed. |
|
*/ |
|
|
|
|
|
|
|
*/ |
|
@Native public static final int NO_CONTEXT_FLAGS = (0 << 0); |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
@Native public static final int SRC_IS_OPAQUE = (1 << 0); |
|
|
|
|
|
|
|
*/ |
|
@Native public static final int USE_MASK = (1 << 1); |
|
|
|
protected RenderQueue rq; |
|
protected RenderBuffer buf; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected static BufferedContext currentContext; |
|
|
|
private Reference<AccelSurface> validSrcDataRef = new WeakReference<>(null); |
|
private Reference<AccelSurface> validDstDataRef = new WeakReference<>(null); |
|
private Reference<Region> validClipRef = new WeakReference<>(null); |
|
private Reference<Composite> validCompRef = new WeakReference<>(null); |
|
private Reference<Paint> validPaintRef = new WeakReference<>(null); |
|
|
|
private boolean isValidatedPaintJustAColor; |
|
private int validatedRGB; |
|
private int validatedFlags; |
|
private boolean xformInUse; |
|
private AffineTransform transform; |
|
|
|
protected BufferedContext(RenderQueue rq) { |
|
this.rq = rq; |
|
this.buf = rq.getBuffer(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static void validateContext(AccelSurface srcData, |
|
AccelSurface dstData, |
|
Region clip, Composite comp, |
|
AffineTransform xform, |
|
Paint paint, SunGraphics2D sg2d, |
|
int flags) |
|
{ |
|
|
|
BufferedContext context = dstData.getContext(); |
|
context.validate(srcData, dstData, |
|
clip, comp, xform, paint, sg2d, flags); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static void validateContext(AccelSurface surface) { |
|
|
|
validateContext(surface, surface, |
|
null, null, null, null, null, NO_CONTEXT_FLAGS); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public void validate(AccelSurface srcData, AccelSurface dstData, |
|
Region clip, Composite comp, |
|
AffineTransform xform, |
|
Paint paint, SunGraphics2D sg2d, int flags) |
|
{ |
|
// assert rq.lock.isHeldByCurrentThread(); |
|
|
|
boolean updateClip = false; |
|
boolean updatePaint = false; |
|
|
|
if (!dstData.isValid() || |
|
dstData.isSurfaceLost() || srcData.isSurfaceLost()) |
|
{ |
|
invalidateContext(); |
|
throw new InvalidPipeException("bounds changed or surface lost"); |
|
} |
|
|
|
if (paint instanceof Color) { |
|
|
|
int newRGB = ((Color)paint).getRGB(); |
|
if (isValidatedPaintJustAColor) { |
|
if (newRGB != validatedRGB) { |
|
validatedRGB = newRGB; |
|
updatePaint = true; |
|
} |
|
} else { |
|
validatedRGB = newRGB; |
|
updatePaint = true; |
|
isValidatedPaintJustAColor = true; |
|
} |
|
} else if (validPaintRef.get() != paint) { |
|
updatePaint = true; |
|
// this should be set when we are switching from paint to color |
|
|
|
isValidatedPaintJustAColor = false; |
|
} |
|
|
|
final AccelSurface validatedSrcData = validSrcDataRef.get(); |
|
final AccelSurface validatedDstData = validDstDataRef.get(); |
|
if ((currentContext != this) || |
|
(srcData != validatedSrcData) || |
|
(dstData != validatedDstData)) |
|
{ |
|
if (dstData != validatedDstData) { |
|
// the clip is dependent on the destination surface, so we |
|
|
|
updateClip = true; |
|
} |
|
|
|
if (paint == null) { |
|
// make sure we update the color state (otherwise, it might |
|
// not be updated if this is the first time the context |
|
|
|
updatePaint = true; |
|
} |
|
|
|
|
|
setSurfaces(srcData, dstData); |
|
|
|
currentContext = this; |
|
validSrcDataRef = new WeakReference<>(srcData); |
|
validDstDataRef = new WeakReference<>(dstData); |
|
} |
|
|
|
|
|
final Region validatedClip = validClipRef.get(); |
|
if ((clip != validatedClip) || updateClip) { |
|
if (clip != null) { |
|
if (updateClip || |
|
validatedClip == null || |
|
!(validatedClip.isRectangular() && clip.isRectangular()) || |
|
((clip.getLoX() != validatedClip.getLoX() || |
|
clip.getLoY() != validatedClip.getLoY() || |
|
clip.getHiX() != validatedClip.getHiX() || |
|
clip.getHiY() != validatedClip.getHiY()))) |
|
{ |
|
setClip(clip); |
|
} |
|
} else { |
|
resetClip(); |
|
} |
|
validClipRef = new WeakReference<>(clip); |
|
} |
|
|
|
// validate composite (note that a change in the context flags |
|
// may require us to update the composite state, even if the |
|
|
|
if ((comp != validCompRef.get()) || (flags != validatedFlags)) { |
|
if (comp != null) { |
|
setComposite(comp, flags); |
|
} else { |
|
resetComposite(); |
|
} |
|
// the paint state is dependent on the composite state, so make |
|
|
|
updatePaint = true; |
|
validCompRef = new WeakReference<>(comp); |
|
validatedFlags = flags; |
|
} |
|
|
|
|
|
boolean txChanged = false; |
|
if (xform == null) { |
|
if (xformInUse) { |
|
resetTransform(); |
|
xformInUse = false; |
|
txChanged = true; |
|
} else if (sg2d != null && !sg2d.transform.equals(transform)) { |
|
txChanged = true; |
|
} |
|
if (sg2d != null && txChanged) { |
|
transform = new AffineTransform(sg2d.transform); |
|
} |
|
} else { |
|
setTransform(xform); |
|
xformInUse = true; |
|
txChanged = true; |
|
} |
|
|
|
if (!isValidatedPaintJustAColor && txChanged) { |
|
updatePaint = true; |
|
} |
|
|
|
|
|
if (updatePaint) { |
|
if (paint != null) { |
|
BufferedPaints.setPaint(rq, sg2d, paint, flags); |
|
} else { |
|
BufferedPaints.resetPaint(rq); |
|
} |
|
validPaintRef = new WeakReference<>(paint); |
|
} |
|
|
|
// mark dstData dirty |
|
|
|
dstData.markDirty(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private void invalidateSurfaces() { |
|
validSrcDataRef.clear(); |
|
validDstDataRef.clear(); |
|
} |
|
|
|
private void setSurfaces(AccelSurface srcData, |
|
AccelSurface dstData) |
|
{ |
|
|
|
rq.ensureCapacityAndAlignment(20, 4); |
|
buf.putInt(SET_SURFACES); |
|
buf.putLong(srcData.getNativeOps()); |
|
buf.putLong(dstData.getNativeOps()); |
|
} |
|
|
|
private void resetClip() { |
|
|
|
rq.ensureCapacity(4); |
|
buf.putInt(RESET_CLIP); |
|
} |
|
|
|
private void setClip(Region clip) { |
|
|
|
if (clip.isRectangular()) { |
|
rq.ensureCapacity(20); |
|
buf.putInt(SET_RECT_CLIP); |
|
buf.putInt(clip.getLoX()).putInt(clip.getLoY()); |
|
buf.putInt(clip.getHiX()).putInt(clip.getHiY()); |
|
} else { |
|
rq.ensureCapacity(28); |
|
buf.putInt(BEGIN_SHAPE_CLIP); |
|
buf.putInt(SET_SHAPE_CLIP_SPANS); |
|
|
|
int countIndex = buf.position(); |
|
buf.putInt(0); |
|
int spanCount = 0; |
|
int remainingSpans = buf.remaining() / BYTES_PER_SPAN; |
|
int span[] = new int[4]; |
|
SpanIterator si = clip.getSpanIterator(); |
|
while (si.nextSpan(span)) { |
|
if (remainingSpans == 0) { |
|
buf.putInt(countIndex, spanCount); |
|
rq.flushNow(); |
|
buf.putInt(SET_SHAPE_CLIP_SPANS); |
|
countIndex = buf.position(); |
|
buf.putInt(0); |
|
spanCount = 0; |
|
remainingSpans = buf.remaining() / BYTES_PER_SPAN; |
|
} |
|
buf.putInt(span[0]); |
|
buf.putInt(span[1]); |
|
buf.putInt(span[2]); |
|
buf.putInt(span[3]); |
|
spanCount++; |
|
remainingSpans--; |
|
} |
|
buf.putInt(countIndex, spanCount); |
|
rq.ensureCapacity(4); |
|
buf.putInt(END_SHAPE_CLIP); |
|
} |
|
} |
|
|
|
private void resetComposite() { |
|
|
|
rq.ensureCapacity(4); |
|
buf.putInt(RESET_COMPOSITE); |
|
} |
|
|
|
private void setComposite(Composite comp, int flags) { |
|
|
|
if (comp instanceof AlphaComposite) { |
|
AlphaComposite ac = (AlphaComposite)comp; |
|
rq.ensureCapacity(16); |
|
buf.putInt(SET_ALPHA_COMPOSITE); |
|
buf.putInt(ac.getRule()); |
|
buf.putFloat(ac.getAlpha()); |
|
buf.putInt(flags); |
|
} else if (comp instanceof XORComposite) { |
|
int xorPixel = ((XORComposite)comp).getXorPixel(); |
|
rq.ensureCapacity(8); |
|
buf.putInt(SET_XOR_COMPOSITE); |
|
buf.putInt(xorPixel); |
|
} else { |
|
throw new InternalError("not yet implemented"); |
|
} |
|
} |
|
|
|
private void resetTransform() { |
|
|
|
rq.ensureCapacity(4); |
|
buf.putInt(RESET_TRANSFORM); |
|
} |
|
|
|
private void setTransform(AffineTransform xform) { |
|
|
|
rq.ensureCapacityAndAlignment(52, 4); |
|
buf.putInt(SET_TRANSFORM); |
|
buf.putDouble(xform.getScaleX()); |
|
buf.putDouble(xform.getShearY()); |
|
buf.putDouble(xform.getShearX()); |
|
buf.putDouble(xform.getScaleY()); |
|
buf.putDouble(xform.getTranslateX()); |
|
buf.putDouble(xform.getTranslateY()); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public void invalidateContext() { |
|
resetTransform(); |
|
resetComposite(); |
|
resetClip(); |
|
BufferedPaints.resetPaint(rq); |
|
invalidateSurfaces(); |
|
validCompRef.clear(); |
|
validClipRef.clear(); |
|
validPaintRef.clear(); |
|
isValidatedPaintJustAColor = false; |
|
xformInUse = false; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public abstract RenderQueue getRenderQueue(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public abstract void saveState(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public abstract void restoreState(); |
|
} |