1 /*
   2  * Copyright 1999-2008 Sun Microsystems, Inc.  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.  Sun designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22  * CA 95054 USA or visit www.sun.com if you need additional information or
  23  * have any questions.
  24  */
  25 
  26 package sun.java2d.windows;
  27 
  28 import java.awt.Rectangle;
  29 import java.awt.GraphicsConfiguration;
  30 import java.awt.color.ColorSpace;
  31 import java.awt.image.ColorModel;
  32 import java.awt.image.ComponentColorModel;
  33 import java.awt.image.DirectColorModel;
  34 import java.awt.image.IndexColorModel;
  35 import java.awt.image.Raster;
  36 
  37 import sun.awt.SunHints;
  38 import sun.awt.Win32GraphicsConfig;
  39 import sun.awt.Win32GraphicsDevice;
  40 import sun.awt.windows.WComponentPeer;
  41 import sun.awt.windows.WFileDialogPeer;
  42 import sun.awt.windows.WPrintDialogPeer;
  43 import sun.java2d.ScreenUpdateManager;
  44 import sun.java2d.SunGraphics2D;
  45 import sun.java2d.SurfaceData;
  46 import sun.java2d.SurfaceDataProxy;
  47 import sun.java2d.pipe.Region;
  48 import sun.java2d.pipe.PixelToShapeConverter;
  49 import sun.java2d.loops.GraphicsPrimitive;
  50 import sun.java2d.loops.SurfaceType;
  51 import sun.java2d.loops.CompositeType;
  52 import sun.java2d.loops.RenderLoops;
  53 import sun.java2d.loops.XORComposite;
  54 
  55 public class GDIWindowSurfaceData extends SurfaceData {
  56     private WComponentPeer peer;
  57     private Win32GraphicsConfig graphicsConfig;
  58     private RenderLoops solidloops;
  59 
  60     // GDI onscreen surface type
  61     public static final String
  62         DESC_GDI                = "GDI";
  63 
  64     // Generic GDI surface type - used for registering all loops
  65     public static final SurfaceType AnyGdi =
  66         SurfaceType.IntRgb.deriveSubType(DESC_GDI);
  67 
  68     public static final SurfaceType IntRgbGdi =
  69         SurfaceType.IntRgb.deriveSubType(DESC_GDI);
  70 
  71     public static final SurfaceType Ushort565RgbGdi =
  72         SurfaceType.Ushort565Rgb.deriveSubType(DESC_GDI);
  73 
  74     public static final SurfaceType Ushort555RgbGdi =
  75         SurfaceType.Ushort555Rgb.deriveSubType(DESC_GDI);
  76 
  77     public static final SurfaceType ThreeByteBgrGdi =
  78         SurfaceType.ThreeByteBgr.deriveSubType(DESC_GDI);
  79 
  80     private static native void initIDs(Class xorComp);
  81 
  82     static {
  83         initIDs(XORComposite.class);
  84         if (WindowsFlags.isGdiBlitEnabled()) {
  85             // Register our gdi Blit loops
  86             GDIBlitLoops.register();
  87         }
  88     }
  89 
  90     public static SurfaceType getSurfaceType(ColorModel cm) {
  91         switch (cm.getPixelSize()) {
  92         case 32:
  93         case 24:
  94             if (cm instanceof DirectColorModel) {
  95                 if (((DirectColorModel)cm).getRedMask() == 0xff0000) {
  96                     return IntRgbGdi;
  97                 } else {
  98                     return SurfaceType.IntRgbx;
  99                 }
 100             } else {
 101                 return ThreeByteBgrGdi;
 102             }
 103         case 15:
 104             return Ushort555RgbGdi;
 105         case 16:
 106             if ((cm instanceof DirectColorModel) &&
 107                 (((DirectColorModel)cm).getBlueMask() == 0x3e))
 108             {
 109                 return SurfaceType.Ushort555Rgbx;
 110             } else {
 111                 return Ushort565RgbGdi;
 112             }
 113         case 8:
 114             if (cm.getColorSpace().getType() == ColorSpace.TYPE_GRAY &&
 115                 cm instanceof ComponentColorModel) {
 116                 return SurfaceType.ByteGray;
 117             } else if (cm instanceof IndexColorModel &&
 118                        isOpaqueGray((IndexColorModel)cm)) {
 119                 return SurfaceType.Index8Gray;
 120             } else {
 121                 return SurfaceType.ByteIndexedOpaque;
 122             }
 123         default:
 124             throw new sun.java2d.InvalidPipeException("Unsupported bit " +
 125                                                       "depth: " +
 126                                                       cm.getPixelSize());
 127         }
 128     }
 129 
 130     public static GDIWindowSurfaceData createData(WComponentPeer peer) {
 131         SurfaceType sType = getSurfaceType(peer.getDeviceColorModel());
 132         return new GDIWindowSurfaceData(peer, sType);
 133     }
 134 
 135     @Override
 136     public SurfaceDataProxy makeProxyFor(SurfaceData srcData) {
 137         return SurfaceDataProxy.UNCACHED;
 138     }
 139 
 140     public Raster getRaster(int x, int y, int w, int h) {
 141         throw new InternalError("not implemented yet");
 142     }
 143 
 144     protected static GDIRenderer gdiPipe;
 145     protected static PixelToShapeConverter gdiTxPipe;
 146 
 147     static {
 148         gdiPipe = new GDIRenderer();
 149         if (GraphicsPrimitive.tracingEnabled()) {
 150             gdiPipe = gdiPipe.traceWrap();
 151         }
 152         gdiTxPipe = new PixelToShapeConverter(gdiPipe);
 153 
 154     }
 155 
 156     public void validatePipe(SunGraphics2D sg2d) {
 157         if (sg2d.antialiasHint != SunHints.INTVAL_ANTIALIAS_ON &&
 158             sg2d.paintState <= sg2d.PAINT_ALPHACOLOR &&
 159             (sg2d.compositeState <= sg2d.COMP_ISCOPY ||
 160              sg2d.compositeState == sg2d.COMP_XOR))
 161         {
 162             if (sg2d.clipState == sg2d.CLIP_SHAPE) {
 163                 // Do this to init textpipe correctly; we will override the
 164                 // other non-text pipes below
 165                 // REMIND: we should clean this up eventually instead of
 166                 // having this work duplicated.
 167                 super.validatePipe(sg2d);
 168             } else {
 169                 switch (sg2d.textAntialiasHint) {
 170 
 171                 case SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT:
 172                     /* equate DEFAULT to OFF which it is for us */
 173                 case SunHints.INTVAL_TEXT_ANTIALIAS_OFF:
 174                     sg2d.textpipe = solidTextRenderer;
 175                     break;
 176 
 177                 case SunHints.INTVAL_TEXT_ANTIALIAS_ON:
 178                     sg2d.textpipe = aaTextRenderer;
 179                     break;
 180 
 181                 default:
 182                     switch (sg2d.getFontInfo().aaHint) {
 183 
 184                     case SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HRGB:
 185                     case SunHints.INTVAL_TEXT_ANTIALIAS_LCD_VRGB:
 186                         sg2d.textpipe = lcdTextRenderer;
 187                         break;
 188 
 189                     case SunHints.INTVAL_TEXT_ANTIALIAS_ON:
 190                         sg2d.textpipe = aaTextRenderer;
 191                         break;
 192 
 193                     default:
 194                         sg2d.textpipe = solidTextRenderer;
 195                     }
 196                 }
 197             }
 198             sg2d.imagepipe = imagepipe;
 199             if (sg2d.transformState >= sg2d.TRANSFORM_TRANSLATESCALE) {
 200                 sg2d.drawpipe = gdiTxPipe;
 201                 sg2d.fillpipe = gdiTxPipe;
 202             } else if (sg2d.strokeState != sg2d.STROKE_THIN){
 203                 sg2d.drawpipe = gdiTxPipe;
 204                 sg2d.fillpipe = gdiPipe;
 205             } else {
 206                 sg2d.drawpipe = gdiPipe;
 207                 sg2d.fillpipe = gdiPipe;
 208             }
 209             sg2d.shapepipe = gdiPipe;
 210             // This is needed for AA text.
 211             // Note that even a SolidTextRenderer can dispatch AA text
 212             // if a GlyphVector overrides the AA setting.
 213             // We use getRenderLoops() rather than setting solidloops
 214             // directly so that we get the appropriate loops in XOR mode.
 215             sg2d.setLoops(getRenderLoops(sg2d));
 216         } else {
 217             super.validatePipe(sg2d);
 218         }
 219     }
 220 
 221     public RenderLoops getRenderLoops(SunGraphics2D sg2d) {
 222         if (sg2d.paintState <= sg2d.PAINT_ALPHACOLOR &&
 223             sg2d.compositeState <= sg2d.COMP_ISCOPY)
 224         {
 225             return solidloops;
 226         }
 227         return super.getRenderLoops(sg2d);
 228     }
 229 
 230     public GraphicsConfiguration getDeviceConfiguration() {
 231         return graphicsConfig;
 232     }
 233 
 234     /**
 235      * Initializes the native Ops pointer.
 236      */
 237     private native void initOps(WComponentPeer peer, int depth, int redMask,
 238                                 int greenMask, int blueMask, int screen);
 239 
 240     private GDIWindowSurfaceData(WComponentPeer peer, SurfaceType sType) {
 241         super(sType, peer.getDeviceColorModel());
 242         ColorModel cm = peer.getDeviceColorModel();
 243         this.peer = peer;
 244         int rMask = 0, gMask = 0, bMask = 0;
 245         int depth;
 246         switch (cm.getPixelSize()) {
 247         case 32:
 248         case 24:
 249             if (cm instanceof DirectColorModel) {
 250                 depth = 32;
 251             } else {
 252                 depth = 24;
 253             }
 254             break;
 255         default:
 256             depth = cm.getPixelSize();
 257         }
 258         if (cm instanceof DirectColorModel) {
 259             DirectColorModel dcm = (DirectColorModel)cm;
 260             rMask = dcm.getRedMask();
 261             gMask = dcm.getGreenMask();
 262             bMask = dcm.getBlueMask();
 263         }
 264         this.graphicsConfig =
 265             (Win32GraphicsConfig) peer.getGraphicsConfiguration();
 266         this.solidloops = graphicsConfig.getSolidLoops(sType);
 267         if (peer instanceof WFileDialogPeer ||
 268             peer instanceof WPrintDialogPeer )
 269         {
 270             // REMIND: Awful hack.  The right fix for this problem
 271             // would be for these type of Peers to not even use a
 272             // GDIWindowSurfaceData object since they never do any
 273             // rendering.  Or they could actually implement the
 274             // functionality needed in initOps.  But this seems
 275             // to work for now.  See bug 4391928 for more info.
 276             return;
 277         }
 278         Win32GraphicsDevice gd =
 279             (Win32GraphicsDevice)graphicsConfig.getDevice();
 280         initOps(peer, depth, rMask, gMask, bMask, gd.getScreen());
 281         setBlitProxyKey(graphicsConfig.getProxyKey());
 282     }
 283 
 284     /**
 285      * {@inheritDoc}
 286      *
 287      * Overridden to use ScreenUpdateManager to obtain the replacement surface.
 288      *
 289      * @see sun.java2d.ScreenUpdateManager#getReplacementScreenSurface
 290      */
 291     @Override
 292     public SurfaceData getReplacement() {
 293         ScreenUpdateManager mgr = ScreenUpdateManager.getInstance();
 294         return mgr.getReplacementScreenSurface(peer, this);
 295     }
 296 
 297     public Rectangle getBounds() {
 298         Rectangle r = peer.getBounds();
 299         r.x = r.y = 0;
 300         return r;
 301     }
 302 
 303     public boolean copyArea(SunGraphics2D sg2d,
 304                             int x, int y, int w, int h, int dx, int dy)
 305     {
 306         CompositeType comptype = sg2d.imageComp;
 307         if (sg2d.transformState < sg2d.TRANSFORM_TRANSLATESCALE &&
 308             sg2d.clipState != sg2d.CLIP_SHAPE &&
 309             (CompositeType.SrcOverNoEa.equals(comptype) ||
 310              CompositeType.SrcNoEa.equals(comptype)))
 311         {
 312             x += sg2d.transX;
 313             y += sg2d.transY;
 314             int dstx1 = x + dx;
 315             int dsty1 = y + dy;
 316             int dstx2 = dstx1 + w;
 317             int dsty2 = dsty1 + h;
 318             Region clip = sg2d.getCompClip();
 319             if (dstx1 < clip.getLoX()) dstx1 = clip.getLoX();
 320             if (dsty1 < clip.getLoY()) dsty1 = clip.getLoY();
 321             if (dstx2 > clip.getHiX()) dstx2 = clip.getHiX();
 322             if (dsty2 > clip.getHiY()) dsty2 = clip.getHiY();
 323             if (dstx1 < dstx2 && dsty1 < dsty2) {
 324                 gdiPipe.devCopyArea(this, dstx1 - dx, dsty1 - dy,
 325                                     dx, dy,
 326                                     dstx2 - dstx1, dsty2 - dsty1);
 327             }
 328             return true;
 329         }
 330         return false;
 331     }
 332 
 333     private native void invalidateSD();
 334     @Override
 335     public void invalidate() {
 336         if (isValid()) {
 337             invalidateSD();
 338             super.invalidate();
 339             //peer.invalidateBackBuffer();
 340         }
 341     }
 342 
 343     /**
 344      * Returns destination Component associated with this SurfaceData.
 345      */
 346     @Override
 347     public Object getDestination() {
 348         return peer.getTarget();
 349     }
 350 
 351     public WComponentPeer getPeer() {
 352         return peer;
 353     }
 354 }