Path: blob/master/src/java.desktop/share/classes/sun/java2d/SurfaceData.java
41152 views
/*1* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.java2d;2627import java.awt.Color;28import java.awt.Rectangle;29import java.awt.Transparency;30import java.awt.GraphicsConfiguration;31import java.awt.Image;32import java.awt.image.ColorModel;33import java.awt.image.IndexColorModel;34import java.awt.image.Raster;3536import sun.font.FontUtilities;37import sun.java2d.loops.RenderCache;38import sun.java2d.loops.RenderLoops;39import sun.java2d.loops.CompositeType;40import sun.java2d.loops.SurfaceType;41import sun.java2d.loops.MaskFill;42import sun.java2d.loops.DrawLine;43import sun.java2d.loops.FillRect;44import sun.java2d.loops.DrawRect;45import sun.java2d.loops.DrawPolygons;46import sun.java2d.loops.DrawPath;47import sun.java2d.loops.FillPath;48import sun.java2d.loops.FillSpans;49import sun.java2d.loops.FillParallelogram;50import sun.java2d.loops.DrawParallelogram;51import sun.java2d.loops.FontInfo;52import sun.java2d.loops.DrawGlyphList;53import sun.java2d.loops.DrawGlyphListAA;54import sun.java2d.loops.DrawGlyphListLCD;55import sun.java2d.loops.DrawGlyphListColor;56import sun.java2d.pipe.LoopPipe;57import sun.java2d.pipe.ShapeDrawPipe;58import sun.java2d.pipe.ParallelogramPipe;59import sun.java2d.pipe.CompositePipe;60import sun.java2d.pipe.GeneralCompositePipe;61import sun.java2d.pipe.SpanClipRenderer;62import sun.java2d.pipe.SpanShapeRenderer;63import sun.java2d.pipe.AAShapePipe;64import sun.java2d.pipe.AlphaPaintPipe;65import sun.java2d.pipe.AlphaColorPipe;66import sun.java2d.pipe.PixelToShapeConverter;67import sun.java2d.pipe.PixelToParallelogramConverter;68import sun.java2d.pipe.TextPipe;69import sun.java2d.pipe.TextRenderer;70import sun.java2d.pipe.AATextRenderer;71import sun.java2d.pipe.LCDTextRenderer;72import sun.java2d.pipe.SolidTextRenderer;73import sun.java2d.pipe.OutlineTextRenderer;74import sun.java2d.pipe.DrawImagePipe;75import sun.java2d.pipe.DrawImage;76import sun.awt.SunHints;77import sun.awt.image.SurfaceManager;78import sun.java2d.pipe.LoopBasedPipe;7980/**81* This class provides various pieces of information relevant to a82* particular drawing surface. The information obtained from this83* object describes the pixels of a particular instance of a drawing84* surface and can only be shared among the various graphics objects85* that target the same BufferedImage or the same screen Component.86* <p>87* Each SurfaceData object holds a StateTrackableDelegate object88* which tracks both changes to the content of the pixels of this89* surface and changes to the overall state of the pixels - such90* as becoming invalid or losing the surface. The delegate is91* marked "dirty" whenever the setSurfaceLost() or invalidate()92* methods are called and should also be marked "dirty" by the93* rendering pipelines whenever they modify the pixels of this94* SurfaceData.95* <p>96* If you get a StateTracker from a SurfaceData and it reports97* that it is still "current", then you can trust that the pixels98* have not changed and that the SurfaceData is still valid and99* has not lost its underlying storage (surfaceLost) since you100* retrieved the tracker.101*/102public abstract class SurfaceData103implements Transparency, DisposerTarget, StateTrackable, Surface104{105private long pData;106private boolean valid;107private boolean surfaceLost; // = false;108private SurfaceType surfaceType;109private ColorModel colorModel;110111private Object disposerReferent = new Object();112113private static native void initIDs();114115private Object blitProxyKey;116private StateTrackableDelegate stateDelegate;117118static {119initIDs();120}121122protected SurfaceData(SurfaceType surfaceType, ColorModel cm) {123this(State.STABLE, surfaceType, cm);124}125126protected SurfaceData(State state, SurfaceType surfaceType, ColorModel cm) {127this(StateTrackableDelegate.createInstance(state), surfaceType, cm);128}129130protected SurfaceData(StateTrackableDelegate trackable,131SurfaceType surfaceType, ColorModel cm)132{133this.stateDelegate = trackable;134this.colorModel = cm;135this.surfaceType = surfaceType;136valid = true;137}138139protected SurfaceData(State state) {140this.stateDelegate = StateTrackableDelegate.createInstance(state);141valid = true;142}143144/**145* Subclasses can set a "blit proxy key" which will be used146* along with the SurfaceManager.getCacheData() mechanism to147* store acceleration-compatible cached copies of source images.148* This key is a "tag" used to identify which cached copies149* are compatible with this destination SurfaceData.150* The getSourceSurfaceData() method uses this key to manage151* cached copies of a source image as described below.152* <p>153* The Object used as this key should be as unique as it needs154* to be to ensure that multiple acceleratible destinations can155* each store their cached copies separately under different keys156* without interfering with each other or getting back the wrong157* cached copy.158* <p>159* Many acceleratable SurfaceData objects can use their own160* GraphicsConfiguration as their proxy key as the GC object will161* typically be unique to a given screen and pixel format, but162* other rendering destinations may have more or less stringent163* sharing requirements. For instance, X11 pixmaps can be164* shared on a given screen by any GraphicsConfiguration that165* has the same depth and SurfaceType. Multiple such GCs with166* the same depth and SurfaceType can exist per screen so storing167* a different cached proxy for each would be a waste. One can168* imagine platforms where a single cached copy can be created169* and shared across all screens and pixel formats - such170* implementations could use a single heavily shared key Object.171*/172protected void setBlitProxyKey(Object key) {173// Caching is effectively disabled if we never have a proxy key174// since the getSourceSurfaceData() method only does caching175// if the key is not null.176if (SurfaceDataProxy.isCachingAllowed()) {177this.blitProxyKey = key;178}179}180181/**182* This method is called on a destination SurfaceData to choose183* the best SurfaceData from a source Image for an imaging184* operation, with help from its SurfaceManager.185* The method may determine that the default SurfaceData was186* really the best choice in the first place, or it may decide187* to use a cached surface. Some general decisions about whether188* acceleration is enabled are made by this method, but any189* decision based on the type of the source image is made in190* the makeProxyFor method below when it comes up with the191* appropriate SurfaceDataProxy instance.192* The parameters describe the type of imaging operation being performed.193* <p>194* If a blitProxyKey was supplied by the subclass then it is195* used to potentially override the choice of source SurfaceData.196* The outline of this process is:197* <ol>198* <li> Image pipeline asks destSD to find an appropriate199* srcSD for a given source Image object.200* <li> destSD gets the SurfaceManager of the source Image201* and first retrieves the default SD from it using202* getPrimarySurfaceData()203* <li> destSD uses its "blit proxy key" (if set) to look for204* some cached data stored in the source SurfaceManager205* <li> If the cached data is null then makeProxyFor() is used206* to create some cached data which is stored back in the207* source SurfaceManager under the same key for future uses.208* <li> The cached data will be a SurfaceDataProxy object.209* <li> The SurfaceDataProxy object is then consulted to210* return a replacement SurfaceData object (typically211* a cached copy if appropriate, or the original if not).212* </ol>213*/214public SurfaceData getSourceSurfaceData(Image img,215int txtype,216CompositeType comp,217Color bgColor)218{219SurfaceManager srcMgr = SurfaceManager.getManager(img);220SurfaceData srcData = srcMgr.getPrimarySurfaceData();221if (img.getAccelerationPriority() > 0.0f &&222blitProxyKey != null)223{224SurfaceDataProxy sdp =225(SurfaceDataProxy) srcMgr.getCacheData(blitProxyKey);226if (sdp == null || !sdp.isValid()) {227if (srcData.getState() == State.UNTRACKABLE) {228sdp = SurfaceDataProxy.UNCACHED;229} else {230sdp = makeProxyFor(srcData);231}232srcMgr.setCacheData(blitProxyKey, sdp);233}234srcData = sdp.replaceData(srcData, txtype, comp, bgColor);235}236return srcData;237}238239/**240* This method is called on a destination SurfaceData to choose241* a proper SurfaceDataProxy subclass for a source SurfaceData242* to use to control when and with what surface to override a243* given image operation. The argument is the default SurfaceData244* for the source Image.245* <p>246* The type of the return object is chosen based on the247* acceleration capabilities of this SurfaceData and the248* type of the given source SurfaceData object.249* <p>250* In some cases the original SurfaceData will always be the251* best choice to use to blit to this SurfaceData. This can252* happen if the source image is a hardware surface of the253* same type as this one and so acceleration will happen without254* any caching. It may also be the case that the source image255* can never be accelerated on this SurfaceData - for example256* because it is translucent and there are no accelerated257* translucent image ops for this surface.258* <p>259* In those cases there is a special SurfaceDataProxy.UNCACHED260* instance that represents a NOP for caching purposes - it261* always returns the original sourceSD object as the replacement262* copy so no caching is ever performed.263*/264public SurfaceDataProxy makeProxyFor(SurfaceData srcData) {265return SurfaceDataProxy.UNCACHED;266}267268/**269* Extracts the SurfaceManager from the given Image, and then270* returns the SurfaceData object that would best be suited as the271* destination surface in some rendering operation.272*/273public static SurfaceData getPrimarySurfaceData(Image img) {274SurfaceManager sMgr = SurfaceManager.getManager(img);275return sMgr.getPrimarySurfaceData();276}277278/**279* Restores the contents of the given Image and then returns the new280* SurfaceData object in use by the Image's SurfaceManager.281*/282public static SurfaceData restoreContents(Image img) {283SurfaceManager sMgr = SurfaceManager.getManager(img);284return sMgr.restoreContents();285}286287public State getState() {288return stateDelegate.getState();289}290291public StateTracker getStateTracker() {292return stateDelegate.getStateTracker();293}294295/**296* Marks this surface as dirty.297*/298public final void markDirty() {299stateDelegate.markDirty();300}301302/**303* Sets the value of the surfaceLost variable, which indicates whether304* something has happened to the rendering surface such that it needs305* to be restored and re-rendered.306*/307public void setSurfaceLost(boolean lost) {308surfaceLost = lost;309stateDelegate.markDirty();310}311312public boolean isSurfaceLost() {313return surfaceLost;314}315316/**317* Returns a boolean indicating whether or not this SurfaceData is valid.318*/319public final boolean isValid() {320return valid;321}322323public Object getDisposerReferent() {324return disposerReferent;325}326327public long getNativeOps() {328return pData;329}330331/**332* Sets this SurfaceData object to the invalid state. All Graphics333* objects must get a new SurfaceData object via the refresh method334* and revalidate their pipelines before continuing.335*/336public void invalidate() {337valid = false;338stateDelegate.markDirty();339}340341/**342* Certain changes in the configuration of a surface require the343* invalidation of existing associated SurfaceData objects and344* the creation of brand new ones. These changes include size,345* ColorModel, or SurfaceType. Existing Graphics objects346* which are directed at such surfaces, however, must continue347* to render to them even after the change occurs underneath348* the covers. The getReplacement() method is called from349* SunGraphics2D.revalidateAll() when the associated SurfaceData350* is found to be invalid so that a Graphics object can continue351* to render to the surface in its new configuration.352*353* Such changes only tend to happen to window based surfaces since354* most image based surfaces never change size or pixel format.355* Even VolatileImage objects never change size and they only356* change their pixel format when manually validated against a357* new GraphicsConfiguration, at which point old Graphics objects358* are no longer expected to render to them after the validation359* step. Thus, only window based surfaces really need to deal360* with this form of replacement.361*/362public abstract SurfaceData getReplacement();363364protected static final LoopPipe colorPrimitives;365366public static final TextPipe outlineTextRenderer;367public static final TextPipe solidTextRenderer;368public static final TextPipe aaTextRenderer;369public static final TextPipe lcdTextRenderer;370371protected static final AlphaColorPipe colorPipe;372protected static final PixelToShapeConverter colorViaShape;373protected static final PixelToParallelogramConverter colorViaPgram;374protected static final TextPipe colorText;375protected static final CompositePipe clipColorPipe;376protected static final TextPipe clipColorText;377protected static final AAShapePipe AAColorShape;378protected static final PixelToParallelogramConverter AAColorViaShape;379protected static final PixelToParallelogramConverter AAColorViaPgram;380protected static final AAShapePipe AAClipColorShape;381protected static final PixelToParallelogramConverter AAClipColorViaShape;382383protected static final CompositePipe paintPipe;384protected static final SpanShapeRenderer paintShape;385protected static final PixelToShapeConverter paintViaShape;386protected static final TextPipe paintText;387protected static final CompositePipe clipPaintPipe;388protected static final TextPipe clipPaintText;389protected static final AAShapePipe AAPaintShape;390protected static final PixelToParallelogramConverter AAPaintViaShape;391protected static final AAShapePipe AAClipPaintShape;392protected static final PixelToParallelogramConverter AAClipPaintViaShape;393394protected static final CompositePipe compPipe;395protected static final SpanShapeRenderer compShape;396protected static final PixelToShapeConverter compViaShape;397protected static final TextPipe compText;398protected static final CompositePipe clipCompPipe;399protected static final TextPipe clipCompText;400protected static final AAShapePipe AACompShape;401protected static final PixelToParallelogramConverter AACompViaShape;402protected static final AAShapePipe AAClipCompShape;403protected static final PixelToParallelogramConverter AAClipCompViaShape;404405protected static final DrawImagePipe imagepipe;406407// Utility subclass to add the LoopBasedPipe tagging interface408static class PixelToShapeLoopConverter409extends PixelToShapeConverter410implements LoopBasedPipe411{412public PixelToShapeLoopConverter(ShapeDrawPipe pipe) {413super(pipe);414}415}416417// Utility subclass to add the LoopBasedPipe tagging interface418static class PixelToPgramLoopConverter419extends PixelToParallelogramConverter420implements LoopBasedPipe421{422public PixelToPgramLoopConverter(ShapeDrawPipe shapepipe,423ParallelogramPipe pgrampipe,424double minPenSize,425double normPosition,426boolean adjustfill)427{428super(shapepipe, pgrampipe, minPenSize, normPosition, adjustfill);429}430}431432private static PixelToParallelogramConverter433makeConverter(AAShapePipe renderer,434ParallelogramPipe pgrampipe)435{436return new PixelToParallelogramConverter(renderer,437pgrampipe,4381.0/8.0, 0.499,439false);440}441442private static PixelToParallelogramConverter443makeConverter(AAShapePipe renderer)444{445return makeConverter(renderer, renderer);446}447448static {449colorPrimitives = new LoopPipe();450451outlineTextRenderer = new OutlineTextRenderer();452aaTextRenderer = new AATextRenderer();453if (FontUtilities.isMacOSX14) {454solidTextRenderer = aaTextRenderer;455} else {456solidTextRenderer = new SolidTextRenderer();457}458lcdTextRenderer = new LCDTextRenderer();459460colorPipe = new AlphaColorPipe();461// colorShape = colorPrimitives;462colorViaShape = new PixelToShapeLoopConverter(colorPrimitives);463colorViaPgram = new PixelToPgramLoopConverter(colorPrimitives,464colorPrimitives,4651.0, 0.25, true);466colorText = new TextRenderer(colorPipe);467clipColorPipe = new SpanClipRenderer(colorPipe);468clipColorText = new TextRenderer(clipColorPipe);469AAColorShape = new AAShapePipe(colorPipe);470AAColorViaShape = makeConverter(AAColorShape);471AAColorViaPgram = makeConverter(AAColorShape, colorPipe);472AAClipColorShape = new AAShapePipe(clipColorPipe);473AAClipColorViaShape = makeConverter(AAClipColorShape);474475paintPipe = new AlphaPaintPipe();476paintShape = new SpanShapeRenderer.Composite(paintPipe);477paintViaShape = new PixelToShapeConverter(paintShape);478paintText = new TextRenderer(paintPipe);479clipPaintPipe = new SpanClipRenderer(paintPipe);480clipPaintText = new TextRenderer(clipPaintPipe);481AAPaintShape = new AAShapePipe(paintPipe);482AAPaintViaShape = makeConverter(AAPaintShape);483AAClipPaintShape = new AAShapePipe(clipPaintPipe);484AAClipPaintViaShape = makeConverter(AAClipPaintShape);485486compPipe = new GeneralCompositePipe();487compShape = new SpanShapeRenderer.Composite(compPipe);488compViaShape = new PixelToShapeConverter(compShape);489compText = new TextRenderer(compPipe);490clipCompPipe = new SpanClipRenderer(compPipe);491clipCompText = new TextRenderer(clipCompPipe);492AACompShape = new AAShapePipe(compPipe);493AACompViaShape = makeConverter(AACompShape);494AAClipCompShape = new AAShapePipe(clipCompPipe);495AAClipCompViaShape = makeConverter(AAClipCompShape);496497imagepipe = new DrawImage();498}499500/* Not all surfaces and rendering mode combinations support LCD text. */501static final int LOOP_UNKNOWN = 0;502static final int LOOP_FOUND = 1;503static final int LOOP_NOTFOUND = 2;504int haveLCDLoop;505int havePgramXORLoop;506int havePgramSolidLoop;507508public boolean canRenderLCDText(SunGraphics2D sg2d) {509// For now the answer can only be true in the following cases:510if (sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY &&511sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR &&512sg2d.clipState <= SunGraphics2D.CLIP_RECTANGULAR &&513sg2d.surfaceData.getTransparency() == Transparency.OPAQUE)514{515if (haveLCDLoop == LOOP_UNKNOWN) {516DrawGlyphListLCD loop =517DrawGlyphListLCD.locate(SurfaceType.AnyColor,518CompositeType.SrcNoEa,519getSurfaceType());520haveLCDLoop = (loop != null) ? LOOP_FOUND : LOOP_NOTFOUND;521}522return haveLCDLoop == LOOP_FOUND;523}524return false; /* for now - in the future we may want to search */525}526527public boolean canRenderParallelograms(SunGraphics2D sg2d) {528if (sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR) {529if (sg2d.compositeState == SunGraphics2D.COMP_XOR) {530if (havePgramXORLoop == LOOP_UNKNOWN) {531FillParallelogram loop =532FillParallelogram.locate(SurfaceType.AnyColor,533CompositeType.Xor,534getSurfaceType());535havePgramXORLoop =536(loop != null) ? LOOP_FOUND : LOOP_NOTFOUND;537}538return havePgramXORLoop == LOOP_FOUND;539} else if (sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY &&540sg2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON &&541sg2d.clipState != SunGraphics2D.CLIP_SHAPE)542{543if (havePgramSolidLoop == LOOP_UNKNOWN) {544FillParallelogram loop =545FillParallelogram.locate(SurfaceType.AnyColor,546CompositeType.SrcNoEa,547getSurfaceType());548havePgramSolidLoop =549(loop != null) ? LOOP_FOUND : LOOP_NOTFOUND;550}551return havePgramSolidLoop == LOOP_FOUND;552}553}554return false;555}556557public void validatePipe(SunGraphics2D sg2d) {558sg2d.imagepipe = imagepipe;559if (sg2d.compositeState == SunGraphics2D.COMP_XOR) {560if (sg2d.paintState > SunGraphics2D.PAINT_ALPHACOLOR) {561sg2d.drawpipe = paintViaShape;562sg2d.fillpipe = paintViaShape;563sg2d.shapepipe = paintShape;564// REMIND: Ideally custom paint mode would use glyph565// rendering as opposed to outline rendering but the566// glyph paint rendering pipeline uses MaskBlit which567// is not defined for XOR. This means that text drawn568// in XOR mode with a Color object is different than569// text drawn in XOR mode with a Paint object.570sg2d.textpipe = outlineTextRenderer;571} else {572PixelToShapeConverter converter;573if (canRenderParallelograms(sg2d)) {574converter = colorViaPgram;575// Note that we use the transforming pipe here because it576// will examine the shape and possibly perform an optimized577// operation if it can be simplified. The simplifications578// will be valid for all STROKE and TRANSFORM types.579sg2d.shapepipe = colorViaPgram;580} else {581converter = colorViaShape;582sg2d.shapepipe = colorPrimitives;583}584if (sg2d.clipState == SunGraphics2D.CLIP_SHAPE) {585sg2d.drawpipe = converter;586sg2d.fillpipe = converter;587// REMIND: We should not be changing text strategies588// between outline and glyph rendering based upon the589// presence of a complex clip as that could cause a590// mismatch when drawing the same text both clipped591// and unclipped on two separate rendering passes.592// Unfortunately, all of the clipped glyph rendering593// pipelines rely on the use of the MaskBlit operation594// which is not defined for XOR.595sg2d.textpipe = outlineTextRenderer;596} else {597if (sg2d.transformState >= SunGraphics2D.TRANSFORM_TRANSLATESCALE) {598sg2d.drawpipe = converter;599sg2d.fillpipe = converter;600} else {601if (sg2d.strokeState != SunGraphics2D.STROKE_THIN) {602sg2d.drawpipe = converter;603} else {604sg2d.drawpipe = colorPrimitives;605}606sg2d.fillpipe = colorPrimitives;607}608sg2d.textpipe = solidTextRenderer;609}610// assert(sg2d.surfaceData == this);611}612} else if (sg2d.compositeState == SunGraphics2D.COMP_CUSTOM) {613if (sg2d.antialiasHint == SunHints.INTVAL_ANTIALIAS_ON) {614if (sg2d.clipState == SunGraphics2D.CLIP_SHAPE) {615sg2d.drawpipe = AAClipCompViaShape;616sg2d.fillpipe = AAClipCompViaShape;617sg2d.shapepipe = AAClipCompViaShape;618sg2d.textpipe = clipCompText;619} else {620sg2d.drawpipe = AACompViaShape;621sg2d.fillpipe = AACompViaShape;622sg2d.shapepipe = AACompViaShape;623sg2d.textpipe = compText;624}625} else {626sg2d.drawpipe = compViaShape;627sg2d.fillpipe = compViaShape;628sg2d.shapepipe = compShape;629if (sg2d.clipState == SunGraphics2D.CLIP_SHAPE) {630sg2d.textpipe = clipCompText;631} else {632sg2d.textpipe = compText;633}634}635} else if (sg2d.antialiasHint == SunHints.INTVAL_ANTIALIAS_ON) {636sg2d.alphafill = getMaskFill(sg2d);637// assert(sg2d.surfaceData == this);638if (sg2d.alphafill != null) {639if (sg2d.clipState == SunGraphics2D.CLIP_SHAPE) {640sg2d.drawpipe = AAClipColorViaShape;641sg2d.fillpipe = AAClipColorViaShape;642sg2d.shapepipe = AAClipColorViaShape;643sg2d.textpipe = clipColorText;644} else {645PixelToParallelogramConverter converter =646(sg2d.alphafill.canDoParallelograms()647? AAColorViaPgram648: AAColorViaShape);649sg2d.drawpipe = converter;650sg2d.fillpipe = converter;651sg2d.shapepipe = converter;652if (sg2d.paintState > SunGraphics2D.PAINT_ALPHACOLOR ||653sg2d.compositeState > SunGraphics2D.COMP_ISCOPY)654{655sg2d.textpipe = colorText;656} else {657sg2d.textpipe = getTextPipe(sg2d, true /* AA==ON */);658}659}660} else {661if (sg2d.clipState == SunGraphics2D.CLIP_SHAPE) {662sg2d.drawpipe = AAClipPaintViaShape;663sg2d.fillpipe = AAClipPaintViaShape;664sg2d.shapepipe = AAClipPaintViaShape;665sg2d.textpipe = clipPaintText;666} else {667sg2d.drawpipe = AAPaintViaShape;668sg2d.fillpipe = AAPaintViaShape;669sg2d.shapepipe = AAPaintViaShape;670sg2d.textpipe = paintText;671}672}673} else if (sg2d.paintState > SunGraphics2D.PAINT_ALPHACOLOR ||674sg2d.compositeState > SunGraphics2D.COMP_ISCOPY ||675sg2d.clipState == SunGraphics2D.CLIP_SHAPE)676{677sg2d.drawpipe = paintViaShape;678sg2d.fillpipe = paintViaShape;679sg2d.shapepipe = paintShape;680sg2d.alphafill = getMaskFill(sg2d);681// assert(sg2d.surfaceData == this);682if (sg2d.alphafill != null) {683if (sg2d.clipState == SunGraphics2D.CLIP_SHAPE) {684sg2d.textpipe = clipColorText;685} else {686sg2d.textpipe = colorText;687}688} else {689if (sg2d.clipState == SunGraphics2D.CLIP_SHAPE) {690sg2d.textpipe = clipPaintText;691} else {692sg2d.textpipe = paintText;693}694}695} else {696PixelToShapeConverter converter;697if (canRenderParallelograms(sg2d)) {698converter = colorViaPgram;699// Note that we use the transforming pipe here because it700// will examine the shape and possibly perform an optimized701// operation if it can be simplified. The simplifications702// will be valid for all STROKE and TRANSFORM types.703sg2d.shapepipe = colorViaPgram;704} else {705converter = colorViaShape;706sg2d.shapepipe = colorPrimitives;707}708if (sg2d.transformState >= SunGraphics2D.TRANSFORM_TRANSLATESCALE) {709sg2d.drawpipe = converter;710sg2d.fillpipe = converter;711} else {712if (sg2d.strokeState != SunGraphics2D.STROKE_THIN) {713sg2d.drawpipe = converter;714} else {715sg2d.drawpipe = colorPrimitives;716}717sg2d.fillpipe = colorPrimitives;718}719720sg2d.textpipe = getTextPipe(sg2d, false /* AA==OFF */);721// assert(sg2d.surfaceData == this);722}723724// check for loops725if (sg2d.textpipe instanceof LoopBasedPipe ||726sg2d.shapepipe instanceof LoopBasedPipe ||727sg2d.fillpipe instanceof LoopBasedPipe ||728sg2d.drawpipe instanceof LoopBasedPipe ||729sg2d.imagepipe instanceof LoopBasedPipe)730{731sg2d.loops = getRenderLoops(sg2d);732}733}734735/* Return the text pipe to be used based on the graphics AA hint setting,736* and the rest of the graphics state is compatible with these loops.737* If the text AA hint is "DEFAULT", then the AA graphics hint requests738* the AA text renderer, else it requests the B&W text renderer.739*/740private TextPipe getTextPipe(SunGraphics2D sg2d, boolean aaHintIsOn) {741742/* Try to avoid calling getFontInfo() unless its needed to743* resolve one of the new AA types.744*/745switch (sg2d.textAntialiasHint) {746case SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT:747if (aaHintIsOn) {748return aaTextRenderer;749} else {750return solidTextRenderer;751}752case SunHints.INTVAL_TEXT_ANTIALIAS_OFF:753return solidTextRenderer;754755case SunHints.INTVAL_TEXT_ANTIALIAS_ON:756return aaTextRenderer;757758default:759switch (sg2d.getFontInfo().aaHint) {760761case SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HRGB:762case SunHints.INTVAL_TEXT_ANTIALIAS_LCD_VRGB:763return lcdTextRenderer;764765case SunHints.INTVAL_TEXT_ANTIALIAS_ON:766return aaTextRenderer;767768case SunHints.INTVAL_TEXT_ANTIALIAS_OFF:769return solidTextRenderer;770771/* This should not be reached as the FontInfo will772* always explicitly set its hint value. So whilst773* this could be collapsed to returning say just774* solidTextRenderer, or even removed, its left775* here in case DEFAULT is ever passed in.776*/777default:778if (aaHintIsOn) {779return aaTextRenderer;780} else {781return solidTextRenderer;782}783}784}785}786787private static SurfaceType getPaintSurfaceType(SunGraphics2D sg2d) {788switch (sg2d.paintState) {789case SunGraphics2D.PAINT_OPAQUECOLOR:790return SurfaceType.OpaqueColor;791case SunGraphics2D.PAINT_ALPHACOLOR:792return SurfaceType.AnyColor;793case SunGraphics2D.PAINT_GRADIENT:794if (sg2d.paint.getTransparency() == OPAQUE) {795return SurfaceType.OpaqueGradientPaint;796} else {797return SurfaceType.GradientPaint;798}799case SunGraphics2D.PAINT_LIN_GRADIENT:800if (sg2d.paint.getTransparency() == OPAQUE) {801return SurfaceType.OpaqueLinearGradientPaint;802} else {803return SurfaceType.LinearGradientPaint;804}805case SunGraphics2D.PAINT_RAD_GRADIENT:806if (sg2d.paint.getTransparency() == OPAQUE) {807return SurfaceType.OpaqueRadialGradientPaint;808} else {809return SurfaceType.RadialGradientPaint;810}811case SunGraphics2D.PAINT_TEXTURE:812if (sg2d.paint.getTransparency() == OPAQUE) {813return SurfaceType.OpaqueTexturePaint;814} else {815return SurfaceType.TexturePaint;816}817default:818case SunGraphics2D.PAINT_CUSTOM:819return SurfaceType.AnyPaint;820}821}822823private static CompositeType getFillCompositeType(SunGraphics2D sg2d) {824CompositeType compType = sg2d.imageComp;825if (sg2d.compositeState == SunGraphics2D.COMP_ISCOPY) {826if (compType == CompositeType.SrcOverNoEa) {827compType = CompositeType.OpaqueSrcOverNoEa;828} else {829compType = CompositeType.SrcNoEa;830}831}832return compType;833}834835/**836* Returns a MaskFill object that can be used on this destination837* with the source (paint) and composite types determined by the given838* SunGraphics2D, or null if no such MaskFill object can be located.839* Subclasses can override this method if they wish to filter other840* attributes (such as the hardware capabilities of the destination841* surface) before returning a specific MaskFill object.842*/843protected MaskFill getMaskFill(SunGraphics2D sg2d) {844SurfaceType src = getPaintSurfaceType(sg2d);845CompositeType comp = getFillCompositeType(sg2d);846SurfaceType dst = getSurfaceType();847return MaskFill.getFromCache(src, comp, dst);848}849850private static RenderCache loopcache = new RenderCache(30);851852/**853* Return a RenderLoops object containing all of the basic854* GraphicsPrimitive objects for rendering to the destination855* surface with the current attributes of the given SunGraphics2D.856*/857public RenderLoops getRenderLoops(SunGraphics2D sg2d) {858SurfaceType src = getPaintSurfaceType(sg2d);859CompositeType comp = getFillCompositeType(sg2d);860SurfaceType dst = sg2d.getSurfaceData().getSurfaceType();861862Object o = loopcache.get(src, comp, dst);863if (o != null) {864return (RenderLoops) o;865}866867RenderLoops loops = makeRenderLoops(src, comp, dst);868loopcache.put(src, comp, dst, loops);869return loops;870}871872/**873* Construct and return a RenderLoops object containing all of874* the basic GraphicsPrimitive objects for rendering to the875* destination surface with the given source, destination, and876* composite types.877*/878public static RenderLoops makeRenderLoops(SurfaceType src,879CompositeType comp,880SurfaceType dst)881{882RenderLoops loops = new RenderLoops();883loops.drawLineLoop = DrawLine.locate(src, comp, dst);884loops.fillRectLoop = FillRect.locate(src, comp, dst);885loops.drawRectLoop = DrawRect.locate(src, comp, dst);886loops.drawPolygonsLoop = DrawPolygons.locate(src, comp, dst);887loops.drawPathLoop = DrawPath.locate(src, comp, dst);888loops.fillPathLoop = FillPath.locate(src, comp, dst);889loops.fillSpansLoop = FillSpans.locate(src, comp, dst);890loops.fillParallelogramLoop = FillParallelogram.locate(src, comp, dst);891loops.drawParallelogramLoop = DrawParallelogram.locate(src, comp, dst);892loops.drawGlyphListLoop = DrawGlyphList.locate(src, comp, dst);893loops.drawGlyphListAALoop = DrawGlyphListAA.locate(src, comp, dst);894loops.drawGlyphListLCDLoop = DrawGlyphListLCD.locate(src, comp, dst);895loops.drawGlyphListColorLoop =896DrawGlyphListColor.locate(src, comp, dst);897/*898System.out.println("drawLine: "+loops.drawLineLoop);899System.out.println("fillRect: "+loops.fillRectLoop);900System.out.println("drawRect: "+loops.drawRectLoop);901System.out.println("drawPolygons: "+loops.drawPolygonsLoop);902System.out.println("fillSpans: "+loops.fillSpansLoop);903System.out.println("drawGlyphList: "+loops.drawGlyphListLoop);904System.out.println("drawGlyphListAA: "+loops.drawGlyphListAALoop);905System.out.println("drawGlyphListLCD: "+loops.drawGlyphListLCDLoop);906*/907return loops;908}909910/**911* Return the GraphicsConfiguration object that describes this912* destination surface.913*/914public abstract GraphicsConfiguration getDeviceConfiguration();915916/**917* Return the SurfaceType object that describes the destination918* surface.919*/920public final SurfaceType getSurfaceType() {921return surfaceType;922}923924/**925* Return the ColorModel for the destination surface.926*/927public final ColorModel getColorModel() {928return colorModel;929}930931/**932* Returns the type of this {@code Transparency}.933* @return the field type of this {@code Transparency}, which is934* either OPAQUE, BITMASK or TRANSLUCENT.935*/936public int getTransparency() {937return getColorModel().getTransparency();938}939940/**941* Return a readable Raster which contains the pixels for the942* specified rectangular region of the destination surface.943* The coordinate origin of the returned Raster is the same as944* the device space origin of the destination surface.945* In some cases the returned Raster might also be writeable.946* In most cases, the returned Raster might contain more pixels947* than requested.948*949* @see #useTightBBoxes950*/951public abstract Raster getRaster(int x, int y, int w, int h);952953/**954* Does the pixel accessibility of the destination surface955* suggest that rendering algorithms might want to take956* extra time to calculate a more accurate bounding box for957* the operation being performed?958* The typical case when this will be true is when a copy of959* the pixels has to be made when doing a getRaster. The960* fewer pixels copied, the faster the operation will go.961*962* @see #getRaster963*/964public boolean useTightBBoxes() {965// Note: The native equivalent would trigger on VISIBLE_TO_NATIVE966// REMIND: This is not used - should be obsoleted maybe967return true;968}969970/**971* Returns the pixel data for the specified Argb value packed972* into an integer for easy storage and conveyance.973*/974public int pixelFor(int rgb) {975return surfaceType.pixelFor(rgb, colorModel);976}977978/**979* Returns the pixel data for the specified color packed into an980* integer for easy storage and conveyance.981*982* This method will use the getRGB() method of the Color object983* and defer to the pixelFor(int rgb) method if not overridden.984*985* For now this is a convenience function, but for cases where986* the highest quality color conversion is requested, this method987* should be overridden in those cases so that a more direct988* conversion of the color to the destination color space989* can be done using the additional information in the Color990* object.991*/992public int pixelFor(Color c) {993return pixelFor(c.getRGB());994}995996/**997* Returns the Argb representation for the specified integer value998* which is packed in the format of the associated ColorModel.999*/1000public int rgbFor(int pixel) {1001return surfaceType.rgbFor(pixel, colorModel);1002}10031004/**1005* Returns the bounds of the destination surface.1006*/1007public abstract Rectangle getBounds();10081009static java.security.Permission compPermission;10101011/**1012* Performs Security Permissions checks to see if a Custom1013* Composite object should be allowed access to the pixels1014* of this surface.1015*/1016protected void checkCustomComposite() {1017@SuppressWarnings("removal")1018SecurityManager sm = System.getSecurityManager();1019if (sm != null) {1020if (compPermission == null) {1021compPermission =1022new java.awt.AWTPermission("readDisplayPixels");1023}1024sm.checkPermission(compPermission);1025}1026}10271028/**1029* Fetches private field IndexColorModel.allgrayopaque1030* which is true when all palette entries in the color1031* model are gray and opaque.1032*/1033protected static native boolean isOpaqueGray(IndexColorModel icm);10341035/**1036* For our purposes null and NullSurfaceData are the same as1037* they represent a disposed surface.1038*/1039public static boolean isNull(SurfaceData sd) {1040if (sd == null || sd == NullSurfaceData.theInstance) {1041return true;1042}1043return false;1044}10451046/**1047* Performs a copyarea within this surface. Returns1048* false if there is no algorithm to perform the copyarea1049* given the current settings of the SunGraphics2D.1050*1051* @param x the x coordinate of the area in device space1052* @param y the y coordinate of the area in device space1053* @param w the width of the area in device space1054* @param h the height of the area in device space1055*/1056public boolean copyArea(SunGraphics2D sg2d,1057int x, int y, int w, int h, int dx, int dy)1058{1059return false;1060}10611062/**1063* Synchronously releases resources associated with this surface.1064*/1065public void flush() {}10661067/**1068* Returns destination associated with this SurfaceData. This could be1069* either an Image or a Component; subclasses of SurfaceData are1070* responsible for returning the appropriate object.1071*/1072public abstract Object getDestination();10731074/**1075* Returns default horizontal scale factor of the destination surface. Scale1076* factor describes the mapping between virtual and physical coordinates of the1077* SurfaceData. If the scale is 2 then virtual pixel coordinates need to be1078* doubled for physical pixels.1079*/1080public double getDefaultScaleX() {1081return 1;1082}10831084/**1085* Returns default vertical scale factor of the destination surface. Scale1086* factor describes the mapping between virtual and physical coordinates of the1087* SurfaceData. If the scale is 2 then virtual pixel coordinates need to be1088* doubled for physical pixels.1089*/1090public double getDefaultScaleY() {1091return 1;1092}1093}109410951096