8153522: Update JLightweightFrame to allow non-integer (and X/Y) scales
authorssadetsky
Mon, 07 Nov 2016 10:36:52 +0300
changeset 42199 8c0e8e13d4d8
parent 42198 6ff366cc096b
child 42200 0ab62056c933
8153522: Update JLightweightFrame to allow non-integer (and X/Y) scales Reviewed-by: alexsch
jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformLWWindow.java
jdk/src/java.desktop/share/classes/sun/awt/LightweightFrame.java
jdk/src/java.desktop/share/classes/sun/swing/JLightweightFrame.java
jdk/src/java.desktop/share/classes/sun/swing/LightweightContent.java
--- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformLWWindow.java	Fri Nov 04 15:59:59 2016 -0700
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformLWWindow.java	Mon Nov 07 10:36:52 2016 +0300
@@ -196,7 +196,8 @@
                                   getLocalGraphicsEnvironment();
 
         LWLightweightFramePeer peer = (LWLightweightFramePeer)getPeer();
-        int scale = ((LightweightFrame)peer.getTarget()).getScaleFactor();
+        int scale =(int) Math.round(((LightweightFrame)peer.getTarget())
+                                                            .getScaleFactorX());
 
         Rectangle bounds = ((LightweightFrame)peer.getTarget()).getHostBounds();
         for (GraphicsDevice d : ge.getScreenDevices()) {
--- a/jdk/src/java.desktop/share/classes/sun/awt/LightweightFrame.java	Fri Nov 04 15:59:59 2016 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/awt/LightweightFrame.java	Mon Nov 07 10:36:52 2016 +0300
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -141,17 +141,52 @@
      *
      * @return the scale factor
      * @see #notifyDisplayChanged(int)
+     * @Depricated replaced by {@link #getScaleFactorX()} and
+     * {@link #getScaleFactorY}
      */
+    @Deprecated(since = "9")
     public abstract int getScaleFactor();
 
     /**
+     * Returns the scale factor of this frame along x coordinate. The default
+     * value is 1.
+     *
+     * @return the x coordinate scale factor
+     * @see #notifyDisplayChanged(double, double)
+     * @since 9
+     */
+    public abstract double getScaleFactorX();
+
+    /**
+     * Returns the scale factor of this frame along y coordinate. The default
+     * value is 1.
+     *
+     * @return the y coordinate scale factor
+     * @see #notifyDisplayChanged(double, double)
+     * @since 9
+     */
+    public abstract double getScaleFactorY();
+
+    /**
      * Called when display of the hosted frame is changed.
      *
      * @param scaleFactor the scale factor
+     * @Depricated replaced by {@link #notifyDisplayChanged(double, double)}
      */
+    @Deprecated(since = "9")
     public abstract void notifyDisplayChanged(int scaleFactor);
 
     /**
+     * Called when display of the hosted frame is changed.
+     *
+     * @param scaleFactorX the scale factor
+     * @param scaleFactorY the scale factor
+     * @since 9
+     */
+    public abstract void notifyDisplayChanged(double scaleFactorX,
+                                              double scaleFactorY);
+
+    /**
      * Host window absolute bounds.
      */
     private int hostX, hostY, hostW, hostH;
@@ -202,4 +237,5 @@
      * Removes a drop target from the lightweight frame.
      */
     public abstract void removeDropTarget(DropTarget dt);
+
 }
--- a/jdk/src/java.desktop/share/classes/sun/swing/JLightweightFrame.java	Fri Nov 04 15:59:59 2016 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/swing/JLightweightFrame.java	Mon Nov 07 10:36:52 2016 +0300
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,18 +25,7 @@
 
 package sun.swing;
 
-import java.awt.BorderLayout;
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.Container;
-import java.awt.Dimension;
-import java.awt.EventQueue;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
-import java.awt.MouseInfo;
-import java.awt.Point;
-import java.awt.Rectangle;
-import java.awt.Window;
+import java.awt.*;
 import java.awt.dnd.DragGestureEvent;
 import java.awt.dnd.DragGestureListener;
 import java.awt.dnd.DragGestureRecognizer;
@@ -46,6 +35,7 @@
 import java.awt.dnd.peer.DragSourceContextPeer;
 import java.awt.event.ContainerEvent;
 import java.awt.event.ContainerListener;
+import java.awt.geom.AffineTransform;
 import java.awt.image.BufferedImage;
 import java.awt.image.DataBufferInt;
 import java.beans.PropertyChangeEvent;
@@ -89,7 +79,8 @@
 
     private BufferedImage bbImage;
 
-    private volatile int scaleFactor = 1;
+    private volatile double scaleFactorX;
+    private volatile double scaleFactorY;
 
     /**
      * {@code copyBufferEnabled}, true by default, defines the following strategy.
@@ -124,6 +115,10 @@
      */
     public JLightweightFrame() {
         super();
+        AffineTransform defaultTransform =
+                           getGraphicsConfiguration().getDefaultTransform();
+        scaleFactorX = defaultTransform.getScaleX();
+        scaleFactorY = defaultTransform.getScaleY();
         copyBufferEnabled = "true".equals(AccessController.
             doPrivileged(new GetPropertyAction("swing.jlf.copyBufferEnabled", "true")));
 
@@ -157,8 +152,9 @@
             }
             Point p = SwingUtilities.convertPoint(c, x, y, jlf);
             Rectangle r = new Rectangle(p.x, p.y, w, h).intersection(
-                    new Rectangle(0, 0, bbImage.getWidth() / scaleFactor,
-                                  bbImage.getHeight() / scaleFactor));
+                    new Rectangle(0, 0,
+                          (int)Math.round(bbImage.getWidth() / scaleFactorX),
+                          (int)Math.round(bbImage.getHeight() / scaleFactorY)));
 
             if (!r.isEmpty()) {
                 notifyImageUpdated(r.x, r.y, r.width, r.height);
@@ -212,7 +208,7 @@
         g.setBackground(getBackground());
         g.setColor(getForeground());
         g.setFont(getFont());
-        g.scale(scaleFactor, scaleFactor);
+        g.scale(scaleFactorX, scaleFactorY);
         return g;
     }
 
@@ -237,28 +233,52 @@
     }
 
     @Override
+    @SuppressWarnings("deprecation")
     public int getScaleFactor() {
-        return scaleFactor;
+        return (int)scaleFactorX;
+    }
+
+    @Override
+    public double getScaleFactorX() {
+        return scaleFactorX;
+    }
+
+    @Override
+    public double getScaleFactorY() {
+        return scaleFactorY;
     }
 
     @Override
     public void notifyDisplayChanged(final int scaleFactor) {
-        if (scaleFactor != this.scaleFactor) {
+        notifyDisplayChanged(scaleFactor, scaleFactor);
+    }
+
+    @Override
+    public void notifyDisplayChanged(final double scaleFactorX,
+                                                    final double scaleFactorY) {
+        if (Double.compare(scaleFactorX, this.scaleFactorX) != 0 ||
+                         Double.compare(scaleFactorY, this.scaleFactorY) != 0) {
             if (!copyBufferEnabled) content.paintLock();
             try {
                 if (bbImage != null) {
-                    resizeBuffer(getWidth(), getHeight(), scaleFactor);
+                    resizeBuffer(getWidth(), getHeight(), scaleFactorX,
+                                                                  scaleFactorY);
                 }
             } finally {
                 if (!copyBufferEnabled) content.paintUnlock();
             }
-            this.scaleFactor = scaleFactor;
+            this.scaleFactorX = scaleFactorX;
+            this.scaleFactorY = scaleFactorY;
+
+            if(isVisible()) {
+                final Object peer =
+                        AWTAccessor.getComponentAccessor().getPeer(this);
+                if (peer instanceof DisplayChangedListener) {
+                    ((DisplayChangedListener) peer).displayChanged();
+                }
+                repaint();
+            }
         }
-        final Object peer = AWTAccessor.getComponentAccessor().getPeer(this);
-        if (peer instanceof DisplayChangedListener) {
-            ((DisplayChangedListener) peer).displayChanged();
-        }
-        repaint();
     }
 
     @Override
@@ -270,7 +290,8 @@
         }
     }
 
-    private void syncCopyBuffer(boolean reset, int x, int y, int w, int h, int scale) {
+    private void syncCopyBuffer(boolean reset, int x, int y, int w, int h,
+                                                 double scaleX, double scaleY) {
         content.paintLock();
         try {
             int[] srcBuffer = ((DataBufferInt)bbImage.getRaster().getDataBuffer()).getData();
@@ -279,14 +300,14 @@
             }
             int linestride = bbImage.getWidth();
 
-            x *= scale;
-            y *= scale;
-            w *= scale;
-            h *= scale;
+            int startX = (int)Math.floor(x * scaleX);
+            int startY = (int)Math.floor(y * scaleY);
+            int width  = (int)Math.ceil((x + w) * scaleX) - startX;
+            int height = (int)Math.ceil((y + h) * scaleY) - startY;
 
-            for (int i=0; i<h; i++) {
-                int from = (y + i) * linestride + x;
-                System.arraycopy(srcBuffer, from, copyBuffer, from, w);
+            for (int i = 0; i < height; i++) {
+                int from = (startY + i) * linestride + startX;
+                System.arraycopy(srcBuffer, from, copyBuffer, from, width);
             }
         } finally {
             content.paintUnlock();
@@ -295,7 +316,8 @@
 
     private void notifyImageUpdated(int x, int y, int width, int height) {
         if (copyBufferEnabled) {
-            syncCopyBuffer(false, x, y, width, height, scaleFactor);
+            syncCopyBuffer(false, x, y, width, height, scaleFactorX,
+                                                                  scaleFactorY);
         }
         content.imageUpdated(x, y, width, height);
     }
@@ -382,8 +404,10 @@
             int newW = width;
             int newH = height;
             if (bbImage != null) {
-                int imgWidth = bbImage.getWidth() / scaleFactor;
-                int imgHeight = bbImage.getHeight() / scaleFactor;
+                int imgWidth = (int)Math.round(bbImage.getWidth() /
+                                                                  scaleFactorX);
+                int imgHeight = (int)Math.round(bbImage.getHeight() /
+                                                                  scaleFactorY);
                 if (width != imgWidth || height != imgHeight) {
                     createBB = true;
                     if (bbImage != null) {
@@ -407,7 +431,7 @@
                 }
             }
             if (createBB) {
-                resizeBuffer(newW, newH, scaleFactor);
+                resizeBuffer(newW, newH, scaleFactorX, scaleFactorY);
                 return;
             }
             content.imageReshaped(0, 0, width, height);
@@ -419,16 +443,19 @@
         }
     }
 
-    private void resizeBuffer(int width, int height, int newScaleFactor) {
-            bbImage = new BufferedImage(width*newScaleFactor,height*newScaleFactor,
+    private void resizeBuffer(int width, int height, double newScaleFactorX,
+                                                     double newScaleFactorY) {
+        bbImage = new BufferedImage((int)Math.round(width * newScaleFactorX),
+                                    (int)Math.round(height * newScaleFactorY),
                                         BufferedImage.TYPE_INT_ARGB_PRE);
         int[] pixels= ((DataBufferInt)bbImage.getRaster().getDataBuffer()).getData();
         if (copyBufferEnabled) {
-            syncCopyBuffer(true, 0, 0, width, height, newScaleFactor);
+            syncCopyBuffer(true, 0, 0, width, height, newScaleFactorX,
+                                                               newScaleFactorY);
             pixels = copyBuffer;
         }
         content.imageBufferReset(pixels, 0, 0, width, height,
-                                 width * newScaleFactor, newScaleFactor);
+                          bbImage.getWidth(), newScaleFactorX, newScaleFactorY);
     }
 
     @Override
--- a/jdk/src/java.desktop/share/classes/sun/swing/LightweightContent.java	Fri Nov 04 15:59:59 2016 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/swing/LightweightContent.java	Mon Nov 07 10:36:52 2016 +0300
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016 Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -117,7 +117,10 @@
      * @param height the logical height of the image
      * @param linestride the line stride of the pixel buffer
      * @param scale the scale factor of the pixel buffer
+     * @Depricated replaced by
+     * {@link #imageBufferReset(int[],int,int,int,int,int,double,double)}
      */
+    @Deprecated(since = "9")
     default public void imageBufferReset(int[] data,
                                  int x, int y,
                                  int width, int height,
@@ -128,11 +131,54 @@
     }
 
     /**
+     * {@code JLightweightFrame} calls this method to notify the client
+     * application that a new data buffer has been set as a content pixel
+     * buffer. Typically this occurs when a buffer of a larger size is
+     * created in response to a content resize event.
+     * <p>
+     * The method reports a reference to the pixel data buffer, the content
+     * image bounds within the buffer and the line stride of the buffer.
+     * These values have the following correlation.
+     * The {@code width} and {@code height} matches the layout size of the
+     * content (the component returned from the {@link #getComponent} method).
+     * The {@code x} and {@code y} is the origin of the content, {@code (0, 0)}
+     * in the layout coordinate space of the content, appearing at
+     * {@code data[y * scaleY * linestride + x * scaleX]} in the buffer.
+     * A pixel with indices {@code (i, j)}, where {@code (0 <= i < width)} and
+     * {@code (0 <= j < height)}, in the layout coordinate space of the content
+     * is represented by a {@code scaleX * scaleY} square of pixels in the
+     * physical coordinate space of the buffer. The top-left corner of the
+     * square has the following physical coordinate in the buffer:
+     * {@code data[(y + j) * scaleY * linestride + (x + i) * scaleX]}.
+     *
+     * @param data the content pixel data buffer of INT_ARGB_PRE type
+     * @param x the logical x coordinate of the image
+     * @param y the logical y coordinate of the image
+     * @param width the logical width of the image
+     * @param height the logical height of the image
+     * @param linestride the line stride of the pixel buffer
+     * @param scaleX the x coordinate scale factor of the pixel buffer
+     * @param scaleY the y coordinate scale factor of the pixel buffer
+     * @since 9
+     */
+    @SuppressWarnings("deprecation")
+    default public void imageBufferReset(int[] data,
+                                         int x, int y,
+                                         int width, int height,
+                                         int linestride,
+                                         double scaleX, double scaleY)
+    {
+        imageBufferReset(data, x, y, width, height, linestride,
+                                                       (int)Math.round(scaleX));
+    }
+
+    /**
      * The default implementation for #imageBufferReset uses a hard-coded value
      * of 1 for the scale factor. Both the old and the new methods provide
      * default implementations in order to allow a client application to run
      * with any JDK version without breaking backward compatibility.
      */
+    @SuppressWarnings("deprecation")
     default public void imageBufferReset(int[] data,
                                  int x, int y,
                                  int width, int height,