1 /*
   2  * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
   3  *
   4  * Redistribution and use in source and binary forms, with or without
   5  * modification, are permitted provided that the following conditions
   6  * are met:
   7  *
   8  *   - Redistributions of source code must retain the above copyright
   9  *     notice, this list of conditions and the following disclaimer.
  10  *
  11  *   - Redistributions in binary form must reproduce the above copyright
  12  *     notice, this list of conditions and the following disclaimer in the
  13  *     documentation and/or other materials provided with the distribution.
  14  *
  15  *   - Neither the name of Oracle nor the names of its
  16  *     contributors may be used to endorse or promote products derived
  17  *     from this software without specific prior written permission.
  18  *
  19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  20  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30  */
  31 
  32 /*
  33  * This source code is provided to illustrate the usage of a given feature
  34  * or technique and has been deliberately simplified. Additional steps
  35  * required for a production-quality application, such as security checks,
  36  * input validation and proper error handling, might not be present in
  37  * this sample code.
  38  */
  39 
  40 
  41 package j2dbench.tests;
  42 
  43 import j2dbench.Destinations;
  44 import j2dbench.Group;
  45 import j2dbench.Modifier;
  46 import j2dbench.Option;
  47 import j2dbench.TestEnvironment;
  48 import java.awt.Graphics;
  49 import java.awt.Graphics2D;
  50 import java.awt.Color;
  51 import java.awt.Image;
  52 import java.awt.Canvas;
  53 import java.awt.AlphaComposite;
  54 import java.awt.Dimension;
  55 import java.awt.GraphicsConfiguration;
  56 import java.awt.RenderingHints;
  57 import java.awt.image.BufferedImage;
  58 import java.awt.image.BufferedImageOp;
  59 import java.awt.image.ByteLookupTable;
  60 import java.awt.image.ConvolveOp;
  61 import java.awt.image.DataBuffer;
  62 import java.awt.image.IndexColorModel;
  63 import java.awt.image.Kernel;
  64 import java.awt.image.LookupOp;
  65 import java.awt.image.Raster;
  66 import java.awt.image.RasterOp;
  67 import java.awt.image.RescaleOp;
  68 import java.awt.image.ShortLookupTable;
  69 import java.awt.image.VolatileImage;
  70 import java.awt.image.WritableRaster;
  71 import java.awt.Transparency;
  72 import java.awt.geom.AffineTransform;
  73 import java.awt.image.DataBufferByte;
  74 import java.awt.image.DataBufferInt;
  75 import java.awt.image.DataBufferShort;
  76 import java.util.ArrayList;
  77 import javax.swing.JComponent;
  78 
  79 public abstract class ImageTests extends GraphicsTests {
  80     public static boolean hasVolatileImage;
  81     public static boolean hasTransparentVolatileImage;
  82     public static boolean hasCompatImage;
  83 
  84     static {
  85         try {
  86             hasVolatileImage = (VolatileImage.class != null);
  87         } catch (NoClassDefFoundError e) {
  88         }
  89         try {
  90             new Canvas().getGraphicsConfiguration();
  91             hasCompatImage = true;
  92         } catch (NoSuchMethodError e) {
  93         }
  94         try {
  95             new Canvas().getMousePosition();
  96             hasTransparentVolatileImage = true;
  97         } catch (NoSuchMethodError e) {
  98         }
  99     }
 100 
 101     static Group imageroot;
 102     static Group.EnableSet imgsrcroot;
 103     static Group.EnableSet bufimgsrcroot;
 104 
 105     static Group imgbenchroot;
 106     static Group imgtestroot;
 107     static Group imgtestOptRoot;
 108 
 109     static Group imageOpRoot;
 110     static Group imageOpOptRoot;
 111     static Group imageOpTestRoot;
 112     static Group graphicsTestRoot;
 113     static Group bufImgOpTestRoot;
 114     static Group rasterOpTestRoot;
 115     static Option opList;
 116     static Option doTouchSrc;
 117     static Option interpolation;
 118 
 119     static String transNodeNames[] = {
 120         null, "opaque", "bitmask", "translucent",
 121     };
 122 
 123     static String transDescriptions[] = {
 124         null, "Opaque", "Bitmask", "Translucent",
 125     };
 126 
 127     public static void init() {
 128         imageroot = new Group(graphicsroot, "imaging",
 129                               "Imaging Benchmarks");
 130         imageroot.setTabbed();
 131 
 132         imgsrcroot = new Group.EnableSet(imageroot, "src",
 133                                          "Image Rendering Sources");
 134         imgbenchroot = new Group(imageroot, "benchmarks",
 135                                 "Image Rendering Benchmarks");
 136         imgtestOptRoot = new Group(imgbenchroot, "opts", "Options");
 137 
 138         new OffScreen();
 139 
 140         if (hasGraphics2D) {
 141             if (hasCompatImage) {
 142                 new CompatImg(Transparency.OPAQUE);
 143                 new CompatImg(Transparency.BITMASK);
 144                 new CompatImg(Transparency.TRANSLUCENT);
 145             }
 146             if (hasVolatileImage) {
 147                 if (hasTransparentVolatileImage) {
 148                     new VolatileImg(Transparency.OPAQUE);
 149                     new VolatileImg(Transparency.BITMASK);
 150                     new VolatileImg(Transparency.TRANSLUCENT);
 151                 } else {
 152                     new VolatileImg();
 153                 }
 154             }
 155 
 156             bufimgsrcroot =
 157                 new Group.EnableSet(imgsrcroot, "bufimg",
 158                                     "BufferedImage Rendering Sources");
 159             new BufImg(BufferedImage.TYPE_INT_RGB);
 160             new BufImg(BufferedImage.TYPE_INT_ARGB);
 161             new BufImg(BufferedImage.TYPE_INT_ARGB_PRE);
 162             new BufImg(BufferedImage.TYPE_BYTE_GRAY);
 163             new BufImg(BufferedImage.TYPE_3BYTE_BGR);
 164             new BufImg(BufferedImage.TYPE_4BYTE_ABGR);
 165             new BufImg(BufferedImage.TYPE_4BYTE_ABGR_PRE);
 166             new BmByteIndexBufImg();
 167             new BufImg(BufferedImage.TYPE_INT_RGB, true);
 168             new BufImg(BufferedImage.TYPE_INT_ARGB, true);
 169             new BufImg(BufferedImage.TYPE_INT_ARGB_PRE, true);
 170             new BufImg(BufferedImage.TYPE_3BYTE_BGR, true);
 171 
 172             imageOpRoot = new Group(imageroot, "imageops",
 173                                     "Image Op Benchmarks");
 174             imageOpOptRoot = new Group(imageOpRoot, "opts", "Options");
 175             imageOpTestRoot = new Group(imageOpRoot, "tests", "Tests");
 176             graphicsTestRoot = new Group(imageOpTestRoot, "graphics2d",
 177                                          "Graphics2D Tests");
 178             bufImgOpTestRoot = new Group(imageOpTestRoot, "bufimgop",
 179                                          "BufferedImageOp Tests");
 180             rasterOpTestRoot = new Group(imageOpTestRoot, "rasterop",
 181                                          "RasterOp Tests");
 182 
 183             ArrayList opStrs = new ArrayList();
 184             ArrayList opDescs = new ArrayList();
 185             opStrs.add("convolve3x3zero");
 186             opDescs.add("ConvolveOp (3x3 blur, zero)");
 187             opStrs.add("convolve3x3noop");
 188             opDescs.add("ConvolveOp (3x3 blur, noop)");
 189             opStrs.add("convolve5x5zero");
 190             opDescs.add("ConvolveOp (5x5 edge, zero)");
 191             opStrs.add("convolve5x5noop");
 192             opDescs.add("ConvolveOp (5x5 edge, noop)");
 193             opStrs.add("lookup1byte");
 194             opDescs.add("LookupOp (1 band, byte)");
 195             opStrs.add("lookup1short");
 196             opDescs.add("LookupOp (1 band, short)");
 197             opStrs.add("lookup3byte");
 198             opDescs.add("LookupOp (3 band, byte)");
 199             opStrs.add("lookup3short");
 200             opDescs.add("LookupOp (3 band, short)");
 201             opStrs.add("rescale1band");
 202             opDescs.add("RescaleOp (1 band)");
 203             opStrs.add("rescale3band");
 204             opDescs.add("RescaleOp (3 band)");
 205             String[] opStrArr = new String[opStrs.size()];
 206             opStrArr = (String[])opStrs.toArray(opStrArr);
 207             String[] opDescArr = new String[opDescs.size()];
 208             opDescArr = (String[])opDescs.toArray(opDescArr);
 209             opList =
 210                 new Option.ObjectList(imageOpOptRoot,
 211                                       "op", "Operation",
 212                                       opStrArr, opStrArr,
 213                                       opStrArr, opDescArr,
 214                                       0x1);
 215             ((Option.ObjectList) opList).setNumRows(4);
 216 
 217             new DrawImageOp();
 218             new BufImgOpFilter(false);
 219             new BufImgOpFilter(true);
 220             new RasterOpFilter(false);
 221             new RasterOpFilter(true);
 222 
 223             String interpolationnames[] = {"Nearest neighbor", "Bilinear",
 224                                            "Bicubic",};
 225             interpolation =
 226                     new ObjectList(imgtestOptRoot, "interpolation",
 227                                    "Interpolation",
 228                                    interpolationnames, new Object[] {
 229                             RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR,
 230                             RenderingHints.VALUE_INTERPOLATION_BILINEAR,
 231                             RenderingHints.VALUE_INTERPOLATION_BICUBIC,
 232                     }, interpolationnames, interpolationnames, 1);
 233         }
 234 
 235         doTouchSrc =
 236                 new Option.Toggle(imgtestOptRoot, "touchsrc",
 237                                   "Touch source image before every operation",
 238                                   Option.Toggle.Off);
 239 
 240         imgtestroot = new Group(imgbenchroot, "tests", "Image Rendering Tests");
 241 
 242         new DrawImage();
 243         new DrawImageBg();
 244         new DrawImageScale("up", 1.5f);
 245         new DrawImageScale("down", .75f);
 246         new DrawImageScale("split", .5f);
 247         new DrawImageTransform();
 248     }
 249 
 250     public static class Context extends GraphicsTests.Context {
 251         boolean touchSrc;
 252         Image src;
 253         AffineTransform tx;
 254     }
 255 
 256     public ImageTests(Group parent, String nodeName, String description) {
 257         this(parent, nodeName, description, null);
 258     }
 259 
 260     public ImageTests(Group parent, String nodeName, String description,
 261                       Modifier.Filter srcFilter)
 262     {
 263         super(parent, nodeName, description);
 264         addDependency(imgsrcroot, srcFilter);
 265         addDependency(doTouchSrc);
 266         addDependency(interpolation);
 267     }
 268 
 269     public GraphicsTests.Context createContext() {
 270         return new ImageTests.Context();
 271     }
 272 
 273     public void initContext(TestEnvironment env, GraphicsTests.Context ctx) {
 274         super.initContext(env, ctx);
 275         ImageTests.Context ictx = (ImageTests.Context) ctx;
 276 
 277         ictx.src = env.getSrcImage();
 278         ictx.touchSrc = env.isEnabled(doTouchSrc);
 279         if (hasGraphics2D) {
 280             Graphics2D g2d = (Graphics2D) ctx.graphics;
 281             final Object modifier = env.getModifier(interpolation);
 282             g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, modifier);
 283         }
 284     }
 285 
 286     public abstract static class TriStateImageType extends Group {
 287         Image theImage;
 288 
 289         public TriStateImageType(Group parent, String nodename, String desc,
 290                                  int transparency)
 291         {
 292             super(parent, nodename, desc);
 293             setHorizontal();
 294             new DrawableImage(this, Transparency.OPAQUE, true);
 295             new DrawableImage(this, Transparency.BITMASK,
 296                               (transparency != Transparency.OPAQUE));
 297             new DrawableImage(this, Transparency.TRANSLUCENT,
 298                               (transparency == Transparency.TRANSLUCENT));
 299         }
 300 
 301         public Image getImage(TestEnvironment env, int w, int h) {
 302             if (theImage == null ||
 303                 theImage.getWidth(null) != w ||
 304                 theImage.getHeight(null) != h)
 305             {
 306                 theImage = makeImage(env, w, h);
 307             }
 308             return theImage;
 309         }
 310 
 311         public abstract Image makeImage(TestEnvironment env, int w, int h);
 312     }
 313 
 314     public static class OffScreen extends TriStateImageType {
 315         public OffScreen() {
 316             super(imgsrcroot, "offscr", "Offscreen Image", Transparency.OPAQUE);
 317         }
 318 
 319         public Image makeImage(TestEnvironment env, int w, int h) {
 320             Canvas c = env.getCanvas();
 321             return c.createImage(w, h);
 322         }
 323     }
 324 
 325     public static class VolatileImg extends TriStateImageType {
 326         private final int transparency;
 327 
 328         public VolatileImg() {
 329             this(0);
 330         }
 331 
 332         public VolatileImg(int transparency) {
 333             super(imgsrcroot, Destinations.VolatileImg.ShortNames[transparency],
 334                   Destinations.VolatileImg.LongDescriptions[transparency],
 335                   transparency);
 336             this.transparency = transparency;
 337         }
 338 
 339         public Image makeImage(TestEnvironment env, int w, int h) {
 340             Canvas c = env.getCanvas();
 341             GraphicsConfiguration gc = c.getGraphicsConfiguration();
 342             if (transparency == 0) {
 343                 return gc.createCompatibleVolatileImage(w, h);
 344             } else {
 345                 return gc.createCompatibleVolatileImage(w, h, transparency);
 346             }
 347         }
 348     }
 349 
 350     public static class CompatImg extends TriStateImageType {
 351         int transparency;
 352 
 353         public CompatImg(int transparency) {
 354             super(imgsrcroot,
 355                   Destinations.CompatImg.ShortNames[transparency],
 356                   Destinations.CompatImg.LongDescriptions[transparency],
 357                   transparency);
 358             this.transparency = transparency;
 359         }
 360 
 361         public Image makeImage(TestEnvironment env, int w, int h) {
 362             Canvas c = env.getCanvas();
 363             GraphicsConfiguration gc = c.getGraphicsConfiguration();
 364             return gc.createCompatibleImage(w, h, transparency);
 365         }
 366     }
 367 
 368     public static class BufImg extends TriStateImageType {
 369         int type;
 370         boolean unmanaged;
 371 
 372         static int Transparencies[] = {
 373             Transparency.TRANSLUCENT, // "custom",
 374             Transparency.OPAQUE,      // "IntXrgb",
 375             Transparency.TRANSLUCENT, // "IntArgb",
 376             Transparency.TRANSLUCENT, // "IntArgbPre",
 377             Transparency.OPAQUE,      // "IntXbgr",
 378             Transparency.OPAQUE,      // "3ByteBgr",
 379             Transparency.TRANSLUCENT, // "4ByteAbgr",
 380             Transparency.TRANSLUCENT, // "4ByteAbgrPre",
 381             Transparency.OPAQUE,      // "Short565",
 382             Transparency.OPAQUE,      // "Short555",
 383             Transparency.OPAQUE,      // "ByteGray",
 384             Transparency.OPAQUE,      // "ShortGray",
 385             Transparency.OPAQUE,      // "ByteBinary",
 386             Transparency.OPAQUE,      // "ByteIndexed",
 387         };
 388 
 389         public BufImg(int type) {
 390             this(type, false);
 391         }
 392 
 393         public BufImg(int type, boolean unmanaged) {
 394             super(bufimgsrcroot,
 395                   (unmanaged ? "unmanaged" : "") +
 396                   Destinations.BufImg.ShortNames[type],
 397                   (unmanaged ? "Unmanaged " : "") +
 398                   Destinations.BufImg.Descriptions[type],
 399                   Transparencies[type]);
 400             this.type = type;
 401             this.unmanaged = unmanaged;
 402         }
 403 
 404         public Image makeImage(TestEnvironment env, int w, int h) {
 405             BufferedImage img = new BufferedImage(w, h, type);
 406             if (unmanaged) {
 407                 DataBuffer db = img.getRaster().getDataBuffer();
 408                 if (db instanceof DataBufferInt) {
 409                     ((DataBufferInt)db).getData();
 410                 } else if (db instanceof DataBufferShort) {
 411                     ((DataBufferShort)db).getData();
 412                 } else if (db instanceof DataBufferByte) {
 413                     ((DataBufferByte)db).getData();
 414                 } else {
 415                     try {
 416                         img.setAccelerationPriority(0.0f);
 417                     } catch (Throwable e) {}
 418                 }
 419             }
 420             return img;
 421         }
 422     }
 423 
 424     public static class BmByteIndexBufImg extends TriStateImageType {
 425         static IndexColorModel icm;
 426 
 427         public BmByteIndexBufImg() {
 428             super(bufimgsrcroot,
 429                   "ByteIndexedBm",
 430                   "8-bit Transparent Indexed Image",
 431                   Transparency.BITMASK);
 432         }
 433 
 434         public Image makeImage(TestEnvironment env, int w, int h) {
 435             if (icm == null) {
 436                 int cmap[] = new int[256];
 437                 // Workaround for transparency rendering bug in earlier VMs
 438                 // Can only render transparency if first cmap entry is 0x0
 439                 // This bug is fixed in 1.4.2 (Mantis)
 440                 int i = 1;
 441                 for (int r = 0; r < 256; r += 51) {
 442                     for (int g = 0; g < 256; g += 51) {
 443                         for (int b = 0; b < 256; b += 51) {
 444                             cmap[i++] = (0xff<<24)|(r<<16)|(g<<8)|b;
 445                         }
 446                     }
 447                 }
 448 
 449                 // Leave the rest of the colormap transparent
 450 
 451                 icm = new IndexColorModel(8, 256, cmap, 0, true, 255,
 452                                           DataBuffer.TYPE_BYTE);
 453             }
 454             return new BufferedImage(w, h, BufferedImage.TYPE_BYTE_INDEXED,
 455                                      icm);
 456         }
 457     }
 458 
 459     public static class DrawableImage extends Option.Enable {
 460         static Color transparentBlack  = makeAlphaColor(Color.black, 0);
 461         static Color translucentRed    = makeAlphaColor(Color.red, 192);
 462         static Color translucentGreen  = makeAlphaColor(Color.green, 128);
 463         static Color translucentYellow = makeAlphaColor(Color.yellow, 64);
 464 
 465         static Color colorsets[][] = new Color[][] {
 466             null,
 467             {
 468                 Color.blue,       Color.red,
 469                 Color.green,      Color.yellow,
 470                 Color.blue,
 471             },
 472             {
 473                 transparentBlack, Color.red,
 474                 Color.green,      transparentBlack,
 475                 transparentBlack,
 476             },
 477             {
 478                 Color.blue,       translucentRed,
 479                 translucentGreen, translucentYellow,
 480                 translucentRed,
 481             },
 482         };
 483 
 484         TriStateImageType tsit;
 485         int transparency;
 486         boolean possible;
 487 
 488         public DrawableImage(TriStateImageType parent, int transparency,
 489                              boolean possible)
 490         {
 491             super(parent,
 492                   transNodeNames[transparency],
 493                   transDescriptions[transparency],
 494                   false);
 495             this.tsit = parent;
 496             this.transparency = transparency;
 497             this.possible = possible;
 498         }
 499 
 500         public int getTransparency() {
 501             return transparency;
 502         }
 503 
 504         public JComponent getJComponent() {
 505             JComponent comp = super.getJComponent();
 506             comp.setEnabled(possible);
 507             return comp;
 508         }
 509 
 510         public String setValueFromString(String value) {
 511             if (!possible && !value.equalsIgnoreCase("disabled")) {
 512                 return "Bad Value";
 513             }
 514             return super.setValueFromString(value);
 515         }
 516 
 517         public void modifyTest(TestEnvironment env) {
 518             int size = env.getIntValue(sizeList);
 519             Image src = tsit.getImage(env, size, size);
 520             Graphics g = src.getGraphics();
 521             if (hasGraphics2D) {
 522                 ((Graphics2D) g).setComposite(AlphaComposite.Src);
 523             }
 524             if (size == 1) {
 525                 g.setColor(colorsets[transparency][4]);
 526                 g.fillRect(0, 0, 1, 1);
 527             } else {
 528                 int mid = size/2;
 529                 g.setColor(colorsets[transparency][0]);
 530                 g.fillRect(0, 0, mid, mid);
 531                 g.setColor(colorsets[transparency][1]);
 532                 g.fillRect(mid, 0, size-mid, mid);
 533                 g.setColor(colorsets[transparency][2]);
 534                 g.fillRect(0, mid, mid, size-mid);
 535                 g.setColor(colorsets[transparency][3]);
 536                 g.fillRect(mid, mid, size-mid, size-mid);
 537             }
 538             g.dispose();
 539             env.setSrcImage(src);
 540         }
 541 
 542         public void restoreTest(TestEnvironment env) {
 543             env.setSrcImage(null);
 544         }
 545 
 546         public String getAbbreviatedModifierDescription(Object value) {
 547             return "from "+getModifierValueName(value);
 548         }
 549 
 550         public String getModifierValueName(Object val) {
 551             return getParent().getNodeName()+" "+getNodeName();
 552         }
 553     }
 554 
 555     public static class DrawImage extends ImageTests {
 556         public DrawImage() {
 557             super(imgtestroot, "drawimage", "drawImage(img, x, y, obs);");
 558         }
 559 
 560         public void runTest(Object ctx, int numReps) {
 561             ImageTests.Context ictx = (ImageTests.Context) ctx;
 562             int x = ictx.initX;
 563             int y = ictx.initY;
 564             Graphics g = ictx.graphics;
 565             g.translate(ictx.orgX, ictx.orgY);
 566             Image src = ictx.src;
 567             if (ictx.animate) {
 568                 if (ictx.touchSrc) {
 569                     Graphics srcG = src.getGraphics();
 570                     do {
 571                         srcG.fillRect(0, 0, 1, 1);
 572                         g.drawImage(src, x, y, null);
 573                         if ((x -= 3) < 0) x += ictx.maxX;
 574                         if ((y -= 1) < 0) y += ictx.maxY;
 575                     } while (--numReps > 0);
 576                 } else {
 577                     do {
 578                         g.drawImage(src, x, y, null);
 579                         if ((x -= 3) < 0) x += ictx.maxX;
 580                         if ((y -= 1) < 0) y += ictx.maxY;
 581                     } while (--numReps > 0);
 582                 }
 583             } else {
 584                 if (ictx.touchSrc) {
 585                     Graphics srcG = src.getGraphics();
 586                     do {
 587                         srcG.fillRect(0, 0, 1, 1);
 588                         g.drawImage(src, x, y, null);
 589                     } while (--numReps > 0);
 590                 } else {
 591                     do {
 592                         g.drawImage(src, x, y, null);
 593                     } while (--numReps > 0);
 594                 }
 595             }
 596             g.translate(-ictx.orgX, -ictx.orgY);
 597         }
 598     }
 599 
 600     public static class DrawImageBg extends ImageTests {
 601         public DrawImageBg() {
 602             super(imgtestroot, "drawimagebg", "drawImage(img, x, y, bg, obs);",
 603                   new Modifier.Filter() {
 604                       public boolean isCompatible(Object val) {
 605                           DrawableImage di = (DrawableImage) val;
 606                           return (di.getTransparency() != Transparency.OPAQUE);
 607                       }
 608                   });
 609         }
 610 
 611         public void runTest(Object ctx, int numReps) {
 612             ImageTests.Context ictx = (ImageTests.Context) ctx;
 613             int x = ictx.initX;
 614             int y = ictx.initY;
 615             Graphics g = ictx.graphics;
 616             g.translate(ictx.orgX, ictx.orgY);
 617             Image src = ictx.src;
 618             Color bg = Color.orange;
 619             if (ictx.animate) {
 620                 if (ictx.touchSrc) {
 621                     Graphics srcG = src.getGraphics();
 622                     do {
 623                         srcG.fillRect(0, 0, 1, 1);
 624                         g.drawImage(src, x, y, bg, null);
 625                         if ((x -= 3) < 0) x += ictx.maxX;
 626                         if ((y -= 1) < 0) y += ictx.maxY;
 627                     } while (--numReps > 0);
 628                 } else {
 629                     do {
 630                         g.drawImage(src, x, y, bg, null);
 631                         if ((x -= 3) < 0) x += ictx.maxX;
 632                         if ((y -= 1) < 0) y += ictx.maxY;
 633                     } while (--numReps > 0);
 634                 }
 635             } else {
 636                 if (ictx.touchSrc) {
 637                     Graphics srcG = src.getGraphics();
 638                     do {
 639                         srcG.fillRect(0, 0, 1, 1);
 640                         g.drawImage(src, x, y, bg, null);
 641                     } while (--numReps > 0);
 642                 } else {
 643                     do {
 644                         g.drawImage(src, x, y, bg, null);
 645                     } while (--numReps > 0);
 646                 }
 647             }
 648             g.translate(-ictx.orgX, -ictx.orgY);
 649         }
 650     }
 651 
 652     public static class DrawImageScale extends ImageTests {
 653         float scale;
 654 
 655         public DrawImageScale(String dir, float scale) {
 656             super(imgtestroot, "drawimagescale"+dir,
 657                                "drawImage(img, x, y, w*"+scale+", h*"+scale+", obs);");
 658             this.scale = scale;
 659         }
 660 
 661         public Dimension getOutputSize(int w, int h) {
 662             int neww = (int) (w * scale);
 663             int newh = (int) (h * scale);
 664             if (neww == w && scale > 1f) neww = w+1;
 665             if (newh == h && scale > 1f) newh = h+1;
 666             return new Dimension(neww, newh);
 667         }
 668 
 669         public void runTest(Object ctx, int numReps) {
 670             ImageTests.Context ictx = (ImageTests.Context) ctx;
 671             int x = ictx.initX;
 672             int y = ictx.initY;
 673             int w = ictx.outdim.width;
 674             int h = ictx.outdim.height;
 675             Graphics g = ictx.graphics;
 676             g.translate(ictx.orgX, ictx.orgY);
 677             Image src = ictx.src;
 678             if (ictx.animate) {
 679                 if (ictx.touchSrc) {
 680                     Graphics srcG = src.getGraphics();
 681                     do {
 682                         srcG.fillRect(0, 0, 1, 1);
 683                         g.drawImage(src, x, y, w, h, null);
 684                         if ((x -= 3) < 0) x += ictx.maxX;
 685                         if ((y -= 1) < 0) y += ictx.maxY;
 686                     } while (--numReps > 0);
 687                 } else {
 688                     do {
 689                         g.drawImage(src, x, y, w, h, null);
 690                         if ((x -= 3) < 0) x += ictx.maxX;
 691                         if ((y -= 1) < 0) y += ictx.maxY;
 692                     } while (--numReps > 0);
 693                 }
 694             } else {
 695                 Graphics srcG = src.getGraphics();
 696                 if (ictx.touchSrc) {
 697                     do {
 698                         srcG.fillRect(0, 0, 1, 1);
 699                         g.drawImage(src, x, y, w, h, null);
 700                     } while (--numReps > 0);
 701                 } else {
 702                     do {
 703                         g.drawImage(src, x, y, w, h, null);
 704                     } while (--numReps > 0);
 705                 }
 706             }
 707             g.translate(-ictx.orgX, -ictx.orgY);
 708         }
 709     }
 710 
 711     public static class DrawImageTransform extends ImageTests {
 712         public DrawImageTransform() {
 713             super(imgtestroot, "drawimagetxform", "drawImage(img, tx, obs);");
 714         }
 715 
 716         public Dimension getOutputSize(int w, int h) {
 717             int neww = (int) Math.ceil(w * 1.1);
 718             int newh = (int) Math.ceil(h * 1.1);
 719             return new Dimension(neww, newh);
 720         }
 721 
 722         public void initContext(TestEnvironment env, GraphicsTests.Context ctx)
 723         {
 724             super.initContext(env, ctx);
 725             ImageTests.Context ictx = (ImageTests.Context) ctx;
 726 
 727             ictx.tx = new AffineTransform();
 728         }
 729 
 730         public void runTest(Object ctx, int numReps) {
 731             ImageTests.Context ictx = (ImageTests.Context) ctx;
 732             int x = ictx.initX;
 733             int y = ictx.initY;
 734             Graphics2D g = (Graphics2D) ictx.graphics;
 735             g.translate(ictx.orgX, ictx.orgY);
 736             Image src = ictx.src;
 737             AffineTransform tx = ictx.tx;
 738             if (ictx.animate) {
 739                 if (ictx.touchSrc) {
 740                     Graphics srcG = src.getGraphics();
 741                     do {
 742                         tx.setTransform(1.0, 0.1, 0.1, 1.0, x, y);
 743                         srcG.fillRect(0, 0, 1, 1);
 744                         g.drawImage(src, tx, null);
 745                         if ((x -= 3) < 0) x += ictx.maxX;
 746                         if ((y -= 1) < 0) y += ictx.maxY;
 747                     } while (--numReps > 0);
 748                 } else {
 749                     do {
 750                         tx.setTransform(1.0, 0.1, 0.1, 1.0, x, y);
 751                         g.drawImage(src, tx, null);
 752                         if ((x -= 3) < 0) x += ictx.maxX;
 753                         if ((y -= 1) < 0) y += ictx.maxY;
 754                     } while (--numReps > 0);
 755                 }
 756             } else {
 757                 tx.setTransform(1.0, 0.1, 0.1, 1.0, x, y);
 758                 if (ictx.touchSrc) {
 759                     Graphics srcG = src.getGraphics();
 760                     do {
 761                         srcG.fillRect(0, 0, 1, 1);
 762                         g.drawImage(src, tx, null);
 763                     } while (--numReps > 0);
 764                 } else {
 765                     do {
 766                         g.drawImage(src, tx, null);
 767                     } while (--numReps > 0);
 768                 }
 769             }
 770             g.translate(-ictx.orgX, -ictx.orgY);
 771         }
 772     }
 773 
 774     private abstract static class ImageOpTests extends ImageTests {
 775         ImageOpTests(Group parent, String nodeName, String desc) {
 776             super(parent, nodeName, desc,
 777                   new Modifier.Filter() {
 778                       public boolean isCompatible(Object val) {
 779                           // Filter out all non-BufferedImage sources
 780                           DrawableImage di = (DrawableImage) val;
 781                           Group imgtype = di.getParent();
 782                           return
 783                               !(imgtype instanceof VolatileImg) &&
 784                               !(imgtype instanceof OffScreen);
 785                       }
 786                   });
 787             addDependencies(imageOpOptRoot, true);
 788         }
 789 
 790         private static class Context extends ImageTests.Context {
 791             BufferedImageOp bufImgOp;
 792             BufferedImage   bufSrc;
 793             BufferedImage   bufDst;
 794 
 795             RasterOp        rasterOp;
 796             Raster          rasSrc;
 797             WritableRaster  rasDst;
 798         }
 799 
 800         public GraphicsTests.Context createContext() {
 801             return new ImageOpTests.Context();
 802         }
 803 
 804         public void initContext(TestEnvironment env,
 805                                 GraphicsTests.Context ctx)
 806         {
 807             super.initContext(env, ctx);
 808             ImageOpTests.Context ictx = (ImageOpTests.Context)ctx;
 809 
 810             // Note: We filter out all non-BufferedImage sources in the
 811             // ImageOpTests constructor above, so the following is safe...
 812             ictx.bufSrc = (BufferedImage)ictx.src;
 813 
 814             String op = (String)env.getModifier(opList);
 815             if (op.startsWith("convolve")) {
 816                 Kernel kernel;
 817                 if (op.startsWith("convolve3x3")) {
 818                     // 3x3 blur
 819                     float[] data = {
 820                         0.1f, 0.1f, 0.1f,
 821                         0.1f, 0.2f, 0.1f,
 822                         0.1f, 0.1f, 0.1f,
 823                     };
 824                     kernel = new Kernel(3, 3, data);
 825                 } else { // (op.startsWith("convolve5x5"))
 826                     // 5x5 edge
 827                     float[] data = {
 828                         -1.0f, -1.0f, -1.0f, -1.0f, -1.0f,
 829                         -1.0f, -1.0f, -1.0f, -1.0f, -1.0f,
 830                         -1.0f, -1.0f, 24.0f, -1.0f, -1.0f,
 831                         -1.0f, -1.0f, -1.0f, -1.0f, -1.0f,
 832                         -1.0f, -1.0f, -1.0f, -1.0f, -1.0f,
 833                     };
 834                     kernel = new Kernel(5, 5, data);
 835                 }
 836                 int edge = op.endsWith("zero") ?
 837                     ConvolveOp.EDGE_ZERO_FILL : ConvolveOp.EDGE_NO_OP;
 838                 ictx.bufImgOp = new ConvolveOp(kernel, edge, null);
 839             } else if (op.startsWith("lookup")) {
 840                 if (op.endsWith("byte")) {
 841                     byte invert[] = new byte[256];
 842                     byte ordered[] = new byte[256];
 843                     for (int j = 0; j < 256 ; j++) {
 844                         invert[j] = (byte)(255-j);
 845                         ordered[j] = (byte)j;
 846                     }
 847                     if (op.equals("lookup1byte")) {
 848                         ictx.bufImgOp =
 849                             new LookupOp(new ByteLookupTable(0, invert),
 850                                          null);
 851                     } else { // (op.equals("lookup3byte"))
 852                         byte[][] yellowInvert =
 853                             new byte[][] { invert, invert, ordered };
 854                         ictx.bufImgOp =
 855                             new LookupOp(new ByteLookupTable(0, yellowInvert),
 856                                          null);
 857                     }
 858                 } else { // (op.endsWith("short"))
 859                     short invert[] = new short[256];
 860                     short ordered[] = new short[256];
 861                     for (int j = 0; j < 256 ; j++) {
 862                         invert[j] = (short)((255-j) * 255);
 863                         ordered[j] = (short)(j * 255);
 864                     }
 865                     if (op.equals("lookup1short")) {
 866                         ictx.bufImgOp =
 867                             new LookupOp(new ShortLookupTable(0, invert),
 868                                          null);
 869                     } else { // (op.equals("lookup3short"))
 870                         short[][] yellowInvert =
 871                             new short[][] { invert, invert, ordered };
 872                         ictx.bufImgOp =
 873                             new LookupOp(new ShortLookupTable(0, yellowInvert),
 874                                          null);
 875                     }
 876                 }
 877             } else if (op.equals("rescale1band")) {
 878                 ictx.bufImgOp = new RescaleOp(0.5f, 10.0f, null);
 879             } else if (op.equals("rescale3band")) {
 880                 float[] scaleFactors = { 0.5f,  0.3f, 0.8f };
 881                 float[] offsets      = { 5.0f, -7.5f, 1.0f };
 882                 ictx.bufImgOp = new RescaleOp(scaleFactors, offsets, null);
 883             } else {
 884                 throw new InternalError("Invalid image op");
 885             }
 886 
 887             ictx.rasterOp = (RasterOp)ictx.bufImgOp;
 888         }
 889     }
 890 
 891     private static class DrawImageOp extends ImageOpTests {
 892         DrawImageOp() {
 893             super(graphicsTestRoot, "drawimageop",
 894                   "drawImage(srcBufImg, op, x, y);");
 895         }
 896 
 897         public void runTest(Object ctx, int numReps) {
 898             ImageOpTests.Context ictx = (ImageOpTests.Context)ctx;
 899             int x = ictx.initX;
 900             int y = ictx.initY;
 901             BufferedImageOp op = ictx.bufImgOp;
 902             BufferedImage src = ictx.bufSrc;
 903             Graphics2D g2 = (Graphics2D)ictx.graphics;
 904             g2.translate(ictx.orgX, ictx.orgY);
 905             if (ictx.animate) {
 906                 if (ictx.touchSrc) {
 907                     Graphics gSrc = src.getGraphics();
 908                     do {
 909                         gSrc.fillRect(0, 0, 1, 1);
 910                         g2.drawImage(src, op, x, y);
 911                         if ((x -= 3) < 0) x += ictx.maxX;
 912                         if ((y -= 1) < 0) y += ictx.maxY;
 913                     } while (--numReps > 0);
 914                 } else {
 915                     do {
 916                         g2.drawImage(src, op, x, y);
 917                         if ((x -= 3) < 0) x += ictx.maxX;
 918                         if ((y -= 1) < 0) y += ictx.maxY;
 919                     } while (--numReps > 0);
 920                 }
 921             } else {
 922                 if (ictx.touchSrc) {
 923                     Graphics gSrc = src.getGraphics();
 924                     do {
 925                         gSrc.fillRect(0, 0, 1, 1);
 926                         g2.drawImage(src, op, x, y);
 927                     } while (--numReps > 0);
 928                 } else {
 929                     do {
 930                         g2.drawImage(src, op, x, y);
 931                     } while (--numReps > 0);
 932                 }
 933             }
 934             g2.translate(-ictx.orgX, -ictx.orgY);
 935         }
 936     }
 937 
 938     private static class BufImgOpFilter extends ImageOpTests {
 939         private boolean cached;
 940 
 941         BufImgOpFilter(boolean cached) {
 942             super(bufImgOpTestRoot,
 943                   "filter" + (cached ? "cached" : "null"),
 944                   "op.filter(srcBufImg, " +
 945                   (cached ? "cachedCompatibleDestImg" : "null") + ");");
 946             this.cached = cached;
 947         }
 948 
 949         public void initContext(TestEnvironment env,
 950                                 GraphicsTests.Context ctx)
 951         {
 952             super.initContext(env, ctx);
 953             ImageOpTests.Context ictx = (ImageOpTests.Context)ctx;
 954 
 955             if (cached) {
 956                 ictx.bufDst =
 957                     ictx.bufImgOp.createCompatibleDestImage(ictx.bufSrc, null);
 958             }
 959         }
 960 
 961         public void runTest(Object ctx, int numReps) {
 962             ImageOpTests.Context ictx = (ImageOpTests.Context)ctx;
 963             BufferedImageOp op = ictx.bufImgOp;
 964             BufferedImage src = ictx.bufSrc;
 965             BufferedImage dst = ictx.bufDst;
 966             if (ictx.touchSrc) {
 967                 Graphics gSrc = src.getGraphics();
 968                 do {
 969                     gSrc.fillRect(0, 0, 1, 1);
 970                     op.filter(src, dst);
 971                 } while (--numReps > 0);
 972             } else {
 973                 do {
 974                     op.filter(src, dst);
 975                 } while (--numReps > 0);
 976             }
 977         }
 978     }
 979 
 980     private static class RasterOpFilter extends ImageOpTests {
 981         private boolean cached;
 982 
 983         RasterOpFilter(boolean cached) {
 984             super(rasterOpTestRoot,
 985                   "filter" + (cached ? "cached" : "null"),
 986                   "op.filter(srcRaster, " +
 987                   (cached ? "cachedCompatibleDestRaster" : "null") + ");");
 988             this.cached = cached;
 989         }
 990 
 991         public void initContext(TestEnvironment env,
 992                                 GraphicsTests.Context ctx)
 993         {
 994             super.initContext(env, ctx);
 995             ImageOpTests.Context ictx = (ImageOpTests.Context)ctx;
 996 
 997             ictx.rasSrc = ictx.bufSrc.getRaster();
 998             if (cached) {
 999                 ictx.bufDst =
1000                     ictx.bufImgOp.createCompatibleDestImage(ictx.bufSrc, null);
1001                 ictx.rasDst = ictx.bufDst.getRaster();
1002             }
1003         }
1004 
1005         public void runTest(Object ctx, int numReps) {
1006             ImageOpTests.Context ictx = (ImageOpTests.Context)ctx;
1007             RasterOp op = ictx.rasterOp;
1008             Raster src = ictx.rasSrc;
1009             WritableRaster dst = ictx.rasDst;
1010             if (ictx.touchSrc) {
1011                 Graphics gSrc = ictx.bufSrc.getGraphics();
1012                 do {
1013                     gSrc.fillRect(0, 0, 1, 1);
1014                     op.filter(src, dst);
1015                 } while (--numReps > 0);
1016             } else {
1017                 do {
1018                     op.filter(src, dst);
1019                 } while (--numReps > 0);
1020             }
1021         }
1022     }
1023 }