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