/*
 * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

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.ColorModel;
import java.awt.image.IndexColorModel;
import java.awt.image.Raster;

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.DrawPath;
import sun.java2d.loops.FillPath;
import sun.java2d.loops.FillSpans;
import sun.java2d.loops.FillParallelogram;
import sun.java2d.loops.DrawParallelogram;
import sun.java2d.loops.FontInfo;
import sun.java2d.loops.DrawGlyphList;
import sun.java2d.loops.DrawGlyphListAA;
import sun.java2d.loops.DrawGlyphListLCD;
import sun.java2d.pipe.LoopPipe;
import sun.java2d.pipe.ShapeDrawPipe;
import sun.java2d.pipe.ParallelogramPipe;
import sun.java2d.pipe.CompositePipe;
import sun.java2d.pipe.GeneralCompositePipe;
import sun.java2d.pipe.SpanClipRenderer;
import sun.java2d.pipe.SpanShapeRenderer;
import sun.java2d.pipe.AAShapePipe;
import sun.java2d.pipe.AlphaPaintPipe;
import sun.java2d.pipe.AlphaColorPipe;
import sun.java2d.pipe.PixelToShapeConverter;
import sun.java2d.pipe.PixelToParallelogramConverter;
import sun.java2d.pipe.TextPipe;
import sun.java2d.pipe.TextRenderer;
import sun.java2d.pipe.AATextRenderer;
import sun.java2d.pipe.LCDTextRenderer;
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.SurfaceManager;
import sun.java2d.pipe.LoopBasedPipe;

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.

Each SurfaceData object holds a StateTrackableDelegate object which tracks both changes to the content of the pixels of this surface and changes to the overall state of the pixels - such as becoming invalid or losing the surface. The delegate is marked "dirty" whenever the setSurfaceLost() or invalidate() methods are called and should also be marked "dirty" by the rendering pipelines whenever they modify the pixels of this SurfaceData.

If you get a StateTracker from a SurfaceData and it reports that it is still "current", then you can trust that the pixels have not changed and that the SurfaceData is still valid and has not lost its underlying storage (surfaceLost) since you retrieved the tracker.

/** * 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. * <p> * Each SurfaceData object holds a StateTrackableDelegate object * which tracks both changes to the content of the pixels of this * surface and changes to the overall state of the pixels - such * as becoming invalid or losing the surface. The delegate is * marked "dirty" whenever the setSurfaceLost() or invalidate() * methods are called and should also be marked "dirty" by the * rendering pipelines whenever they modify the pixels of this * SurfaceData. * <p> * If you get a StateTracker from a SurfaceData and it reports * that it is still "current", then you can trust that the pixels * have not changed and that the SurfaceData is still valid and * has not lost its underlying storage (surfaceLost) since you * retrieved the tracker. */
public abstract class SurfaceData implements Transparency, DisposerTarget, StateTrackable, Surface { private long pData; private boolean valid; private boolean surfaceLost; // = false; private SurfaceType surfaceType; private ColorModel colorModel; private Object disposerReferent = new Object(); private static native void initIDs(); private Object blitProxyKey; private StateTrackableDelegate stateDelegate; static { initIDs(); } protected SurfaceData(SurfaceType surfaceType, ColorModel cm) { this(State.STABLE, surfaceType, cm); } protected SurfaceData(State state, SurfaceType surfaceType, ColorModel cm) { this(StateTrackableDelegate.createInstance(state), surfaceType, cm); } protected SurfaceData(StateTrackableDelegate trackable, SurfaceType surfaceType, ColorModel cm) { this.stateDelegate = trackable; this.colorModel = cm; this.surfaceType = surfaceType; valid = true; } protected SurfaceData(State state) { this.stateDelegate = StateTrackableDelegate.createInstance(state); valid = true; }
Subclasses can set a "blit proxy key" which will be used along with the SurfaceManager.getCacheData() mechanism to store acceleration-compatible cached copies of source images. This key is a "tag" used to identify which cached copies are compatible with this destination SurfaceData. The getSourceSurfaceData() method uses this key to manage cached copies of a source image as described below.

The Object used as this key should be as unique as it needs to be to ensure that multiple acceleratible destinations can each store their cached copies separately under different keys without interfering with each other or getting back the wrong cached copy.

Many acceleratable SurfaceData objects can use their own GraphicsConfiguration as their proxy key as the GC object will typically be unique to a given screen and pixel format, but other rendering destinations may have more or less stringent sharing requirements. For instance, X11 pixmaps can be shared on a given screen by any GraphicsConfiguration that has the same depth and SurfaceType. Multiple such GCs with the same depth and SurfaceType can exist per screen so storing a different cached proxy for each would be a waste. One can imagine platforms where a single cached copy can be created and shared across all screens and pixel formats - such implementations could use a single heavily shared key Object.

/** * Subclasses can set a "blit proxy key" which will be used * along with the SurfaceManager.getCacheData() mechanism to * store acceleration-compatible cached copies of source images. * This key is a "tag" used to identify which cached copies * are compatible with this destination SurfaceData. * The getSourceSurfaceData() method uses this key to manage * cached copies of a source image as described below. * <p> * The Object used as this key should be as unique as it needs * to be to ensure that multiple acceleratible destinations can * each store their cached copies separately under different keys * without interfering with each other or getting back the wrong * cached copy. * <p> * Many acceleratable SurfaceData objects can use their own * GraphicsConfiguration as their proxy key as the GC object will * typically be unique to a given screen and pixel format, but * other rendering destinations may have more or less stringent * sharing requirements. For instance, X11 pixmaps can be * shared on a given screen by any GraphicsConfiguration that * has the same depth and SurfaceType. Multiple such GCs with * the same depth and SurfaceType can exist per screen so storing * a different cached proxy for each would be a waste. One can * imagine platforms where a single cached copy can be created * and shared across all screens and pixel formats - such * implementations could use a single heavily shared key Object. */
protected void setBlitProxyKey(Object key) { // Caching is effectively disabled if we never have a proxy key // since the getSourceSurfaceData() method only does caching // if the key is not null. if (SurfaceDataProxy.isCachingAllowed()) { this.blitProxyKey = key; } }
This method is called on a destination SurfaceData to choose the best SurfaceData from a source Image for an imaging operation, with help from its SurfaceManager. The method may determine that the default SurfaceData was really the best choice in the first place, or it may decide to use a cached surface. Some general decisions about whether acceleration is enabled are made by this method, but any decision based on the type of the source image is made in the makeProxyFor method below when it comes up with the appropriate SurfaceDataProxy instance. The parameters describe the type of imaging operation being performed.

If a blitProxyKey was supplied by the subclass then it is used to potentially override the choice of source SurfaceData. The outline of this process is:

  1. Image pipeline asks destSD to find an appropriate srcSD for a given source Image object.
  2. destSD gets the SurfaceManager of the source Image and first retrieves the default SD from it using getPrimarySurfaceData()
  3. destSD uses its "blit proxy key" (if set) to look for some cached data stored in the source SurfaceManager
  4. If the cached data is null then makeProxyFor() is used to create some cached data which is stored back in the source SurfaceManager under the same key for future uses.
  5. The cached data will be a SurfaceDataProxy object.
  6. The SurfaceDataProxy object is then consulted to return a replacement SurfaceData object (typically a cached copy if appropriate, or the original if not).
/** * This method is called on a destination SurfaceData to choose * the best SurfaceData from a source Image for an imaging * operation, with help from its SurfaceManager. * The method may determine that the default SurfaceData was * really the best choice in the first place, or it may decide * to use a cached surface. Some general decisions about whether * acceleration is enabled are made by this method, but any * decision based on the type of the source image is made in * the makeProxyFor method below when it comes up with the * appropriate SurfaceDataProxy instance. * The parameters describe the type of imaging operation being performed. * <p> * If a blitProxyKey was supplied by the subclass then it is * used to potentially override the choice of source SurfaceData. * The outline of this process is: * <ol> * <li> Image pipeline asks destSD to find an appropriate * srcSD for a given source Image object. * <li> destSD gets the SurfaceManager of the source Image * and first retrieves the default SD from it using * getPrimarySurfaceData() * <li> destSD uses its "blit proxy key" (if set) to look for * some cached data stored in the source SurfaceManager * <li> If the cached data is null then makeProxyFor() is used * to create some cached data which is stored back in the * source SurfaceManager under the same key for future uses. * <li> The cached data will be a SurfaceDataProxy object. * <li> The SurfaceDataProxy object is then consulted to * return a replacement SurfaceData object (typically * a cached copy if appropriate, or the original if not). * </ol> */
public SurfaceData getSourceSurfaceData(Image img, int txtype, CompositeType comp, Color bgColor) { SurfaceManager srcMgr = SurfaceManager.getManager(img); SurfaceData srcData = srcMgr.getPrimarySurfaceData(); if (img.getAccelerationPriority() > 0.0f && blitProxyKey != null) { SurfaceDataProxy sdp = (SurfaceDataProxy) srcMgr.getCacheData(blitProxyKey); if (sdp == null || !sdp.isValid()) { if (srcData.getState() == State.UNTRACKABLE) { sdp = SurfaceDataProxy.UNCACHED; } else { sdp = makeProxyFor(srcData); } srcMgr.setCacheData(blitProxyKey, sdp); } srcData = sdp.replaceData(srcData, txtype, comp, bgColor); } return srcData; }
This method is called on a destination SurfaceData to choose a proper SurfaceDataProxy subclass for a source SurfaceData to use to control when and with what surface to override a given image operation. The argument is the default SurfaceData for the source Image.

The type of the return object is chosen based on the acceleration capabilities of this SurfaceData and the type of the given source SurfaceData object.

In some cases the original SurfaceData will always be the best choice to use to blit to this SurfaceData. This can happen if the source image is a hardware surface of the same type as this one and so acceleration will happen without any caching. It may also be the case that the source image can never be accelerated on this SurfaceData - for example because it is translucent and there are no accelerated translucent image ops for this surface.

In those cases there is a special SurfaceDataProxy.UNCACHED instance that represents a NOP for caching purposes - it always returns the original sourceSD object as the replacement copy so no caching is ever performed.

/** * This method is called on a destination SurfaceData to choose * a proper SurfaceDataProxy subclass for a source SurfaceData * to use to control when and with what surface to override a * given image operation. The argument is the default SurfaceData * for the source Image. * <p> * The type of the return object is chosen based on the * acceleration capabilities of this SurfaceData and the * type of the given source SurfaceData object. * <p> * In some cases the original SurfaceData will always be the * best choice to use to blit to this SurfaceData. This can * happen if the source image is a hardware surface of the * same type as this one and so acceleration will happen without * any caching. It may also be the case that the source image * can never be accelerated on this SurfaceData - for example * because it is translucent and there are no accelerated * translucent image ops for this surface. * <p> * In those cases there is a special SurfaceDataProxy.UNCACHED * instance that represents a NOP for caching purposes - it * always returns the original sourceSD object as the replacement * copy so no caching is ever performed. */
public SurfaceDataProxy makeProxyFor(SurfaceData srcData) { return SurfaceDataProxy.UNCACHED; }
Extracts the SurfaceManager from the given Image, and then returns the SurfaceData object that would best be suited as the destination surface in some rendering operation.
/** * Extracts the SurfaceManager from the given Image, and then * returns the SurfaceData object that would best be suited as the * destination surface in some rendering operation. */
public static SurfaceData getPrimarySurfaceData(Image img) { SurfaceManager sMgr = SurfaceManager.getManager(img); return sMgr.getPrimarySurfaceData(); }
Restores the contents of the given Image and then returns the new SurfaceData object in use by the Image's SurfaceManager.
/** * Restores the contents of the given Image and then returns the new * SurfaceData object in use by the Image's SurfaceManager. */
public static SurfaceData restoreContents(Image img) { SurfaceManager sMgr = SurfaceManager.getManager(img); return sMgr.restoreContents(); } public State getState() { return stateDelegate.getState(); } public StateTracker getStateTracker() { return stateDelegate.getStateTracker(); }
Marks this surface as dirty.
/** * Marks this surface as dirty. */
public final void markDirty() { stateDelegate.markDirty(); }
Sets the value of the surfaceLost variable, which indicates whether something has happened to the rendering surface such that it needs to be restored and re-rendered.
/** * Sets the value of the surfaceLost variable, which indicates whether * something has happened to the rendering surface such that it needs * to be restored and re-rendered. */
public void setSurfaceLost(boolean lost) { surfaceLost = lost; stateDelegate.markDirty(); } public boolean isSurfaceLost() { return surfaceLost; }
Returns a boolean indicating whether or not this SurfaceData is valid.
/** * Returns a boolean indicating whether or not this SurfaceData is valid. */
public final boolean isValid() { return valid; } public Object getDisposerReferent() { return disposerReferent; } public long getNativeOps() { return pData; }
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.
/** * 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; stateDelegate.markDirty(); }
Certain changes in the configuration of a surface require the invalidation of existing associated SurfaceData objects and the creation of brand new ones. These changes include size, ColorModel, or SurfaceType. Existing Graphics objects which are directed at such surfaces, however, must continue to render to them even after the change occurs underneath the covers. The getReplacement() method is called from SunGraphics2D.revalidateAll() when the associated SurfaceData is found to be invalid so that a Graphics object can continue to render to the surface in its new configuration. Such changes only tend to happen to window based surfaces since most image based surfaces never change size or pixel format. Even VolatileImage objects never change size and they only change their pixel format when manually validated against a new GraphicsConfiguration, at which point old Graphics objects are no longer expected to render to them after the validation step. Thus, only window based surfaces really need to deal with this form of replacement.
/** * Certain changes in the configuration of a surface require the * invalidation of existing associated SurfaceData objects and * the creation of brand new ones. These changes include size, * ColorModel, or SurfaceType. Existing Graphics objects * which are directed at such surfaces, however, must continue * to render to them even after the change occurs underneath * the covers. The getReplacement() method is called from * SunGraphics2D.revalidateAll() when the associated SurfaceData * is found to be invalid so that a Graphics object can continue * to render to the surface in its new configuration. * * Such changes only tend to happen to window based surfaces since * most image based surfaces never change size or pixel format. * Even VolatileImage objects never change size and they only * change their pixel format when manually validated against a * new GraphicsConfiguration, at which point old Graphics objects * are no longer expected to render to them after the validation * step. Thus, only window based surfaces really need to deal * with this form of replacement. */
public abstract SurfaceData getReplacement(); protected static final LoopPipe colorPrimitives; public static final TextPipe outlineTextRenderer; public static final TextPipe solidTextRenderer; public static final TextPipe aaTextRenderer; public static final TextPipe lcdTextRenderer; protected static final AlphaColorPipe colorPipe; protected static final PixelToShapeConverter colorViaShape; protected static final PixelToParallelogramConverter colorViaPgram; protected static final TextPipe colorText; protected static final CompositePipe clipColorPipe; protected static final TextPipe clipColorText; protected static final AAShapePipe AAColorShape; protected static final PixelToParallelogramConverter AAColorViaShape; protected static final PixelToParallelogramConverter AAColorViaPgram; protected static final AAShapePipe AAClipColorShape; protected static final PixelToParallelogramConverter 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 AAShapePipe AAPaintShape; protected static final PixelToParallelogramConverter AAPaintViaShape; protected static final AAShapePipe AAClipPaintShape; protected static final PixelToParallelogramConverter 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 AAShapePipe AACompShape; protected static final PixelToParallelogramConverter AACompViaShape; protected static final AAShapePipe AAClipCompShape; protected static final PixelToParallelogramConverter AAClipCompViaShape; protected static final DrawImagePipe imagepipe; // Utility subclass to add the LoopBasedPipe tagging interface static class PixelToShapeLoopConverter extends PixelToShapeConverter implements LoopBasedPipe { public PixelToShapeLoopConverter(ShapeDrawPipe pipe) { super(pipe); } } // Utility subclass to add the LoopBasedPipe tagging interface static class PixelToPgramLoopConverter extends PixelToParallelogramConverter implements LoopBasedPipe { public PixelToPgramLoopConverter(ShapeDrawPipe shapepipe, ParallelogramPipe pgrampipe, double minPenSize, double normPosition, boolean adjustfill) { super(shapepipe, pgrampipe, minPenSize, normPosition, adjustfill); } } private static PixelToParallelogramConverter makeConverter(AAShapePipe renderer, ParallelogramPipe pgrampipe) { return new PixelToParallelogramConverter(renderer, pgrampipe, 1.0/8.0, 0.499, false); } private static PixelToParallelogramConverter makeConverter(AAShapePipe renderer) { return makeConverter(renderer, renderer); } static { colorPrimitives = new LoopPipe(); outlineTextRenderer = new OutlineTextRenderer(); solidTextRenderer = new SolidTextRenderer(); aaTextRenderer = new AATextRenderer(); lcdTextRenderer = new LCDTextRenderer(); colorPipe = new AlphaColorPipe(); // colorShape = colorPrimitives; colorViaShape = new PixelToShapeLoopConverter(colorPrimitives); colorViaPgram = new PixelToPgramLoopConverter(colorPrimitives, colorPrimitives, 1.0, 0.25, true); colorText = new TextRenderer(colorPipe); clipColorPipe = new SpanClipRenderer(colorPipe); clipColorText = new TextRenderer(clipColorPipe); AAColorShape = new AAShapePipe(colorPipe); AAColorViaShape = makeConverter(AAColorShape); AAColorViaPgram = makeConverter(AAColorShape, colorPipe); AAClipColorShape = new AAShapePipe(clipColorPipe); AAClipColorViaShape = makeConverter(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 AAShapePipe(paintPipe); AAPaintViaShape = makeConverter(AAPaintShape); AAClipPaintShape = new AAShapePipe(clipPaintPipe); AAClipPaintViaShape = makeConverter(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 AAShapePipe(compPipe); AACompViaShape = makeConverter(AACompShape); AAClipCompShape = new AAShapePipe(clipCompPipe); AAClipCompViaShape = makeConverter(AAClipCompShape); imagepipe = new DrawImage(); } /* Not all surfaces and rendering mode combinations support LCD text. */ static final int LOOP_UNKNOWN = 0; static final int LOOP_FOUND = 1; static final int LOOP_NOTFOUND = 2; int haveLCDLoop; int havePgramXORLoop; int havePgramSolidLoop; public boolean canRenderLCDText(SunGraphics2D sg2d) { // For now the answer can only be true in the following cases: if (sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY && sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR && sg2d.clipState <= SunGraphics2D.CLIP_RECTANGULAR && sg2d.surfaceData.getTransparency() == Transparency.OPAQUE) { if (haveLCDLoop == LOOP_UNKNOWN) { DrawGlyphListLCD loop = DrawGlyphListLCD.locate(SurfaceType.AnyColor, CompositeType.SrcNoEa, getSurfaceType()); haveLCDLoop = (loop != null) ? LOOP_FOUND : LOOP_NOTFOUND; } return haveLCDLoop == LOOP_FOUND; } return false; /* for now - in the future we may want to search */ } public boolean canRenderParallelograms(SunGraphics2D sg2d) { if (sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR) { if (sg2d.compositeState == SunGraphics2D.COMP_XOR) { if (havePgramXORLoop == LOOP_UNKNOWN) { FillParallelogram loop = FillParallelogram.locate(SurfaceType.AnyColor, CompositeType.Xor, getSurfaceType()); havePgramXORLoop = (loop != null) ? LOOP_FOUND : LOOP_NOTFOUND; } return havePgramXORLoop == LOOP_FOUND; } else if (sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY && sg2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON && sg2d.clipState != SunGraphics2D.CLIP_SHAPE) { if (havePgramSolidLoop == LOOP_UNKNOWN) { FillParallelogram loop = FillParallelogram.locate(SurfaceType.AnyColor, CompositeType.SrcNoEa, getSurfaceType()); havePgramSolidLoop = (loop != null) ? LOOP_FOUND : LOOP_NOTFOUND; } return havePgramSolidLoop == LOOP_FOUND; } } return false; } public void validatePipe(SunGraphics2D sg2d) { sg2d.imagepipe = imagepipe; if (sg2d.compositeState == SunGraphics2D.COMP_XOR) { if (sg2d.paintState > SunGraphics2D.PAINT_ALPHACOLOR) { sg2d.drawpipe = paintViaShape; sg2d.fillpipe = paintViaShape; sg2d.shapepipe = paintShape; // REMIND: Ideally custom paint 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 { PixelToShapeConverter converter; if (canRenderParallelograms(sg2d)) { converter = colorViaPgram; // Note that we use the transforming pipe here because it // will examine the shape and possibly perform an optimized // operation if it can be simplified. The simplifications // will be valid for all STROKE and TRANSFORM types. sg2d.shapepipe = colorViaPgram; } else { converter = colorViaShape; sg2d.shapepipe = colorPrimitives; } if (sg2d.clipState == SunGraphics2D.CLIP_SHAPE) { sg2d.drawpipe = converter; sg2d.fillpipe = converter; // 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 >= SunGraphics2D.TRANSFORM_TRANSLATESCALE) { sg2d.drawpipe = converter; sg2d.fillpipe = converter; } else { if (sg2d.strokeState != SunGraphics2D.STROKE_THIN) { sg2d.drawpipe = converter; } else { sg2d.drawpipe = colorPrimitives; } sg2d.fillpipe = colorPrimitives; } sg2d.textpipe = solidTextRenderer; } // assert(sg2d.surfaceData == this); } } else if (sg2d.compositeState == SunGraphics2D.COMP_CUSTOM) { if (sg2d.antialiasHint == SunHints.INTVAL_ANTIALIAS_ON) { if (sg2d.clipState == SunGraphics2D.CLIP_SHAPE) { sg2d.drawpipe = AAClipCompViaShape; sg2d.fillpipe = AAClipCompViaShape; sg2d.shapepipe = AAClipCompViaShape; sg2d.textpipe = clipCompText; } else { sg2d.drawpipe = AACompViaShape; sg2d.fillpipe = AACompViaShape; sg2d.shapepipe = AACompViaShape; sg2d.textpipe = compText; } } else { sg2d.drawpipe = compViaShape; sg2d.fillpipe = compViaShape; sg2d.shapepipe = compShape; if (sg2d.clipState == SunGraphics2D.CLIP_SHAPE) { sg2d.textpipe = clipCompText; } else { sg2d.textpipe = compText; } } } else if (sg2d.antialiasHint == SunHints.INTVAL_ANTIALIAS_ON) { sg2d.alphafill = getMaskFill(sg2d); // assert(sg2d.surfaceData == this); if (sg2d.alphafill != null) { if (sg2d.clipState == SunGraphics2D.CLIP_SHAPE) { sg2d.drawpipe = AAClipColorViaShape; sg2d.fillpipe = AAClipColorViaShape; sg2d.shapepipe = AAClipColorViaShape; sg2d.textpipe = clipColorText; } else { PixelToParallelogramConverter converter = (sg2d.alphafill.canDoParallelograms() ? AAColorViaPgram : AAColorViaShape); sg2d.drawpipe = converter; sg2d.fillpipe = converter; sg2d.shapepipe = converter; if (sg2d.paintState > SunGraphics2D.PAINT_ALPHACOLOR || sg2d.compositeState > SunGraphics2D.COMP_ISCOPY) { sg2d.textpipe = colorText; } else { sg2d.textpipe = getTextPipe(sg2d, true /* AA==ON */); } } } else { if (sg2d.clipState == SunGraphics2D.CLIP_SHAPE) { sg2d.drawpipe = AAClipPaintViaShape; sg2d.fillpipe = AAClipPaintViaShape; sg2d.shapepipe = AAClipPaintViaShape; sg2d.textpipe = clipPaintText; } else { sg2d.drawpipe = AAPaintViaShape; sg2d.fillpipe = AAPaintViaShape; sg2d.shapepipe = AAPaintViaShape; sg2d.textpipe = paintText; } } } else if (sg2d.paintState > SunGraphics2D.PAINT_ALPHACOLOR || sg2d.compositeState > SunGraphics2D.COMP_ISCOPY || sg2d.clipState == SunGraphics2D.CLIP_SHAPE) { sg2d.drawpipe = paintViaShape; sg2d.fillpipe = paintViaShape; sg2d.shapepipe = paintShape; sg2d.alphafill = getMaskFill(sg2d); // assert(sg2d.surfaceData == this); if (sg2d.alphafill != null) { if (sg2d.clipState == SunGraphics2D.CLIP_SHAPE) { sg2d.textpipe = clipColorText; } else { sg2d.textpipe = colorText; } } else { if (sg2d.clipState == SunGraphics2D.CLIP_SHAPE) { sg2d.textpipe = clipPaintText; } else { sg2d.textpipe = paintText; } } } else { PixelToShapeConverter converter; if (canRenderParallelograms(sg2d)) { converter = colorViaPgram; // Note that we use the transforming pipe here because it // will examine the shape and possibly perform an optimized // operation if it can be simplified. The simplifications // will be valid for all STROKE and TRANSFORM types. sg2d.shapepipe = colorViaPgram; } else { converter = colorViaShape; sg2d.shapepipe = colorPrimitives; } if (sg2d.transformState >= SunGraphics2D.TRANSFORM_TRANSLATESCALE) { sg2d.drawpipe = converter; sg2d.fillpipe = converter; } else { if (sg2d.strokeState != SunGraphics2D.STROKE_THIN) { sg2d.drawpipe = converter; } else { sg2d.drawpipe = colorPrimitives; } sg2d.fillpipe = colorPrimitives; } sg2d.textpipe = getTextPipe(sg2d, false /* AA==OFF */); // assert(sg2d.surfaceData == this); } // check for loops if (sg2d.textpipe instanceof LoopBasedPipe || sg2d.shapepipe instanceof LoopBasedPipe || sg2d.fillpipe instanceof LoopBasedPipe || sg2d.drawpipe instanceof LoopBasedPipe || sg2d.imagepipe instanceof LoopBasedPipe) { sg2d.loops = getRenderLoops(sg2d); } } /* Return the text pipe to be used based on the graphics AA hint setting, * and the rest of the graphics state is compatible with these loops. * If the text AA hint is "DEFAULT", then the AA graphics hint requests * the AA text renderer, else it requests the B&W text renderer. */ private TextPipe getTextPipe(SunGraphics2D sg2d, boolean aaHintIsOn) { /* Try to avoid calling getFontInfo() unless its needed to * resolve one of the new AA types. */ switch (sg2d.textAntialiasHint) { case SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT: if (aaHintIsOn) { return aaTextRenderer; } else { return solidTextRenderer; } case SunHints.INTVAL_TEXT_ANTIALIAS_OFF: return solidTextRenderer; case SunHints.INTVAL_TEXT_ANTIALIAS_ON: return aaTextRenderer; default: switch (sg2d.getFontInfo().aaHint) { case SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HRGB: case SunHints.INTVAL_TEXT_ANTIALIAS_LCD_VRGB: return lcdTextRenderer; case SunHints.INTVAL_TEXT_ANTIALIAS_ON: return aaTextRenderer; case SunHints.INTVAL_TEXT_ANTIALIAS_OFF: return solidTextRenderer; /* This should not be reached as the FontInfo will * always explicitly set its hint value. So whilst * this could be collapsed to returning say just * solidTextRenderer, or even removed, its left * here in case DEFAULT is ever passed in. */ default: if (aaHintIsOn) { return aaTextRenderer; } else { return solidTextRenderer; } } } } private static SurfaceType getPaintSurfaceType(SunGraphics2D sg2d) { switch (sg2d.paintState) { case SunGraphics2D.PAINT_OPAQUECOLOR: return SurfaceType.OpaqueColor; case SunGraphics2D.PAINT_ALPHACOLOR: return SurfaceType.AnyColor; case SunGraphics2D.PAINT_GRADIENT: if (sg2d.paint.getTransparency() == OPAQUE) { return SurfaceType.OpaqueGradientPaint; } else { return SurfaceType.GradientPaint; } case SunGraphics2D.PAINT_LIN_GRADIENT: if (sg2d.paint.getTransparency() == OPAQUE) { return SurfaceType.OpaqueLinearGradientPaint; } else { return SurfaceType.LinearGradientPaint; } case SunGraphics2D.PAINT_RAD_GRADIENT: if (sg2d.paint.getTransparency() == OPAQUE) { return SurfaceType.OpaqueRadialGradientPaint; } else { return SurfaceType.RadialGradientPaint; } case SunGraphics2D.PAINT_TEXTURE: if (sg2d.paint.getTransparency() == OPAQUE) { return SurfaceType.OpaqueTexturePaint; } else { return SurfaceType.TexturePaint; } default: case SunGraphics2D.PAINT_CUSTOM: return SurfaceType.AnyPaint; } } private static CompositeType getFillCompositeType(SunGraphics2D sg2d) { CompositeType compType = sg2d.imageComp; if (sg2d.compositeState == SunGraphics2D.COMP_ISCOPY) { if (compType == CompositeType.SrcOverNoEa) { compType = CompositeType.OpaqueSrcOverNoEa; } else { compType = CompositeType.SrcNoEa; } } return compType; }
Returns a MaskFill object that can be used on this destination with the source (paint) and composite types determined by the given SunGraphics2D, or null if no such MaskFill object can be located. Subclasses can override this method if they wish to filter other attributes (such as the hardware capabilities of the destination surface) before returning a specific MaskFill object.
/** * Returns a MaskFill object that can be used on this destination * with the source (paint) and composite types determined by the given * SunGraphics2D, or null if no such MaskFill object can be located. * Subclasses can override this method if they wish to filter other * attributes (such as the hardware capabilities of the destination * surface) before returning a specific MaskFill object. */
protected MaskFill getMaskFill(SunGraphics2D sg2d) { SurfaceType src = getPaintSurfaceType(sg2d); CompositeType comp = getFillCompositeType(sg2d); SurfaceType dst = getSurfaceType(); return MaskFill.getFromCache(src, comp, dst); } 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.
/** * 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 = getPaintSurfaceType(sg2d); CompositeType comp = getFillCompositeType(sg2d); 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.
/** * 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.drawPathLoop = DrawPath.locate(src, comp, dst); loops.fillPathLoop = FillPath.locate(src, comp, dst); loops.fillSpansLoop = FillSpans.locate(src, comp, dst); loops.fillParallelogramLoop = FillParallelogram.locate(src, comp, dst); loops.drawParallelogramLoop = DrawParallelogram.locate(src, comp, dst); loops.drawGlyphListLoop = DrawGlyphList.locate(src, comp, dst); loops.drawGlyphListAALoop = DrawGlyphListAA.locate(src, comp, dst); loops.drawGlyphListLCDLoop = DrawGlyphListLCD.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); System.out.println("drawGlyphListLCD: "+loops.drawGlyphListLCDLoop); */ return loops; }
Return the GraphicsConfiguration object that describes this destination surface.
/** * Return the GraphicsConfiguration object that describes this * destination surface. */
public abstract GraphicsConfiguration getDeviceConfiguration();
Return the SurfaceType object that describes the destination surface.
/** * Return the SurfaceType object that describes the destination * surface. */
public final SurfaceType getSurfaceType() { return surfaceType; }
Return the ColorModel for the destination surface.
/** * Return the ColorModel for the destination surface. */
public final ColorModel getColorModel() { return colorModel; }
Returns the type of this Transparency.
Returns:the field type of this Transparency, which is either OPAQUE, BITMASK or TRANSLUCENT.
/** * 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 Also:
  • useTightBBoxes
/** * 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 Also:
  • getRaster
/** * 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.
/** * 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.
/** * 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.
/** * 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.
/** * 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.
/** * 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.
/** * 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);
For our purposes null and NullSurfaceData are the same as they represent a disposed surface.
/** * For our purposes null and NullSurfaceData are the same as * they represent a disposed surface. */
public static boolean isNull(SurfaceData sd) { if (sd == null || sd == NullSurfaceData.theInstance) { return true; } return false; }
Performs a copyarea within this surface. Returns false if there is no algorithm to perform the copyarea given the current settings of the SunGraphics2D.
/** * 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; }
Synchronously releases resources associated with this surface.
/** * Synchronously releases resources associated with this surface. */
public void flush() {}
Returns destination associated with this SurfaceData. This could be either an Image or a Component; subclasses of SurfaceData are responsible for returning the appropriate object.
/** * Returns destination associated with this SurfaceData. This could be * either an Image or a Component; subclasses of SurfaceData are * responsible for returning the appropriate object. */
public abstract Object getDestination();
Returns default scale factor of the destination surface. Scale factor describes the mapping between virtual and physical coordinates of the SurfaceData. If the scale is 2 then virtual pixel coordinates need to be doubled for physical pixels.
/** * Returns default scale factor of the destination surface. Scale factor * describes the mapping between virtual and physical coordinates of the * SurfaceData. If the scale is 2 then virtual pixel coordinates need to be * doubled for physical pixels. */
public int getDefaultScale() { return 1; } }