1 /*
2  * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package sun.java2d.xr;
27 
28 import java.awt.AlphaComposite;
29 import java.awt.GraphicsConfiguration;
30 import java.awt.GraphicsDevice;
31 import java.awt.GraphicsEnvironment;
32 import java.awt.Image;
33 import java.awt.Rectangle;
34 import java.awt.Transparency;
35 import java.awt.geom.AffineTransform;
36 import java.awt.image.ColorModel;
37 import java.awt.image.DirectColorModel;
38 import java.awt.image.Raster;
39 import sun.awt.SunHints;
40 import sun.awt.SunToolkit;
41 import sun.awt.X11ComponentPeer;
42 import sun.awt.image.PixelConverter;
43 import sun.java2d.InvalidPipeException;
44 import sun.java2d.SunGraphics2D;
45 import sun.java2d.SurfaceData;
46 import sun.java2d.SurfaceDataProxy;
47 import sun.java2d.loops.CompositeType;
48 import sun.java2d.loops.MaskFill;
49 import sun.java2d.loops.RenderLoops;
50 import sun.java2d.loops.SurfaceType;
51 import sun.java2d.loops.XORComposite;
52 import sun.java2d.pipe.PixelToShapeConverter;
53 import sun.java2d.pipe.Region;
54 import sun.java2d.pipe.ShapeDrawPipe;
55 import sun.java2d.pipe.TextPipe;
56 import sun.java2d.pipe.ValidatePipe;
57 import sun.java2d.x11.XSurfaceData;
58 import sun.font.FontManagerNativeLibrary;
59 
60 public abstract class XRSurfaceData extends XSurfaceData {
61     X11ComponentPeer peer;
62     XRGraphicsConfig graphicsConfig;
63     XRBackend renderQueue;
64 
65     private RenderLoops solidloops;
66 
67     protected int depth;
68 
initIDs()69     private static native void initIDs();
70 
XRInitSurface(int depth, int width, int height, long drawable, int pictFormat)71     protected native void XRInitSurface(int depth, int width, int height,
72                                         long drawable, int pictFormat);
73 
initXRPicture(long xsdo, int pictForm)74     native void initXRPicture(long xsdo, int pictForm);
75 
freeXSDOPicture(long xsdo)76     native void freeXSDOPicture(long xsdo);
77 
78     public static final String DESC_BYTE_A8_X11 = "Byte A8 Pixmap";
79     public static final String DESC_INT_RGB_X11 = "Integer RGB Pixmap";
80     public static final String DESC_INT_ARGB_X11 = "Integer ARGB-Pre Pixmap";
81 
82     public static final SurfaceType
83         ByteA8X11 = SurfaceType.ByteGray.deriveSubType(DESC_BYTE_A8_X11);
84     public static final SurfaceType
85         IntRgbX11 = SurfaceType.IntRgb.deriveSubType(DESC_INT_RGB_X11,
86                                               PixelConverter.ArgbPre.instance);
87     public static final SurfaceType
88         IntArgbPreX11 = SurfaceType.IntArgbPre.deriveSubType(DESC_INT_ARGB_X11);
89 
getRaster(int x, int y, int w, int h)90     public Raster getRaster(int x, int y, int w, int h) {
91         throw new InternalError("not implemented yet");
92     }
93 
94     protected XRRenderer xrpipe;
95     protected PixelToShapeConverter xrtxpipe;
96     protected TextPipe xrtextpipe;
97     protected XRDrawImage xrDrawImage;
98 
99     protected ShapeDrawPipe aaShapePipe;
100     protected PixelToShapeConverter aaPixelToShapeConv;
101 
initXRSurfaceData()102     public static void initXRSurfaceData() {
103         if (!isX11SurfaceDataInitialized()) {
104             FontManagerNativeLibrary.load();
105             initIDs();
106             XRPMBlitLoops.register();
107             XRMaskFill.register();
108             XRMaskBlit.register();
109 
110             setX11SurfaceDataInitialized();
111         }
112     }
113 
114     /**
115      * Synchronized accessor method for isDrawableValid.
116      */
isXRDrawableValid()117     protected boolean isXRDrawableValid() {
118         try {
119             SunToolkit.awtLock();
120             return isDrawableValid();
121         } finally {
122             SunToolkit.awtUnlock();
123         }
124     }
125 
126     @Override
makeProxyFor(SurfaceData srcData)127     public SurfaceDataProxy makeProxyFor(SurfaceData srcData) {
128         return XRSurfaceDataProxy.createProxy(srcData, graphicsConfig);
129     }
130 
131     @Override
validatePipe(SunGraphics2D sg2d)132     public void validatePipe(SunGraphics2D sg2d) {
133         TextPipe textpipe;
134         boolean validated = false;
135 
136         /*
137          * The textpipe for now can't handle TexturePaint when extra-alpha is
138          * specified nore XOR mode
139          */
140         if ((textpipe = getTextPipe(sg2d)) == null)
141         {
142             super.validatePipe(sg2d);
143             textpipe = sg2d.textpipe;
144             validated = true;
145         }
146 
147         PixelToShapeConverter txPipe = null;
148         XRRenderer nonTxPipe = null;
149 
150         /*
151          * TODO: Can we rely on the GC for ARGB32 surfaces?
152          */
153         if (sg2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON) {
154             if (sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR) {
155                 if (sg2d.compositeState <= SunGraphics2D.COMP_XOR) {
156                     txPipe = xrtxpipe;
157                     nonTxPipe = xrpipe;
158                 }
159             } else if (sg2d.compositeState <= SunGraphics2D.COMP_ALPHA) {
160                 if (XRPaints.isValid(sg2d)) {
161                     txPipe = xrtxpipe;
162                     nonTxPipe = xrpipe;
163                 }
164                 // custom paints handled by super.validatePipe() below
165             }
166         }
167 
168         if (txPipe != null) {
169             if (sg2d.transformState >= SunGraphics2D.TRANSFORM_TRANSLATESCALE) {
170                 sg2d.drawpipe = txPipe;
171                 sg2d.fillpipe = txPipe;
172             } else if (sg2d.strokeState != SunGraphics2D.STROKE_THIN) {
173                 sg2d.drawpipe = txPipe;
174                 sg2d.fillpipe = nonTxPipe;
175             } else {
176                 sg2d.drawpipe = nonTxPipe;
177                 sg2d.fillpipe = nonTxPipe;
178             }
179             sg2d.shapepipe = nonTxPipe;
180         } else {
181             if (!validated) {
182                 super.validatePipe(sg2d);
183             }
184         }
185 
186         // install the text pipe based on our earlier decision
187         sg2d.textpipe = textpipe;
188 
189         // always override the image pipe with the specialized XRender pipe
190         sg2d.imagepipe = xrDrawImage;
191     }
192 
getTextPipe(SunGraphics2D sg2d)193     protected TextPipe getTextPipe(SunGraphics2D sg2d) {
194         boolean supportedPaint = sg2d.compositeState <= SunGraphics2D.COMP_ALPHA
195                 && (sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR || sg2d.composite == null);
196 
197         boolean supportedCompOp = false;
198         if (sg2d.composite instanceof AlphaComposite) {
199             int compRule = ((AlphaComposite) sg2d.composite).getRule();
200             supportedCompOp = XRUtils.isMaskEvaluated(XRUtils.j2dAlphaCompToXR(compRule))
201                     || (compRule == AlphaComposite.SRC
202                                 && sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR);
203         }
204 
205         return (supportedPaint && supportedCompOp) ? xrtextpipe : null;
206     }
207 
getMaskFill(SunGraphics2D sg2d)208     protected MaskFill getMaskFill(SunGraphics2D sg2d) {
209         AlphaComposite aComp = null;
210         if(sg2d.composite != null
211                 && sg2d.composite instanceof AlphaComposite) {
212             aComp = (AlphaComposite) sg2d.composite;
213         }
214 
215         boolean supportedPaint = sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR
216                 || XRPaints.isValid(sg2d);
217 
218         boolean supportedCompOp = false;
219         if(aComp != null) {
220             int rule = aComp.getRule();
221             supportedCompOp = XRUtils.isMaskEvaluated(XRUtils.j2dAlphaCompToXR(rule));
222         }
223 
224         return (supportedPaint && supportedCompOp) ?  super.getMaskFill(sg2d) : null;
225     }
226 
getRenderLoops(SunGraphics2D sg2d)227     public RenderLoops getRenderLoops(SunGraphics2D sg2d) {
228         if (sg2d.paintState <= SunGraphics2D.PAINT_ALPHACOLOR &&
229             sg2d.compositeState <= SunGraphics2D.COMP_ALPHA)
230         {
231             return solidloops;
232         }
233 
234         return super.getRenderLoops(sg2d);
235     }
236 
getDeviceConfiguration()237     public GraphicsConfiguration getDeviceConfiguration() {
238         return graphicsConfig;
239     }
240 
241     /**
242      * Method for instantiating a Window SurfaceData
243      */
createData(X11ComponentPeer peer)244     public static XRWindowSurfaceData createData(X11ComponentPeer peer) {
245         XRGraphicsConfig gc = getGC(peer);
246         return new XRWindowSurfaceData(peer, gc, gc.getSurfaceType());
247     }
248 
249     /**
250      * Method for instantiating a Pixmap SurfaceData (offscreen).
251      * If the surface * is opaque a 24-bit/RGB surface is chosen,
252      * otherwise a 32-bit ARGB surface.
253      */
createData(XRGraphicsConfig gc, int width, int height, ColorModel cm, Image image, long drawable, int transparency, boolean isTexture)254     public static XRPixmapSurfaceData createData(XRGraphicsConfig gc,
255                                                  int width, int height,
256                                                  ColorModel cm, Image image,
257                                                  long drawable,
258                                                  int transparency,
259                                                  boolean isTexture) {
260         int depth;
261         // If we have a 32 bit color model for the window it needs
262         // alpha to support translucency of the window so we need
263         //  to upgrade what was requested for the surface.
264         if (gc.getColorModel().getPixelSize() == 32) {
265            depth = 32;
266            transparency = Transparency.TRANSLUCENT;
267         } else {
268             depth = transparency > Transparency.OPAQUE ? 32 : 24;
269         }
270 
271         if (depth == 24) {
272             cm = new DirectColorModel(depth,
273                                       0x00FF0000, 0x0000FF00, 0x000000FF);
274         } else {
275             cm = new DirectColorModel(depth, 0x00FF0000, 0x0000FF00,
276                                       0x000000FF, 0xFF000000);
277         }
278 
279         return new XRPixmapSurfaceData
280             (gc, width, height, image, getSurfaceType(gc, transparency),
281              cm, drawable, transparency,
282              XRUtils.getPictureFormatForTransparency(transparency), depth, isTexture);
283     }
284 
XRSurfaceData(X11ComponentPeer peer, XRGraphicsConfig gc, SurfaceType sType, ColorModel cm, int depth, int transparency)285     protected XRSurfaceData(X11ComponentPeer peer, XRGraphicsConfig gc,
286         SurfaceType sType, ColorModel cm, int depth, int transparency)
287     {
288         super(sType, cm);
289         this.peer = peer;
290         this.graphicsConfig = gc;
291         this.solidloops = graphicsConfig.getSolidLoops(sType);
292         this.depth = depth;
293         initOps(peer, graphicsConfig, depth);
294 
295         setBlitProxyKey(gc.getProxyKey());
296     }
297 
XRSurfaceData(XRBackend renderQueue)298     protected XRSurfaceData(XRBackend renderQueue) {
299         super(XRSurfaceData.IntRgbX11,
300               new DirectColorModel(24, 0x00FF0000, 0x0000FF00, 0x000000FF));
301         this.renderQueue = renderQueue;
302     }
303 
304     /**
305      * Inits the XRender-data-structures which belong to the XRSurfaceData.
306      *
307      * @param pictureFormat
308      */
initXRender(int pictureFormat)309     public void initXRender(int pictureFormat) {
310         try {
311             SunToolkit.awtLock();
312             initXRPicture(getNativeOps(), pictureFormat);
313             renderQueue = XRCompositeManager.getInstance(this).getBackend();
314             maskBuffer = XRCompositeManager.getInstance(this);
315         } catch (Throwable ex) {
316             ex.printStackTrace();
317         } finally {
318             SunToolkit.awtUnlock();
319         }
320     }
321 
getGC(X11ComponentPeer peer)322     public static XRGraphicsConfig getGC(X11ComponentPeer peer) {
323         if (peer != null) {
324             return (XRGraphicsConfig) peer.getGraphicsConfiguration();
325         } else {
326             GraphicsEnvironment env =
327                 GraphicsEnvironment.getLocalGraphicsEnvironment();
328             GraphicsDevice gd = env.getDefaultScreenDevice();
329             return (XRGraphicsConfig) gd.getDefaultConfiguration();
330         }
331     }
332 
333     /**
334      * Returns a boolean indicating whether or not a copyArea from the given
335      * rectangle source coordinates might be incomplete and result in X11
336      * GraphicsExposure events being generated from XCopyArea. This method
337      * allows the SurfaceData copyArea method to determine if it needs to set
338      * the GraphicsExposures attribute of the X11 GC to True or False to receive
339      * or avoid the events.
340      *
341      * @return true if there is any chance that an XCopyArea from the given
342      *         source coordinates could produce any X11 Exposure events.
343      */
canSourceSendExposures(int x, int y, int w, int h)344     public abstract boolean canSourceSendExposures(int x, int y, int w, int h);
345 
346     /**
347      * CopyArea is implemented using the "old" X11 GC, therefor clip and
348      * needExposures have to be validated against that GC. Pictures and GCs
349      * don't share state.
350      */
validateCopyAreaGC(Region gcClip, boolean needExposures)351     public void validateCopyAreaGC(Region gcClip, boolean needExposures) {
352         if (validatedGCClip != gcClip) {
353             if (gcClip != null)
354                 renderQueue.setGCClipRectangles(xgc, gcClip);
355             validatedGCClip = gcClip;
356         }
357 
358         if (validatedExposures != needExposures) {
359             validatedExposures = needExposures;
360             renderQueue.setGCExposures(xgc, needExposures);
361         }
362 
363         if (validatedXorComp != null) {
364             renderQueue.setGCMode(xgc, true);
365             renderQueue.setGCForeground(xgc, validatedGCForegroundPixel);
366             validatedXorComp = null;
367         }
368     }
369 
copyArea(SunGraphics2D sg2d, int x, int y, int w, int h, int dx, int dy)370     public boolean copyArea(SunGraphics2D sg2d, int x, int y, int w, int h,
371                             int dx, int dy) {
372         if (xrpipe == null) {
373             if (!isXRDrawableValid()) {
374                 return true;
375             }
376             makePipes();
377         }
378         CompositeType comptype = sg2d.imageComp;
379         if (CompositeType.SrcOverNoEa.equals(comptype) ||
380              CompositeType.SrcNoEa.equals(comptype))
381         {
382             try {
383                 SunToolkit.awtLock();
384                 boolean needExposures = canSourceSendExposures(x, y, w, h);
385                 validateCopyAreaGC(sg2d.getCompClip(), needExposures);
386                 renderQueue.copyArea(xid, xid, xgc, x, y, w, h, x + dx, y + dy);
387             } finally {
388                 SunToolkit.awtUnlock();
389             }
390             return true;
391         }
392         return false;
393     }
394 
395     /**
396      * Returns the XRender SurfaceType which is able to fullfill the specified
397      * transparency requirement.
398      */
getSurfaceType(XRGraphicsConfig gc, int transparency)399     public static SurfaceType getSurfaceType(XRGraphicsConfig gc,
400                                              int transparency) {
401         SurfaceType sType = null;
402 
403         switch (transparency) {
404         case Transparency.OPAQUE:
405             sType = XRSurfaceData.IntRgbX11;
406             break;
407 
408         case Transparency.BITMASK:
409         case Transparency.TRANSLUCENT:
410             sType = XRSurfaceData.IntArgbPreX11;
411             break;
412         }
413 
414         return sType;
415     }
416 
invalidate()417     public void invalidate() {
418         if (isValid()) {
419             setInvalid();
420             super.invalidate();
421         }
422     }
423 
424     private long xgc; // GC is still used for copyArea
425     private int validatedGCForegroundPixel = 0;
426     private XORComposite validatedXorComp;
427     private int xid;
428     public int picture;
429     public XRCompositeManager maskBuffer;
430 
431     private Region validatedClip;
432     private Region validatedGCClip;
433     private boolean validatedExposures = true;
434 
435     boolean transformInUse = false;
436     AffineTransform validatedSourceTransform = new AffineTransform();
437     AffineTransform staticSrcTx = null;
438     int validatedRepeat = XRUtils.RepeatNone;
439     int validatedFilter = XRUtils.FAST;
440 
441     /**
442      * Validates an XRSurfaceData when used as source. Note that the clip is
443      * applied when used as source as well as destination.
444      */
validateAsSource(AffineTransform sxForm, int repeat, int filter)445     void validateAsSource(AffineTransform sxForm, int repeat, int filter) {
446 
447         if (validatedClip != null) {
448             validatedClip = null;
449             renderQueue.setClipRectangles(picture, null);
450         }
451 
452         if (validatedRepeat != repeat && repeat != -1) {
453             validatedRepeat = repeat;
454             renderQueue.setPictureRepeat(picture, repeat);
455         }
456 
457         if (sxForm == null) {
458             if (transformInUse) {
459                 validatedSourceTransform.setToIdentity();
460                 renderQueue.setPictureTransform(picture,
461                                                 validatedSourceTransform);
462                 transformInUse = false;
463             }
464         } else if (!transformInUse ||
465                    (transformInUse && !sxForm.equals(validatedSourceTransform))) {
466 
467             validatedSourceTransform.setTransform(sxForm.getScaleX(),
468                                                   sxForm.getShearY(),
469                                                   sxForm.getShearX(),
470                                                   sxForm.getScaleY(),
471                                                   sxForm.getTranslateX(),
472                                                   sxForm.getTranslateY());
473 
474             AffineTransform srcTransform = validatedSourceTransform;
475             if(staticSrcTx != null) {
476                 // Apply static transform set when used as texture or gradient.
477                 // Create a copy to not modify validatedSourceTransform as
478                 // this would confuse the validation logic.
479                 srcTransform = new AffineTransform(validatedSourceTransform);
480                 srcTransform.preConcatenate(staticSrcTx);
481             }
482 
483             renderQueue.setPictureTransform(picture, srcTransform);
484             transformInUse = true;
485         }
486 
487         if (filter != validatedFilter && filter != -1) {
488             renderQueue.setFilter(picture, filter);
489             validatedFilter = filter;
490         }
491     }
492 
493     /**
494      * Validates the Surface when used as destination.
495      */
validateAsDestination(SunGraphics2D sg2d, Region clip)496     public void validateAsDestination(SunGraphics2D sg2d, Region clip) {
497         if (!isValid()) {
498             throw new InvalidPipeException("bounds changed");
499         }
500 
501         boolean updateGCClip = false;
502         if (clip != validatedClip) {
503             renderQueue.setClipRectangles(picture, clip);
504             validatedClip = clip;
505             updateGCClip = true;
506         }
507 
508         if (sg2d != null && sg2d.compositeState == SunGraphics2D.COMP_XOR) {
509             if (validatedXorComp != sg2d.getComposite()) {
510                 validatedXorComp = (XORComposite) sg2d.getComposite();
511                 renderQueue.setGCMode(xgc, false);
512             }
513 
514             // validate pixel
515             int pixel = sg2d.pixel;
516             if (validatedGCForegroundPixel != pixel) {
517                 int xorpixelmod = validatedXorComp.getXorPixel();
518                 renderQueue.setGCForeground(xgc, pixel ^ xorpixelmod);
519                 validatedGCForegroundPixel = pixel;
520             }
521 
522             if (updateGCClip) {
523                 renderQueue.setGCClipRectangles(xgc, clip);
524             }
525         }
526     }
527 
makePipes()528     public synchronized void makePipes() { /*
529                                             * TODO: Why is this synchronized,
530                                             * but access not?
531                                             */
532         if (xrpipe == null) {
533             try {
534                 SunToolkit.awtLock();
535                 xgc = XCreateGC(getNativeOps());
536 
537                 xrpipe = new XRRenderer(maskBuffer.getMaskBuffer());
538                 xrtxpipe = new PixelToShapeConverter(xrpipe);
539                 xrtextpipe = maskBuffer.getTextRenderer();
540                 xrDrawImage = new XRDrawImage();
541 
542             } finally {
543                 SunToolkit.awtUnlock();
544             }
545         }
546     }
547 
548     public static class XRWindowSurfaceData extends XRSurfaceData {
549 
550         protected final int scale;
551 
XRWindowSurfaceData(X11ComponentPeer peer, XRGraphicsConfig gc, SurfaceType sType)552         public XRWindowSurfaceData(X11ComponentPeer peer,
553                                    XRGraphicsConfig gc, SurfaceType sType) {
554             super(peer, gc, sType, peer.getColorModel(),
555                   peer.getColorModel().getPixelSize(), Transparency.OPAQUE);
556 
557             this.scale = gc.getScale();
558 
559             if (isXRDrawableValid()) {
560                 // If we have a 32 bit color model for the window it needs
561                 // alpha to support translucency of the window so we need
562                 // to get the ARGB32 XRender picture format else for
563                 // 24 bit colormodel we need RGB24 or OPAQUE pictureformat.
564                 if (peer.getColorModel().getPixelSize() == 32) {
565                      initXRender(XRUtils.
566                       getPictureFormatForTransparency(Transparency.TRANSLUCENT));
567                  }
568                  else {
569                      initXRender(XRUtils.
570                        getPictureFormatForTransparency(Transparency.OPAQUE));
571                  }
572                 makePipes();
573             }
574         }
575 
getReplacement()576         public SurfaceData getReplacement() {
577             return peer.getSurfaceData();
578         }
579 
getBounds()580         public Rectangle getBounds() {
581             Rectangle r = peer.getBounds();
582             r.x = r.y = 0;
583             r.width *= scale;
584             r.height *= scale;
585             return r;
586         }
587 
588         @Override
canSourceSendExposures(int x, int y, int w, int h)589         public boolean canSourceSendExposures(int x, int y, int w, int h) {
590             return true;
591         }
592 
593         /**
594          * Returns destination Component associated with this SurfaceData.
595          */
getDestination()596         public Object getDestination() {
597             return peer.getTarget();
598         }
599 
invalidate()600        public void invalidate() {
601            try {
602                SunToolkit.awtLock();
603                freeXSDOPicture(getNativeOps());
604            }finally {
605                SunToolkit.awtUnlock();
606            }
607 
608            super.invalidate();
609        }
610 
611         @Override
getDefaultScaleX()612         public double getDefaultScaleX() {
613             return scale;
614         }
615 
616         @Override
getDefaultScaleY()617         public double getDefaultScaleY() {
618             return scale;
619         }
620     }
621 
622     public static class XRInternalSurfaceData extends XRSurfaceData {
XRInternalSurfaceData(XRBackend renderQueue, int pictXid)623         public XRInternalSurfaceData(XRBackend renderQueue, int pictXid) {
624           super(renderQueue);
625           this.picture = pictXid;
626           this.transformInUse = false;
627         }
628 
canSourceSendExposures(int x, int y, int w, int h)629         public boolean canSourceSendExposures(int x, int y, int w, int h) {
630             return false;
631         }
632 
getBounds()633         public Rectangle getBounds() {
634             return null;
635         }
636 
getDestination()637         public Object getDestination() {
638             return null;
639         }
640 
getReplacement()641         public SurfaceData getReplacement() {
642             return null;
643         }
644     }
645 
646     public static class XRPixmapSurfaceData extends XRSurfaceData {
647         Image offscreenImage;
648         int width;
649         int height;
650         int transparency;
651         private final int scale;
652 
XRPixmapSurfaceData(XRGraphicsConfig gc, int width, int height, Image image, SurfaceType sType, ColorModel cm, long drawable, int transparency, int pictFormat, int depth, boolean isTexture)653         public XRPixmapSurfaceData(XRGraphicsConfig gc, int width, int height,
654                                    Image image, SurfaceType sType,
655                                    ColorModel cm, long drawable,
656                                    int transparency, int pictFormat,
657                                    int depth, boolean isTexture) {
658             super(null, gc, sType, cm, depth, transparency);
659             this.scale = isTexture ? 1 : gc.getDevice().getScaleFactor();
660             this.width = width * scale;
661             this.height = height * scale;
662             offscreenImage = image;
663             this.transparency = transparency;
664             initSurface(depth, this.width, this.height, drawable, pictFormat);
665 
666             initXRender(pictFormat);
667             makePipes();
668         }
669 
initSurface(int depth, int width, int height, long drawable, int pictFormat)670         public void initSurface(int depth, int width, int height,
671                                 long drawable, int pictFormat) {
672             try {
673                 SunToolkit.awtLock();
674                 XRInitSurface(depth, width, height, drawable, pictFormat);
675             } finally {
676                 SunToolkit.awtUnlock();
677             }
678         }
679 
getReplacement()680         public SurfaceData getReplacement() {
681             return restoreContents(offscreenImage);
682         }
683 
684         /**
685          * Need this since the surface data is created with the color model of
686          * the target GC, which is always opaque. But in SunGraphics2D.blitSD we
687          * choose loops based on the transparency on the source SD, so it could
688          * choose wrong loop (blit instead of blitbg, for example).
689          */
getTransparency()690         public int getTransparency() {
691             return transparency;
692         }
693 
getBounds()694         public Rectangle getBounds() {
695             return new Rectangle(width, height);
696         }
697 
698         @Override
canSourceSendExposures(int x, int y, int w, int h)699         public boolean canSourceSendExposures(int x, int y, int w, int h) {
700             return (x < 0 || y < 0 || (x + w) > width || (y + h) > height);
701         }
702 
flush()703         public void flush() {
704             /*
705              * We need to invalidate the surface before disposing the native
706              * Drawable and Picture. This way if an application tries to render
707              * to an already flushed XRSurfaceData, we will notice in the
708              * validate() method above that it has been invalidated, and we will
709              * avoid using those native resources that have already been
710              * disposed.
711              */
712             invalidate();
713             flushNativeSurface();
714         }
715 
716         /**
717          * Returns destination Image associated with this SurfaceData.
718          */
getDestination()719         public Object getDestination() {
720             return offscreenImage;
721         }
722 
723         @Override
getDefaultScaleX()724         public double getDefaultScaleX() {
725             return scale;
726         }
727 
728         @Override
getDefaultScaleY()729         public double getDefaultScaleY() {
730             return scale;
731         }
732     }
733 
getGC()734     public long getGC() {
735         return xgc;
736     }
737 
738     public static class LazyPipe extends ValidatePipe {
validate(SunGraphics2D sg2d)739         public boolean validate(SunGraphics2D sg2d) {
740             XRSurfaceData xsd = (XRSurfaceData) sg2d.surfaceData;
741             if (!xsd.isXRDrawableValid()) {
742                 return false;
743             }
744             xsd.makePipes();
745             return super.validate(sg2d);
746         }
747     }
748 
getPicture()749     public int getPicture() {
750         return picture;
751     }
752 
getXid()753     public int getXid() {
754         return xid;
755     }
756 
getGraphicsConfig()757     public XRGraphicsConfig getGraphicsConfig() {
758         return graphicsConfig;
759     }
760 
setStaticSrcTx(AffineTransform staticSrcTx)761     public void setStaticSrcTx(AffineTransform staticSrcTx) {
762         this.staticSrcTx = staticSrcTx;
763     }
764 }
765