src/share/classes/sun/java2d/pipe/DrawImage.java

Print this page




 129                        0, 0, imgw, imgh, bgColor);
 130         return true;
 131     }
 132 
 133     /*
 134      * This method is only called in those circumstances where the
 135      * operation has a non-null secondary transform specfied.  Its
 136      * role is to check for various optimizations based on the types
 137      * of both the secondary and SG2D transforms and to do some
 138      * quick calculations to avoid having to combine the transforms
 139      * and/or to call a more generalized method.
 140      */
 141     protected void transformImage(SunGraphics2D sg, Image img, int x, int y,
 142                                   AffineTransform extraAT, int interpType)
 143     {
 144         int txtype = extraAT.getType();
 145         int imgw = img.getWidth(null);
 146         int imgh = img.getHeight(null);
 147         boolean checkfinalxform;
 148 
 149         if (sg.transformState <= sg.TRANSFORM_ANY_TRANSLATE &&
 150             (txtype == AffineTransform.TYPE_IDENTITY ||
 151              txtype == AffineTransform.TYPE_TRANSLATION))
 152         {
 153             // First optimization - both are some kind of translate
 154 
 155             // Combine the translations and check if interpolation is necessary.
 156             double tx = extraAT.getTranslateX();
 157             double ty = extraAT.getTranslateY();
 158             tx += sg.transform.getTranslateX();
 159             ty += sg.transform.getTranslateY();
 160             int itx = (int) Math.floor(tx + 0.5);
 161             int ity = (int) Math.floor(ty + 0.5);
 162             if (interpType == AffineTransformOp.TYPE_NEAREST_NEIGHBOR ||
 163                 (closeToInteger(itx, tx) && closeToInteger(ity, ty)))
 164             {
 165                 renderImageCopy(sg, img, null, x+itx, y+ity, 0, 0, imgw, imgh);
 166                 return;
 167             }
 168             checkfinalxform = false;
 169         } else if (sg.transformState <= sg.TRANSFORM_TRANSLATESCALE &&
 170                    ((txtype & (AffineTransform.TYPE_FLIP |
 171                                AffineTransform.TYPE_MASK_ROTATION |
 172                                AffineTransform.TYPE_GENERAL_TRANSFORM)) == 0))
 173         {
 174             // Second optimization - both are some kind of translate or scale
 175 
 176             // Combine the scales and check if interpolation is necessary.
 177 
 178             // Transform source bounds by extraAT,
 179             // then translate the bounds again by x, y
 180             // then transform the bounds again by sg.transform
 181             double coords[] = new double[] {
 182                 0, 0, imgw, imgh,
 183             };
 184             extraAT.transform(coords, 0, coords, 0, 2);
 185             coords[0] += x;
 186             coords[1] += y;
 187             coords[2] += x;
 188             coords[3] += y;
 189             sg.transform.transform(coords, 0, coords, 0, 2);


 327         Graphics2D g2d = bimg.createGraphics();
 328         g2d.setComposite(AlphaComposite.Src);
 329         if (bgColor != null) {
 330             g2d.setColor(bgColor);
 331             g2d.fillRect(0, 0, sx2-sx1, sy2-sy1);
 332             g2d.setComposite(AlphaComposite.SrcOver);
 333         }
 334         g2d.drawImage(img, -sx1, -sy1, null);
 335         g2d.dispose();
 336         return bimg;
 337     }
 338 
 339     protected void renderImageXform(SunGraphics2D sg, Image img,
 340                                     AffineTransform tx, int interpType,
 341                                     int sx1, int sy1, int sx2, int sy2,
 342                                     Color bgColor)
 343     {
 344         Region clip = sg.getCompClip();
 345         SurfaceData dstData = sg.surfaceData;
 346         SurfaceData srcData = dstData.getSourceSurfaceData(img,
 347                                                            sg.TRANSFORM_GENERIC,
 348                                                            sg.imageComp,
 349                                                            bgColor);
 350 
 351         if (srcData == null) {
 352             img = getBufferedImage(img);
 353             srcData = dstData.getSourceSurfaceData(img,
 354                                                    sg.TRANSFORM_GENERIC,
 355                                                    sg.imageComp,
 356                                                    bgColor);
 357             if (srcData == null) {
 358                 // REMIND: Is this correct?  Can this happen?
 359                 return;
 360             }
 361         }
 362 
 363         if (isBgOperation(srcData, bgColor)) {
 364             // We cannot perform bg operations during transform so make
 365             // an opaque temp image with the appropriate background
 366             // and work from there.
 367             img = makeBufferedImage(img, bgColor, BufferedImage.TYPE_INT_RGB,
 368                                     sx1, sy1, sx2, sy2);
 369             // Temp image has appropriate subimage at 0,0 now.
 370             sx2 -= sx1;
 371             sy2 -= sy1;
 372             sx1 = sy1 = 0;
 373 
 374             srcData = dstData.getSourceSurfaceData(img,
 375                                                    sg.TRANSFORM_GENERIC,
 376                                                    sg.imageComp,
 377                                                    bgColor);
 378         }
 379 
 380         SurfaceType srcType = srcData.getSurfaceType();
 381         TransformHelper helper = TransformHelper.getFromCache(srcType);
 382 
 383         if (helper == null) {
 384             /* We have no helper for this source image type.
 385              * But we know that we do have helpers for both RGB and ARGB,
 386              * so convert to one of those types depending on transparency.
 387              * ARGB_PRE might be a better choice if the source image has
 388              * alpha, but it may cause some recursion here since we only
 389              * tend to have converters that convert to ARGB.
 390              */
 391             int type = ((srcData.getTransparency() == Transparency.OPAQUE)
 392                         ? BufferedImage.TYPE_INT_RGB
 393                         : BufferedImage.TYPE_INT_ARGB);
 394             img = makeBufferedImage(img, null, type, sx1, sy1, sx2, sy2);
 395             // Temp image has appropriate subimage at 0,0 now.
 396             sx2 -= sx1;
 397             sy2 -= sy1;
 398             sx1 = sy1 = 0;
 399 
 400             srcData = dstData.getSourceSurfaceData(img,
 401                                                    sg.TRANSFORM_GENERIC,
 402                                                    sg.imageComp,
 403                                                    null);
 404             srcType = srcData.getSurfaceType();
 405             helper = TransformHelper.getFromCache(srcType);
 406             // assert(helper != null);
 407         }
 408 
 409         AffineTransform itx;
 410         try {
 411             itx = tx.createInverse();
 412         } catch (NoninvertibleTransformException e) {
 413             // Non-invertible transform means no output
 414             return;
 415         }
 416 
 417         /*
 418          * Find the maximum bounds on the destination that will be
 419          * affected by the transformed source.  First, transform all
 420          * four corners of the source and then min and max the resulting
 421          * destination coordinates of the transformed corners.


 432         tx.transform(coords, 0, coords, 0, 4);
 433         double ddx1, ddy1, ddx2, ddy2;
 434         ddx1 = ddx2 = coords[0];
 435         ddy1 = ddy2 = coords[1];
 436         for (int i = 2; i < coords.length; i += 2) {
 437             double d = coords[i];
 438             if (ddx1 > d) ddx1 = d;
 439             else if (ddx2 < d) ddx2 = d;
 440             d = coords[i+1];
 441             if (ddy1 > d) ddy1 = d;
 442             else if (ddy2 < d) ddy2 = d;
 443         }
 444         int dx1 = (int) Math.floor(ddx1);
 445         int dy1 = (int) Math.floor(ddy1);
 446         int dx2 = (int) Math.ceil(ddx2);
 447         int dy2 = (int) Math.ceil(ddy2);
 448 
 449         SurfaceType dstType = dstData.getSurfaceType();
 450         MaskBlit maskblit;
 451         Blit blit;
 452         if (sg.compositeState <= sg.COMP_ALPHA) {
 453             /* NOTE: We either have, or we can make,
 454              * a MaskBlit for any alpha composite type
 455              */
 456             maskblit = MaskBlit.getFromCache(SurfaceType.IntArgbPre,
 457                                              sg.imageComp,
 458                                              dstType);
 459 
 460             /* NOTE: We can only use the native TransformHelper
 461              * func to go directly to the dest if both the helper
 462              * and the MaskBlit are native.
 463              * All helpers are native at this point, but some MaskBlit
 464              * objects are implemented in Java, so we need to check.
 465              */
 466             if (maskblit.getNativePrim() != 0) {
 467                 // We can render directly.
 468                 helper.Transform(maskblit, srcData, dstData,
 469                                  sg.composite, clip,
 470                                  itx, interpType,
 471                                  sx1, sy1, sx2, sy2,
 472                                  dx1, dy1, dx2, dy2,


 548     }
 549 
 550     // Render an image using only integer translation
 551     // (no scale or transform or sub-pixel interpolated translations).
 552     protected boolean renderImageCopy(SunGraphics2D sg, Image img,
 553                                       Color bgColor,
 554                                       int dx, int dy,
 555                                       int sx, int sy,
 556                                       int w, int h)
 557     {
 558         Region clip = sg.getCompClip();
 559         SurfaceData dstData = sg.surfaceData;
 560 
 561         int attempts = 0;
 562         // Loop up to twice through; this gives us a chance to
 563         // revalidate the surfaceData objects in case of an exception
 564         // and try it once more
 565         while (true) {
 566             SurfaceData srcData =
 567                 dstData.getSourceSurfaceData(img,
 568                                              sg.TRANSFORM_ISIDENT,
 569                                              sg.imageComp,
 570                                              bgColor);
 571             if (srcData == null) {
 572                 return false;
 573             }
 574 
 575             try {
 576                 SurfaceType srcType = srcData.getSurfaceType();
 577                 SurfaceType dstType = dstData.getSurfaceType();
 578                 blitSurfaceData(sg, clip,
 579                                 srcData, dstData, srcType, dstType,
 580                                 sx, sy, dx, dy, w, h, bgColor);
 581                 return true;
 582             } catch (NullPointerException e) {
 583                 if (!(SurfaceData.isNull(dstData) ||
 584                       SurfaceData.isNull(srcData)))
 585                 {
 586                     // Something else caused the exception, throw it...
 587                     throw e;
 588                 }


 611                                        int sx2, int sy2,
 612                                        double dx1, double dy1,
 613                                        double dx2, double dy2)
 614     {
 615         // Currently only NEAREST_NEIGHBOR interpolation is implemented
 616         // for ScaledBlit operations.
 617         if (interpType != AffineTransformOp.TYPE_NEAREST_NEIGHBOR) {
 618             return false;
 619         }
 620 
 621         Region clip = sg.getCompClip();
 622         SurfaceData dstData = sg.surfaceData;
 623 
 624         int attempts = 0;
 625         // Loop up to twice through; this gives us a chance to
 626         // revalidate the surfaceData objects in case of an exception
 627         // and try it once more
 628         while (true) {
 629             SurfaceData srcData =
 630                 dstData.getSourceSurfaceData(img,
 631                                              sg.TRANSFORM_TRANSLATESCALE,
 632                                              sg.imageComp,
 633                                              bgColor);
 634 
 635             if (srcData == null || isBgOperation(srcData, bgColor)) {
 636                 return false;
 637             }
 638 
 639             try {
 640                 SurfaceType srcType = srcData.getSurfaceType();
 641                 SurfaceType dstType = dstData.getSurfaceType();
 642                 return scaleSurfaceData(sg, clip,
 643                                         srcData, dstData, srcType, dstType,
 644                                         sx1, sy1, sx2, sy2,
 645                                         dx1, dy1, dx2, dy2);
 646             } catch (NullPointerException e) {
 647                 if (!SurfaceData.isNull(dstData)) {
 648                     // Something else caused the exception, throw it...
 649                     throw e;
 650                 }
 651                 return false;


 783      * need to make sure that image transformations are
 784      * "very close" to integer device coordinates before
 785      * we decide to use an integer scale or copy operation
 786      * as a substitute and the fact that roundoff errors
 787      * in AffineTransforms are frequently introduced by
 788      * performing multiple sequential operations on them.
 789      *
 790      * The evaluation of bug 4990624 details the potential
 791      * for this error cutoff to result in display anomalies
 792      * in different types of image operations and how this
 793      * value represents a good compromise here.
 794      */
 795     private static final double MAX_TX_ERROR = .0001;
 796 
 797     public static boolean closeToInteger(int i, double d) {
 798         return (Math.abs(d-i) < MAX_TX_ERROR);
 799     }
 800 
 801     public static boolean isSimpleTranslate(SunGraphics2D sg) {
 802         int ts = sg.transformState;
 803         if (ts <= sg.TRANSFORM_INT_TRANSLATE) {
 804             // Integer translates are always "simple"
 805             return true;
 806         }
 807         if (ts >= sg.TRANSFORM_TRANSLATESCALE) {
 808             // Scales and beyond are always "not simple"
 809             return false;
 810         }
 811         // non-integer translates are only simple when not interpolating
 812         if (sg.interpolationType == AffineTransformOp.TYPE_NEAREST_NEIGHBOR) {
 813             return true;
 814         }
 815         return false;
 816     }
 817 
 818     protected static boolean isBgOperation(SurfaceData srcData, Color bgColor) {
 819         // If we cannot get the srcData, then cannot assume anything about
 820         // the image
 821         return ((srcData == null) ||
 822                 ((bgColor != null) &&
 823                  (srcData.getTransparency() != Transparency.OPAQUE)));
 824     }
 825 
 826     protected BufferedImage getBufferedImage(Image img) {
 827         if (img instanceof BufferedImage) {


 829         }
 830         // Must be VolatileImage; get BufferedImage representation
 831         return ((VolatileImage)img).getSnapshot();
 832     }
 833 
 834     /*
 835      * Return the color model to be used with this BufferedImage and
 836      * transform.
 837      */
 838     private ColorModel getTransformColorModel(SunGraphics2D sg,
 839                                               BufferedImage bImg,
 840                                               AffineTransform tx) {
 841         ColorModel cm = bImg.getColorModel();
 842         ColorModel dstCM = cm;
 843 
 844         if (tx.isIdentity()) {
 845             return dstCM;
 846         }
 847         int type = tx.getType();
 848         boolean needTrans =
 849             ((type&(tx.TYPE_MASK_ROTATION|tx.TYPE_GENERAL_TRANSFORM)) != 0);
 850         if (! needTrans && type != tx.TYPE_TRANSLATION && type != tx.TYPE_IDENTITY)



 851         {
 852             double[] mtx = new double[4];
 853             tx.getMatrix(mtx);
 854             // Check out the matrix.  A non-integral scale will force ARGB
 855             // since the edge conditions cannot be guaranteed.
 856             needTrans = (mtx[0] != (int)mtx[0] || mtx[3] != (int)mtx[3]);
 857         }
 858 
 859         if (sg.renderHint != SunHints.INTVAL_RENDER_QUALITY) {
 860             if (cm instanceof IndexColorModel) {
 861                 Raster raster = bImg.getRaster();
 862                 IndexColorModel icm = (IndexColorModel) cm;
 863                 // Just need to make sure that we have a transparent pixel
 864                 if (needTrans && cm.getTransparency() == cm.OPAQUE) {
 865                     // Fix 4221407
 866                     if (raster instanceof sun.awt.image.BytePackedRaster) {
 867                         dstCM = ColorModel.getRGBdefault();
 868                     }
 869                     else {
 870                         double[] matrix = new double[6];
 871                         tx.getMatrix(matrix);
 872                         if (matrix[1] == 0. && matrix[2] ==0.
 873                             && matrix[4] == 0. && matrix[5] == 0.) {
 874                             // Only scaling so do not need to create
 875                         }
 876                         else {
 877                             int mapSize = icm.getMapSize();
 878                             if (mapSize < 256) {
 879                                 int[] cmap = new int[mapSize+1];
 880                                 icm.getRGBs(cmap);
 881                                 cmap[mapSize] = 0x0000;
 882                                 dstCM = new
 883                                     IndexColorModel(icm.getPixelSize(),
 884                                                     mapSize+1,
 885                                                     cmap, 0, true, mapSize,
 886                                                     DataBuffer.TYPE_BYTE);
 887                             }
 888                             else {
 889                                 dstCM = ColorModel.getRGBdefault();
 890                             }
 891                         }  /* if (matrix[0] < 1.f ...) */
 892                     }   /* raster instanceof sun.awt.image.BytePackedRaster */
 893                 } /* if (cm.getTransparency() == cm.OPAQUE) */
 894             } /* if (cm instanceof IndexColorModel) */
 895             else if (needTrans && cm.getTransparency() == cm.OPAQUE) {
 896                 // Need a bitmask transparency
 897                 // REMIND: for now, use full transparency since no loops
 898                 // for bitmask
 899                 dstCM = ColorModel.getRGBdefault();
 900             }
 901         } /* if (sg.renderHint == RENDER_QUALITY) */
 902         else {
 903 
 904             if (cm instanceof IndexColorModel ||
 905                 (needTrans && cm.getTransparency() == cm.OPAQUE))
 906             {
 907                 // Need a bitmask transparency
 908                 // REMIND: for now, use full transparency since no loops
 909                 // for bitmask
 910                 dstCM = ColorModel.getRGBdefault();
 911             }
 912         }
 913 
 914         return dstCM;
 915     }
 916 
 917     protected void blitSurfaceData(SunGraphics2D sg,
 918                                    Region clipRegion,
 919                                    SurfaceData srcData,
 920                                    SurfaceData dstData,
 921                                    SurfaceType srcType,
 922                                    SurfaceType dstType,
 923                                    int sx, int sy, int dx, int dy,
 924                                    int w, int h,
 925                                    Color bgColor)




 129                        0, 0, imgw, imgh, bgColor);
 130         return true;
 131     }
 132 
 133     /*
 134      * This method is only called in those circumstances where the
 135      * operation has a non-null secondary transform specfied.  Its
 136      * role is to check for various optimizations based on the types
 137      * of both the secondary and SG2D transforms and to do some
 138      * quick calculations to avoid having to combine the transforms
 139      * and/or to call a more generalized method.
 140      */
 141     protected void transformImage(SunGraphics2D sg, Image img, int x, int y,
 142                                   AffineTransform extraAT, int interpType)
 143     {
 144         int txtype = extraAT.getType();
 145         int imgw = img.getWidth(null);
 146         int imgh = img.getHeight(null);
 147         boolean checkfinalxform;
 148 
 149         if (sg.transformState <= SunGraphics2D.TRANSFORM_ANY_TRANSLATE &&
 150             (txtype == AffineTransform.TYPE_IDENTITY ||
 151              txtype == AffineTransform.TYPE_TRANSLATION))
 152         {
 153             // First optimization - both are some kind of translate
 154 
 155             // Combine the translations and check if interpolation is necessary.
 156             double tx = extraAT.getTranslateX();
 157             double ty = extraAT.getTranslateY();
 158             tx += sg.transform.getTranslateX();
 159             ty += sg.transform.getTranslateY();
 160             int itx = (int) Math.floor(tx + 0.5);
 161             int ity = (int) Math.floor(ty + 0.5);
 162             if (interpType == AffineTransformOp.TYPE_NEAREST_NEIGHBOR ||
 163                 (closeToInteger(itx, tx) && closeToInteger(ity, ty)))
 164             {
 165                 renderImageCopy(sg, img, null, x+itx, y+ity, 0, 0, imgw, imgh);
 166                 return;
 167             }
 168             checkfinalxform = false;
 169         } else if (sg.transformState <= SunGraphics2D.TRANSFORM_TRANSLATESCALE &&
 170                    ((txtype & (AffineTransform.TYPE_FLIP |
 171                                AffineTransform.TYPE_MASK_ROTATION |
 172                                AffineTransform.TYPE_GENERAL_TRANSFORM)) == 0))
 173         {
 174             // Second optimization - both are some kind of translate or scale
 175 
 176             // Combine the scales and check if interpolation is necessary.
 177 
 178             // Transform source bounds by extraAT,
 179             // then translate the bounds again by x, y
 180             // then transform the bounds again by sg.transform
 181             double coords[] = new double[] {
 182                 0, 0, imgw, imgh,
 183             };
 184             extraAT.transform(coords, 0, coords, 0, 2);
 185             coords[0] += x;
 186             coords[1] += y;
 187             coords[2] += x;
 188             coords[3] += y;
 189             sg.transform.transform(coords, 0, coords, 0, 2);


 327         Graphics2D g2d = bimg.createGraphics();
 328         g2d.setComposite(AlphaComposite.Src);
 329         if (bgColor != null) {
 330             g2d.setColor(bgColor);
 331             g2d.fillRect(0, 0, sx2-sx1, sy2-sy1);
 332             g2d.setComposite(AlphaComposite.SrcOver);
 333         }
 334         g2d.drawImage(img, -sx1, -sy1, null);
 335         g2d.dispose();
 336         return bimg;
 337     }
 338 
 339     protected void renderImageXform(SunGraphics2D sg, Image img,
 340                                     AffineTransform tx, int interpType,
 341                                     int sx1, int sy1, int sx2, int sy2,
 342                                     Color bgColor)
 343     {
 344         Region clip = sg.getCompClip();
 345         SurfaceData dstData = sg.surfaceData;
 346         SurfaceData srcData = dstData.getSourceSurfaceData(img,
 347                                                            SunGraphics2D.TRANSFORM_GENERIC,
 348                                                            sg.imageComp,
 349                                                            bgColor);
 350 
 351         if (srcData == null) {
 352             img = getBufferedImage(img);
 353             srcData = dstData.getSourceSurfaceData(img,
 354                                                    SunGraphics2D.TRANSFORM_GENERIC,
 355                                                    sg.imageComp,
 356                                                    bgColor);
 357             if (srcData == null) {
 358                 // REMIND: Is this correct?  Can this happen?
 359                 return;
 360             }
 361         }
 362 
 363         if (isBgOperation(srcData, bgColor)) {
 364             // We cannot perform bg operations during transform so make
 365             // an opaque temp image with the appropriate background
 366             // and work from there.
 367             img = makeBufferedImage(img, bgColor, BufferedImage.TYPE_INT_RGB,
 368                                     sx1, sy1, sx2, sy2);
 369             // Temp image has appropriate subimage at 0,0 now.
 370             sx2 -= sx1;
 371             sy2 -= sy1;
 372             sx1 = sy1 = 0;
 373 
 374             srcData = dstData.getSourceSurfaceData(img,
 375                                                    SunGraphics2D.TRANSFORM_GENERIC,
 376                                                    sg.imageComp,
 377                                                    bgColor);
 378         }
 379 
 380         SurfaceType srcType = srcData.getSurfaceType();
 381         TransformHelper helper = TransformHelper.getFromCache(srcType);
 382 
 383         if (helper == null) {
 384             /* We have no helper for this source image type.
 385              * But we know that we do have helpers for both RGB and ARGB,
 386              * so convert to one of those types depending on transparency.
 387              * ARGB_PRE might be a better choice if the source image has
 388              * alpha, but it may cause some recursion here since we only
 389              * tend to have converters that convert to ARGB.
 390              */
 391             int type = ((srcData.getTransparency() == Transparency.OPAQUE)
 392                         ? BufferedImage.TYPE_INT_RGB
 393                         : BufferedImage.TYPE_INT_ARGB);
 394             img = makeBufferedImage(img, null, type, sx1, sy1, sx2, sy2);
 395             // Temp image has appropriate subimage at 0,0 now.
 396             sx2 -= sx1;
 397             sy2 -= sy1;
 398             sx1 = sy1 = 0;
 399 
 400             srcData = dstData.getSourceSurfaceData(img,
 401                                                    SunGraphics2D.TRANSFORM_GENERIC,
 402                                                    sg.imageComp,
 403                                                    null);
 404             srcType = srcData.getSurfaceType();
 405             helper = TransformHelper.getFromCache(srcType);
 406             // assert(helper != null);
 407         }
 408 
 409         AffineTransform itx;
 410         try {
 411             itx = tx.createInverse();
 412         } catch (NoninvertibleTransformException e) {
 413             // Non-invertible transform means no output
 414             return;
 415         }
 416 
 417         /*
 418          * Find the maximum bounds on the destination that will be
 419          * affected by the transformed source.  First, transform all
 420          * four corners of the source and then min and max the resulting
 421          * destination coordinates of the transformed corners.


 432         tx.transform(coords, 0, coords, 0, 4);
 433         double ddx1, ddy1, ddx2, ddy2;
 434         ddx1 = ddx2 = coords[0];
 435         ddy1 = ddy2 = coords[1];
 436         for (int i = 2; i < coords.length; i += 2) {
 437             double d = coords[i];
 438             if (ddx1 > d) ddx1 = d;
 439             else if (ddx2 < d) ddx2 = d;
 440             d = coords[i+1];
 441             if (ddy1 > d) ddy1 = d;
 442             else if (ddy2 < d) ddy2 = d;
 443         }
 444         int dx1 = (int) Math.floor(ddx1);
 445         int dy1 = (int) Math.floor(ddy1);
 446         int dx2 = (int) Math.ceil(ddx2);
 447         int dy2 = (int) Math.ceil(ddy2);
 448 
 449         SurfaceType dstType = dstData.getSurfaceType();
 450         MaskBlit maskblit;
 451         Blit blit;
 452         if (sg.compositeState <= SunGraphics2D.COMP_ALPHA) {
 453             /* NOTE: We either have, or we can make,
 454              * a MaskBlit for any alpha composite type
 455              */
 456             maskblit = MaskBlit.getFromCache(SurfaceType.IntArgbPre,
 457                                              sg.imageComp,
 458                                              dstType);
 459 
 460             /* NOTE: We can only use the native TransformHelper
 461              * func to go directly to the dest if both the helper
 462              * and the MaskBlit are native.
 463              * All helpers are native at this point, but some MaskBlit
 464              * objects are implemented in Java, so we need to check.
 465              */
 466             if (maskblit.getNativePrim() != 0) {
 467                 // We can render directly.
 468                 helper.Transform(maskblit, srcData, dstData,
 469                                  sg.composite, clip,
 470                                  itx, interpType,
 471                                  sx1, sy1, sx2, sy2,
 472                                  dx1, dy1, dx2, dy2,


 548     }
 549 
 550     // Render an image using only integer translation
 551     // (no scale or transform or sub-pixel interpolated translations).
 552     protected boolean renderImageCopy(SunGraphics2D sg, Image img,
 553                                       Color bgColor,
 554                                       int dx, int dy,
 555                                       int sx, int sy,
 556                                       int w, int h)
 557     {
 558         Region clip = sg.getCompClip();
 559         SurfaceData dstData = sg.surfaceData;
 560 
 561         int attempts = 0;
 562         // Loop up to twice through; this gives us a chance to
 563         // revalidate the surfaceData objects in case of an exception
 564         // and try it once more
 565         while (true) {
 566             SurfaceData srcData =
 567                 dstData.getSourceSurfaceData(img,
 568                                              SunGraphics2D.TRANSFORM_ISIDENT,
 569                                              sg.imageComp,
 570                                              bgColor);
 571             if (srcData == null) {
 572                 return false;
 573             }
 574 
 575             try {
 576                 SurfaceType srcType = srcData.getSurfaceType();
 577                 SurfaceType dstType = dstData.getSurfaceType();
 578                 blitSurfaceData(sg, clip,
 579                                 srcData, dstData, srcType, dstType,
 580                                 sx, sy, dx, dy, w, h, bgColor);
 581                 return true;
 582             } catch (NullPointerException e) {
 583                 if (!(SurfaceData.isNull(dstData) ||
 584                       SurfaceData.isNull(srcData)))
 585                 {
 586                     // Something else caused the exception, throw it...
 587                     throw e;
 588                 }


 611                                        int sx2, int sy2,
 612                                        double dx1, double dy1,
 613                                        double dx2, double dy2)
 614     {
 615         // Currently only NEAREST_NEIGHBOR interpolation is implemented
 616         // for ScaledBlit operations.
 617         if (interpType != AffineTransformOp.TYPE_NEAREST_NEIGHBOR) {
 618             return false;
 619         }
 620 
 621         Region clip = sg.getCompClip();
 622         SurfaceData dstData = sg.surfaceData;
 623 
 624         int attempts = 0;
 625         // Loop up to twice through; this gives us a chance to
 626         // revalidate the surfaceData objects in case of an exception
 627         // and try it once more
 628         while (true) {
 629             SurfaceData srcData =
 630                 dstData.getSourceSurfaceData(img,
 631                                              SunGraphics2D.TRANSFORM_TRANSLATESCALE,
 632                                              sg.imageComp,
 633                                              bgColor);
 634 
 635             if (srcData == null || isBgOperation(srcData, bgColor)) {
 636                 return false;
 637             }
 638 
 639             try {
 640                 SurfaceType srcType = srcData.getSurfaceType();
 641                 SurfaceType dstType = dstData.getSurfaceType();
 642                 return scaleSurfaceData(sg, clip,
 643                                         srcData, dstData, srcType, dstType,
 644                                         sx1, sy1, sx2, sy2,
 645                                         dx1, dy1, dx2, dy2);
 646             } catch (NullPointerException e) {
 647                 if (!SurfaceData.isNull(dstData)) {
 648                     // Something else caused the exception, throw it...
 649                     throw e;
 650                 }
 651                 return false;


 783      * need to make sure that image transformations are
 784      * "very close" to integer device coordinates before
 785      * we decide to use an integer scale or copy operation
 786      * as a substitute and the fact that roundoff errors
 787      * in AffineTransforms are frequently introduced by
 788      * performing multiple sequential operations on them.
 789      *
 790      * The evaluation of bug 4990624 details the potential
 791      * for this error cutoff to result in display anomalies
 792      * in different types of image operations and how this
 793      * value represents a good compromise here.
 794      */
 795     private static final double MAX_TX_ERROR = .0001;
 796 
 797     public static boolean closeToInteger(int i, double d) {
 798         return (Math.abs(d-i) < MAX_TX_ERROR);
 799     }
 800 
 801     public static boolean isSimpleTranslate(SunGraphics2D sg) {
 802         int ts = sg.transformState;
 803         if (ts <= SunGraphics2D.TRANSFORM_INT_TRANSLATE) {
 804             // Integer translates are always "simple"
 805             return true;
 806         }
 807         if (ts >= SunGraphics2D.TRANSFORM_TRANSLATESCALE) {
 808             // Scales and beyond are always "not simple"
 809             return false;
 810         }
 811         // non-integer translates are only simple when not interpolating
 812         if (sg.interpolationType == AffineTransformOp.TYPE_NEAREST_NEIGHBOR) {
 813             return true;
 814         }
 815         return false;
 816     }
 817 
 818     protected static boolean isBgOperation(SurfaceData srcData, Color bgColor) {
 819         // If we cannot get the srcData, then cannot assume anything about
 820         // the image
 821         return ((srcData == null) ||
 822                 ((bgColor != null) &&
 823                  (srcData.getTransparency() != Transparency.OPAQUE)));
 824     }
 825 
 826     protected BufferedImage getBufferedImage(Image img) {
 827         if (img instanceof BufferedImage) {


 829         }
 830         // Must be VolatileImage; get BufferedImage representation
 831         return ((VolatileImage)img).getSnapshot();
 832     }
 833 
 834     /*
 835      * Return the color model to be used with this BufferedImage and
 836      * transform.
 837      */
 838     private ColorModel getTransformColorModel(SunGraphics2D sg,
 839                                               BufferedImage bImg,
 840                                               AffineTransform tx) {
 841         ColorModel cm = bImg.getColorModel();
 842         ColorModel dstCM = cm;
 843 
 844         if (tx.isIdentity()) {
 845             return dstCM;
 846         }
 847         int type = tx.getType();
 848         boolean needTrans =
 849                 ((type & (AffineTransform.TYPE_MASK_ROTATION |
 850                           AffineTransform.TYPE_GENERAL_TRANSFORM)) != 0);
 851         if (! needTrans &&
 852               type != AffineTransform.TYPE_TRANSLATION &&
 853               type != AffineTransform.TYPE_IDENTITY)
 854         {
 855             double[] mtx = new double[4];
 856             tx.getMatrix(mtx);
 857             // Check out the matrix.  A non-integral scale will force ARGB
 858             // since the edge conditions cannot be guaranteed.
 859             needTrans = (mtx[0] != (int)mtx[0] || mtx[3] != (int)mtx[3]);
 860         }
 861 
 862         if (sg.renderHint != SunHints.INTVAL_RENDER_QUALITY) {
 863             if (cm instanceof IndexColorModel) {
 864                 Raster raster = bImg.getRaster();
 865                 IndexColorModel icm = (IndexColorModel) cm;
 866                 // Just need to make sure that we have a transparent pixel
 867                 if (needTrans && cm.getTransparency() == Transparency.OPAQUE) {
 868                     // Fix 4221407
 869                     if (raster instanceof sun.awt.image.BytePackedRaster) {
 870                         dstCM = ColorModel.getRGBdefault();
 871                     }
 872                     else {
 873                         double[] matrix = new double[6];
 874                         tx.getMatrix(matrix);
 875                         if (matrix[1] == 0. && matrix[2] ==0.
 876                             && matrix[4] == 0. && matrix[5] == 0.) {
 877                             // Only scaling so do not need to create
 878                         }
 879                         else {
 880                             int mapSize = icm.getMapSize();
 881                             if (mapSize < 256) {
 882                                 int[] cmap = new int[mapSize+1];
 883                                 icm.getRGBs(cmap);
 884                                 cmap[mapSize] = 0x0000;
 885                                 dstCM = new
 886                                     IndexColorModel(icm.getPixelSize(),
 887                                                     mapSize+1,
 888                                                     cmap, 0, true, mapSize,
 889                                                     DataBuffer.TYPE_BYTE);
 890                             }
 891                             else {
 892                                 dstCM = ColorModel.getRGBdefault();
 893                             }
 894                         }  /* if (matrix[0] < 1.f ...) */
 895                     }   /* raster instanceof sun.awt.image.BytePackedRaster */
 896                 } /* if (cm.getTransparency() == cm.OPAQUE) */
 897             } /* if (cm instanceof IndexColorModel) */
 898             else if (needTrans && cm.getTransparency() == Transparency.OPAQUE) {
 899                 // Need a bitmask transparency
 900                 // REMIND: for now, use full transparency since no loops
 901                 // for bitmask
 902                 dstCM = ColorModel.getRGBdefault();
 903             }
 904         } /* if (sg.renderHint == RENDER_QUALITY) */
 905         else {
 906 
 907             if (cm instanceof IndexColorModel ||
 908                 (needTrans && cm.getTransparency() == Transparency.OPAQUE))
 909             {
 910                 // Need a bitmask transparency
 911                 // REMIND: for now, use full transparency since no loops
 912                 // for bitmask
 913                 dstCM = ColorModel.getRGBdefault();
 914             }
 915         }
 916 
 917         return dstCM;
 918     }
 919 
 920     protected void blitSurfaceData(SunGraphics2D sg,
 921                                    Region clipRegion,
 922                                    SurfaceData srcData,
 923                                    SurfaceData dstData,
 924                                    SurfaceType srcType,
 925                                    SurfaceType dstType,
 926                                    int sx, int sy, int dx, int dy,
 927                                    int w, int h,
 928                                    Color bgColor)