Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8262470: Printed GlyphVector outline with low DPI has bad quality on Windows #2756

Closed
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2021, 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
@@ -85,6 +85,8 @@
private static final float MIN_DEVICE_LINEWIDTH = 1.2f;
private static final float MAX_THINLINE_INCHES = 0.014f;

private static final float precisionScale = 1000.0f;

/* Note that preferGDITextLayout implies useGDITextLayout.
* "prefer" is used to override cases where would otherwise
* 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,
}
}

private void precisionScaleUp(float[] values, int size) {
for (int i = 0; i < size; i++) {
values[i] = values[i] * precisionScale;
}
}

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

wPrinterJob.scaleTransform(1.0f / precisionScale);
wPrinterJob.beginPath();

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

switch (segmentType) {
case PathIterator.SEG_MOVETO:
precisionScaleUp(segment, 2);
wPrinterJob.moveTo(segment[0], segment[1]);
break;

case PathIterator.SEG_LINETO:
precisionScaleUp(segment, 2);
wPrinterJob.lineTo(segment[0], segment[1]);
break;

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

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

wPrinterJob.endPath();
wPrinterJob.restoreTransform();

}

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2021, 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
@@ -362,6 +362,9 @@ public void dispose() {

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

private int graphicsMode;
private double[] worldTransform = new double[6];

/* Static Initializations */

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

protected void scaleTransform(float scale) {
graphicsMode = setAdvancedGraphicsMode();
getWorldTransform(worldTransform);
scale(scale, scale);
}

protected void restoreTransform() {
setWorldTransform(worldTransform);
setGraphicsMode(graphicsMode);
}

protected void closeFigure() {
closeFigure(getPrintDC());
}
@@ -995,6 +1009,44 @@ protected void setPolyFillMode(int fillRule) {
setPolyFillMode(getPrintDC(), fillRule);
}

/**
* Set the GDI graphics mode to {@code GM_ADVANCED}.
*/
private int setAdvancedGraphicsMode() {
return setAdvancedGraphicsMode(getPrintDC());
}

/**
* Set the GDI graphics mode.
* The {@code mode} should
* be one of the following Windows constants:
* {@code GM_COMPATIBLE} or {@code GM_ADVANCED}.
*/
private void setGraphicsMode(int mode) {
setGraphicsMode(getPrintDC(), mode);
}

/**
* Scale the GDI World Transform.
*/
private void scale(double scaleX, double scaleY) {
scale(getPrintDC(), scaleX, scaleY);
}

/**
* Get the GDI World Transform.
*/
private void getWorldTransform(double[] transform) {
getWorldTransform(getPrintDC(), transform);
}

/**
* Set the GDI World Transform.
*/
private void setWorldTransform(double[] transform) {
setWorldTransform(getPrintDC(), transform);
}

/*
* Create a Window's solid brush for the color specified
* by {@code (red, green, blue)}. Once the brush
@@ -1470,6 +1522,39 @@ protected native void polyBezierTo(long printDC,
*/
protected native void setPolyFillMode(long printDC, int fillRule);

/**
* Set the GDI graphics mode to {@code GM_ADVANCED}
* into the device context {@code printDC}.
*/
protected native int setAdvancedGraphicsMode(long printDC);

/**
* Set the GDI graphics {@code mode}
* into the device context {@code printDC}.
* The {@code mode} should
* be one of the following Windows constants:
* {@code GM_COMPATIBLE} or {@code GM_ADVANCED}.
*/
protected native void setGraphicsMode(long printDC, int mode);

/**
* Scale the GDI World Transform
* of the device context {@code printDC}.
*/
protected native void scale(long printDC, double scaleX, double scaleY);

/**
* Get the GDI World Transform
* from the device context {@code printDC}.
*/
protected native void getWorldTransform(long printDC, double[] transform);

/**
* Set the GDI World Transform
* into the device context {@code printDC}.
*/
protected native void setWorldTransform(long printDC, double[] transform);

/**
* Create a Window's solid brush for the color specified
* by {@code (red, green, blue)}. Once the brush
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2021, 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
@@ -1932,6 +1932,117 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_setPolyFillMode
CATCH_BAD_ALLOC;
}

/*
* Class: sun_awt_windows_WPrinterJob
* Method: setAdvancedGraphicsMode
* Signature: (J)I
*/
JNIEXPORT jint JNICALL Java_sun_awt_windows_WPrinterJob_setAdvancedGraphicsMode
(JNIEnv *env, jobject self, jlong printDC) {
TRY;

int oldGraphicsMode = ::SetGraphicsMode((HDC)printDC, GM_ADVANCED);
DASSERT(oldGraphicsMode != 0);
return (jint) oldGraphicsMode;

CATCH_BAD_ALLOC_RET(0);
}

/*
* Class: sun_awt_windows_WPrinterJob
* Method: setGraphicsMode
* Signature: (JI)V
*/
JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_setGraphicsMode
(JNIEnv *env, jobject self, jlong printDC, jint mode) {
TRY;

int oldGraphicsMode = ::SetGraphicsMode((HDC)printDC, mode);
DASSERT(oldGraphicsMode != 0);

CATCH_BAD_ALLOC;
}

/*
* Class: sun_awt_windows_WPrinterJob
* Method: scale
* Signature: (JDD)V
*/
JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_scale
(JNIEnv *env, jobject self, jlong printDC, jdouble scaleX, jdouble scaleY) {
TRY;

XFORM xForm;

xForm.eM11 = (FLOAT) scaleX;
xForm.eM12 = (FLOAT) 0;
xForm.eM21 = (FLOAT) 0;
xForm.eM22 = (FLOAT) scaleY;
xForm.eDx = (FLOAT) 0;
xForm.eDy = (FLOAT) 0;

BOOL result = ::ModifyWorldTransform((HDC)printDC, &xForm, MWT_RIGHTMULTIPLY);
DASSERT(result);

CATCH_BAD_ALLOC;
}

/*
* Class: sun_awt_windows_WPrinterJob
* Method: getWorldTransform
* Signature: (J[D)V
*/
JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_getWorldTransform
(JNIEnv* env, jobject self, jlong printDC, jdoubleArray transform) {
TRY;

double elems[6];
XFORM xForm;

BOOL result = ::GetWorldTransform((HDC)printDC, &xForm);
DASSERT(result);

elems[0] = (double) xForm.eM11;
elems[1] = (double) xForm.eM12;
elems[2] = (double) xForm.eM21;
elems[3] = (double) xForm.eM22;
elems[4] = (double) xForm.eDx;
elems[5] = (double) xForm.eDy;

env->SetDoubleArrayRegion(transform, 0, 6, elems);

CATCH_BAD_ALLOC;
}

/*
* Class: sun_awt_windows_WPrinterJob
* Method: setWorldTransform
* Signature: (J[D)V
*/
JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_setWorldTransform
(JNIEnv* env, jobject self, jlong printDC, jdoubleArray transform) {
TRY;

double *elems;
XFORM xForm;

elems = env->GetDoubleArrayElements(transform, 0);

xForm.eM11 = (FLOAT) elems[0];
xForm.eM12 = (FLOAT) elems[1];
xForm.eM21 = (FLOAT) elems[2];
xForm.eM22 = (FLOAT) elems[3];
xForm.eDx = (FLOAT) elems[4];
xForm.eDy = (FLOAT) elems[5];

env->ReleaseDoubleArrayElements(transform, elems, 0);

BOOL result = ::SetWorldTransform((HDC)printDC, &xForm);
DASSERT(result);

CATCH_BAD_ALLOC;
}

/*
* Class: sun_awt_windows_WPrinterJob
* Method: selectSolidBrush