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