Skip to content

Commit 0228734

Browse files
author
Alexander Scherbatiy
committed
8262470: Printed GlyphVector outline with low DPI has bad quality on Windows
Reviewed-by: serb, psadhukhan
1 parent 3997c99 commit 0228734

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
@@ -1719,6 +1721,11 @@ protected void deviceDrawLine(int xBegin, int yBegin, int xEnd, int yEnd,
17191721
}
17201722
}
17211723

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

17231730
/**
17241731
* Given a Java2D {@code PathIterator} instance,
@@ -1743,23 +1750,27 @@ private void convertToWPath(PathIterator pathIter) {
17431750
}
17441751
wPrinterJob.setPolyFillMode(polyFillRule);
17451752

1753+
wPrinterJob.scaleTransform(1.0f / precisionScale);
17461754
wPrinterJob.beginPath();
17471755

17481756
while (pathIter.isDone() == false) {
17491757
segmentType = pathIter.currentSegment(segment);
17501758

17511759
switch (segmentType) {
17521760
case PathIterator.SEG_MOVETO:
1761+
precisionScaleUp(segment, 2);
17531762
wPrinterJob.moveTo(segment[0], segment[1]);
17541763
break;
17551764

17561765
case PathIterator.SEG_LINETO:
1766+
precisionScaleUp(segment, 2);
17571767
wPrinterJob.lineTo(segment[0], segment[1]);
17581768
break;
17591769

17601770
/* Convert the quad path to a bezier.
17611771
*/
17621772
case PathIterator.SEG_QUADTO:
1773+
precisionScaleUp(segment, 4);
17631774
int lastX = wPrinterJob.getPenX();
17641775
int lastY = wPrinterJob.getPenY();
17651776
float c1x = lastX + (segment[0] - lastX) * 2 / 3;
@@ -1772,6 +1783,7 @@ private void convertToWPath(PathIterator pathIter) {
17721783
break;
17731784

17741785
case PathIterator.SEG_CUBICTO:
1786+
precisionScaleUp(segment, 6);
17751787
wPrinterJob.polyBezierTo(segment[0], segment[1],
17761788
segment[2], segment[3],
17771789
segment[4], segment[5]);
@@ -1787,6 +1799,7 @@ private void convertToWPath(PathIterator pathIter) {
17871799
}
17881800

17891801
wPrinterJob.endPath();
1802+
wPrinterJob.restoreTransform();
17901803

17911804
}
17921805

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, 2018, 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
@@ -1470,6 +1522,39 @@ protected native void polyBezierTo(long printDC,
14701522
*/
14711523
protected native void setPolyFillMode(long printDC, int fillRule);
14721524

1525+
/**
1526+
* Set the GDI graphics mode to {@code GM_ADVANCED}
1527+
* into the device context {@code printDC}.
1528+
*/
1529+
protected native int setAdvancedGraphicsMode(long printDC);
1530+
1531+
/**
1532+
* Set the GDI graphics {@code mode}
1533+
* into the device context {@code printDC}.
1534+
* The {@code mode} should
1535+
* be one of the following Windows constants:
1536+
* {@code GM_COMPATIBLE} or {@code GM_ADVANCED}.
1537+
*/
1538+
protected native void setGraphicsMode(long printDC, int mode);
1539+
1540+
/**
1541+
* Scale the GDI World Transform
1542+
* of the device context {@code printDC}.
1543+
*/
1544+
protected native void scale(long printDC, double scaleX, double scaleY);
1545+
1546+
/**
1547+
* Get the GDI World Transform
1548+
* from the device context {@code printDC}.
1549+
*/
1550+
protected native void getWorldTransform(long printDC, double[] transform);
1551+
1552+
/**
1553+
* Set the GDI World Transform
1554+
* into the device context {@code printDC}.
1555+
*/
1556+
protected native void setWorldTransform(long printDC, double[] transform);
1557+
14731558
/**
14741559
* Create a Window's solid brush for the color specified
14751560
* 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
@@ -1931,6 +1931,117 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_setPolyFillMode
19311931
CATCH_BAD_ALLOC;
19321932
}
19331933

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

0 commit comments

Comments
 (0)