| /* |
| * Copyright (c) 1999, 2010, 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. |
| * <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. |
| * <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. |
| * <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. |
| * <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. |
| */ |
| 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. |
| */ |
| 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. |
| */ |
| 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. |
| */ |
| 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. |
| */ |
| 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. |
| */ |
| 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. |
| */ |
| 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 <= sg2d.PAINT_ALPHACOLOR) { |
| if (sg2d.compositeState == sg2d.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 <= sg2d.COMP_ISCOPY && |
| sg2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON && |
| sg2d.clipState != sg2d.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 == sg2d.COMP_XOR) { |
| if (sg2d.paintState > sg2d.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 == sg2d.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 >= sg2d.TRANSFORM_TRANSLATESCALE) { |
| sg2d.drawpipe = converter; |
| sg2d.fillpipe = converter; |
| } else { |
| if (sg2d.strokeState != sg2d.STROKE_THIN) { |
| sg2d.drawpipe = converter; |
| } else { |
| sg2d.drawpipe = colorPrimitives; |
| } |
| sg2d.fillpipe = colorPrimitives; |
| } |
| sg2d.textpipe = solidTextRenderer; |
| } |
| // assert(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 = 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 == sg2d.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 == sg2d.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 > sg2d.PAINT_ALPHACOLOR || |
| sg2d.compositeState > sg2d.COMP_ISCOPY) |
| { |
| sg2d.textpipe = colorText; |
| } else { |
| sg2d.textpipe = getTextPipe(sg2d, true /* AA==ON */); |
| } |
| } |
| } else { |
| if (sg2d.clipState == sg2d.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 > sg2d.PAINT_ALPHACOLOR || |
| sg2d.compositeState > sg2d.COMP_ISCOPY || |
| sg2d.clipState == sg2d.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 == sg2d.CLIP_SHAPE) { |
| sg2d.textpipe = clipColorText; |
| } else { |
| sg2d.textpipe = colorText; |
| } |
| } else { |
| if (sg2d.clipState == sg2d.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 >= sg2d.TRANSFORM_TRANSLATESCALE) { |
| sg2d.drawpipe = converter; |
| sg2d.fillpipe = converter; |
| } else { |
| if (sg2d.strokeState != sg2d.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 == sg2d.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. |
| */ |
| 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. |
| */ |
| 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. |
| */ |
| 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. |
| */ |
| 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); |
| |
| /** |
| * 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. |
| */ |
| 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. |
| */ |
| 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. |
| */ |
| public abstract Object getDestination(); |
| } |