Skip to content

Commit 7639f8c

Browse files
author
Alexander Scherbatiy
committed
8262470: Printed GlyphVector outline with low DPI has bad quality on Windows
Reviewed-by: clanger Backport-of: 0228734
1 parent 0e2d915 commit 7639f8c

File tree

5 files changed

+731
-3
lines changed

5 files changed

+731
-3
lines changed

src/java.desktop/windows/classes/sun/awt/windows/WPathGraphics.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -85,6 +85,8 @@ final class WPathGraphics extends PathGraphics {
8585
private static final float MIN_DEVICE_LINEWIDTH = 1.2f;
8686
private static final float MAX_THINLINE_INCHES = 0.014f;
8787

88+
private static final float precisionScale = 1000.0f;
89+
8890
/* Note that preferGDITextLayout implies useGDITextLayout.
8991
* "prefer" is used to override cases where would otherwise
9092
* choose not to use it. Note that non-layout factors may
@@ -1717,6 +1719,11 @@ protected void deviceDrawLine(int xBegin, int yBegin, int xEnd, int yEnd,
17171719
}
17181720
}
17191721

1722+
private void precisionScaleUp(float[] values, int size) {
1723+
for (int i = 0; i < size; i++) {
1724+
values[i] = values[i] * precisionScale;
1725+
}
1726+
}
17201727

17211728
/**
17221729
* Given a Java2D {@code PathIterator} instance,
@@ -1741,23 +1748,27 @@ private void convertToWPath(PathIterator pathIter) {
17411748
}
17421749
wPrinterJob.setPolyFillMode(polyFillRule);
17431750

1751+
wPrinterJob.scaleTransform(1.0f / precisionScale);
17441752
wPrinterJob.beginPath();
17451753

17461754
while (pathIter.isDone() == false) {
17471755
segmentType = pathIter.currentSegment(segment);
17481756

17491757
switch (segmentType) {
17501758
case PathIterator.SEG_MOVETO:
1759+
precisionScaleUp(segment, 2);
17511760
wPrinterJob.moveTo(segment[0], segment[1]);
17521761
break;
17531762

17541763
case PathIterator.SEG_LINETO:
1764+
precisionScaleUp(segment, 2);
17551765
wPrinterJob.lineTo(segment[0], segment[1]);
17561766
break;
17571767

17581768
/* Convert the quad path to a bezier.
17591769
*/
17601770
case PathIterator.SEG_QUADTO:
1771+
precisionScaleUp(segment, 4);
17611772
int lastX = wPrinterJob.getPenX();
17621773
int lastY = wPrinterJob.getPenY();
17631774
float c1x = lastX + (segment[0] - lastX) * 2 / 3;
@@ -1770,6 +1781,7 @@ private void convertToWPath(PathIterator pathIter) {
17701781
break;
17711782

17721783
case PathIterator.SEG_CUBICTO:
1784+
precisionScaleUp(segment, 6);
17731785
wPrinterJob.polyBezierTo(segment[0], segment[1],
17741786
segment[2], segment[3],
17751787
segment[4], segment[5]);
@@ -1785,6 +1797,7 @@ private void convertToWPath(PathIterator pathIter) {
17851797
}
17861798

17871799
wPrinterJob.endPath();
1800+
wPrinterJob.restoreTransform();
17881801

17891802
}
17901803

src/java.desktop/windows/classes/sun/awt/windows/WPrinterJob.java

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -362,6 +362,9 @@ public void dispose() {
362362

363363
private java.awt.peer.ComponentPeer dialogOwnerPeer = null;
364364

365+
private int graphicsMode;
366+
private double[] worldTransform = new double[6];
367+
365368
/* Static Initializations */
366369

367370
static {
@@ -960,6 +963,17 @@ protected void endPath() {
960963
endPath(getPrintDC());
961964
}
962965

966+
protected void scaleTransform(float scale) {
967+
graphicsMode = setAdvancedGraphicsMode();
968+
getWorldTransform(worldTransform);
969+
scale(scale, scale);
970+
}
971+
972+
protected void restoreTransform() {
973+
setWorldTransform(worldTransform);
974+
setGraphicsMode(graphicsMode);
975+
}
976+
963977
protected void closeFigure() {
964978
closeFigure(getPrintDC());
965979
}
@@ -995,6 +1009,44 @@ protected void setPolyFillMode(int fillRule) {
9951009
setPolyFillMode(getPrintDC(), fillRule);
9961010
}
9971011

1012+
/**
1013+
* Set the GDI graphics mode to {@code GM_ADVANCED}.
1014+
*/
1015+
private int setAdvancedGraphicsMode() {
1016+
return setAdvancedGraphicsMode(getPrintDC());
1017+
}
1018+
1019+
/**
1020+
* Set the GDI graphics mode.
1021+
* The {@code mode} should
1022+
* be one of the following Windows constants:
1023+
* {@code GM_COMPATIBLE} or {@code GM_ADVANCED}.
1024+
*/
1025+
private void setGraphicsMode(int mode) {
1026+
setGraphicsMode(getPrintDC(), mode);
1027+
}
1028+
1029+
/**
1030+
* Scale the GDI World Transform.
1031+
*/
1032+
private void scale(double scaleX, double scaleY) {
1033+
scale(getPrintDC(), scaleX, scaleY);
1034+
}
1035+
1036+
/**
1037+
* Get the GDI World Transform.
1038+
*/
1039+
private void getWorldTransform(double[] transform) {
1040+
getWorldTransform(getPrintDC(), transform);
1041+
}
1042+
1043+
/**
1044+
* Set the GDI World Transform.
1045+
*/
1046+
private void setWorldTransform(double[] transform) {
1047+
setWorldTransform(getPrintDC(), transform);
1048+
}
1049+
9981050
/*
9991051
* Create a Window's solid brush for the color specified
10001052
* by {@code (red, green, blue)}. Once the brush
@@ -1474,6 +1526,39 @@ protected native void polyBezierTo(long printDC,
14741526
*/
14751527
protected native void setPolyFillMode(long printDC, int fillRule);
14761528

1529+
/**
1530+
* Set the GDI graphics mode to {@code GM_ADVANCED}
1531+
* into the device context {@code printDC}.
1532+
*/
1533+
protected native int setAdvancedGraphicsMode(long printDC);
1534+
1535+
/**
1536+
* Set the GDI graphics {@code mode}
1537+
* into the device context {@code printDC}.
1538+
* The {@code mode} should
1539+
* be one of the following Windows constants:
1540+
* {@code GM_COMPATIBLE} or {@code GM_ADVANCED}.
1541+
*/
1542+
protected native void setGraphicsMode(long printDC, int mode);
1543+
1544+
/**
1545+
* Scale the GDI World Transform
1546+
* of the device context {@code printDC}.
1547+
*/
1548+
protected native void scale(long printDC, double scaleX, double scaleY);
1549+
1550+
/**
1551+
* Get the GDI World Transform
1552+
* from the device context {@code printDC}.
1553+
*/
1554+
protected native void getWorldTransform(long printDC, double[] transform);
1555+
1556+
/**
1557+
* Set the GDI World Transform
1558+
* into the device context {@code printDC}.
1559+
*/
1560+
protected native void setWorldTransform(long printDC, double[] transform);
1561+
14771562
/**
14781563
* Create a Window's solid brush for the color specified
14791564
* by {@code (red, green, blue)}. Once the brush

src/java.desktop/windows/native/libawt/windows/awt_PrintJob.cpp

Lines changed: 112 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -1927,6 +1927,117 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_setPolyFillMode
19271927
CATCH_BAD_ALLOC;
19281928
}
19291929

1930+
/*
1931+
* Class: sun_awt_windows_WPrinterJob
1932+
* Method: setAdvancedGraphicsMode
1933+
* Signature: (J)I
1934+
*/
1935+
JNIEXPORT jint JNICALL Java_sun_awt_windows_WPrinterJob_setAdvancedGraphicsMode
1936+
(JNIEnv *env, jobject self, jlong printDC) {
1937+
TRY;
1938+
1939+
int oldGraphicsMode = ::SetGraphicsMode((HDC)printDC, GM_ADVANCED);
1940+
DASSERT(oldGraphicsMode != 0);
1941+
return (jint) oldGraphicsMode;
1942+
1943+
CATCH_BAD_ALLOC_RET(0);
1944+
}
1945+
1946+
/*
1947+
* Class: sun_awt_windows_WPrinterJob
1948+
* Method: setGraphicsMode
1949+
* Signature: (JI)V
1950+
*/
1951+
JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_setGraphicsMode
1952+
(JNIEnv *env, jobject self, jlong printDC, jint mode) {
1953+
TRY;
1954+
1955+
int oldGraphicsMode = ::SetGraphicsMode((HDC)printDC, mode);
1956+
DASSERT(oldGraphicsMode != 0);
1957+
1958+
CATCH_BAD_ALLOC;
1959+
}
1960+
1961+
/*
1962+
* Class: sun_awt_windows_WPrinterJob
1963+
* Method: scale
1964+
* Signature: (JDD)V
1965+
*/
1966+
JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_scale
1967+
(JNIEnv *env, jobject self, jlong printDC, jdouble scaleX, jdouble scaleY) {
1968+
TRY;
1969+
1970+
XFORM xForm;
1971+
1972+
xForm.eM11 = (FLOAT) scaleX;
1973+
xForm.eM12 = (FLOAT) 0;
1974+
xForm.eM21 = (FLOAT) 0;
1975+
xForm.eM22 = (FLOAT) scaleY;
1976+
xForm.eDx = (FLOAT) 0;
1977+
xForm.eDy = (FLOAT) 0;
1978+
1979+
BOOL result = ::ModifyWorldTransform((HDC)printDC, &xForm, MWT_RIGHTMULTIPLY);
1980+
DASSERT(result);
1981+
1982+
CATCH_BAD_ALLOC;
1983+
}
1984+
1985+
/*
1986+
* Class: sun_awt_windows_WPrinterJob
1987+
* Method: getWorldTransform
1988+
* Signature: (J[D)V
1989+
*/
1990+
JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_getWorldTransform
1991+
(JNIEnv* env, jobject self, jlong printDC, jdoubleArray transform) {
1992+
TRY;
1993+
1994+
double elems[6];
1995+
XFORM xForm;
1996+
1997+
BOOL result = ::GetWorldTransform((HDC)printDC, &xForm);
1998+
DASSERT(result);
1999+
2000+
elems[0] = (double) xForm.eM11;
2001+
elems[1] = (double) xForm.eM12;
2002+
elems[2] = (double) xForm.eM21;
2003+
elems[3] = (double) xForm.eM22;
2004+
elems[4] = (double) xForm.eDx;
2005+
elems[5] = (double) xForm.eDy;
2006+
2007+
env->SetDoubleArrayRegion(transform, 0, 6, elems);
2008+
2009+
CATCH_BAD_ALLOC;
2010+
}
2011+
2012+
/*
2013+
* Class: sun_awt_windows_WPrinterJob
2014+
* Method: setWorldTransform
2015+
* Signature: (J[D)V
2016+
*/
2017+
JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_setWorldTransform
2018+
(JNIEnv* env, jobject self, jlong printDC, jdoubleArray transform) {
2019+
TRY;
2020+
2021+
double *elems;
2022+
XFORM xForm;
2023+
2024+
elems = env->GetDoubleArrayElements(transform, 0);
2025+
2026+
xForm.eM11 = (FLOAT) elems[0];
2027+
xForm.eM12 = (FLOAT) elems[1];
2028+
xForm.eM21 = (FLOAT) elems[2];
2029+
xForm.eM22 = (FLOAT) elems[3];
2030+
xForm.eDx = (FLOAT) elems[4];
2031+
xForm.eDy = (FLOAT) elems[5];
2032+
2033+
env->ReleaseDoubleArrayElements(transform, elems, 0);
2034+
2035+
BOOL result = ::SetWorldTransform((HDC)printDC, &xForm);
2036+
DASSERT(result);
2037+
2038+
CATCH_BAD_ALLOC;
2039+
}
2040+
19302041
/*
19312042
* Class: sun_awt_windows_WPrinterJob
19322043
* Method: selectSolidBrush

0 commit comments

Comments
 (0)