001: /*
002: * Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.java2d;
027:
028: import java.awt.Color;
029: import java.awt.Rectangle;
030: import java.awt.Transparency;
031: import java.awt.GraphicsConfiguration;
032: import java.awt.Image;
033: import java.awt.image.ColorModel;
034: import java.awt.image.IndexColorModel;
035: import java.awt.image.Raster;
036:
037: import sun.java2d.loops.RenderCache;
038: import sun.java2d.loops.RenderLoops;
039: import sun.java2d.loops.CompositeType;
040: import sun.java2d.loops.SurfaceType;
041: import sun.java2d.loops.MaskFill;
042: import sun.java2d.loops.DrawLine;
043: import sun.java2d.loops.FillRect;
044: import sun.java2d.loops.DrawRect;
045: import sun.java2d.loops.DrawPolygons;
046: import sun.java2d.loops.DrawPath;
047: import sun.java2d.loops.FillPath;
048: import sun.java2d.loops.FillSpans;
049: import sun.java2d.loops.FontInfo;
050: import sun.java2d.loops.DrawGlyphList;
051: import sun.java2d.loops.DrawGlyphListAA;
052: import sun.java2d.loops.DrawGlyphListLCD;
053: import sun.java2d.pipe.LoopPipe;
054: import sun.java2d.pipe.CompositePipe;
055: import sun.java2d.pipe.GeneralCompositePipe;
056: import sun.java2d.pipe.SpanClipRenderer;
057: import sun.java2d.pipe.SpanShapeRenderer;
058: import sun.java2d.pipe.AAShapePipe;
059: import sun.java2d.pipe.AlphaPaintPipe;
060: import sun.java2d.pipe.AlphaColorPipe;
061: import sun.java2d.pipe.PixelToShapeConverter;
062: import sun.java2d.pipe.TextPipe;
063: import sun.java2d.pipe.TextRenderer;
064: import sun.java2d.pipe.AATextRenderer;
065: import sun.java2d.pipe.LCDTextRenderer;
066: import sun.java2d.pipe.SolidTextRenderer;
067: import sun.java2d.pipe.OutlineTextRenderer;
068: import sun.java2d.pipe.DrawImagePipe;
069: import sun.java2d.pipe.DrawImage;
070: import sun.awt.SunHints;
071: import sun.awt.image.SurfaceManager;
072:
073: /**
074: * This class provides various pieces of information relevant to a
075: * particular drawing surface. The information obtained from this
076: * object describes the pixels of a particular instance of a drawing
077: * surface and can only be shared among the various graphics objects
078: * that target the same BufferedImage or the same screen Component.
079: * <p>
080: * Each SurfaceData object holds a StateTrackableDelegate object
081: * which tracks both changes to the content of the pixels of this
082: * surface and changes to the overall state of the pixels - such
083: * as becoming invalid or losing the surface. The delegate is
084: * marked "dirty" whenever the setSurfaceLost() or invalidate()
085: * methods are called and should also be marked "dirty" by the
086: * rendering pipelines whenever they modify the pixels of this
087: * SurfaceData.
088: * <p>
089: * If you get a StateTracker from a SurfaceData and it reports
090: * that it is still "current", then you can trust that the pixels
091: * have not changed and that the SurfaceData is still valid and
092: * has not lost its underlying storage (surfaceLost) since you
093: * retrieved the tracker.
094: */
095: public abstract class SurfaceData implements Transparency,
096: DisposerTarget, StateTrackable {
097: private long pData;
098: private boolean valid;
099: private boolean surfaceLost; // = false;
100: private SurfaceType surfaceType;
101: private ColorModel colorModel;
102:
103: private Object disposerReferent = new Object();
104:
105: private static native void initIDs();
106:
107: private Object blitProxyKey;
108: private StateTrackableDelegate stateDelegate;
109:
110: static {
111: initIDs();
112: }
113:
114: protected SurfaceData(SurfaceType surfaceType, ColorModel cm) {
115: this (State.STABLE, surfaceType, cm);
116: }
117:
118: protected SurfaceData(State state, SurfaceType surfaceType,
119: ColorModel cm) {
120: this (StateTrackableDelegate.createInstance(state), surfaceType,
121: cm);
122: }
123:
124: protected SurfaceData(StateTrackableDelegate trackable,
125: SurfaceType surfaceType, ColorModel cm) {
126: this .stateDelegate = trackable;
127: this .colorModel = cm;
128: this .surfaceType = surfaceType;
129: valid = true;
130: }
131:
132: protected SurfaceData(State state) {
133: this .stateDelegate = StateTrackableDelegate
134: .createInstance(state);
135: valid = true;
136: }
137:
138: /**
139: * Subclasses can set a "blit proxy key" which will be used
140: * along with the SurfaceManager.getCacheData() mechanism to
141: * store acceleration-compatible cached copies of source images.
142: * This key is a "tag" used to identify which cached copies
143: * are compatible with this destination SurfaceData.
144: * The getSourceSurfaceData() method uses this key to manage
145: * cached copies of a source image as described below.
146: * <p>
147: * The Object used as this key should be as unique as it needs
148: * to be to ensure that multiple acceleratible destinations can
149: * each store their cached copies separately under different keys
150: * without interfering with each other or getting back the wrong
151: * cached copy.
152: * <p>
153: * Many acceleratable SurfaceData objects can use their own
154: * GraphicsConfiguration as their proxy key as the GC object will
155: * typically be unique to a given screen and pixel format, but
156: * other rendering destinations may have more or less stringent
157: * sharing requirements. For instance, X11 pixmaps can be
158: * shared on a given screen by any GraphicsConfiguration that
159: * has the same depth and SurfaceType. Multiple such GCs with
160: * the same depth and SurfaceType can exist per screen so storing
161: * a different cached proxy for each would be a waste. One can
162: * imagine platforms where a single cached copy can be created
163: * and shared across all screens and pixel formats - such
164: * implementations could use a single heavily shared key Object.
165: */
166: protected void setBlitProxyKey(Object key) {
167: // Caching is effectively disabled if we never have a proxy key
168: // since the getSourceSurfaceData() method only does caching
169: // if the key is not null.
170: if (SurfaceDataProxy.isCachingAllowed()) {
171: this .blitProxyKey = key;
172: }
173: }
174:
175: /**
176: * This method is called on a destination SurfaceData to choose
177: * the best SurfaceData from a source Image for an imaging
178: * operation, with help from its SurfaceManager.
179: * The method may determine that the default SurfaceData was
180: * really the best choice in the first place, or it may decide
181: * to use a cached surface. Some general decisions about whether
182: * acceleration is enabled are made by this method, but any
183: * decision based on the type of the source image is made in
184: * the makeProxyFor method below when it comes up with the
185: * appropriate SurfaceDataProxy instance.
186: * The parameters describe the type of imaging operation being performed.
187: * <p>
188: * If a blitProxyKey was supplied by the subclass then it is
189: * used to potentially override the choice of source SurfaceData.
190: * The outline of this process is:
191: * <ol>
192: * <li> Image pipeline asks destSD to find an appropriate
193: * srcSD for a given source Image object.
194: * <li> destSD gets the SurfaceManager of the source Image
195: * and first retrieves the default SD from it using
196: * getPrimarySurfaceData()
197: * <li> destSD uses its "blit proxy key" (if set) to look for
198: * some cached data stored in the source SurfaceManager
199: * <li> If the cached data is null then makeProxyFor() is used
200: * to create some cached data which is stored back in the
201: * source SurfaceManager under the same key for future uses.
202: * <li> The cached data will be a SurfaceDataProxy object.
203: * <li> The SurfaceDataProxy object is then consulted to
204: * return a replacement SurfaceData object (typically
205: * a cached copy if appropriate, or the original if not).
206: * </ol>
207: */
208: public SurfaceData getSourceSurfaceData(Image img, int txtype,
209: CompositeType comp, Color bgColor) {
210: SurfaceManager srcMgr = SurfaceManager.getManager(img);
211: SurfaceData srcData = srcMgr.getPrimarySurfaceData();
212: if (img.getAccelerationPriority() > 0.0f
213: && blitProxyKey != null) {
214: SurfaceDataProxy sdp = (SurfaceDataProxy) srcMgr
215: .getCacheData(blitProxyKey);
216: if (sdp == null || !sdp.isValid()) {
217: if (srcData.getState() == State.UNTRACKABLE) {
218: sdp = SurfaceDataProxy.UNCACHED;
219: } else {
220: sdp = makeProxyFor(srcData);
221: }
222: srcMgr.setCacheData(blitProxyKey, sdp);
223: }
224: srcData = sdp.replaceData(srcData, txtype, comp, bgColor);
225: }
226: return srcData;
227: }
228:
229: /**
230: * This method is called on a destination SurfaceData to choose
231: * a proper SurfaceDataProxy subclass for a source SurfaceData
232: * to use to control when and with what surface to override a
233: * given image operation. The argument is the default SurfaceData
234: * for the source Image.
235: * <p>
236: * The type of the return object is chosen based on the
237: * acceleration capabilities of this SurfaceData and the
238: * type of the given source SurfaceData object.
239: * <p>
240: * In some cases the original SurfaceData will always be the
241: * best choice to use to blit to this SurfaceData. This can
242: * happen if the source image is a hardware surface of the
243: * same type as this one and so acceleration will happen without
244: * any caching. It may also be the case that the source image
245: * can never be accelerated on this SurfaceData - for example
246: * because it is translucent and there are no accelerated
247: * translucent image ops for this surface.
248: * <p>
249: * In those cases there is a special SurfaceDataProxy.UNCACHED
250: * instance that represents a NOP for caching purposes - it
251: * always returns the original sourceSD object as the replacement
252: * copy so no caching is ever performed.
253: */
254: public SurfaceDataProxy makeProxyFor(SurfaceData srcData) {
255: return SurfaceDataProxy.UNCACHED;
256: }
257:
258: /**
259: * Extracts the SurfaceManager from the given Image, and then
260: * returns the SurfaceData object that would best be suited as the
261: * destination surface in some rendering operation.
262: */
263: public static SurfaceData getPrimarySurfaceData(Image img) {
264: SurfaceManager sMgr = SurfaceManager.getManager(img);
265: return sMgr.getPrimarySurfaceData();
266: }
267:
268: /**
269: * Restores the contents of the given Image and then returns the new
270: * SurfaceData object in use by the Image's SurfaceManager.
271: */
272: public static SurfaceData restoreContents(Image img) {
273: SurfaceManager sMgr = SurfaceManager.getManager(img);
274: return sMgr.restoreContents();
275: }
276:
277: public State getState() {
278: return stateDelegate.getState();
279: }
280:
281: public StateTracker getStateTracker() {
282: return stateDelegate.getStateTracker();
283: }
284:
285: /**
286: * Marks this surface as dirty.
287: */
288: public final void markDirty() {
289: stateDelegate.markDirty();
290: }
291:
292: /**
293: * Sets the value of the surfaceLost variable, which indicates whether
294: * something has happened to the rendering surface such that it needs
295: * to be restored and re-rendered.
296: */
297: public void setSurfaceLost(boolean lost) {
298: surfaceLost = lost;
299: stateDelegate.markDirty();
300: }
301:
302: public boolean isSurfaceLost() {
303: return surfaceLost;
304: }
305:
306: /**
307: * Returns a boolean indicating whether or not this SurfaceData is valid.
308: */
309: public final boolean isValid() {
310: return valid;
311: }
312:
313: public Object getDisposerReferent() {
314: return disposerReferent;
315: }
316:
317: public long getNativeOps() {
318: return pData;
319: }
320:
321: /**
322: * Sets this SurfaceData object to the invalid state. All Graphics
323: * objects must get a new SurfaceData object via the refresh method
324: * and revalidate their pipelines before continuing.
325: */
326: public void invalidate() {
327: valid = false;
328: stateDelegate.markDirty();
329: }
330:
331: /**
332: * Certain changes in the configuration of a surface require the
333: * invalidation of existing associated SurfaceData objects and
334: * the creation of brand new ones. These changes include size,
335: * ColorModel, or SurfaceType. Existing Graphics objects
336: * which are directed at such surfaces, however, must continue
337: * to render to them even after the change occurs underneath
338: * the covers. The getReplacement() method is called from
339: * SunGraphics2D.revalidateAll() when the associated SurfaceData
340: * is found to be invalid so that a Graphics object can continue
341: * to render to the surface in its new configuration.
342: *
343: * Such changes only tend to happen to window based surfaces since
344: * most image based surfaces never change size or pixel format.
345: * Even VolatileImage objects never change size and they only
346: * change their pixel format when manually validated against a
347: * new GraphicsConfiguration, at which point old Graphics objects
348: * are no longer expected to render to them after the validation
349: * step. Thus, only window based surfaces really need to deal
350: * with this form of replacement.
351: */
352: public abstract SurfaceData getReplacement();
353:
354: protected static final LoopPipe colorPrimitives;
355:
356: public static final TextPipe outlineTextRenderer;
357: public static final TextPipe solidTextRenderer;
358: public static final TextPipe aaTextRenderer;
359: public static final TextPipe lcdTextRenderer;
360:
361: protected static final CompositePipe colorPipe;
362: protected static final PixelToShapeConverter colorViaShape;
363: protected static final TextPipe colorText;
364: protected static final CompositePipe clipColorPipe;
365: protected static final TextPipe clipColorText;
366: protected static final AAShapePipe AAColorShape;
367: protected static final PixelToShapeConverter AAColorViaShape;
368: protected static final AAShapePipe AAClipColorShape;
369: protected static final PixelToShapeConverter AAClipColorViaShape;
370:
371: protected static final CompositePipe paintPipe;
372: protected static final SpanShapeRenderer paintShape;
373: protected static final PixelToShapeConverter paintViaShape;
374: protected static final TextPipe paintText;
375: protected static final CompositePipe clipPaintPipe;
376: protected static final TextPipe clipPaintText;
377: protected static final AAShapePipe AAPaintShape;
378: protected static final PixelToShapeConverter AAPaintViaShape;
379: protected static final AAShapePipe AAClipPaintShape;
380: protected static final PixelToShapeConverter AAClipPaintViaShape;
381:
382: protected static final CompositePipe compPipe;
383: protected static final SpanShapeRenderer compShape;
384: protected static final PixelToShapeConverter compViaShape;
385: protected static final TextPipe compText;
386: protected static final CompositePipe clipCompPipe;
387: protected static final TextPipe clipCompText;
388: protected static final AAShapePipe AACompShape;
389: protected static final PixelToShapeConverter AACompViaShape;
390: protected static final AAShapePipe AAClipCompShape;
391: protected static final PixelToShapeConverter AAClipCompViaShape;
392:
393: protected static final DrawImagePipe imagepipe;
394:
395: static {
396: colorPrimitives = new LoopPipe();
397:
398: outlineTextRenderer = new OutlineTextRenderer();
399: solidTextRenderer = new SolidTextRenderer();
400: aaTextRenderer = new AATextRenderer();
401: lcdTextRenderer = new LCDTextRenderer();
402:
403: colorPipe = new AlphaColorPipe();
404: // colorShape = colorPrimitives;
405: colorViaShape = new PixelToShapeConverter(colorPrimitives);
406: colorText = new TextRenderer(colorPipe);
407: clipColorPipe = new SpanClipRenderer(colorPipe);
408: clipColorText = new TextRenderer(clipColorPipe);
409: AAColorShape = new AAShapePipe(colorPipe);
410: AAColorViaShape = new PixelToShapeConverter(AAColorShape);
411: AAClipColorShape = new AAShapePipe(clipColorPipe);
412: AAClipColorViaShape = new PixelToShapeConverter(
413: AAClipColorShape);
414:
415: paintPipe = new AlphaPaintPipe();
416: paintShape = new SpanShapeRenderer.Composite(paintPipe);
417: paintViaShape = new PixelToShapeConverter(paintShape);
418: paintText = new TextRenderer(paintPipe);
419: clipPaintPipe = new SpanClipRenderer(paintPipe);
420: clipPaintText = new TextRenderer(clipPaintPipe);
421: AAPaintShape = new AAShapePipe(paintPipe);
422: AAPaintViaShape = new PixelToShapeConverter(AAPaintShape);
423: AAClipPaintShape = new AAShapePipe(clipPaintPipe);
424: AAClipPaintViaShape = new PixelToShapeConverter(
425: AAClipPaintShape);
426:
427: compPipe = new GeneralCompositePipe();
428: compShape = new SpanShapeRenderer.Composite(compPipe);
429: compViaShape = new PixelToShapeConverter(compShape);
430: compText = new TextRenderer(compPipe);
431: clipCompPipe = new SpanClipRenderer(compPipe);
432: clipCompText = new TextRenderer(clipCompPipe);
433: AACompShape = new AAShapePipe(compPipe);
434: AACompViaShape = new PixelToShapeConverter(AACompShape);
435: AAClipCompShape = new AAShapePipe(clipCompPipe);
436: AAClipCompViaShape = new PixelToShapeConverter(AAClipCompShape);
437:
438: imagepipe = new DrawImage();
439: }
440:
441: /* Not all surfaces and rendering mode combinations support LCD text. */
442: static final int LCDLOOP_UNKNOWN = 0;
443: static final int LCDLOOP_FOUND = 1;
444: static final int LCDLOOP_NOTFOUND = 2;
445: int haveLCDLoop;
446:
447: public boolean canRenderLCDText(SunGraphics2D sg2d) {
448: // For now the answer can only be true in the following cases:
449: if (sg2d.compositeState <= SunGraphics2D.COMP_ISCOPY
450: && sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR
451: && sg2d.clipState <= SunGraphics2D.CLIP_RECTANGULAR) {
452: if (haveLCDLoop == LCDLOOP_UNKNOWN) {
453: DrawGlyphListLCD loop = DrawGlyphListLCD.locate(
454: SurfaceType.AnyColor, CompositeType.SrcNoEa,
455: getSurfaceType());
456: haveLCDLoop = (loop != null) ? LCDLOOP_FOUND
457: : LCDLOOP_NOTFOUND;
458: }
459: return haveLCDLoop == LCDLOOP_FOUND;
460: }
461: return false; /* for now - in the future we may want to search */
462: }
463:
464: public void validatePipe(SunGraphics2D sg2d) {
465: sg2d.imagepipe = imagepipe;
466: if (sg2d.compositeState == sg2d.COMP_XOR) {
467: if (sg2d.paintState > sg2d.PAINT_ALPHACOLOR) {
468: sg2d.drawpipe = paintViaShape;
469: sg2d.fillpipe = paintViaShape;
470: sg2d.shapepipe = paintShape;
471: // REMIND: Ideally custom paint mode would use glyph
472: // rendering as opposed to outline rendering but the
473: // glyph paint rendering pipeline uses MaskBlit which
474: // is not defined for XOR. This means that text drawn
475: // in XOR mode with a Color object is different than
476: // text drawn in XOR mode with a Paint object.
477: sg2d.textpipe = outlineTextRenderer;
478: } else {
479: if (sg2d.clipState == sg2d.CLIP_SHAPE) {
480: sg2d.drawpipe = colorViaShape;
481: sg2d.fillpipe = colorViaShape;
482: // REMIND: We should not be changing text strategies
483: // between outline and glyph rendering based upon the
484: // presence of a complex clip as that could cause a
485: // mismatch when drawing the same text both clipped
486: // and unclipped on two separate rendering passes.
487: // Unfortunately, all of the clipped glyph rendering
488: // pipelines rely on the use of the MaskBlit operation
489: // which is not defined for XOR.
490: sg2d.textpipe = outlineTextRenderer;
491: } else {
492: if (sg2d.transformState >= sg2d.TRANSFORM_TRANSLATESCALE) {
493: sg2d.drawpipe = colorViaShape;
494: sg2d.fillpipe = colorViaShape;
495: } else {
496: if (sg2d.strokeState != sg2d.STROKE_THIN) {
497: sg2d.drawpipe = colorViaShape;
498: } else {
499: sg2d.drawpipe = colorPrimitives;
500: }
501: sg2d.fillpipe = colorPrimitives;
502: }
503: sg2d.textpipe = solidTextRenderer;
504: }
505: sg2d.shapepipe = colorPrimitives;
506: sg2d.loops = getRenderLoops(sg2d);
507: // assert(sg2d.surfaceData == this);
508: }
509: } else if (sg2d.compositeState == sg2d.COMP_CUSTOM) {
510: if (sg2d.antialiasHint == SunHints.INTVAL_ANTIALIAS_ON) {
511: if (sg2d.clipState == sg2d.CLIP_SHAPE) {
512: sg2d.drawpipe = AAClipCompViaShape;
513: sg2d.fillpipe = AAClipCompViaShape;
514: sg2d.shapepipe = AAClipCompShape;
515: sg2d.textpipe = clipCompText;
516: } else {
517: sg2d.drawpipe = AACompViaShape;
518: sg2d.fillpipe = AACompViaShape;
519: sg2d.shapepipe = AACompShape;
520: sg2d.textpipe = compText;
521: }
522: } else {
523: sg2d.drawpipe = compViaShape;
524: sg2d.fillpipe = compViaShape;
525: sg2d.shapepipe = compShape;
526: if (sg2d.clipState == sg2d.CLIP_SHAPE) {
527: sg2d.textpipe = clipCompText;
528: } else {
529: sg2d.textpipe = compText;
530: }
531: }
532: } else if (sg2d.antialiasHint == SunHints.INTVAL_ANTIALIAS_ON) {
533: sg2d.alphafill = getMaskFill(sg2d);
534: // assert(sg2d.surfaceData == this);
535: if (sg2d.alphafill != null) {
536: if (sg2d.clipState == sg2d.CLIP_SHAPE) {
537: sg2d.drawpipe = AAClipColorViaShape;
538: sg2d.fillpipe = AAClipColorViaShape;
539: sg2d.shapepipe = AAClipColorShape;
540: sg2d.textpipe = clipColorText;
541: } else {
542: sg2d.drawpipe = AAColorViaShape;
543: sg2d.fillpipe = AAColorViaShape;
544: sg2d.shapepipe = AAColorShape;
545: if (sg2d.paintState > sg2d.PAINT_OPAQUECOLOR
546: || sg2d.compositeState > sg2d.COMP_ISCOPY) {
547: sg2d.textpipe = colorText;
548: } else {
549: sg2d.textpipe = getTextPipe(sg2d, true /* AA==ON */);
550: }
551: }
552: } else {
553: if (sg2d.clipState == sg2d.CLIP_SHAPE) {
554: sg2d.drawpipe = AAClipPaintViaShape;
555: sg2d.fillpipe = AAClipPaintViaShape;
556: sg2d.shapepipe = AAClipPaintShape;
557: sg2d.textpipe = clipPaintText;
558: } else {
559: sg2d.drawpipe = AAPaintViaShape;
560: sg2d.fillpipe = AAPaintViaShape;
561: sg2d.shapepipe = AAPaintShape;
562: sg2d.textpipe = paintText;
563: }
564: }
565: } else if (sg2d.paintState > sg2d.PAINT_ALPHACOLOR
566: || sg2d.compositeState > sg2d.COMP_ISCOPY
567: || sg2d.clipState == sg2d.CLIP_SHAPE) {
568: sg2d.drawpipe = paintViaShape;
569: sg2d.fillpipe = paintViaShape;
570: sg2d.shapepipe = paintShape;
571: sg2d.alphafill = getMaskFill(sg2d);
572: // assert(sg2d.surfaceData == this);
573: if (sg2d.alphafill != null) {
574: if (sg2d.clipState == sg2d.CLIP_SHAPE) {
575: sg2d.textpipe = clipColorText;
576: } else {
577: sg2d.textpipe = colorText;
578: }
579: } else {
580: if (sg2d.clipState == sg2d.CLIP_SHAPE) {
581: sg2d.textpipe = clipPaintText;
582: } else {
583: sg2d.textpipe = paintText;
584: }
585: }
586: } else {
587: if (sg2d.transformState >= sg2d.TRANSFORM_TRANSLATESCALE) {
588: sg2d.drawpipe = colorViaShape;
589: sg2d.fillpipe = colorViaShape;
590: } else {
591: if (sg2d.strokeState != sg2d.STROKE_THIN) {
592: sg2d.drawpipe = colorViaShape;
593: } else {
594: sg2d.drawpipe = colorPrimitives;
595: }
596: sg2d.fillpipe = colorPrimitives;
597: }
598:
599: sg2d.textpipe = getTextPipe(sg2d, false /* AA==OFF */);
600: sg2d.shapepipe = colorPrimitives;
601: sg2d.loops = getRenderLoops(sg2d);
602: // assert(sg2d.surfaceData == this);
603: }
604: }
605:
606: /* Return the text pipe to be used based on the graphics AA hint setting,
607: * and the rest of the graphics state is compatible with these loops.
608: * If the text AA hint is "DEFAULT", then the AA graphics hint requests
609: * the AA text renderer, else it requests the B&W text renderer.
610: */
611: private TextPipe getTextPipe(SunGraphics2D sg2d, boolean aaHintIsOn) {
612:
613: /* Try to avoid calling getFontInfo() unless its needed to
614: * resolve one of the new AA types.
615: */
616: switch (sg2d.textAntialiasHint) {
617: case SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT:
618: if (aaHintIsOn) {
619: return aaTextRenderer;
620: } else {
621: return solidTextRenderer;
622: }
623: case SunHints.INTVAL_TEXT_ANTIALIAS_OFF:
624: return solidTextRenderer;
625:
626: case SunHints.INTVAL_TEXT_ANTIALIAS_ON:
627: return aaTextRenderer;
628:
629: default:
630: switch (sg2d.getFontInfo().aaHint) {
631:
632: case SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HRGB:
633: case SunHints.INTVAL_TEXT_ANTIALIAS_LCD_VRGB:
634: return lcdTextRenderer;
635:
636: case SunHints.INTVAL_TEXT_ANTIALIAS_ON:
637: return aaTextRenderer;
638:
639: case SunHints.INTVAL_TEXT_ANTIALIAS_OFF:
640: return solidTextRenderer;
641:
642: /* This should not be reached as the FontInfo will
643: * always explicitly set its hint value. So whilst
644: * this could be collapsed to returning say just
645: * solidTextRenderer, or even removed, its left
646: * here in case DEFAULT is ever passed in.
647: */
648: default:
649: if (aaHintIsOn) {
650: return aaTextRenderer;
651: } else {
652: return solidTextRenderer;
653: }
654: }
655: }
656: }
657:
658: private static SurfaceType getPaintSurfaceType(SunGraphics2D sg2d) {
659: switch (sg2d.paintState) {
660: case SunGraphics2D.PAINT_OPAQUECOLOR:
661: return SurfaceType.OpaqueColor;
662: case SunGraphics2D.PAINT_ALPHACOLOR:
663: return SurfaceType.AnyColor;
664: case SunGraphics2D.PAINT_GRADIENT:
665: if (sg2d.paint.getTransparency() == OPAQUE) {
666: return SurfaceType.OpaqueGradientPaint;
667: } else {
668: return SurfaceType.GradientPaint;
669: }
670: case SunGraphics2D.PAINT_LIN_GRADIENT:
671: if (sg2d.paint.getTransparency() == OPAQUE) {
672: return SurfaceType.OpaqueLinearGradientPaint;
673: } else {
674: return SurfaceType.LinearGradientPaint;
675: }
676: case SunGraphics2D.PAINT_RAD_GRADIENT:
677: if (sg2d.paint.getTransparency() == OPAQUE) {
678: return SurfaceType.OpaqueRadialGradientPaint;
679: } else {
680: return SurfaceType.RadialGradientPaint;
681: }
682: case SunGraphics2D.PAINT_TEXTURE:
683: if (sg2d.paint.getTransparency() == OPAQUE) {
684: return SurfaceType.OpaqueTexturePaint;
685: } else {
686: return SurfaceType.TexturePaint;
687: }
688: default:
689: case SunGraphics2D.PAINT_CUSTOM:
690: return SurfaceType.AnyPaint;
691: }
692: }
693:
694: /**
695: * Returns a MaskFill object that can be used on this destination
696: * with the source (paint) and composite types determined by the given
697: * SunGraphics2D, or null if no such MaskFill object can be located.
698: * Subclasses can override this method if they wish to filter other
699: * attributes (such as the hardware capabilities of the destination
700: * surface) before returning a specific MaskFill object.
701: */
702: protected MaskFill getMaskFill(SunGraphics2D sg2d) {
703: return MaskFill.getFromCache(getPaintSurfaceType(sg2d),
704: sg2d.imageComp, getSurfaceType());
705: }
706:
707: private static RenderCache loopcache = new RenderCache(30);
708:
709: /**
710: * Return a RenderLoops object containing all of the basic
711: * GraphicsPrimitive objects for rendering to the destination
712: * surface with the current attributes of the given SunGraphics2D.
713: */
714: public RenderLoops getRenderLoops(SunGraphics2D sg2d) {
715: SurfaceType src = getPaintSurfaceType(sg2d);
716: CompositeType comp = (sg2d.compositeState == sg2d.COMP_ISCOPY ? CompositeType.SrcNoEa
717: : sg2d.imageComp);
718: SurfaceType dst = sg2d.getSurfaceData().getSurfaceType();
719:
720: Object o = loopcache.get(src, comp, dst);
721: if (o != null) {
722: return (RenderLoops) o;
723: }
724:
725: RenderLoops loops = makeRenderLoops(src, comp, dst);
726: loopcache.put(src, comp, dst, loops);
727: return loops;
728: }
729:
730: /**
731: * Construct and return a RenderLoops object containing all of
732: * the basic GraphicsPrimitive objects for rendering to the
733: * destination surface with the given source, destination, and
734: * composite types.
735: */
736: public static RenderLoops makeRenderLoops(SurfaceType src,
737: CompositeType comp, SurfaceType dst) {
738: RenderLoops loops = new RenderLoops();
739: loops.drawLineLoop = DrawLine.locate(src, comp, dst);
740: loops.fillRectLoop = FillRect.locate(src, comp, dst);
741: loops.drawRectLoop = DrawRect.locate(src, comp, dst);
742: loops.drawPolygonsLoop = DrawPolygons.locate(src, comp, dst);
743: loops.drawPathLoop = DrawPath.locate(src, comp, dst);
744: loops.fillPathLoop = FillPath.locate(src, comp, dst);
745: loops.fillSpansLoop = FillSpans.locate(src, comp, dst);
746: loops.drawGlyphListLoop = DrawGlyphList.locate(src, comp, dst);
747: loops.drawGlyphListAALoop = DrawGlyphListAA.locate(src, comp,
748: dst);
749: loops.drawGlyphListLCDLoop = DrawGlyphListLCD.locate(src, comp,
750: dst);
751: /*
752: System.out.println("drawLine: "+loops.drawLineLoop);
753: System.out.println("fillRect: "+loops.fillRectLoop);
754: System.out.println("drawRect: "+loops.drawRectLoop);
755: System.out.println("drawPolygons: "+loops.drawPolygonsLoop);
756: System.out.println("fillSpans: "+loops.fillSpansLoop);
757: System.out.println("drawGlyphList: "+loops.drawGlyphListLoop);
758: System.out.println("drawGlyphListAA: "+loops.drawGlyphListAALoop);
759: System.out.println("drawGlyphListLCD: "+loops.drawGlyphListLCDLoop);
760: */
761: return loops;
762: }
763:
764: /**
765: * Return the GraphicsConfiguration object that describes this
766: * destination surface.
767: */
768: public abstract GraphicsConfiguration getDeviceConfiguration();
769:
770: /**
771: * Return the SurfaceType object that describes the destination
772: * surface.
773: */
774: public final SurfaceType getSurfaceType() {
775: return surfaceType;
776: }
777:
778: /**
779: * Return the ColorModel for the destination surface.
780: */
781: public final ColorModel getColorModel() {
782: return colorModel;
783: }
784:
785: /**
786: * Returns the type of this <code>Transparency</code>.
787: * @return the field type of this <code>Transparency</code>, which is
788: * either OPAQUE, BITMASK or TRANSLUCENT.
789: */
790: public int getTransparency() {
791: return getColorModel().getTransparency();
792: }
793:
794: /**
795: * Return a readable Raster which contains the pixels for the
796: * specified rectangular region of the destination surface.
797: * The coordinate origin of the returned Raster is the same as
798: * the device space origin of the destination surface.
799: * In some cases the returned Raster might also be writeable.
800: * In most cases, the returned Raster might contain more pixels
801: * than requested.
802: *
803: * @see useTightBBoxes
804: */
805: public abstract Raster getRaster(int x, int y, int w, int h);
806:
807: /**
808: * Does the pixel accessibility of the destination surface
809: * suggest that rendering algorithms might want to take
810: * extra time to calculate a more accurate bounding box for
811: * the operation being performed?
812: * The typical case when this will be true is when a copy of
813: * the pixels has to be made when doing a getRaster. The
814: * fewer pixels copied, the faster the operation will go.
815: *
816: * @see getRaster
817: */
818: public boolean useTightBBoxes() {
819: // Note: The native equivalent would trigger on VISIBLE_TO_NATIVE
820: // REMIND: This is not used - should be obsoleted maybe
821: return true;
822: }
823:
824: /**
825: * Returns the pixel data for the specified Argb value packed
826: * into an integer for easy storage and conveyance.
827: */
828: public int pixelFor(int rgb) {
829: return surfaceType.pixelFor(rgb, colorModel);
830: }
831:
832: /**
833: * Returns the pixel data for the specified color packed into an
834: * integer for easy storage and conveyance.
835: *
836: * This method will use the getRGB() method of the Color object
837: * and defer to the pixelFor(int rgb) method if not overridden.
838: *
839: * For now this is a convenience function, but for cases where
840: * the highest quality color conversion is requested, this method
841: * should be overridden in those cases so that a more direct
842: * conversion of the color to the destination color space
843: * can be done using the additional information in the Color
844: * object.
845: */
846: public int pixelFor(Color c) {
847: return pixelFor(c.getRGB());
848: }
849:
850: /**
851: * Returns the Argb representation for the specified integer value
852: * which is packed in the format of the associated ColorModel.
853: */
854: public int rgbFor(int pixel) {
855: return surfaceType.rgbFor(pixel, colorModel);
856: }
857:
858: /**
859: * Returns the bounds of the destination surface.
860: */
861: public abstract Rectangle getBounds();
862:
863: static java.security.Permission compPermission;
864:
865: /**
866: * Performs Security Permissions checks to see if a Custom
867: * Composite object should be allowed access to the pixels
868: * of this surface.
869: */
870: protected void checkCustomComposite() {
871: SecurityManager sm = System.getSecurityManager();
872: if (sm != null) {
873: if (compPermission == null) {
874: compPermission = new java.awt.AWTPermission(
875: "readDisplayPixels");
876: }
877: sm.checkPermission(compPermission);
878: }
879: }
880:
881: /**
882: * Fetches private field IndexColorModel.allgrayopaque
883: * which is true when all palette entries in the color
884: * model are gray and opaque.
885: */
886: protected static native boolean isOpaqueGray(IndexColorModel icm);
887:
888: /**
889: * For our purposes null and NullSurfaceData are the same as
890: * they represent a disposed surface.
891: */
892: public static boolean isNull(SurfaceData sd) {
893: if (sd == null || sd == NullSurfaceData.theInstance) {
894: return true;
895: }
896: return false;
897: }
898:
899: /**
900: * Performs a copyarea within this surface. Returns
901: * false if there is no algorithm to perform the copyarea
902: * given the current settings of the SunGraphics2D.
903: */
904: public boolean copyArea(SunGraphics2D sg2d, int x, int y, int w,
905: int h, int dx, int dy) {
906: return false;
907: }
908:
909: /**
910: * Synchronously releases resources associated with this surface.
911: */
912: public void flush() {
913: }
914:
915: /**
916: * Returns destination associated with this SurfaceData. This could be
917: * either an Image or a Component; subclasses of SurfaceData are
918: * responsible for returning the appropriate object.
919: */
920: public abstract Object getDestination();
921: }
|