--- old/src/java.desktop/macosx/classes/sun/java2d/OSXSurfaceData.java 2016-10-26 11:06:59.000000000 +0530 +++ new/src/java.desktop/macosx/classes/sun/java2d/OSXSurfaceData.java 2016-10-26 11:06:58.000000000 +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; } --- old/src/java.desktop/macosx/native/libawt_lwawt/awt/QuartzSurfaceData.m 2016-10-26 11:07:00.000000000 +0530 +++ new/src/java.desktop/macosx/native/libawt_lwawt/awt/QuartzSurfaceData.m 2016-10-26 11:06:59.000000000 +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; iReleasePrimitiveArrayCritical(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; igradientInfo->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; + } } --- old/src/java.desktop/macosx/native/libawt_lwawt/awt/QuartzSurfaceData.h 2016-10-26 11:07:01.000000000 +0530 +++ new/src/java.desktop/macosx/native/libawt_lwawt/awt/QuartzSurfaceData.h 2016-10-26 11:07:00.000000000 +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 --- /dev/null 2016-10-26 11:07:02.000000000 +0530 +++ new/test/java/awt/print/PrinterJob/LinearGradientPrintingTest.java 2016-10-26 11:07:01.000000000 +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 2016-10-26 11:07:02.000000000 +0530 +++ new/test/java/awt/print/PrinterJob/RadialGradientPrintingTest.java 2016-10-26 11:07:02.000000000 +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(); + } + }); + } + +}