Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
8220484: JFXPanel renders a slanted image with a hidpi monitor scale …
…of 125% or 175%

Reviewed-by: kcr, psadhukhan
  • Loading branch information
Schmidor authored and kevinrushforth committed Jul 22, 2020
1 parent 5f60ea5 commit 3cc29e3
Show file tree
Hide file tree
Showing 7 changed files with 351 additions and 10 deletions.
14 changes: 12 additions & 2 deletions build.gradle
Expand Up @@ -2574,8 +2574,18 @@ project(":swing") {

sourceSets {
main
//shims // no test shims needed
test
shims {
java {
compileClasspath += sourceSets.main.output
runtimeClasspath += sourceSets.main.output
}
}
test {
java {
compileClasspath += sourceSets.shims.output
runtimeClasspath += sourceSets.shims.output
}
}
}

project.ext.moduleSourcePath = defaultModuleSourcePath
Expand Down
Expand Up @@ -231,8 +231,8 @@ public boolean getPixels(final IntBuffer dest, final int width, final int height
{
return false;
}
scaledWidth = Math.round(scaledWidth * texScaleFactorX);
scaledHeight = Math.round(scaledHeight * texScaleFactorY);
scaledWidth = (int) Math.ceil(scaledWidth * texScaleFactorX);
scaledHeight = (int) Math.ceil(scaledHeight * texScaleFactorY);

dest.rewind();
texBits.rewind();
Expand Down
Expand Up @@ -687,8 +687,8 @@ private void createResizePixelBuffer(double newScaleFactorX, double newScaleFact
double ratioX = newScaleFactorX / scaleFactorX;
double ratioY = newScaleFactorY / scaleFactorY;
// Transform old size to the new coordinate space.
int oldW = (int)Math.round(oldIm.getWidth() * ratioX);
int oldH = (int)Math.round(oldIm.getHeight() * ratioY);
int oldW = (int)Math.ceil(oldIm.getWidth() * ratioX);
int oldH = (int)Math.ceil(oldIm.getHeight() * ratioY);

Graphics g = pixelsIm.getGraphics();
try {
Expand Down Expand Up @@ -932,6 +932,11 @@ private void invokeOnClientEDT(Runnable r) {
jfxPanelIOP.postEvent(this, new InvocationEvent(this, r));
}

// Package scope method for testing
final BufferedImage test_getPixelsIm() {
return pixelsIm;
}

private class HostContainer implements HostInterface {

@Override
Expand Down
@@ -0,0 +1,35 @@
/*
* Copyright (c) 2020, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javafx.embed.swing;

import java.awt.image.BufferedImage;

public class JFXPanelShim {

public static BufferedImage getPixelsIm(JFXPanel panel) {
return panel.test_getPixelsIm();
}

}
Expand Up @@ -634,8 +634,8 @@ private void paintControl(PaintEvent pe) {
height = lastHeight;
buffer = lastPixelsBuf;
}
width = (int)Math.round(width * scaleFactor);
height = (int)Math.round(height * scaleFactor);
width = (int)Math.ceil(width * scaleFactor);
height = (int)Math.ceil(height * scaleFactor);

// Consider optimizing this
ImageData imageData = null;
Expand Down Expand Up @@ -1053,8 +1053,8 @@ private void resizePixelBuffer(double newScaleFactor) {
if ((pWidth <= 0) || (pHeight <= 0)) {
pixelsBuf = null;
} else {
pixelsBuf = IntBuffer.allocate((int)Math.round(pWidth * newScaleFactor) *
(int)Math.round(pHeight * newScaleFactor));
pixelsBuf = IntBuffer.allocate((int)Math.ceil(pWidth * newScaleFactor) *
(int)Math.ceil(pHeight * newScaleFactor));
// The bg color may show through on resize. See RT-34380.
RGB rgb = getBackground().getRGB();
Arrays.fill(pixelsBuf.array(), rgb.red << 16 | rgb.green << 8 | rgb.blue);
Expand Down
@@ -0,0 +1,131 @@
/*
* Copyright (c) 2020, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

package test.javafx.embed.swt;

import static org.junit.Assert.fail;

import java.util.Timer;
import java.util.TimerTask;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.PaletteData;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.junit.Test;

import javafx.embed.swt.FXCanvas;
import javafx.scene.Scene;
import javafx.scene.layout.Region;

public class FXCanvasScaledTest {

private int cnt;

static Shell shell;

static Display display;

/* Base size, so that with a scaling of 125% there are different results for Math.round and Math.ceil */
final static int TARGET_BASE_SIZE = 101;

@Test(timeout = 10000)
public void testScale() throws Throwable {
System.setProperty("sun.java2d.uiScale.enabled", "true");
System.setProperty("sun.java2d.uiScale", "125%");
System.setProperty("glass.win.uiScale", "125%");
System.setProperty("glass.win.renderScale", "125%");
System.setProperty("glass.gtk.uiScale", "1.25");
System.setProperty("swt.autoScale", "125");

// Start the Application
display = new Display();
shell = new Shell(display);
shell.setLayout(new FillLayout());
final FXCanvas canvas = new FXCanvas(shell, SWT.NONE);
initFX(canvas);

Timer t = new Timer();
TimerTask task = new TimerTask() {
@Override
public void run() {
switch (cnt) {
case 0:
display.asyncExec(() -> canvas.setBounds(0, 0, 201, 201));
break;
case 1:
display.asyncExec(() -> canvas.setBounds(0, 0, TARGET_BASE_SIZE, TARGET_BASE_SIZE));
break;
case 2:
t.cancel();
display.asyncExec(() -> {
// Capture painted component. Bounds are in pt, so size is 101 and not 127
GC gc = new GC(canvas);
final Image image = new Image(display, canvas.getBounds());
gc.copyArea(image, canvas.getBounds().x, canvas.getBounds().y);
gc.dispose();
PaletteData palette = image.getImageData().palette;
int referenceWhitePixel = image.getImageData().getPixel(0, 0);
RGB referenceRGB = palette.getRGB(referenceWhitePixel);
// check if there is a diagonal, which should be the right border
for (int x = 10; x < 30; x++) {
for (int y = 80; y < 100; y++) {
int pixel = image.getImageData().getPixel(x, y);
RGB rgb = palette.getRGB(pixel);
if (!referenceRGB.equals(rgb)) {
fail("image is skewed");
}
}
}
shell.close();
});
break;
}
cnt++;
}
};
t.schedule(task, 500, 500);

shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}

private static void initFX(FXCanvas canvas) {
Region region = new Region();
region.setStyle("-fx-background-color: #FFFFFF;" + "-fx-border-color: #000000;" + "-fx-border-width: 0 5px 0 0;"
+ "-fx-border-style: solid");
Scene scene = new Scene(region);
canvas.setScene(scene);
canvas.setBounds(0, 0, 100, 100);
}
}

0 comments on commit 3cc29e3

Please sign in to comment.