ImageTransferTest.java revision 14851:980da45565c8
1/* 2 * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24/* 25 @test 26 @key headful 27 @bug 4397404 4720930 28 @summary tests that images of all supported native image formats are transfered properly 29 @library ../../../../lib/testlibrary 30 @library ../../regtesthelpers/process/ 31 @build jdk.testlibrary.OSInfo ProcessResults ProcessCommunicator 32 @author gas@sparc.spb.su area=Clipboard 33 @run main ImageTransferTest 34*/ 35 36import test.java.awt.regtesthelpers.process.ProcessCommunicator; 37import test.java.awt.regtesthelpers.process.ProcessResults; 38import jdk.testlibrary.OSInfo; 39 40import java.awt.*; 41import java.awt.datatransfer.DataFlavor; 42import java.awt.datatransfer.SystemFlavorMap; 43import java.awt.datatransfer.Transferable; 44import java.awt.datatransfer.UnsupportedFlavorException; 45import java.awt.dnd.DnDConstants; 46import java.awt.dnd.DragSource; 47import java.awt.dnd.DragSourceAdapter; 48import java.awt.dnd.DragSourceDropEvent; 49import java.awt.dnd.DragSourceListener; 50import java.awt.dnd.DropTarget; 51import java.awt.dnd.DropTargetAdapter; 52import java.awt.dnd.DropTargetDropEvent; 53import java.awt.event.InputEvent; 54import java.awt.image.BufferedImage; 55import java.awt.image.MemoryImageSource; 56import java.util.stream.Stream; 57 58public class ImageTransferTest { 59 public static void main(String[] arg) throws Exception { 60 ImageDragSource ids = new ImageDragSource(); 61 ids.frame.setLocation(100, 100); 62 ids.frame.setVisible(true); 63 Util.sync(); 64 String classpath = System.getProperty("java.class.path"); 65 String[] args = new String[ids.formats.length + 4]; 66 args[0] = "200"; 67 args[1] = "100"; 68 args[2] = args[3] = "150"; 69 70 System.arraycopy(ids.formats, 0, args, 4, ids.formats.length); 71 ProcessResults pres = ProcessCommunicator.executeChildProcess(ImageDropTarget.class, classpath, args); 72 73 if (pres.getStdErr() != null && pres.getStdErr().length() > 0) { 74 System.err.println("========= Child VM System.err ========"); 75 System.err.print(pres.getStdErr()); 76 System.err.println("======================================"); 77 } 78 79 if (pres.getStdOut() != null && pres.getStdOut().length() > 0) { 80 System.err.println("========= Child VM System.out ========"); 81 System.err.print(pres.getStdOut()); 82 System.err.println("======================================"); 83 } 84 85 boolean failed = false; 86 String passedFormats = ""; 87 String failedFormats = ""; 88 89 for (int i = 0; i < ids.passedArray.length; i++) { 90 if (ids.passedArray[i]) passedFormats += ids.formats[i] + " "; 91 else { 92 failed = true; 93 failedFormats += ids.formats[i] + " "; 94 } 95 } 96 97 if (failed) { 98 throw new RuntimeException("test failed: images in following " + 99 "native formats are not transferred properly: " + failedFormats); 100 } else { 101 System.err.println("images in following " + 102 "native formats are transferred properly: " + passedFormats); 103 } 104 } 105} 106 107 108class Util { 109 private static Robot srobot = null; 110 public static void sync() { 111 try { 112 if(srobot == null) { 113 srobot = new Robot(); 114 } 115 srobot.waitForIdle(); 116 Thread.sleep(500); 117 } catch (Exception e) { 118 throw new RuntimeException(e); 119 } 120 } 121} 122 123abstract class ImageTransferer { 124 Image image; 125 String[] formats; 126 int fi; // current format index 127 Frame frame = new Frame(); 128 129 130 ImageTransferer() { 131 image = createImage(); 132 frame.setSize(100, 100); 133 } 134 135 private static Image createImage() { 136 int w = 100; 137 int h = 100; 138 int[] pix = new int[w * h]; 139 140 int index = 0; 141 for (int y = 0; y < h; y++) { 142 for (int x = 0; x < w; x++) { 143 int red = 127; 144 int green = 127; 145 int blue = y > h / 2 ? 127 : 0; 146 int alpha = 255; 147 if (x < w / 4 && y < h / 4) { 148 alpha = 0; 149 red = 0; 150 } 151 pix[index++] = (alpha << 24) | (red << 16) | (green << 8) | blue; 152 } 153 } 154 return Toolkit.getDefaultToolkit().createImage(new MemoryImageSource(w, h, pix, 0, w)); 155 } 156 157 158 static String[] retrieveFormatsToTest() { 159 SystemFlavorMap sfm = (SystemFlavorMap) SystemFlavorMap.getDefaultFlavorMap(); 160 java.util.List<String> ln = sfm.getNativesForFlavor(DataFlavor.imageFlavor); 161 if (OSInfo.OSType.WINDOWS.equals(OSInfo.getOSType()) && !ln.contains("METAFILEPICT")) { 162 // for test failing on JDK without this fix 163 ln.add("METAFILEPICT"); 164 } 165 return ln.toArray(new String[ln.size()]); 166 } 167 168 static void leaveFormat(String format) { 169 SystemFlavorMap sfm = (SystemFlavorMap) SystemFlavorMap.getDefaultFlavorMap(); 170 sfm.setFlavorsForNative(format, new DataFlavor[]{DataFlavor.imageFlavor}); 171 sfm.setNativesForFlavor(DataFlavor.imageFlavor, new String[]{format}); 172 } 173 174 175 boolean areImagesIdentical(Image im1, Image im2) { 176 if (formats[fi].equals("JFIF") || formats[fi].equals("image/jpeg") || 177 formats[fi].equals("GIF") || formats[fi].equals("image/gif")) { 178 // JFIF and GIF are lossy formats 179 return true; 180 } 181 int[] ib1 = getImageData(im1); 182 int[] ib2 = getImageData(im2); 183 184 if (ib1.length != ib2.length) { 185 return false; 186 } 187 188 if (formats[fi].equals("PNG") || 189 formats[fi].equals("image/png") || 190 formats[fi].equals("image/x-png")) { 191 // check alpha as well 192 for (int i = 0; i < ib1.length; i++) { 193 if (ib1[i] != ib2[i]) { 194 System.err.println("different pixels: " + 195 Integer.toHexString(ib1[i]) + " " + 196 Integer.toHexString(ib2[i])); 197 return false; 198 } 199 } 200 } else { 201 for (int i = 0; i < ib1.length; i++) { 202 if ((ib1[i] & 0x00FFFFFF) != (ib2[i] & 0x00FFFFFF)) { 203 System.err.println("different pixels: " + 204 Integer.toHexString(ib1[i]) + " " + 205 Integer.toHexString(ib2[i])); 206 return false; 207 } 208 } 209 } 210 return true; 211 } 212 213 private static int[] getImageData(Image image) { 214 int width = image.getWidth(null); 215 int height = image.getHeight(null); 216 BufferedImage bimage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); 217 Graphics2D g2d = bimage.createGraphics(); 218 try { 219 g2d.drawImage(image, 0, 0, width, height, null); 220 } finally { 221 g2d.dispose(); 222 } 223 return bimage.getRGB(0, 0, width, height, null, 0, width); 224 } 225 226 public static int sign(int n) { 227 return n < 0 ? -1 : n == 0 ? 0 : 1; 228 } 229 230} 231 232 233class ImageDragSource extends ImageTransferer { 234 boolean[] passedArray; 235 236 ImageDragSource() { 237 formats = retrieveFormatsToTest(); 238 passedArray = new boolean[formats.length]; 239 final DragSourceListener dsl = new DragSourceAdapter() { 240 public void dragDropEnd(DragSourceDropEvent e) { 241 System.err.println("Drop was successful=" + e.getDropSuccess()); 242 notifyTransferSuccess(e.getDropSuccess()); 243 if (++fi < formats.length) { 244 leaveFormat(formats[fi]); 245 } 246 } 247 }; 248 249 new DragSource().createDefaultDragGestureRecognizer(frame, 250 DnDConstants.ACTION_COPY, 251 dge -> dge.startDrag(null, new ImageSelection(image), dsl)); 252 leaveFormat(formats[fi]); 253 } 254 255 256 void notifyTransferSuccess(boolean status) { 257 passedArray[fi] = status; 258 } 259} 260 261 262class ImageDropTarget extends ImageTransferer { 263 private final Robot robot; 264 private static Point startPoint, endPoint = new Point(250, 150); 265 266 ImageDropTarget() throws AWTException { 267 DropTargetAdapter dropTargetAdapter = new DropTargetAdapter() { 268 @Override 269 public void drop(DropTargetDropEvent dtde) { 270 checkImage(dtde); 271 startImageDrag(); 272 } 273 }; 274 new DropTarget(frame, dropTargetAdapter); 275 robot = new Robot(); 276 } 277 278 279 void checkImage(DropTargetDropEvent dtde) { 280 final Transferable t = dtde.getTransferable(); 281 if (t.isDataFlavorSupported(DataFlavor.imageFlavor)) { 282 dtde.acceptDrop(DnDConstants.ACTION_COPY); 283 Image im; 284 try { 285 im = (Image) t.getTransferData(DataFlavor.imageFlavor); 286 System.err.println("getTransferData was successful"); 287 } catch (Exception e) { 288 System.err.println("Can't getTransferData: " + e); 289 dtde.dropComplete(false); 290 notifyTransferSuccess(false); 291 return; 292 } 293 294 if (im == null) { 295 System.err.println("getTransferData returned null"); 296 dtde.dropComplete(false); 297 notifyTransferSuccess(false); 298 } else if (areImagesIdentical(image, im)) { 299 dtde.dropComplete(true); 300 notifyTransferSuccess(true); 301 } else { 302 System.err.println("transferred image is different from initial image"); 303 dtde.dropComplete(false); 304 notifyTransferSuccess(false); 305 } 306 307 } else { 308 System.err.println("imageFlavor is not supported by Transferable"); 309 dtde.rejectDrop(); 310 notifyTransferSuccess(false); 311 } 312 } 313 314 void startImageDrag() { 315 leaveFormat(formats[fi]); 316 new Thread(() -> { 317 try { 318 Thread.sleep(1000); 319 } catch (InterruptedException e) { 320 e.printStackTrace(); 321 // Exit from the child process 322 System.exit(1); 323 } 324 robot.mouseMove(startPoint.x, startPoint.y); 325 robot.mousePress(InputEvent.BUTTON1_MASK); 326 for (Point p = new Point(startPoint); !p.equals(endPoint); 327 p.translate(sign(endPoint.x - p.x), sign(endPoint.y - p.y))) { 328 robot.mouseMove(p.x, p.y); 329 try { 330 Thread.sleep(50); 331 } catch (InterruptedException e) { 332 e.printStackTrace(); 333 } 334 } 335 336 robot.mouseRelease(InputEvent.BUTTON1_MASK); 337 }).start(); 338 } 339 340 void notifyTransferSuccess(boolean status) { 341 if (status) { 342 System.err.println("format passed: " + formats[fi]); 343 } else { 344 System.err.println("format failed: " + formats[fi]); 345 System.exit(1); 346 } 347 if (fi < formats.length - 1) { 348 leaveFormat(formats[++fi]); 349 } else { 350 new Thread(() -> { 351 try { 352 Thread.sleep(500); 353 } catch (InterruptedException e) { 354 e.printStackTrace(); 355 } 356 System.exit(0); 357 }).start(); 358 } 359 } 360 361 362 public static void main(String[] args) { 363 try { 364 ImageDropTarget idt = new ImageDropTarget(); 365 366 int x = Integer.parseInt(args[0]); 367 int y = Integer.parseInt(args[1]); 368 startPoint = new Point(Integer.parseInt(args[2]), Integer.parseInt(args[3])); 369 370 idt.formats = new String[args.length - 4]; 371 System.arraycopy(args, 4, idt.formats, 0, args.length - 4); 372 leaveFormat(idt.formats[0]); 373 374 idt.frame.setLocation(x, y); 375 idt.frame.setVisible(true); 376 Util.sync(); 377 378 idt.startImageDrag(); 379 } catch (Throwable e) { 380 e.printStackTrace(); 381 System.exit(1); 382 } 383 } 384 385} 386 387 388class ImageSelection implements Transferable { 389 private static final int IMAGE = 0; 390 private static final DataFlavor[] flavors = {DataFlavor.imageFlavor}; 391 private Image data; 392 393 public ImageSelection(Image data) { 394 this.data = data; 395 } 396 397 @Override 398 public DataFlavor[] getTransferDataFlavors() { 399 // returning flavors itself would allow client code to modify 400 // our internal behavior 401 return flavors.clone(); 402 } 403 404 @Override 405 public boolean isDataFlavorSupported(DataFlavor flavor) { 406 return Stream.of(flavor).anyMatch(flavor::equals); 407 } 408 409 @Override 410 public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException { 411 if (flavor.equals(flavors[IMAGE])) { 412 return data; 413 } else { 414 throw new UnsupportedFlavorException(flavor); 415 } 416 } 417} 418