/*
* This file is modified by Ivan Maidanski <ivmai@ivmaisoft.com>
* Project name: JCGO-SUNAWT (http://www.ivmaisoft.com/jcgo/)
*/
/*
* @(#)SurfaceData.java 1.35 03/03/19
*
* Copyright 2003 Sun Microsystems, Inc. All rights reserved.
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
package sun.java2d;
import java.awt.Color;
import java.awt.Rectangle;
import java.awt.Transparency;
import java.awt.GraphicsConfiguration;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.IndexColorModel;
import java.awt.image.Raster;
import sun.awt.image.BufImgSurfaceData;
import sun.java2d.loops.RenderCache;
import sun.java2d.loops.RenderLoops;
import sun.java2d.loops.CompositeType;
import sun.java2d.loops.SurfaceType;
import sun.java2d.loops.MaskFill;
import sun.java2d.loops.DrawLine;
import sun.java2d.loops.FillRect;
import sun.java2d.loops.DrawRect;
import sun.java2d.loops.DrawPolygons;
import sun.java2d.loops.FillSpans;
import sun.java2d.loops.DrawGlyphList;
import sun.java2d.loops.DrawGlyphListAA;
import sun.java2d.pipe.LoopPipe;
import sun.java2d.pipe.CompositePipe;
import sun.java2d.pipe.GeneralCompositePipe;
import sun.java2d.pipe.SpanClipRenderer;
import sun.java2d.pipe.SpanShapeRenderer;
import sun.java2d.pipe.DuctusShapeRenderer;
import sun.java2d.pipe.AlphaPaintPipe;
import sun.java2d.pipe.AlphaColorPipe;
import sun.java2d.pipe.PixelToShapeConverter;
import sun.java2d.pipe.TextPipe;
import sun.java2d.pipe.TextRenderer;
import sun.java2d.pipe.AATextRenderer;
import sun.java2d.pipe.SolidTextRenderer;
import sun.java2d.pipe.OutlineTextRenderer;
import sun.java2d.pipe.DrawImagePipe;
import sun.java2d.pipe.DrawImage;
import sun.awt.SunHints;
import sun.awt.image.AcceleratedOffScreenImage;
import sun.awt.image.SunVolatileImage;
/**
* This class provides various pieces of information relevant to a
* particular drawing surface. The information obtained from this
* object describes the pixels of a particular instance of a drawing
* surface and can only be shared among the various graphics objects
* that target the same BufferedImage or the same screen Component.
*/
public abstract class SurfaceData implements Transparency, DisposerTarget {
private long pData;
private boolean valid;
private SurfaceType surfaceType;
private ColorModel colorModel;
/**
* The following variables all deal with our model for transparently
* accelerating copies from surface data objects to hardware-based
* surfaces. See Win32OffScreenImage for more details.
*/
private boolean dirty;
private boolean needsBackup = true;
private int numCopies;
private final Object disposerReferent = new Object();
private static native void initIDs();
static {
initIDs();
}
public void setDisposerRecord(DisposerRecord rec) {
}
protected SurfaceData(SurfaceType surfaceType, ColorModel cm) {
this.colorModel = cm;
this.surfaceType = surfaceType;
valid = true;
}
protected SurfaceData() {
valid = true;
}
public static SurfaceData getSurfaceDataFromImage(Image img,
SurfaceData dstData,
CompositeType comp,
Color bgColor,
boolean scale)
{
if (img instanceof AcceleratedOffScreenImage) {
return ((AcceleratedOffScreenImage)img).
getSourceSurfaceData(dstData, comp, bgColor, scale);
} else if (img instanceof BufferedImage) {
return BufImgSurfaceData.createData((BufferedImage)img);
} else if (img instanceof SunVolatileImage) {
return ((SunVolatileImage)img).getSurfaceData();
} else {
return null;
}
}
/**
* Retrieves the value of the dirty flag. This flag is set to true
* whenever the surface is rendered to and false whenever we copy from
* the surface.
*/
private static native void setDirtyNative(SurfaceData sd, boolean dirty);
/**
* Sets the value of the needsBackup variable, which indicates whether
* the surface is newer than other copies of it we may have. This would
* be true if we rendered to this surface since the last time we backed
* it up.
*/
public void setNeedsBackup(boolean needsBackup) {
this.needsBackup = needsBackup;
if (needsBackup) {
numCopies = 0;
}
}
public boolean needsBackup() {
return needsBackup;
}
/**
* Retrieves value of numCopies variable, which is used to track the number
* of times we have copied from this SurfaceData object since we last
* rendered to it. This is used in some image classes (e.g.,
* Win32OffScreenImage) to determine when to provide under-the-hood
* acceleration by using a vram-based version of the image instead.
*/
public final int getNumCopies() {
return numCopies;
}
/**
* Increments the variable numCopies. See comment for getNumCopies()
* for more information about this variable. Returns the new value of
* the variable. If the surface was marked "dirty" (meaning that it
* has been rendered to since the last time we copied from the image),
* then we clear the flag (both in Java and in native code).
*/
public int increaseNumCopies() {
if (dirty) {
setDirtyNative(this, false);
dirty = false;
}
numCopies++;
return numCopies;
}
/**
* Returns a boolean indicating whether or not this SurfaceData is valid.
*/
public final boolean isValid() {
return valid;
}
public Object getDisposerReferent() {
return disposerReferent;
}
/**
* Sets this SurfaceData object to the invalid state. All Graphics
* objects must get a new SurfaceData object via the refresh method
* and revalidate their pipelines before continuing.
*/
public void invalidate() {
valid = false;
}
public static boolean isNull(SurfaceData sd) {
return sd == null || sd == NullSurfaceData.theInstance;
}
/**
* Return a new SurfaceData object that represents the current state
* of the destination that this SurfaceData object describes.
* This method is typically called when the SurfaceData is invalidated.
*/
public abstract SurfaceData getReplacement();
protected static final LoopPipe colorPrimitives = new LoopPipe();
public static final TextPipe outlineTextRenderer = new OutlineTextRenderer();
public static final TextPipe solidTextRenderer = new SolidTextRenderer();
public static final TextPipe aaTextRenderer = new AATextRenderer();
protected static final CompositePipe colorPipe;
protected static final PixelToShapeConverter colorViaShape;
protected static final TextPipe colorText;
protected static final CompositePipe clipColorPipe;
protected static final TextPipe clipColorText;
protected static final DuctusShapeRenderer AAColorShape;
protected static final PixelToShapeConverter AAColorViaShape;
protected static final DuctusShapeRenderer AAClipColorShape;
protected static final PixelToShapeConverter AAClipColorViaShape;
protected static final CompositePipe paintPipe;
protected static final SpanShapeRenderer paintShape;
protected static final PixelToShapeConverter paintViaShape;
protected static final TextPipe paintText;
protected static final CompositePipe clipPaintPipe;
protected static final TextPipe clipPaintText;
protected static final DuctusShapeRenderer AAPaintShape;
protected static final PixelToShapeConverter AAPaintViaShape;
protected static final DuctusShapeRenderer AAClipPaintShape;
protected static final PixelToShapeConverter AAClipPaintViaShape;
protected static final CompositePipe compPipe;
protected static final SpanShapeRenderer compShape;
protected static final PixelToShapeConverter compViaShape;
protected static final TextPipe compText;
protected static final CompositePipe clipCompPipe;
protected static final TextPipe clipCompText;
protected static final DuctusShapeRenderer AACompShape;
protected static final PixelToShapeConverter AACompViaShape;
protected static final DuctusShapeRenderer AAClipCompShape;
protected static final PixelToShapeConverter AAClipCompViaShape;
static {
colorPipe = new AlphaColorPipe();
// colorShape = colorPrimitives;
colorViaShape = new PixelToShapeConverter(colorPrimitives);
colorText = new TextRenderer(colorPipe);
clipColorPipe = new SpanClipRenderer(colorPipe);
clipColorText = new TextRenderer(clipColorPipe);
AAColorShape = new DuctusShapeRenderer(colorPipe);
AAColorViaShape = new PixelToShapeConverter(AAColorShape);
AAClipColorShape = new DuctusShapeRenderer(clipColorPipe);
AAClipColorViaShape = new PixelToShapeConverter(AAClipColorShape);
paintPipe = new AlphaPaintPipe();
paintShape = new SpanShapeRenderer.Composite(paintPipe);
paintViaShape = new PixelToShapeConverter(paintShape);
paintText = new TextRenderer(paintPipe);
clipPaintPipe = new SpanClipRenderer(paintPipe);
clipPaintText = new TextRenderer(clipPaintPipe);
AAPaintShape = new DuctusShapeRenderer(paintPipe);
AAPaintViaShape = new PixelToShapeConverter(AAPaintShape);
AAClipPaintShape = new DuctusShapeRenderer(clipPaintPipe);
AAClipPaintViaShape = new PixelToShapeConverter(AAClipPaintShape);
compPipe = new GeneralCompositePipe();
compShape = new SpanShapeRenderer.Composite(compPipe);
compViaShape = new PixelToShapeConverter(compShape);
compText = new TextRenderer(compPipe);
clipCompPipe = new SpanClipRenderer(compPipe);
clipCompText = new TextRenderer(clipCompPipe);
AACompShape = new DuctusShapeRenderer(compPipe);
AACompViaShape = new PixelToShapeConverter(AACompShape);
AAClipCompShape = new DuctusShapeRenderer(clipCompPipe);
AAClipCompViaShape = new PixelToShapeConverter(AAClipCompShape);
}
protected static final DrawImagePipe imagepipe = new DrawImage();
public void validatePipe(SunGraphics2D sg2d) {
sg2d.imagepipe = imagepipe;
if (sg2d.compositeState == sg2d.COMP_XOR) {
if (sg2d.paintState == sg2d.PAINT_TILE) {
sg2d.drawpipe = paintViaShape;
sg2d.fillpipe = paintViaShape;
sg2d.shapepipe = paintShape;
// REMIND: Ideally PAINT_TILE mode would use glyph
// rendering as opposed to outline rendering but the
// glyph paint rendering pipeline uses MaskBlit which
// is not defined for XOR. This means that text drawn
// in XOR mode with a Color object is different than
// text drawn in XOR mode with a Paint object.
sg2d.textpipe = outlineTextRenderer;
} else {
if (sg2d.clipState == sg2d.CLIP_SHAPE) {
sg2d.drawpipe = colorViaShape;
sg2d.fillpipe = colorViaShape;
// REMIND: We should not be changing text strategies
// between outline and glyph rendering based upon the
// presence of a complex clip as that could cause a
// mismatch when drawing the same text both clipped
// and unclipped on two separate rendering passes.
// Unfortunately, all of the clipped glyph rendering
// pipelines rely on the use of the MaskBlit operation
// which is not defined for XOR.
sg2d.textpipe = outlineTextRenderer;
} else {
if (sg2d.transformState > sg2d.TRANSFORM_TRANSLATEONLY) {
sg2d.drawpipe = colorViaShape;
sg2d.fillpipe = colorViaShape;
} else {
if (sg2d.strokeState != sg2d.STROKE_THIN) {
sg2d.drawpipe = colorViaShape;
} else {
sg2d.drawpipe = colorPrimitives;
}
sg2d.fillpipe = colorPrimitives;
}
sg2d.textpipe = solidTextRenderer;
}
sg2d.shapepipe = colorPrimitives;
sg2d.loops = getRenderLoops(sg2d);
// assertion: sg2d.surfaceData == this
}
} else if (sg2d.compositeState == sg2d.COMP_CUSTOM) {
if (sg2d.antialiasHint == SunHints.INTVAL_ANTIALIAS_ON) {
if (sg2d.clipState == sg2d.CLIP_SHAPE) {
sg2d.drawpipe = AAClipCompViaShape;
sg2d.fillpipe = AAClipCompViaShape;
sg2d.shapepipe = AAClipCompShape;
sg2d.textpipe = clipCompText;
} else {
sg2d.drawpipe = AACompViaShape;
sg2d.fillpipe = AACompViaShape;
sg2d.shapepipe = AACompShape;
sg2d.textpipe = compText;
}
} else {
sg2d.drawpipe = compViaShape;
sg2d.fillpipe = compViaShape;
sg2d.shapepipe = compShape;
if (sg2d.clipState == sg2d.CLIP_SHAPE) {
sg2d.textpipe = clipCompText;
} else {
sg2d.textpipe = compText;
}
}
} else if (sg2d.antialiasHint == SunHints.INTVAL_ANTIALIAS_ON) {
boolean usingfill = false;
if (sg2d.paintState != sg2d.PAINT_TILE) {
if (sg2d.alphafill == null) {
sg2d.alphafill =
MaskFill.getFromCache(SurfaceType.AnyColor,
sg2d.fillComp,
getSurfaceType());
// assertion: sg2d.surfaceData == this
}
if (sg2d.alphafill != null) {
if (sg2d.clipState == sg2d.CLIP_SHAPE) {
sg2d.drawpipe = AAClipColorViaShape;
sg2d.fillpipe = AAClipColorViaShape;
sg2d.shapepipe = AAClipColorShape;
sg2d.textpipe = clipColorText;
} else {
sg2d.drawpipe = AAColorViaShape;
sg2d.fillpipe = AAColorViaShape;
sg2d.shapepipe = AAColorShape;
sg2d.textpipe = colorText;
}
usingfill = true;
}
}
if (!usingfill) {
if (sg2d.clipState == sg2d.CLIP_SHAPE) {
sg2d.drawpipe = AAClipPaintViaShape;
sg2d.fillpipe = AAClipPaintViaShape;
sg2d.shapepipe = AAClipPaintShape;
sg2d.textpipe = clipPaintText;
} else {
sg2d.drawpipe = AAPaintViaShape;
sg2d.fillpipe = AAPaintViaShape;
sg2d.shapepipe = AAPaintShape;
sg2d.textpipe = paintText;
}
}
} else if (sg2d.paintState != sg2d.PAINT_SOLIDCOLOR ||
sg2d.compositeState != sg2d.COMP_ISCOPY ||
sg2d.clipState == sg2d.CLIP_SHAPE)
{
sg2d.drawpipe = paintViaShape;
sg2d.fillpipe = paintViaShape;
sg2d.shapepipe = paintShape;
boolean usingfill = false;
if (sg2d.paintState != sg2d.PAINT_TILE &&
sg2d.compositeState != sg2d.COMP_CUSTOM)
{
if (sg2d.alphafill == null) {
sg2d.alphafill =
MaskFill.getFromCache(SurfaceType.AnyColor,
sg2d.fillComp,
getSurfaceType());
// assertion: sg2d.surfaceData == this
}
if (sg2d.alphafill != null) {
if (sg2d.clipState == sg2d.CLIP_SHAPE) {
sg2d.textpipe = clipColorText;
} else {
sg2d.textpipe = colorText;
}
usingfill = true;
}
}
if (!usingfill) {
if (sg2d.clipState == sg2d.CLIP_SHAPE) {
sg2d.textpipe = clipPaintText;
} else {
sg2d.textpipe = paintText;
}
}
} else {
if (sg2d.transformState > sg2d.TRANSFORM_TRANSLATEONLY) {
sg2d.drawpipe = colorViaShape;
sg2d.fillpipe = colorViaShape;
} else {
if (sg2d.strokeState != sg2d.STROKE_THIN) {
sg2d.drawpipe = colorViaShape;
} else {
sg2d.drawpipe = colorPrimitives;
}
sg2d.fillpipe = colorPrimitives;
}
if (sg2d.textAntialiasHint == SunHints.INTVAL_TEXT_ANTIALIAS_ON) {
sg2d.textpipe = aaTextRenderer;
} else {
sg2d.textpipe = solidTextRenderer;
}
sg2d.shapepipe = colorPrimitives;
sg2d.loops = getRenderLoops(sg2d);
// assertion: sg2d.surfaceData == this
}
}
private static RenderCache loopcache = new RenderCache(30);
/**
* Return a RenderLoops object containing all of the basic
* GraphicsPrimitive objects for rendering to the destination
* surface with the current attributes of the given SunGraphics2D.
*/
public RenderLoops getRenderLoops(SunGraphics2D sg2d) {
SurfaceType src;
switch (sg2d.paintState) {
case SunGraphics2D.PAINT_SOLIDCOLOR:
src = SurfaceType.OpaqueColor;
break;
case SunGraphics2D.PAINT_SINGLECOLOR:
src = SurfaceType.AnyColor;
break;
default:
case SunGraphics2D.PAINT_TILE:
// REMIND: Distinguish Gradient and Texture fills...
src = SurfaceType.AnyPaint;
break;
}
CompositeType comp = sg2d.fillComp;
SurfaceType dst = sg2d.getSurfaceData().getSurfaceType();
Object o = loopcache.get(src, comp, dst);
if (o != null) {
return (RenderLoops) o;
}
RenderLoops loops = makeRenderLoops(src, comp, dst);
loopcache.put(src, comp, dst, loops);
return loops;
}
/**
* Construct and return a RenderLoops object containing all of
* the basic GraphicsPrimitive objects for rendering to the
* destination surface with the given source, destination, and
* composite types.
*/
public static RenderLoops makeRenderLoops(SurfaceType src,
CompositeType comp,
SurfaceType dst)
{
RenderLoops loops = new RenderLoops();
loops.drawLineLoop = DrawLine.locate(src, comp, dst);
loops.fillRectLoop = FillRect.locate(src, comp, dst);
loops.drawRectLoop = DrawRect.locate(src, comp, dst);
loops.drawPolygonsLoop = DrawPolygons.locate(src, comp, dst);
loops.fillSpansLoop = FillSpans.locate(src, comp, dst);
loops.drawGlyphListLoop = DrawGlyphList.locate(src, comp, dst);
loops.drawGlyphListAALoop = DrawGlyphListAA.locate(src, comp, dst);
/*
System.out.println("drawLine: "+loops.drawLineLoop);
System.out.println("fillRect: "+loops.fillRectLoop);
System.out.println("drawRect: "+loops.drawRectLoop);
System.out.println("drawPolygons: "+loops.drawPolygonsLoop);
System.out.println("fillSpans: "+loops.fillSpansLoop);
System.out.println("drawGlyphList: "+loops.drawGlyphListLoop);
System.out.println("drawGlyphListAA: "+loops.drawGlyphListAALoop);
*/
return loops;
}
public abstract void lock() throws InvalidPipeException;
public abstract void unlock();
/**
* Return the GraphicsConfiguration object that describes this
* destination surface.
*/
public abstract GraphicsConfiguration getDeviceConfiguration();
/**
* Return the SurfaceType object that describes the destination
* surface.
*/
public final SurfaceType getSurfaceType() {
return surfaceType;
}
/**
* Return the ColorModel for the destination surface.
*/
public final ColorModel getColorModel() {
return colorModel;
}
/**
* Returns the type of this <code>Transparency</code>.
* @return the field type of this <code>Transparency</code>, which is
* either OPAQUE, BITMASK or TRANSLUCENT.
*/
public int getTransparency() {
return getColorModel().getTransparency();
}
/**
* Return a readable Raster which contains the pixels for the
* specified rectangular region of the destination surface.
* The coordinate origin of the returned Raster is the same as
* the device space origin of the destination surface.
* In some cases the returned Raster might also be writeable.
* In most cases, the returned Raster might contain more pixels
* than requested.
*
* @see useTightBBoxes
*/
public abstract Raster getRaster(int x, int y, int w, int h);
/**
* Does the pixel accessibility of the destination surface
* suggest that rendering algorithms might want to take
* extra time to calculate a more accurate bounding box for
* the operation being performed?
* The typical case when this will be true is when a copy of
* the pixels has to be made when doing a getRaster. The
* fewer pixels copied, the faster the operation will go.
*
* @see getRaster
*/
public boolean useTightBBoxes() {
// Note: The native equivalent would trigger on VISIBLE_TO_NATIVE
// REMIND: This is not used - should be obsoleted maybe
return true;
}
/**
* Returns the pixel data for the specified Argb value packed
* into an integer for easy storage and conveyance.
*/
public int pixelFor(int rgb) {
return surfaceType.pixelFor(rgb, colorModel);
}
/**
* Returns the pixel data for the specified color packed into an
* integer for easy storage and conveyance.
*
* This method will use the getRGB() method of the Color object
* and defer to the pixelFor(int rgb) method if not overridden.
*
* For now this is a convenience function, but for cases where
* the highest quality color conversion is requested, this method
* should be overridden in those cases so that a more direct
* conversion of the color to the destination color space
* can be done using the additional information in the Color
* object.
*/
public int pixelFor(Color c) {
return pixelFor(c.getRGB());
}
/**
* Returns the Argb representation for the specified integer value
* which is packed in the format of the associated ColorModel.
*/
public int rgbFor(int pixel) {
return surfaceType.rgbFor(pixel, colorModel);
}
/**
* Returns the bounds of the destination surface.
*/
public abstract Rectangle getBounds();
static java.security.Permission compPermission;
/**
* Performs Security Permissions checks to see if a Custom
* Composite object should be allowed access to the pixels
* of this surface.
*/
protected void checkCustomComposite() {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
if (compPermission == null) {
compPermission =
new java.awt.AWTPermission("readDisplayPixels");
}
sm.checkPermission(compPermission);
}
}
/**
* Fetches private field IndexColorModel.allgrayopaque
* which is true when all palette entries in the color
* model are gray and opaque.
*/
protected static native boolean isOpaqueGray(IndexColorModel icm);
/**
* Performs a copyarea within this surface. Returns
* false if there is no algorithm to perform the copyarea
* given the current settings of the SunGraphics2D.
*/
public boolean copyArea(SunGraphics2D sg2d,
int x, int y, int w, int h, int dx, int dy)
{
return false;
}
}