8162796: [macosx] LinearGradientPaint and RadialGradientPaint are not printed on OS X.
Reviewed-by: prr, jdv
--- a/jdk/src/java.desktop/macosx/classes/sun/java2d/OSXSurfaceData.java Thu Oct 27 10:49:16 2016 +0530
+++ b/jdk/src/java.desktop/macosx/classes/sun/java2d/OSXSurfaceData.java Thu Oct 27 17:24:16 2016 +0530
@@ -74,8 +74,13 @@
this.fGraphicsStatesInt = this.fGraphicsStates.asIntBuffer();
this.fGraphicsStatesFloat = this.fGraphicsStates.asFloatBuffer();
this.fGraphicsStatesLong = this.fGraphicsStates.asLongBuffer();
- this.fGraphicsStatesObject = new Object[6]; // clip coordinates + clip types + texture paint image + stroke dash
- // array + font + font paint
+ this.fGraphicsStatesObject = new Object[8]; // clip coordinates +
+ // clip types +
+ // texture paint image +
+ // stroke dash array +
+ // font + font paint +
+ // linear/radial gradient color +
+ // linear/radial gradient fractions
// NOTE: All access to the DrawingQueue comes through this OSXSurfaceData instance. Therefore
// every instance method of OSXSurfaceData that accesses the fDrawingQueue is synchronized.
@@ -292,10 +297,10 @@
@Native static final int kHintsFractionalMetricsIndex = 46;
@Native static final int kHintsRenderingIndex = 47;
@Native static final int kHintsInterpolationIndex = 48;
- // live resizing info
- @Native static final int kCanDrawDuringLiveResizeIndex = 49;
+ //gradient info
+ @Native static final int kRadiusIndex = 49;
- @Native static final int kSizeOfParameters = kCanDrawDuringLiveResizeIndex + 1;
+ @Native static final int kSizeOfParameters = kRadiusIndex + 1;
// for objectParameters
@Native static final int kClipCoordinatesIndex = 0;
@@ -304,6 +309,8 @@
@Native static final int kStrokeDashArrayIndex = 3;
@Native static final int kFontIndex = 4;
@Native static final int kFontPaintIndex = 5;
+ @Native static final int kColorArrayIndex = 6;
+ @Native static final int kFractionsArrayIndex = 7;
// possible state changes
@Native static final int kBoundsChangedBit = 1 << 0;
@@ -329,6 +336,8 @@
@Native static final int kColorSystem = 1;
@Native static final int kColorGradient = 2;
@Native static final int kColorTexture = 3;
+ @Native static final int kColorLinearGradient = 4;
+ @Native static final int kColorRadialGradient = 5;
// possible gradient color states
@Native static final int kColorNonCyclic = 0;
@@ -522,6 +531,28 @@
int lastPaintIndex = 0;
BufferedImage texturePaintImage = null;
+ void setGradientViaRasterPath(SunGraphics2D sg2d) {
+ if ((this.fGraphicsStatesInt.get(kColorStateIndex) != kColorTexture) || (lastPaint != sg2d.paint) || ((this.fChangeFlag & kBoundsChangedBit) != 0)) {
+ PaintContext context = sg2d.paint.createContext(sg2d.getDeviceColorModel(), userBounds, userBounds, sIdentityMatrix, sg2d.getRenderingHints());
+ WritableRaster raster = (WritableRaster) (context.getRaster(userBounds.x, userBounds.y, userBounds.width, userBounds.height));
+ ColorModel cm = context.getColorModel();
+ texturePaintImage = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
+
+ this.fGraphicsStatesInt.put(kColorStateIndex, kColorTexture);
+ this.fGraphicsStatesInt.put(kColorWidthIndex, texturePaintImage.getWidth());
+ this.fGraphicsStatesInt.put(kColorHeightIndex, texturePaintImage.getHeight());
+ this.fGraphicsStatesFloat.put(kColortxIndex, (float) userBounds.getX());
+ this.fGraphicsStatesFloat.put(kColortyIndex, (float) userBounds.getY());
+ this.fGraphicsStatesFloat.put(kColorsxIndex, 1.0f);
+ this.fGraphicsStatesFloat.put(kColorsyIndex, 1.0f);
+ this.fGraphicsStatesObject[kTextureImageIndex] = OSXOffScreenSurfaceData.createNewSurface(texturePaintImage);
+
+ this.fChangeFlag = (this.fChangeFlag | kColorChangedBit);
+ } else {
+ this.fChangeFlag = (this.fChangeFlag & kColorNotChangedBit);
+ }
+ }
+
void setupPaint(SunGraphics2D sg2d, int x, int y, int w, int h) {
if (sg2d.paint instanceof SystemColor) {
SystemColor color = (SystemColor) sg2d.paint;
@@ -567,6 +598,75 @@
} else {
this.fChangeFlag = (this.fChangeFlag & kColorNotChangedBit);
}
+ } else if (sg2d.paint instanceof LinearGradientPaint) {
+ LinearGradientPaint color = (LinearGradientPaint) sg2d.paint;
+ if (color.getCycleMethod() == LinearGradientPaint.CycleMethod.NO_CYCLE) {
+ if ((this.fGraphicsStatesInt.get(kColorStateIndex) != kColorLinearGradient) || (lastPaint != sg2d.paint)) {
+
+ this.fGraphicsStatesInt.put(kColorStateIndex, kColorLinearGradient);
+ int numColor = color.getColors().length;
+ int colorArray[] = new int[numColor];
+ for (int i = 0; i < numColor; i++) {
+ colorArray[i] = color.getColors()[i].getRGB();
+ }
+ this.fGraphicsStatesObject[kColorArrayIndex] = colorArray;
+
+ int numFractions = color.getFractions().length;
+ float fractionArray[] = new float[numFractions];
+ for (int i = 0; i < numFractions; i++) {
+ fractionArray[i] = color.getFractions()[i];
+ }
+ this.fGraphicsStatesObject[kFractionsArrayIndex] = color.getFractions();
+
+ Point2D p = color.getStartPoint();
+ this.fGraphicsStatesFloat.put(kColorx1Index, (float) p.getX());
+ this.fGraphicsStatesFloat.put(kColory1Index, (float) p.getY());
+ p = color.getEndPoint();
+ this.fGraphicsStatesFloat.put(kColorx2Index, (float) p.getX());
+ this.fGraphicsStatesFloat.put(kColory2Index, (float) p.getY());
+
+ this.fChangeFlag = (this.fChangeFlag | kColorChangedBit);
+ } else {
+ this.fChangeFlag = (this.fChangeFlag & kColorNotChangedBit);
+ }
+ } else {
+ setGradientViaRasterPath(sg2d);
+ }
+ } else if (sg2d.paint instanceof RadialGradientPaint) {
+ RadialGradientPaint color = (RadialGradientPaint) sg2d.paint;
+ if (color.getCycleMethod() == RadialGradientPaint.CycleMethod.NO_CYCLE) {
+ if ((this.fGraphicsStatesInt.get(kColorStateIndex) != kColorRadialGradient) || (lastPaint != sg2d.paint)) {
+
+ this.fGraphicsStatesInt.put(kColorStateIndex, kColorRadialGradient);
+ int numColor = color.getColors().length;
+ int colorArray[] = new int[numColor];
+ for (int i = 0; i < numColor; i++) {
+ colorArray[i] = color.getColors()[i].getRGB();
+ }
+ this.fGraphicsStatesObject[kColorArrayIndex] = colorArray;
+
+ int numStops = color.getFractions().length;
+ float stopsArray[] = new float[numStops];
+ for (int i = 0; i < numStops; i++) {
+ stopsArray[i] = color.getFractions()[i];
+ }
+ this.fGraphicsStatesObject[kFractionsArrayIndex] = color.getFractions();
+
+ Point2D p = color.getFocusPoint();
+ this.fGraphicsStatesFloat.put(kColorx1Index, (float) p.getX());
+ this.fGraphicsStatesFloat.put(kColory1Index, (float) p.getY());
+ p = color.getCenterPoint();
+ this.fGraphicsStatesFloat.put(kColorx2Index, (float) p.getX());
+ this.fGraphicsStatesFloat.put(kColory2Index, (float) p.getY());
+ this.fGraphicsStatesFloat.put(kRadiusIndex, color.getRadius());
+
+ this.fChangeFlag = (this.fChangeFlag | kColorChangedBit);
+ } else {
+ this.fChangeFlag = (this.fChangeFlag & kColorNotChangedBit);
+ }
+ } else {
+ setGradientViaRasterPath(sg2d);
+ }
} else if (sg2d.paint instanceof TexturePaint) {
if ((this.fGraphicsStatesInt.get(kColorStateIndex) != kColorTexture) || (lastPaint != sg2d.paint)) {
TexturePaint color = (TexturePaint) sg2d.paint;
@@ -587,27 +687,7 @@
this.fChangeFlag = (this.fChangeFlag & kColorNotChangedBit);
}
} else {
- if ((this.fGraphicsStatesInt.get(kColorStateIndex) != kColorTexture) || (lastPaint != sg2d.paint) || ((this.fChangeFlag & kBoundsChangedBit) != 0)) {
- PaintContext context = sg2d.paint.createContext(sg2d.getDeviceColorModel(), userBounds, userBounds, sIdentityMatrix, sg2d.getRenderingHints());
- WritableRaster raster = (WritableRaster) (context.getRaster(userBounds.x, userBounds.y, userBounds.width, userBounds.height));
- ColorModel cm = context.getColorModel();
- texturePaintImage = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
-
- this.fGraphicsStatesInt.put(kColorStateIndex, kColorTexture);
- this.fGraphicsStatesInt.put(kColorWidthIndex, texturePaintImage.getWidth());
- this.fGraphicsStatesInt.put(kColorHeightIndex, texturePaintImage.getHeight());
- this.fGraphicsStatesFloat.put(kColortxIndex, (float) userBounds.getX());
- this.fGraphicsStatesFloat.put(kColortyIndex, (float) userBounds.getY());
- this.fGraphicsStatesFloat.put(kColorsxIndex, 1.0f);
- this.fGraphicsStatesFloat.put(kColorsyIndex, 1.0f);
- this.fGraphicsStatesObject[kTextureImageIndex] = sun.awt.image.BufImgSurfaceData.createData(texturePaintImage);
-
- context.dispose();
-
- this.fChangeFlag = (this.fChangeFlag | kColorChangedBit);
- } else {
- this.fChangeFlag = (this.fChangeFlag & kColorNotChangedBit);
- }
+ setGradientViaRasterPath(sg2d);
}
lastPaint = sg2d.paint;
}
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/QuartzSurfaceData.h Thu Oct 27 10:49:16 2016 +0530
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/QuartzSurfaceData.h Thu Oct 27 17:24:16 2016 +0530
@@ -44,6 +44,8 @@
SD_Fill,
SD_EOFill,
SD_Shade,
+ SD_LinearGradient,
+ SD_RadialGradient,
SD_Pattern,
SD_Image,
SD_Text,
@@ -65,6 +67,17 @@
};
typedef struct _stateShadingInfo StateShadingInfo;
+struct _stateGradientInfo
+{
+ CGPoint start;
+ CGPoint end;
+ CGFloat radius;
+ CGFloat* colordata;
+ CGFloat* fractionsdata;
+ jint fractionsLength;
+};
+typedef struct _stateGradientInfo StateGradientInfo;
+
struct _statePatternInfo
{
CGFloat tx;
@@ -122,6 +135,7 @@
// its callees.
StateShadingInfo* shadingInfo; // tracks shading and its parameters
+ StateGradientInfo* gradientInfo; // tracks gradient and its parameters
StatePatternInfo* patternInfo; // tracks pattern and its parameters
StateGraphicsInfo graphicsStateInfo; // tracks other graphics state
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/QuartzSurfaceData.m Thu Oct 27 10:49:16 2016 +0530
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/QuartzSurfaceData.m Thu Oct 27 17:24:16 2016 +0530
@@ -268,9 +268,105 @@
free(info);
}
+static inline void contextQuartzLinearGradientPath(QuartzSDOps* qsdo)
+{
+
+PRINT(" contextQuartzLinearGradientPath");
+
+ CGContextRef cgRef = qsdo->cgRef;
+ StateGradientInfo *gradientInfo = qsdo->gradientInfo;
+
+ CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
+ size_t num_locations = gradientInfo->fractionsLength;
+ CGFloat *locations = (CGFloat *) malloc(sizeof(CGFloat) * num_locations);
+ int i = 0;
+ size_t component_size = num_locations * 4;
+ CGFloat components[component_size];
+ CGGradientRef gradient = NULL;
+
+ for (int i = 0; i < num_locations; i++) {
+ locations[i] = gradientInfo->fractionsdata[i];
+//fprintf(stderr, "locations[%d] %f\n", i, locations[i]);
+ }
+ for (i = 0; i < component_size; i++) {
+ components[i] = gradientInfo->colordata[i];
+//fprintf(stderr, "components[%d] %f, gradientInfo->colordata[%d] %f\n",
+// i, components[i], i, gradientInfo->colordata[i]);
+ }
+ CGContextSaveGState(cgRef);
+ gradient = CGGradientCreateWithColorComponents(colorspace, components, locations, num_locations);
+//fprintf(stderr, "gradientInfo->start.x %f, gradientInfo->start.y %f\n",
+// gradientInfo->start.x, gradientInfo->start.y);
+//fprintf(stderr, "gradientInfo->end.x %f, gradientInfo->end.y %f\n",
+// gradientInfo->end.x, gradientInfo->end.y);
+ if (qsdo->isEvenOddFill) {
+ CGContextEOClip(cgRef);
+ } else {
+ CGContextClip(cgRef);
+ }
+ CGContextDrawLinearGradient(cgRef, gradient, gradientInfo->start, gradientInfo->end, kCGGradientDrawsAfterEndLocation);
+
+ CGContextRestoreGState(cgRef);
+ CGColorSpaceRelease(colorspace);
+ CGGradientRelease(gradient);
+ free(locations);
+ free(gradientInfo->colordata);
+ free(gradientInfo->fractionsdata);
+}
+
+static inline void contextQuartzRadialGradientPath(QuartzSDOps* qsdo)
+{
+
+PRINT(" contextQuartzRadialGradientPath");
+
+ CGContextRef cgRef = qsdo->cgRef;
+ StateGradientInfo *gradientInfo = qsdo->gradientInfo;
+
+ CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
+ size_t num_locations = gradientInfo->fractionsLength;
+ CGFloat *locations = (CGFloat *) malloc(sizeof(CGFloat) * num_locations);
+ int i = 0;
+ size_t component_size = num_locations * 4;
+ CGFloat components[component_size];
+ CGGradientRef gradient = NULL;
+ CGFloat startRadius = gradientInfo->radius;
+ CGFloat endRadius = gradientInfo->radius;
+
+ for (int i = 0; i < num_locations; i++) {
+ locations[i] = gradientInfo->fractionsdata[i];
+//fprintf(stderr, "locations[%d] %f\n", i, locations[i]);
+ }
+ for (i = 0; i < component_size; i++) {
+ components[i] = gradientInfo->colordata[i];
+//fprintf(stderr, "components[%d] %f, gradientInfo->colordata[%d] %f\n",
+// i, components[i], i, gradientInfo->colordata[i]);
+ }
+ CGContextSaveGState(cgRef);
+ gradient = CGGradientCreateWithColorComponents(colorspace, components, locations, num_locations);
+//fprintf(stderr, "gradientInfo->start.x %f, gradientInfo->start.y %f\n",
+// gradientInfo->start.x, gradientInfo->start.y);
+//fprintf(stderr, "gradientInfo->end.x %f, gradientInfo->end.y %f\n",
+// gradientInfo->end.x, gradientInfo->end.y);
+ if (qsdo->isEvenOddFill) {
+ CGContextEOClip(cgRef);
+ } else {
+ CGContextClip(cgRef);
+ }
+//fprintf(stderr, "gradientInfo->startRadius %f, gradientInfo->endRadius %f\n",startRadius,endRadius);
+ CGContextDrawRadialGradient(cgRef, gradient, gradientInfo->start, 0, gradientInfo->end, endRadius, kCGGradientDrawsAfterEndLocation);
+
+ CGContextRestoreGState(cgRef);
+ CGColorSpaceRelease(colorspace);
+ CGGradientRelease(gradient);
+ free(locations);
+ free(gradientInfo->colordata);
+ free(gradientInfo->fractionsdata);
+}
+
static inline void contextGradientPath(QuartzSDOps* qsdo)
{
PRINT(" ContextGradientPath")
+
CGContextRef cgRef = qsdo->cgRef;
StateShadingInfo* shadingInfo = qsdo->shadingInfo;
@@ -827,6 +923,81 @@
qsdo->renderType = renderType;
}
+void setupGradient(JNIEnv *env, QuartzSDOps* qsdo, jfloat* javaFloatGraphicsStates)
+{
+ static const CGFloat kColorConversionMultiplier = 1.0f/255.0f;
+ qsdo->gradientInfo = (StateGradientInfo*)malloc(sizeof(StateGradientInfo));
+ if (qsdo->gradientInfo == NULL)
+ {
+ [JNFException raise:env as:kOutOfMemoryError reason:"Failed to malloc memory for gradient paint"];
+ }
+
+ qsdo->graphicsStateInfo.simpleStroke = NO;
+ qsdo->graphicsStateInfo.simpleColor = NO;
+
+ qsdo->gradientInfo->start.x = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColorx1Index];
+ qsdo->gradientInfo->start.y = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColory1Index];
+ qsdo->gradientInfo->end.x = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColorx2Index];
+ qsdo->gradientInfo->end.y = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kColory2Index];
+
+ jobject colorArray = ((*env)->GetObjectArrayElement(env, qsdo->javaGraphicsStatesObjects, sun_java2d_OSXSurfaceData_kColorArrayIndex));
+ if (colorArray != NULL)
+ {
+ jint length = (*env)->GetArrayLength(env, colorArray);
+//fprintf(stderr, "length %d\n", length);
+
+ jint* jcolorData = (jint*)(*env)->GetPrimitiveArrayCritical(env, colorArray, NULL);
+ CGFloat* colors= (CGFloat*)calloc(0, sizeof(CGFloat)*length);
+ if (jcolorData != NULL)
+ {
+ jint i;
+ for (i=0; i<length; i++)
+ {
+ colors[i] = (CGFloat)jcolorData[i];
+ }
+ }
+ (*env)->ReleasePrimitiveArrayCritical(env, colorArray, jcolorData, 0);
+ qsdo->gradientInfo->colordata = (CGFloat*)calloc(0, sizeof(CGFloat)*4*length);
+ for (int i = 0; i < length; i++)
+ {
+ jint c1 = colors[i];
+//fprintf(stderr, "c1 %x\n", c1);
+ qsdo->gradientInfo->colordata[i*4] = ((c1>>16)&0xff)*kColorConversionMultiplier;
+//fprintf(stderr, "qsdo->gradientInfo->colordata[%d] %f\n", i*4, qsdo->gradientInfo->colordata[i*4]);
+
+ qsdo->gradientInfo->colordata[i*4+1] = ((c1>>8)&0xff)*kColorConversionMultiplier;
+//fprintf(stderr, "qsdo->gradientInfo->colordata[%d] %f\n", i*4+1, qsdo->gradientInfo->colordata[i*4+1]);
+
+ qsdo->gradientInfo->colordata[i*4+2] = ((c1>>0)&0xff)*kColorConversionMultiplier;
+//fprintf(stderr, "qsdo->gradientInfo->colordata[%d] %f\n", i*4+2, qsdo->gradientInfo->colordata[i*4+2]);
+
+ qsdo->gradientInfo->colordata[i*4+3] = ((c1>>24)&0xff)*kColorConversionMultiplier;
+//fprintf(stderr, "qsdo->gradientInfo->colordata[%d] %f\n", i*4+3, qsdo->gradientInfo->colordata[i*4+3]);
+ }
+ free(colors);
+ }
+ jobject fractionsArray = ((*env)->GetObjectArrayElement(env, qsdo->javaGraphicsStatesObjects, sun_java2d_OSXSurfaceData_kFractionsArrayIndex));
+ if (fractionsArray != NULL)
+ {
+ jint length = (*env)->GetArrayLength(env, fractionsArray);
+//fprintf(stderr, "fractions length %d\n", length);
+ qsdo->gradientInfo->fractionsLength = length;
+
+ jfloat* jfractionsData = (jfloat*)(*env)->GetPrimitiveArrayCritical(env, fractionsArray, NULL);
+ if (jfractionsData != NULL)
+ {
+ qsdo->gradientInfo->fractionsdata = (CGFloat *)malloc(sizeof(CGFloat) *length);
+ jint i;
+ for (i=0; i<length; i++)
+ {
+ qsdo->gradientInfo->fractionsdata[i] = jfractionsData[i];
+//fprintf(stderr, "jfrationsData[%d] %f, qsdo->gradientInfo->fractionsdata[%d] = %f\n", i, jfractionsData[i], i, qsdo->gradientInfo->fractionsdata[i]);
+ }
+ (*env)->ReleasePrimitiveArrayCritical(env, fractionsArray, jfractionsData, 0);
+ }
+ }
+}
+
SDRenderType SetUpPaint(JNIEnv *env, QuartzSDOps *qsdo, SDRenderType renderType)
{
CGContextRef cgRef = qsdo->cgRef;
@@ -898,6 +1069,21 @@
break;
}
+ case sun_java2d_OSXSurfaceData_kColorLinearGradient:
+ {
+ renderType = SD_LinearGradient;
+ setupGradient(env, qsdo, javaFloatGraphicsStates);
+ break;
+ }
+
+ case sun_java2d_OSXSurfaceData_kColorRadialGradient:
+ {
+ renderType = SD_RadialGradient;
+ setupGradient(env, qsdo, javaFloatGraphicsStates);
+ qsdo->gradientInfo->radius = javaFloatGraphicsStates[sun_java2d_OSXSurfaceData_kRadiusIndex];
+ break;
+ }
+
case sun_java2d_OSXSurfaceData_kColorTexture:
{
qsdo->patternInfo = (StatePatternInfo*)malloc(sizeof(StatePatternInfo));
@@ -1076,11 +1262,24 @@
}
break;
+ case SD_LinearGradient:
+ if (CGContextIsPathEmpty(qsdo->cgRef) == 0)
+ {
+ contextQuartzLinearGradientPath(qsdo);
+ }
+ break;
+
+ case SD_RadialGradient:
+ if (CGContextIsPathEmpty(qsdo->cgRef) == 0)
+ {
+ contextQuartzRadialGradientPath(qsdo);
+ }
+ break;
+
case SD_Pattern:
if (CGContextIsPathEmpty(qsdo->cgRef) == 0)
{
- //TODO:BG
- //contextTexturePath(env, qsdo);
+ contextTexturePath(env, qsdo);
}
break;
@@ -1111,4 +1310,8 @@
gradientPaintReleaseFunction(qsdo->shadingInfo);
qsdo->shadingInfo = NULL;
}
+ if (qsdo->gradientInfo != NULL) {
+ gradientPaintReleaseFunction(qsdo->gradientInfo);
+ qsdo->gradientInfo = NULL;
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/print/PrinterJob/LinearGradientPrintingTest.java Thu Oct 27 17:24:16 2016 +0530
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+/*
+ * @test
+ * @bug 8162796
+ * @summary Verifies if LinearGradientPaint is printed in osx
+ * @run main/manual LinearGradientPrintingTest
+ */
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.LinearGradientPaint;
+import java.awt.Shape;
+import java.awt.event.ActionEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.print.PageFormat;
+import java.awt.print.Printable;
+import java.awt.print.PrinterException;
+import java.awt.print.PrinterJob;
+import javax.swing.AbstractAction;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JTextArea;
+import javax.swing.SwingUtilities;
+import javax.swing.WindowConstants;
+
+public class LinearGradientPrintingTest extends Component implements Printable {
+ private static Thread mainThread;
+ private static boolean testPassed;
+ private static boolean testGeneratedInterrupt;
+ private static JFrame f = null;
+
+ public static void main(String[] args) {
+ SwingUtilities.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ //createUI();
+ doTest(LinearGradientPrintingTest::createUI);
+ }
+ });
+ mainThread = Thread.currentThread();
+ try {
+ Thread.sleep(120000);
+ } catch (InterruptedException e) {
+ if (!testPassed && testGeneratedInterrupt) {
+ throw new RuntimeException("LinearGradientPaint did not print");
+ }
+ }
+ if (!testGeneratedInterrupt) {
+ throw new RuntimeException("user has not executed the test");
+ }
+ }
+
+ public static void createUI() {
+ f = new JFrame("LinearGradient Printing Test");
+ f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+ final LinearGradientPrintingTest gpt = new LinearGradientPrintingTest();
+ Container c = f.getContentPane();
+ c.add(BorderLayout.CENTER, gpt);
+
+ final JButton print = new JButton("Print");
+ print.addActionListener(new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ PrinterJob job = PrinterJob.getPrinterJob();
+ job.setPrintable(gpt);
+ final boolean doPrint = job.printDialog();
+ if (doPrint) {
+ try {
+ job.print();
+ } catch (PrinterException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+ }
+ });
+ c.add(print, BorderLayout.SOUTH);
+
+ f.pack();
+ f.setVisible(true);
+ }
+
+ public Dimension getPreferredSize() {
+ return new Dimension(500,500);
+ }
+
+ public void paint(Graphics g) {
+ doPaint((Graphics2D)g);
+ }
+
+ public int print( Graphics graphics, PageFormat format, int index ) {
+ Graphics2D g2d = (Graphics2D)graphics;
+ g2d.translate(format.getImageableX(), format.getImageableY());
+ doPaint(g2d);
+ return index == 0 ? PAGE_EXISTS : NO_SUCH_PAGE;
+ }
+
+ static final float DIM = 100;
+ public void doPaint(Graphics2D g2d) {
+
+ g2d.translate(DIM*0.2, DIM*0.2);
+ Shape s = new Rectangle2D.Float(0, 0, DIM*2, DIM*2);
+ Point2D.Double p1 = new Point2D.Double(0.0, 0.0);
+ Point2D.Double p2 = new Point2D.Double(DIM/2.0, DIM/2.0);
+
+ // LinearGradientPaint
+ //g2d.translate(DIM*2.2, 0);
+ Color colors[] = { Color.red, Color.blue} ;
+ float fractions[] = { 0.0f, 1.0f };
+
+ LinearGradientPaint lgp =
+ new LinearGradientPaint(p1, p2, fractions, colors,
+ LinearGradientPaint.CycleMethod.NO_CYCLE);
+ g2d.setPaint(lgp);
+ g2d.fill(s);
+
+ g2d.translate(DIM*2.2, 0);
+ Color colors1[] = { Color.red, Color.blue, Color.green, Color.white} ;
+ float fractions1[] = { 0.0f, 0.3f, 0.6f, 1.0f };
+
+ LinearGradientPaint lgp1 =
+ new LinearGradientPaint(p1, p2, fractions1, colors1,
+ LinearGradientPaint.CycleMethod.REFLECT);
+ g2d.setPaint(lgp1);
+ g2d.fill(s);
+
+ g2d.translate(-DIM*2.2, DIM*2.2);
+ Color colors2[] = { Color.red, Color.blue, Color.green, Color.white} ;
+ float fractions2[] = { 0.0f, 0.3f, 0.6f, 1.0f };
+
+ LinearGradientPaint lgp2 =
+ new LinearGradientPaint(p1, p2, fractions2, colors2,
+ LinearGradientPaint.CycleMethod.REPEAT);
+ g2d.setPaint(lgp2);
+ g2d.fill(s);
+ }
+
+ public static synchronized void pass() {
+ testPassed = true;
+ testGeneratedInterrupt = true;
+ mainThread.interrupt();
+ }
+
+ public static synchronized void fail() {
+ testPassed = false;
+ testGeneratedInterrupt = true;
+ mainThread.interrupt();
+ }
+
+ private static void doTest(Runnable action) {
+ String description
+ = " A LinearGradientPaint graphics will be shown on console.\n"
+ + " The same graphics is sent to printer.\n"
+ + " Please verify if LinearGradientPaint shading is printed.\n"
+ + " If none is printed, press FAIL else press PASS";
+
+ final JDialog dialog = new JDialog();
+ dialog.setTitle("printSelectionTest");
+ JTextArea textArea = new JTextArea(description);
+ textArea.setEditable(false);
+ final JButton testButton = new JButton("Start Test");
+ final JButton passButton = new JButton("PASS");
+ passButton.setEnabled(false);
+ passButton.addActionListener((e) -> {
+ f.dispose();
+ dialog.dispose();
+ pass();
+ });
+ final JButton failButton = new JButton("FAIL");
+ failButton.setEnabled(false);
+ failButton.addActionListener((e) -> {
+ f.dispose();
+ dialog.dispose();
+ fail();
+ });
+ testButton.addActionListener((e) -> {
+ testButton.setEnabled(false);
+ action.run();
+ passButton.setEnabled(true);
+ failButton.setEnabled(true);
+ });
+ JPanel mainPanel = new JPanel(new BorderLayout());
+ mainPanel.add(textArea, BorderLayout.CENTER);
+ JPanel buttonPanel = new JPanel(new FlowLayout());
+ buttonPanel.add(testButton);
+ buttonPanel.add(passButton);
+ buttonPanel.add(failButton);
+ mainPanel.add(buttonPanel, BorderLayout.SOUTH);
+ dialog.add(mainPanel);
+
+ dialog.pack();
+ dialog.setVisible(true);
+ dialog.addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowClosing(WindowEvent e) {
+ System.out.println("main dialog closing");
+ testGeneratedInterrupt = false;
+ mainThread.interrupt();
+ }
+ });
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/print/PrinterJob/RadialGradientPrintingTest.java Thu Oct 27 17:24:16 2016 +0530
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+/*
+ * @test
+ * @bug 8162796
+ * @summary Verifies if RadialGradientPaint is printed in osx
+ * @run main/manual RadialGradientPrintingTest
+ */
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.RadialGradientPaint;
+import java.awt.Shape;
+import java.awt.event.ActionEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.print.PageFormat;
+import java.awt.print.Printable;
+import static java.awt.print.Printable.NO_SUCH_PAGE;
+import static java.awt.print.Printable.PAGE_EXISTS;
+import java.awt.print.PrinterException;
+import java.awt.print.PrinterJob;
+import javax.swing.AbstractAction;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JTextArea;
+import javax.swing.SwingUtilities;
+import javax.swing.WindowConstants;
+
+public class RadialGradientPrintingTest extends Component implements Printable {
+ private static Thread mainThread;
+ private static boolean testPassed;
+ private static boolean testGeneratedInterrupt;
+ private static JFrame f = null;
+
+ public static void main(String[] args) {
+ SwingUtilities.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ //createUI();
+ doTest(RadialGradientPrintingTest::createUI);
+ }
+ });
+ mainThread = Thread.currentThread();
+ try {
+ Thread.sleep(120000);
+ } catch (InterruptedException e) {
+ if (!testPassed && testGeneratedInterrupt) {
+ throw new RuntimeException("LinearGradientPaint did not print");
+ }
+ }
+ if (!testGeneratedInterrupt) {
+ throw new RuntimeException("user has not executed the test");
+ }
+ }
+
+ public static void createUI() {
+ f = new JFrame("RadialGradient Printing Test");
+ f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+ final RadialGradientPrintingTest gpt = new RadialGradientPrintingTest();
+ Container c = f.getContentPane();
+ c.add(BorderLayout.CENTER, gpt);
+
+ final JButton print = new JButton("Print");
+ print.addActionListener(new AbstractAction() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ PrinterJob job = PrinterJob.getPrinterJob();
+ job.setPrintable(gpt);
+ final boolean doPrint = job.printDialog();
+ if (doPrint) {
+ try {
+ job.print();
+ } catch (PrinterException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+ }
+ });
+ c.add(print, BorderLayout.SOUTH);
+
+ f.pack();
+ f.setVisible(true);
+ }
+
+ public Dimension getPreferredSize() {
+ return new Dimension(500,500);
+ }
+
+ public void paint(Graphics g) {
+ doPaint((Graphics2D)g);
+ }
+
+ public int print( Graphics graphics, PageFormat format, int index ) {
+ Graphics2D g2d = (Graphics2D)graphics;
+ g2d.translate(format.getImageableX(), format.getImageableY());
+ doPaint(g2d);
+ return index == 0 ? PAGE_EXISTS : NO_SUCH_PAGE;
+ }
+
+ static final float DIM = 100;
+ public void doPaint(Graphics2D g2d) {
+
+ g2d.translate(DIM*0.2, DIM*0.2);
+ Shape s = new Rectangle2D.Float(0, 0, DIM*2, DIM*2);
+
+ // RadialGradientPaint
+ Point2D centre = new Point2D.Float(DIM/2.0f, DIM/2.0f);
+ float radius = DIM/2.0f;
+ Point2D focus = new Point2D.Float(DIM/3.0f, DIM/3.0f);
+ float stops[] = {0.0f, 1.0f};
+ Color colors[] = { Color.red, Color.white} ;
+
+ RadialGradientPaint rgp =
+ new RadialGradientPaint(centre, radius, focus, stops, colors,
+ RadialGradientPaint.CycleMethod.NO_CYCLE);
+ g2d.setPaint(rgp);
+ g2d.fill(s);
+
+ g2d.translate(DIM*2.2, 0);
+ Color colors1[] = { Color.red, Color.blue, Color.green} ;
+ float stops1[] = {0.0f, 0.5f, 1.0f};
+ RadialGradientPaint rgp1 =
+ new RadialGradientPaint(centre, radius, focus, stops1, colors1,
+ RadialGradientPaint.CycleMethod.REFLECT);
+ g2d.setPaint(rgp1);
+ g2d.fill(s);
+
+ g2d.translate(-DIM*2.2, DIM*2.2);
+ Color colors2[] = { Color.red, Color.blue, Color.green, Color.white} ;
+ float stops2[] = {0.0f, 0.3f, 0.6f, 1.0f};
+ RadialGradientPaint rgp2 =
+ new RadialGradientPaint(centre, radius, focus, stops2, colors2,
+ RadialGradientPaint.CycleMethod.REPEAT);
+ g2d.setPaint(rgp2);
+ g2d.fill(s);
+
+ }
+
+ public static synchronized void pass() {
+ testPassed = true;
+ testGeneratedInterrupt = true;
+ mainThread.interrupt();
+ }
+
+ public static synchronized void fail() {
+ testPassed = false;
+ testGeneratedInterrupt = true;
+ mainThread.interrupt();
+ }
+
+ private static void doTest(Runnable action) {
+ String description
+ = " A RadialGradientPaint graphics will be shown on console.\n"
+ + " The same graphics is sent to printer.\n"
+ + " Please verify if RadialGradientPaint shading is printed.\n"
+ + " If none is printed, press FAIL else press PASS";
+
+ final JDialog dialog = new JDialog();
+ dialog.setTitle("printSelectionTest");
+ JTextArea textArea = new JTextArea(description);
+ textArea.setEditable(false);
+ final JButton testButton = new JButton("Start Test");
+ final JButton passButton = new JButton("PASS");
+ passButton.setEnabled(false);
+ passButton.addActionListener((e) -> {
+ f.dispose();
+ dialog.dispose();
+ pass();
+ });
+ final JButton failButton = new JButton("FAIL");
+ failButton.setEnabled(false);
+ failButton.addActionListener((e) -> {
+ f.dispose();
+ dialog.dispose();
+ fail();
+ });
+ testButton.addActionListener((e) -> {
+ testButton.setEnabled(false);
+ action.run();
+ passButton.setEnabled(true);
+ failButton.setEnabled(true);
+ });
+ JPanel mainPanel = new JPanel(new BorderLayout());
+ mainPanel.add(textArea, BorderLayout.CENTER);
+ JPanel buttonPanel = new JPanel(new FlowLayout());
+ buttonPanel.add(testButton);
+ buttonPanel.add(passButton);
+ buttonPanel.add(failButton);
+ mainPanel.add(buttonPanel, BorderLayout.SOUTH);
+ dialog.add(mainPanel);
+
+ dialog.pack();
+ dialog.setVisible(true);
+ dialog.addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowClosing(WindowEvent e) {
+ System.out.println("main dialog closing");
+ testGeneratedInterrupt = false;
+ mainThread.interrupt();
+ }
+ });
+ }
+
+}