From 9e84a85d64267b06197c4228e433d4e3335c3f33 Mon Sep 17 00:00:00 2001 From: Vadim Pakhnushev Date: Fri, 23 Aug 2013 14:13:38 +0400 Subject: [PATCH 1/9] 8023052: JVM crash in native layout Reviewed-by: bae, prr --- jdk/src/share/native/sun/font/layout/SunLayoutEngine.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/jdk/src/share/native/sun/font/layout/SunLayoutEngine.cpp b/jdk/src/share/native/sun/font/layout/SunLayoutEngine.cpp index b32f2601b4d..8036a64c4be 100644 --- a/jdk/src/share/native/sun/font/layout/SunLayoutEngine.cpp +++ b/jdk/src/share/native/sun/font/layout/SunLayoutEngine.cpp @@ -179,6 +179,10 @@ JNIEXPORT void JNICALL Java_sun_font_SunLayoutEngine_nativeLayout FontInstanceAdapter fia(env, font2d, strike, mat, 72, 72, (le_int32) upem, (TTLayoutTableCache *) layoutTables); LEErrorCode success = LE_NO_ERROR; LayoutEngine *engine = LayoutEngine::layoutEngineFactory(&fia, script, lang, typo_flags & TYPO_MASK, success); + if (engine == NULL) { + env->SetIntField(gvdata, gvdCountFID, -1); // flag failure + return; + } if (min < 0) min = 0; if (max < min) max = min; /* defensive coding */ // have to copy, yuck, since code does upcalls now. this will be soooo slow From 9811410a0015461d29ec294c6542a69a62a72744 Mon Sep 17 00:00:00 2001 From: Jennifer Godinez Date: Fri, 30 Aug 2013 09:10:30 -0700 Subject: [PATCH 2/9] 8017469: [macosx] Printing problem using ja and zh_CN locales Reviewed-by: prr, jchen --- jdk/src/macosx/native/sun/awt/CTextPipe.m | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/jdk/src/macosx/native/sun/awt/CTextPipe.m b/jdk/src/macosx/native/sun/awt/CTextPipe.m index d9bf48afd92..f6510f204ae 100644 --- a/jdk/src/macosx/native/sun/awt/CTextPipe.m +++ b/jdk/src/macosx/native/sun/awt/CTextPipe.m @@ -145,11 +145,6 @@ void JavaCT_DrawGlyphVector BOOL saved = false; - /* Save and restore of graphics context is done before the iteration. - This seems to work using our test case (see bug ID 7158350) so we are restoring it at - the end of the for loop. If we find out that save/restore outside the loop - doesn't work on all cases then we will move the Save/Restore inside the loop.*/ - CGContextSaveGState(cgRef); CGAffineTransform invTx = CGAffineTransformInvert(strike->fTx); NSUInteger i; @@ -226,7 +221,9 @@ void JavaCT_DrawGlyphVector } // reset the font on the context after striking a unicode with CoreText - CGContextRestoreGState(cgRef); + if (saved) { + CGContextRestoreGState(cgRef); + } } // Using the Quartz Surface Data context, draw a hot-substituted character run From d5c4be9c658afddd0e33458cd4498fbcb65dcb98 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Fri, 30 Aug 2013 10:25:55 -0700 Subject: [PATCH 3/9] 4673406: RFE: Java Printing: Provide a way to display win32 printer driver's dialog Reviewed-by: jgodinez, bae --- .../sun/print/DocumentPropertiesUI.java | 62 ++++ .../classes/sun/print/PrinterJobWrapper.java | 60 ++++ .../classes/sun/print/RasterPrinterJob.java | 4 + .../classes/sun/print/ServiceDialog.java | 32 +- .../classes/sun/awt/windows/WPrinterJob.java | 315 +++++++++++++++++- .../classes/sun/print/Win32MediaTray.java | 4 + .../classes/sun/print/Win32PrintService.java | 93 +++++- .../native/sun/windows/awt_PrintControl.cpp | 6 + .../native/sun/windows/awt_PrintControl.h | 2 +- .../native/sun/windows/awt_PrintJob.cpp | 167 +++++++++- 10 files changed, 721 insertions(+), 24 deletions(-) create mode 100644 jdk/src/share/classes/sun/print/DocumentPropertiesUI.java create mode 100644 jdk/src/share/classes/sun/print/PrinterJobWrapper.java diff --git a/jdk/src/share/classes/sun/print/DocumentPropertiesUI.java b/jdk/src/share/classes/sun/print/DocumentPropertiesUI.java new file mode 100644 index 00000000000..9938e8b3951 --- /dev/null +++ b/jdk/src/share/classes/sun/print/DocumentPropertiesUI.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2013, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.print; + +import java.awt.Window; +import java.awt.print.PrinterJob; +import javax.print.PrintService; +import javax.print.ServiceUIFactory; +import javax.print.attribute.PrintRequestAttributeSet; + +public abstract class DocumentPropertiesUI { + + /** + * For Win32 doc properties sheet. + */ + public static final int + DOCUMENTPROPERTIES_ROLE = ServiceUIFactory.RESERVED_UIROLE +100; + + /** + * Name of (this) abstract class for Document Properties. + */ + public static final String + DOCPROPERTIESCLASSNAME = DocumentPropertiesUI.class.getName(); + + /** + * Invokes whatever code is needed to display a native dialog + * with the specified owner. The owner should be the cross-platform + * dialog. If the user cancels the dialog the return value is null. + * A non-null return value is always a new attribute set (or is it?) + * The cross-platform dialog may need to be updated to reflect the + * updated properties. + */ + public abstract PrintRequestAttributeSet + showDocumentProperties(PrinterJob job, + Window owner, + PrintService service, + PrintRequestAttributeSet aset); + +} diff --git a/jdk/src/share/classes/sun/print/PrinterJobWrapper.java b/jdk/src/share/classes/sun/print/PrinterJobWrapper.java new file mode 100644 index 00000000000..343da0baa77 --- /dev/null +++ b/jdk/src/share/classes/sun/print/PrinterJobWrapper.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2013, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.print; + +import java.awt.print.PrinterJob; +import javax.print.attribute.PrintRequestAttribute; + +public class PrinterJobWrapper implements PrintRequestAttribute { + + private static final long serialVersionUID = -8792124426995707237L; + + private PrinterJob job; + + public PrinterJobWrapper(PrinterJob job) { + this.job = job; + } + + public PrinterJob getPrinterJob() { + return job; + } + + public final Class getCategory() { + return PrinterJobWrapper.class; + } + + public final String getName() { + return "printerjob-wrapper"; + } + + public String toString() { + return "printerjob-wrapper: " + job.toString(); + } + + public int hashCode() { + return job.hashCode(); + } +} diff --git a/jdk/src/share/classes/sun/print/RasterPrinterJob.java b/jdk/src/share/classes/sun/print/RasterPrinterJob.java index 1752016288e..37865e3246c 100644 --- a/jdk/src/share/classes/sun/print/RasterPrinterJob.java +++ b/jdk/src/share/classes/sun/print/RasterPrinterJob.java @@ -903,6 +903,9 @@ public abstract class RasterPrinterJob extends PrinterJob { int x = bounds.x+bounds.width/3; int y = bounds.y+bounds.height/3; PrintService newService; + // temporarily add an attribute pointing back to this job. + PrinterJobWrapper jobWrapper = new PrinterJobWrapper(this); + attributes.add(jobWrapper); try { newService = ServiceUI.printDialog(gc, x, y, @@ -915,6 +918,7 @@ public abstract class RasterPrinterJob extends PrinterJob { DocFlavor.SERVICE_FORMATTED.PAGEABLE, attributes); } + attributes.remove(PrinterJobWrapper.class); if (newService == null) { return false; diff --git a/jdk/src/share/classes/sun/print/ServiceDialog.java b/jdk/src/share/classes/sun/print/ServiceDialog.java index 82703406aa9..bdfd5ba1242 100644 --- a/jdk/src/share/classes/sun/print/ServiceDialog.java +++ b/jdk/src/share/classes/sun/print/ServiceDialog.java @@ -46,6 +46,7 @@ import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.WindowEvent; import java.awt.event.WindowAdapter; +import java.awt.print.PrinterJob; import java.io.File; import java.io.FilePermission; import java.io.IOException; @@ -119,8 +120,6 @@ public class ServiceDialog extends JDialog implements ActionListener { private AppearancePanel pnlAppearance; private boolean isAWT = false; - - static { initResource(); } @@ -801,9 +800,32 @@ public class ServiceDialog extends JDialog implements ActionListener { if (dialog != null) { dialog.show(); } else { - // REMIND: may want to notify the user why we're - // disabling the button - btnProperties.setEnabled(false); + DocumentPropertiesUI docPropertiesUI = null; + try { + docPropertiesUI = + (DocumentPropertiesUI)uiFactory.getUI + (DocumentPropertiesUI.DOCUMENTPROPERTIES_ROLE, + DocumentPropertiesUI.DOCPROPERTIESCLASSNAME); + } catch (Exception ex) { + } + if (docPropertiesUI != null) { + PrinterJobWrapper wrapper = (PrinterJobWrapper) + asCurrent.get(PrinterJobWrapper.class); + if (wrapper == null) { + return; // should not happen, defensive only. + } + PrinterJob job = wrapper.getPrinterJob(); + if (job == null) { + return; // should not happen, defensive only. + } + PrintRequestAttributeSet newAttrs = + docPropertiesUI.showDocumentProperties + (job, ServiceDialog.this, psCurrent, asCurrent); + if (newAttrs != null) { + asCurrent.addAll(newAttrs); + updatePanels(); + } + } } } } diff --git a/jdk/src/windows/classes/sun/awt/windows/WPrinterJob.java b/jdk/src/windows/classes/sun/awt/windows/WPrinterJob.java index 897e8f1baf1..519a0be422e 100644 --- a/jdk/src/windows/classes/sun/awt/windows/WPrinterJob.java +++ b/jdk/src/windows/classes/sun/awt/windows/WPrinterJob.java @@ -179,6 +179,7 @@ public class WPrinterJob extends RasterPrinterJob implements DisposerTarget { private static final int SET_RES_LOW = 0x00000080; private static final int SET_COLOR = 0x00000200; private static final int SET_ORIENTATION = 0x00004000; + private static final int SET_COLLATED = 0x00008000; /** * Values must match those defined in wingdi.h & commdlg.h @@ -189,10 +190,33 @@ public class WPrinterJob extends RasterPrinterJob implements DisposerTarget { private static final int PD_NOSELECTION = 0x00000004; private static final int PD_COLLATE = 0x00000010; private static final int PD_PRINTTOFILE = 0x00000020; - private static final int DM_ORIENTATION = 0x00000001; - private static final int DM_PRINTQUALITY = 0x00000400; - private static final int DM_COLOR = 0x00000800; - private static final int DM_DUPLEX = 0x00001000; + private static final int DM_ORIENTATION = 0x00000001; + private static final int DM_PAPERSIZE = 0x00000002; + private static final int DM_COPIES = 0x00000100; + private static final int DM_DEFAULTSOURCE = 0x00000200; + private static final int DM_PRINTQUALITY = 0x00000400; + private static final int DM_COLOR = 0x00000800; + private static final int DM_DUPLEX = 0x00001000; + private static final int DM_YRESOLUTION = 0x00002000; + private static final int DM_COLLATE = 0x00008000; + + private static final short DMCOLLATE_FALSE = 0; + private static final short DMCOLLATE_TRUE = 1; + + private static final short DMORIENT_PORTRAIT = 1; + private static final short DMORIENT_LANDSCAPE = 2; + + private static final short DMCOLOR_MONOCHROME = 1; + private static final short DMCOLOR_COLOR = 2; + + private static final short DMRES_DRAFT = -1; + private static final short DMRES_LOW = -2; + private static final short DMRES_MEDIUM = -3; + private static final short DMRES_HIGH = -4; + + private static final short DMDUP_SIMPLEX = 1; + private static final short DMDUP_VERTICAL = 2; + private static final short DMDUP_HORIZONTAL = 3; /** * Pageable MAX pages @@ -592,13 +616,23 @@ public class WPrinterJob extends RasterPrinterJob implements DisposerTarget { } driverDoesMultipleCopies = false; driverDoesCollation = false; - setNativePrintService(service.getName()); + setNativePrintServiceIfNeeded(service.getName()); } /* associates this job with the specified native service */ private native void setNativePrintService(String name) throws PrinterException; + private String lastNativeService = null; + private void setNativePrintServiceIfNeeded(String name) + throws PrinterException { + + if (name != null && !(name.equals(lastNativeService))) { + setNativePrintService(name); + lastNativeService = name; + } + } + public PrintService getPrintService() { if (myService == null) { String printerName = getNativePrintService(); @@ -616,7 +650,7 @@ public class WPrinterJob extends RasterPrinterJob implements DisposerTarget { myService = PrintServiceLookup.lookupDefaultPrintService(); if (myService != null) { try { - setNativePrintService(myService.getName()); + setNativePrintServiceIfNeeded(myService.getName()); } catch (Exception e) { myService = null; } @@ -1754,8 +1788,13 @@ public class WPrinterJob extends RasterPrinterJob implements DisposerTarget { mAttMediaSizeName = ((Win32PrintService)myService).findPaperID(msn); } - private void setWin32MediaAttrib(int dmIndex, int width, int length) { - MediaSizeName msn = + private void addPaperSize(PrintRequestAttributeSet aset, + int dmIndex, int width, int length) { + + if (aset == null) { + return; + } + MediaSizeName msn = ((Win32PrintService)myService).findWin32Media(dmIndex); if (msn == null) { msn = ((Win32PrintService)myService). @@ -1763,10 +1802,12 @@ public class WPrinterJob extends RasterPrinterJob implements DisposerTarget { } if (msn != null) { - if (attributes != null) { - attributes.add(msn); - } + aset.add(msn); } + } + + private void setWin32MediaAttrib(int dmIndex, int width, int length) { + addPaperSize(attributes, dmIndex, width, length); mAttMediaSizeName = dmIndex; } @@ -1788,7 +1829,7 @@ public class WPrinterJob extends RasterPrinterJob implements DisposerTarget { // no equivalent predefined value mAttMediaTray = 7; // DMBIN_AUTO } else if (attr == MediaTray.TOP) { - mAttMediaTray =1; // DMBIN_UPPER + mAttMediaTray = 1; // DMBIN_UPPER } else { if (attr instanceof Win32MediaTray) { mAttMediaTray = ((Win32MediaTray)attr).winID; @@ -1914,6 +1955,254 @@ public class WPrinterJob extends RasterPrinterJob implements DisposerTarget { } } + private static final class DevModeValues { + int dmFields; + short copies; + short collate; + short color; + short duplex; + short orient; + short paper; + short bin; + short xres_quality; + short yres; + } + + private void getDevModeValues(PrintRequestAttributeSet aset, + DevModeValues info) { + + Copies c = (Copies)aset.get(Copies.class); + if (c != null) { + info.dmFields |= DM_COPIES; + info.copies = (short)c.getValue(); + } + + SheetCollate sc = (SheetCollate)aset.get(SheetCollate.class); + if (sc != null) { + info.dmFields |= DM_COLLATE; + info.collate = (sc == SheetCollate.COLLATED) ? + DMCOLLATE_TRUE : DMCOLLATE_FALSE; + } + + Chromaticity ch = (Chromaticity)aset.get(Chromaticity.class); + if (ch != null) { + info.dmFields |= DM_COLOR; + if (ch == Chromaticity.COLOR) { + info.color = DMCOLOR_COLOR; + } else { + info.color = DMCOLOR_MONOCHROME; + } + } + + Sides s = (Sides)aset.get(Sides.class); + if (s != null) { + info.dmFields |= DM_DUPLEX; + if (s == Sides.TWO_SIDED_LONG_EDGE) { + info.duplex = DMDUP_VERTICAL; + } else if (s == Sides.TWO_SIDED_SHORT_EDGE) { + info.duplex = DMDUP_HORIZONTAL; + } else { // Sides.ONE_SIDED + info.duplex = DMDUP_SIMPLEX; + } + } + + OrientationRequested or = + (OrientationRequested)aset.get(OrientationRequested.class); + if (or != null) { + info.dmFields |= DM_ORIENTATION; + info.orient = (or == OrientationRequested.LANDSCAPE) + ? DMORIENT_LANDSCAPE : DMORIENT_PORTRAIT; + } + + Media m = (Media)aset.get(Media.class); + if (m instanceof MediaSizeName) { + info.dmFields |= DM_PAPERSIZE; + MediaSizeName msn = (MediaSizeName)m; + info.paper = + (short)((Win32PrintService)myService).findPaperID(msn); + } + + MediaTray mt = null; + if (m instanceof MediaTray) { + mt = (MediaTray)m; + } + if (mt == null) { + SunAlternateMedia sam = + (SunAlternateMedia)aset.get(SunAlternateMedia.class); + if (sam != null && (sam.getMedia() instanceof MediaTray)) { + mt = (MediaTray)sam.getMedia(); + } + } + + if (mt != null) { + info.dmFields |= DM_DEFAULTSOURCE; + info.bin = (short)(((Win32PrintService)myService).findTrayID(mt)); + } + + PrintQuality q = (PrintQuality)aset.get(PrintQuality.class); + if (q != null) { + info.dmFields |= DM_PRINTQUALITY; + if (q == PrintQuality.DRAFT) { + info.xres_quality = DMRES_DRAFT; + } else if (q == PrintQuality.HIGH) { + info.xres_quality = DMRES_HIGH; + } else { + info.xres_quality = DMRES_MEDIUM; + } + } + + PrinterResolution r = + (PrinterResolution)aset.get(PrinterResolution.class); + if (r != null) { + info.dmFields |= DM_PRINTQUALITY | DM_YRESOLUTION; + info.xres_quality = + (short)r.getCrossFeedResolution(PrinterResolution.DPI); + info.yres = (short)r.getFeedResolution(PrinterResolution.DPI); + } + } + + /* This method is called from native to update the values in the + * attribute set which originates from the cross-platform dialog, + * but updated by the native DocumentPropertiesUI which updates the + * devmode. This syncs the devmode back in to the attributes so that + * we can update the cross-platform dialog. + * The attribute set here is a temporary one installed whilst this + * happens, + */ + private final void setJobAttributes(PrintRequestAttributeSet attributes, + int fields, int values, + short copies, + short dmPaperSize, + short dmPaperWidth, + short dmPaperLength, + short dmDefaultSource, + short xRes, + short yRes) { + + if (attributes == null) { + return; + } + + if ((fields & DM_COPIES) != 0) { + attributes.add(new Copies(copies)); + } + + if ((fields & DM_COLLATE) != 0) { + if ((values & SET_COLLATED) != 0) { + attributes.add(SheetCollate.COLLATED); + } else { + attributes.add(SheetCollate.UNCOLLATED); + } + } + + if ((fields & DM_ORIENTATION) != 0) { + if ((values & SET_ORIENTATION) != 0) { + attributes.add(OrientationRequested.LANDSCAPE); + } else { + attributes.add(OrientationRequested.PORTRAIT); + } + } + + if ((fields & DM_COLOR) != 0) { + if ((values & SET_COLOR) != 0) { + attributes.add(Chromaticity.COLOR); + } else { + attributes.add(Chromaticity.MONOCHROME); + } + } + + if ((fields & DM_PRINTQUALITY) != 0) { + /* value < 0 indicates quality setting. + * value > 0 indicates X resolution. In that case + * hopefully we will also find y-resolution specified. + * If its not, assume its the same as x-res. + * Maybe Java code should try to reconcile this against + * the printers claimed set of supported resolutions. + */ + if (xRes < 0) { + PrintQuality quality; + if ((values & SET_RES_LOW) != 0) { + quality = PrintQuality.DRAFT; + } else if ((fields & SET_RES_HIGH) != 0) { + quality = PrintQuality.HIGH; + } else { + quality = PrintQuality.NORMAL; + } + attributes.add(quality); + } else if (xRes > 0 && yRes > 0) { + attributes.add( + new PrinterResolution(xRes, yRes, PrinterResolution.DPI)); + } + } + + if ((fields & DM_DUPLEX) != 0) { + Sides sides; + if ((values & SET_DUP_VERTICAL) != 0) { + sides = Sides.TWO_SIDED_LONG_EDGE; + } else if ((values & SET_DUP_HORIZONTAL) != 0) { + sides = Sides.TWO_SIDED_SHORT_EDGE; + } else { + sides = Sides.ONE_SIDED; + } + attributes.add(sides); + } + + if ((fields & DM_PAPERSIZE) != 0) { + addPaperSize(attributes, dmPaperSize, dmPaperWidth, dmPaperLength); + } + + if ((fields & DM_DEFAULTSOURCE) != 0) { + MediaTray tray = + ((Win32PrintService)myService).findMediaTray(dmDefaultSource); + attributes.add(new SunAlternateMedia(tray)); + } + } + + private native boolean showDocProperties(long hWnd, + PrintRequestAttributeSet aset, + int dmFields, + short copies, + short collate, + short color, + short duplex, + short orient, + short paper, + short bin, + short xres_quality, + short yres); + + @SuppressWarnings("deprecation") + public PrintRequestAttributeSet + showDocumentProperties(Window owner, + PrintService service, + PrintRequestAttributeSet aset) + { + try { + setNativePrintServiceIfNeeded(service.getName()); + } catch (PrinterException e) { + } + long hWnd = ((WWindowPeer)(owner.getPeer())).getHWnd(); + DevModeValues info = new DevModeValues(); + getDevModeValues(aset, info); + boolean ok = + showDocProperties(hWnd, aset, + info.dmFields, + info.copies, + info.collate, + info.color, + info.duplex, + info.orient, + info.paper, + info.bin, + info.xres_quality, + info.yres); + + if (ok) { + return aset; + } else { + return null; + } + } /* Printer Resolution. See also getXRes() and getYRes() */ private final void setResolutionDPI(int xres, int yres) { @@ -1956,7 +2245,7 @@ public class WPrinterJob extends RasterPrinterJob implements DisposerTarget { } //** END Functions called by native code for querying/updating attributes - } + } class PrintToFileErrorDialog extends Dialog implements ActionListener{ public PrintToFileErrorDialog(Frame parent, String title, String message, diff --git a/jdk/src/windows/classes/sun/print/Win32MediaTray.java b/jdk/src/windows/classes/sun/print/Win32MediaTray.java index ecafcef5668..2f2cafce035 100644 --- a/jdk/src/windows/classes/sun/print/Win32MediaTray.java +++ b/jdk/src/windows/classes/sun/print/Win32MediaTray.java @@ -70,6 +70,10 @@ public class Win32MediaTray extends MediaTray { winEnumTable.add(this); } + public int getDMBinID() { + return winID; + } + private static final String[] myStringTable ={ "Manual-Envelope", "Automatic-Feeder", diff --git a/jdk/src/windows/classes/sun/print/Win32PrintService.java b/jdk/src/windows/classes/sun/print/Win32PrintService.java index c42de1ae7df..73e89269285 100644 --- a/jdk/src/windows/classes/sun/print/Win32PrintService.java +++ b/jdk/src/windows/classes/sun/print/Win32PrintService.java @@ -25,6 +25,8 @@ package sun.print; +import java.awt.Window; +import java.awt.print.PrinterJob; import java.io.File; import java.net.URI; import java.net.URISyntaxException; @@ -39,6 +41,7 @@ import javax.print.attribute.AttributeSet; import javax.print.attribute.AttributeSetUtilities; import javax.print.attribute.EnumSyntax; import javax.print.attribute.HashAttributeSet; +import javax.print.attribute.PrintRequestAttributeSet; import javax.print.attribute.PrintServiceAttribute; import javax.print.attribute.PrintServiceAttributeSet; import javax.print.attribute.HashPrintServiceAttributeSet; @@ -69,6 +72,7 @@ import javax.print.attribute.standard.PrintQuality; import javax.print.attribute.standard.PrinterResolution; import javax.print.attribute.standard.SheetCollate; import javax.print.event.PrintServiceAttributeListener; +import sun.awt.windows.WPrinterJob; public class Win32PrintService implements PrintService, AttributeUpdater, SunPrinterJobService { @@ -282,6 +286,22 @@ public class Win32PrintService implements PrintService, AttributeUpdater, return 0; } + public int findTrayID(MediaTray tray) { + + getMediaTrays(); // make sure they are initialised. + + if (tray instanceof Win32MediaTray) { + Win32MediaTray winTray = (Win32MediaTray)tray; + return winTray.getDMBinID(); + } + for (int id=0; id= 1 && dmBin <= dmPaperBinToPrintService.length) { return dmPaperBinToPrintService[dmBin-1]; @@ -673,7 +693,6 @@ public class Win32PrintService implements PrintService, AttributeUpdater, return arr2; } - private PrinterIsAcceptingJobs getPrinterIsAcceptingJobs() { if (getJobStatus(printer, 2) != 1) { return PrinterIsAcceptingJobs.NOT_ACCEPTING_JOBS; @@ -1596,8 +1615,76 @@ public class Win32PrintService implements PrintService, AttributeUpdater, } } - public ServiceUIFactory getServiceUIFactory() { - return null; + private Win32DocumentPropertiesUI docPropertiesUI = null; + + private static class Win32DocumentPropertiesUI + extends DocumentPropertiesUI { + + Win32PrintService service; + + private Win32DocumentPropertiesUI(Win32PrintService s) { + service = s; + } + + public PrintRequestAttributeSet + showDocumentProperties(PrinterJob job, + Window owner, + PrintService service, + PrintRequestAttributeSet aset) { + + if (!(job instanceof WPrinterJob)) { + return null; + } + WPrinterJob wJob = (WPrinterJob)job; + return wJob.showDocumentProperties(owner, service, aset); + } + } + + private synchronized DocumentPropertiesUI getDocumentPropertiesUI() { + return new Win32DocumentPropertiesUI(this); + } + + private static class Win32ServiceUIFactory extends ServiceUIFactory { + + Win32PrintService service; + + Win32ServiceUIFactory(Win32PrintService s) { + service = s; + } + + public Object getUI(int role, String ui) { + if (role <= ServiceUIFactory.MAIN_UIROLE) { + return null; + } + if (role == DocumentPropertiesUI.DOCUMENTPROPERTIES_ROLE && + DocumentPropertiesUI.DOCPROPERTIESCLASSNAME.equals(ui)) + { + return service.getDocumentPropertiesUI(); + } + throw new IllegalArgumentException("Unsupported role"); + } + + public String[] getUIClassNamesForRole(int role) { + + if (role <= ServiceUIFactory.MAIN_UIROLE) { + return null; + } + if (role == DocumentPropertiesUI.DOCUMENTPROPERTIES_ROLE) { + String[] names = new String[0]; + names[0] = DocumentPropertiesUI.DOCPROPERTIESCLASSNAME; + return names; + } + throw new IllegalArgumentException("Unsupported role"); + } + } + + private Win32ServiceUIFactory uiFactory = null; + + public synchronized ServiceUIFactory getServiceUIFactory() { + if (uiFactory == null) { + uiFactory = new Win32ServiceUIFactory(this); + } + return uiFactory; } public String toString() { diff --git a/jdk/src/windows/native/sun/windows/awt_PrintControl.cpp b/jdk/src/windows/native/sun/windows/awt_PrintControl.cpp index 71a08d3df33..07dd90fcf2c 100644 --- a/jdk/src/windows/native/sun/windows/awt_PrintControl.cpp +++ b/jdk/src/windows/native/sun/windows/awt_PrintControl.cpp @@ -81,6 +81,7 @@ jmethodID AwtPrintControl::setToPageID; jmethodID AwtPrintControl::setNativeAttID; jmethodID AwtPrintControl::setRangeCopiesID; jmethodID AwtPrintControl::setResID; +jmethodID AwtPrintControl::setJobAttributesID; BOOL AwtPrintControl::IsSupportedLevel(HANDLE hPrinter, DWORD dwLevel) { @@ -297,6 +298,10 @@ void AwtPrintControl::initIDs(JNIEnv *env, jclass cls) AwtPrintControl::setPrinterID = env->GetMethodID(cls, "setPrinterNameAttrib", "(Ljava/lang/String;)V"); + AwtPrintControl::setJobAttributesID = + env->GetMethodID(cls, "setJobAttributes", + "(Ljavax/print/attribute/PrintRequestAttributeSet;IISSSSSSS)V"); + DASSERT(AwtPrintControl::driverDoesMultipleCopiesID != NULL); DASSERT(AwtPrintControl::getPrintDCID != NULL); DASSERT(AwtPrintControl::setPrintDCID != NULL); @@ -327,6 +332,7 @@ void AwtPrintControl::initIDs(JNIEnv *env, jclass cls) DASSERT(AwtPrintControl::getSidesID != NULL); DASSERT(AwtPrintControl::getSelectID != NULL); DASSERT(AwtPrintControl::getPrintToFileEnabledID != NULL); + DASSERT(AwtPrintControl::setJobAttributesID != NULL); CATCH_BAD_ALLOC; diff --git a/jdk/src/windows/native/sun/windows/awt_PrintControl.h b/jdk/src/windows/native/sun/windows/awt_PrintControl.h index 2e3fbaf2e60..e8b7415f305 100644 --- a/jdk/src/windows/native/sun/windows/awt_PrintControl.h +++ b/jdk/src/windows/native/sun/windows/awt_PrintControl.h @@ -47,7 +47,6 @@ public: static jmethodID setDevmodeID; static jmethodID getDevnamesID; static jmethodID setDevnamesID; - static jmethodID getWin32MediaID; static jmethodID setWin32MediaID; static jmethodID getWin32MediaTrayID; @@ -73,6 +72,7 @@ public: static jmethodID setNativeAttID; static jmethodID setRangeCopiesID; static jmethodID setResID; + static jmethodID setJobAttributesID; static void initIDs(JNIEnv *env, jclass cls); static BOOL FindPrinter(jstring printerName, LPBYTE pPrinterEnum, diff --git a/jdk/src/windows/native/sun/windows/awt_PrintJob.cpp b/jdk/src/windows/native/sun/windows/awt_PrintJob.cpp index a2deb14b58c..c19e4306114 100644 --- a/jdk/src/windows/native/sun/windows/awt_PrintJob.cpp +++ b/jdk/src/windows/native/sun/windows/awt_PrintJob.cpp @@ -329,6 +329,156 @@ static int CALLBACK fontEnumProcA(ENUMLOGFONTEXA *logfont, static int embolden(int currentWeight); static BOOL getPrintableArea(HDC pdc, HANDLE hDevMode, RectDouble *margin); + + +/************************************************************************ + * DocumentProperties native support + */ + +/* Values must match those defined in WPrinterJob.java */ +static const DWORD SET_COLOR = 0x00000200; +static const DWORD SET_ORIENTATION = 0x00004000; +static const DWORD SET_COLLATED = 0x00008000; +static const DWORD SET_DUP_VERTICAL = 0x00000010; +static const DWORD SET_DUP_HORIZONTAL = 0x00000020; +static const DWORD SET_RES_HIGH = 0x00000040; +static const DWORD SET_RES_LOW = 0x00000080; + +/* + * Copy DEVMODE state back into JobAttributes. + */ + +static void UpdateJobAttributes(JNIEnv *env, + jobject wJob, + jobject attrSet, + DEVMODE *devmode) { + + DWORD dmValues = 0; + int xRes = 0, yRes = 0; + + if (devmode->dmFields & DM_COLOR) { + if (devmode->dmColor == DMCOLOR_COLOR) { + dmValues |= SET_COLOR; + } + } + + if (devmode->dmFields & DM_ORIENTATION) { + if (devmode->dmOrientation == DMORIENT_LANDSCAPE) { + dmValues |= SET_ORIENTATION; + } + } + + if (devmode->dmFields & DM_COLLATE && + devmode->dmCollate == DMCOLLATE_TRUE) { + dmValues |= SET_COLLATED; + } + + if (devmode->dmFields & DM_PRINTQUALITY) { + /* value < 0 indicates quality setting. + * value > 0 indicates X resolution. In that case + * hopefully we will also find y-resolution specified. + * If its not, assume its the same as x-res. + * Maybe Java code should try to reconcile this against + * the printers claimed set of supported resolutions. + */ + if (devmode->dmPrintQuality < 0) { + if (devmode->dmPrintQuality == DMRES_HIGH) { + dmValues |= SET_RES_HIGH; + } else if ((devmode->dmPrintQuality == DMRES_LOW) || + (devmode->dmPrintQuality == DMRES_DRAFT)) { + dmValues |= SET_RES_LOW; + } + /* else if (devmode->dmPrintQuality == DMRES_MEDIUM) + * will set to NORMAL. + */ + } else { + xRes = devmode->dmPrintQuality; + yRes = (devmode->dmFields & DM_YRESOLUTION) ? + devmode->dmYResolution : devmode->dmPrintQuality; + } + } + + if (devmode->dmFields & DM_DUPLEX) { + if (devmode->dmDuplex == DMDUP_HORIZONTAL) { + dmValues |= SET_DUP_HORIZONTAL; + } else if (devmode->dmDuplex == DMDUP_VERTICAL) { + dmValues |= SET_DUP_VERTICAL; + } + } + + env->CallVoidMethod(wJob, AwtPrintControl::setJobAttributesID, attrSet, + devmode->dmFields, dmValues, devmode->dmCopies, + devmode->dmPaperSize, devmode->dmPaperWidth, + devmode->dmPaperLength, devmode->dmDefaultSource, + xRes, yRes); + +} + +JNIEXPORT jboolean JNICALL +Java_sun_awt_windows_WPrinterJob_showDocProperties(JNIEnv *env, + jobject wJob, + jlong hWndParent, + jobject attrSet, + jint dmFields, + jshort copies, + jshort collate, + jshort color, + jshort duplex, + jshort orient, + jshort paper, + jshort bin, + jshort xres_quality, + jshort yres) +{ + TRY; + + HGLOBAL hDevMode = AwtPrintControl::getPrintHDMode(env, wJob); + HGLOBAL hDevNames = AwtPrintControl::getPrintHDName(env, wJob); + DEVMODE *devmode = NULL; + DEVNAMES *devnames = NULL; + LONG rval = IDCANCEL; + jboolean ret = JNI_FALSE; + + if (hDevMode != NULL && hDevNames != NULL) { + devmode = (DEVMODE *)::GlobalLock(hDevMode); + devnames = (DEVNAMES *)::GlobalLock(hDevNames); + + LPTSTR lpdevnames = (LPTSTR)devnames; + // No need to call _tcsdup as we won't unlock until we are done. + LPTSTR printerName = lpdevnames+devnames->wDeviceOffset; + LPTSTR portName = lpdevnames+devnames->wOutputOffset; + + HANDLE hPrinter; + if (::OpenPrinter(printerName, &hPrinter, NULL) == TRUE) { + devmode->dmFields |= dmFields; + devmode->dmCopies = copies; + devmode->dmCollate = collate; + devmode->dmColor = color; + devmode->dmDuplex = duplex; + devmode->dmOrientation = orient; + devmode->dmPrintQuality = xres_quality; + devmode->dmYResolution = yres; + devmode->dmPaperSize = paper; + devmode->dmDefaultSource = bin; + + rval = ::DocumentProperties((HWND)hWndParent, + hPrinter, printerName, devmode, devmode, + DM_IN_BUFFER | DM_OUT_BUFFER | DM_IN_PROMPT); + if (rval == IDOK) { + UpdateJobAttributes(env, wJob, attrSet, devmode); + ret = JNI_TRUE; + } + VERIFY(::ClosePrinter(hPrinter)); + } + ::GlobalUnlock(hDevNames); + ::GlobalUnlock(hDevMode); + } + + return ret; + + CATCH_BAD_ALLOC_RET(0); +} + /************************************************************************ * WPageDialog native methods */ @@ -732,7 +882,6 @@ Java_sun_awt_windows_WPrinterJob_validatePaper(JNIEnv *env, jobject self, memset(&pd, 0, sizeof(PRINTDLG)); pd.lStructSize = sizeof(PRINTDLG); pd.Flags = PD_RETURNDEFAULT | PD_RETURNDC; - if (::PrintDlg(&pd)) { printDC = pd.hDC; hDevMode = pd.hDevMode; @@ -792,8 +941,19 @@ Java_sun_awt_windows_WPrinterJob_validatePaper(JNIEnv *env, jobject self, jint imgPixelWid = GetDeviceCaps(printDC, HORZRES); jint imgPixelHgt = GetDeviceCaps(printDC, VERTRES); + // The DC may be obtained when we first selected the printer as a + // result of a call to setNativePrintService. + // If the Devmode was obtained later on from the DocumentProperties dialog + // the DC won't have been updated and its settings may be for PORTRAIT. + // This may happen in other cases too, but was observed for the above. + // To get a DC compatible with this devmode we should really call + // CreateDC() again to get a DC for the devmode we are using. + // The changes for that are a lot more risk, so to minimise that + // risk, assume its not LANDSCAPE unless width > height, even if the + // devmode says its LANDSCAPE. // if the values were obtained from a rotated device, swap. - if (getOrientationFromDevMode2(hDevMode) == DMORIENT_LANDSCAPE) { + if ((getOrientationFromDevMode2(hDevMode) == DMORIENT_LANDSCAPE) && + (imgPixelWid > imgPixelHgt)) { jint tmp; tmp = xPixelRes; xPixelRes = yPixelRes; @@ -941,6 +1101,9 @@ Java_sun_awt_windows_WPrinterJob_initPrinter(JNIEnv *env, jobject self) { setBooleanField(env, self, DRIVER_COLLATE_STR, JNI_FALSE); } + if (dmFields & DM_COPIES) { + setBooleanField(env, self, DRIVER_COPIES_STR, JNI_TRUE); + } } CATCH_BAD_ALLOC; From 24f306c761ab39cb76b22ddb28fee77074d3c0ef Mon Sep 17 00:00:00 2001 From: Clemens Eisserer Date: Sun, 1 Sep 2013 09:38:03 -0700 Subject: [PATCH 4/9] 7189452: XRender pipeline does ignore source-surface offset for text rendering Reviewed-by: prr, bae --- jdk/src/solaris/classes/sun/font/XRTextRenderer.java | 2 +- .../solaris/classes/sun/java2d/xr/XRBackendNative.java | 9 +++++---- .../classes/sun/java2d/xr/XRCompositeManager.java | 8 ++++---- jdk/src/solaris/native/sun/java2d/x11/XRBackendNative.c | 7 ++++--- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/jdk/src/solaris/classes/sun/font/XRTextRenderer.java b/jdk/src/solaris/classes/sun/font/XRTextRenderer.java index c2aa27b43e0..308de3ab300 100644 --- a/jdk/src/solaris/classes/sun/font/XRTextRenderer.java +++ b/jdk/src/solaris/classes/sun/font/XRTextRenderer.java @@ -142,7 +142,7 @@ public class XRTextRenderer extends GlyphListPipe { } int maskFormat = containsLCDGlyphs ? XRUtils.PictStandardARGB32 : XRUtils.PictStandardA8; - maskBuffer.compositeText(x11sd.picture, 0, maskFormat, eltList); + maskBuffer.compositeText(x11sd, (int) gl.getX(), (int) gl.getY(), 0, maskFormat, eltList); eltList.clear(); } finally { diff --git a/jdk/src/solaris/classes/sun/java2d/xr/XRBackendNative.java b/jdk/src/solaris/classes/sun/java2d/xr/XRBackendNative.java index a6ffd0defcd..205ff13c6fc 100644 --- a/jdk/src/solaris/classes/sun/java2d/xr/XRBackendNative.java +++ b/jdk/src/solaris/classes/sun/java2d/xr/XRBackendNative.java @@ -267,8 +267,9 @@ public class XRBackendNative implements XRBackend { private static native void XRenderCompositeTextNative(int op, int src, int dst, - long maskFormat, int[] eltArray, - int[] glyphIDs, int eltCnt, int glyphCnt); + int srcX, int srcY, long maskFormat, + int[] eltArray, int[] glyphIDs, int eltCnt, + int glyphCnt); public int XRenderCreateGlyphSet(int formatID) { return XRenderCreateGlyphSetNative(getFormatPtr(formatID)); @@ -278,11 +279,11 @@ public class XRBackendNative implements XRBackend { public void XRenderCompositeText(byte op, int src, int dst, int maskFormatID, - int src2, int src3, int dst2, int dst3, + int sx, int sy, int dx, int dy, int glyphset, GrowableEltArray elts) { GrowableIntArray glyphs = elts.getGlyphs(); - XRenderCompositeTextNative(op, src, dst, 0, elts.getArray(), + XRenderCompositeTextNative(op, src, dst, sx, sy, 0, elts.getArray(), glyphs.getArray(), elts.getSize(), glyphs.getSize()); } diff --git a/jdk/src/solaris/classes/sun/java2d/xr/XRCompositeManager.java b/jdk/src/solaris/classes/sun/java2d/xr/XRCompositeManager.java index 1264d539611..b1c2ef08065 100644 --- a/jdk/src/solaris/classes/sun/java2d/xr/XRCompositeManager.java +++ b/jdk/src/solaris/classes/sun/java2d/xr/XRCompositeManager.java @@ -295,10 +295,10 @@ public class XRCompositeManager { sy, 0, 0, dx, dy, w, h); } - public void compositeText(int dst, int glyphSet, int maskFormat, - GrowableEltArray elts) { - con.XRenderCompositeText(compRule, src.picture, dst, maskFormat, 0, 0, - 0, 0, glyphSet, elts); + public void compositeText(XRSurfaceData dst, int sx, int sy, + int glyphSet, int maskFormat, GrowableEltArray elts) { + con.XRenderCompositeText(compRule, src.picture, dst.picture, + maskFormat, sx, sy, 0, 0, glyphSet, elts); } public XRColor getMaskColor() { diff --git a/jdk/src/solaris/native/sun/java2d/x11/XRBackendNative.c b/jdk/src/solaris/native/sun/java2d/x11/XRBackendNative.c index 75d1cd2f4d2..cbcf0c357e3 100644 --- a/jdk/src/solaris/native/sun/java2d/x11/XRBackendNative.c +++ b/jdk/src/solaris/native/sun/java2d/x11/XRBackendNative.c @@ -911,8 +911,9 @@ Java_sun_java2d_xr_XRBackendNative_XRenderCreateGlyphSetNative JNIEXPORT void JNICALL Java_sun_java2d_xr_XRBackendNative_XRenderCompositeTextNative - (JNIEnv *env, jclass cls, jint op, jint src, jint dst, jlong maskFmt, - jintArray eltArray, jintArray glyphIDArray, jint eltCnt, jint glyphCnt) { + (JNIEnv *env, jclass cls, jint op, jint src, jint dst, + jint sx, jint sy, jlong maskFmt, jintArray eltArray, + jintArray glyphIDArray, jint eltCnt, jint glyphCnt) { jint i; jint *ids; jint *elts; @@ -991,7 +992,7 @@ Java_sun_java2d_xr_XRBackendNative_XRenderCompositeTextNative XRenderCompositeText32(awt_display, op, (Picture) src, (Picture) dst, (XRenderPictFormat *) jlong_to_ptr(maskFmt), - 0, 0, 0, 0, xelts, eltCnt); + sx, sy, 0, 0, xelts, eltCnt); (*env)->ReleasePrimitiveArrayCritical(env, glyphIDArray, ids, JNI_ABORT); (*env)->ReleasePrimitiveArrayCritical(env, eltArray, elts, JNI_ABORT); From 256894796fce919d11b720fb5c730f1afd78eecc Mon Sep 17 00:00:00 2001 From: Andrew Brygin Date: Wed, 4 Sep 2013 12:10:07 +0400 Subject: [PATCH 5/9] 7043064: sun/java2d/cmm/ tests failed against RI b141 & b138-nightly Reviewed-by: prr, vadim --- jdk/make/sun/cmm/lcms/mapfile-vers | 5 +- jdk/makefiles/mapfiles/liblcms/mapfile-vers | 5 +- .../classes/java/awt/color/ICC_Profile.java | 73 ++--- .../java/awt/color/ICC_ProfileGray.java | 6 +- .../java/awt/color/ICC_ProfileRGB.java | 6 +- .../classes/sun/java2d/cmm/CMSManager.java | 44 +-- .../share/classes/sun/java2d/cmm/PCMM.java | 14 +- .../share/classes/sun/java2d/cmm/Profile.java | 43 +++ .../classes/sun/java2d/cmm/lcms/LCMS.java | 208 ++++++------ .../sun/java2d/cmm/lcms/LCMSProfile.java | 109 +++++++ .../sun/java2d/cmm/lcms/LCMSTransform.java | 14 +- .../share/native/sun/java2d/cmm/lcms/LCMS.c | 299 +++++++++++------- .../cmm/ProfileOp/ReadWriteProfileTest.java | 34 +- 13 files changed, 551 insertions(+), 309 deletions(-) create mode 100644 jdk/src/share/classes/sun/java2d/cmm/Profile.java create mode 100644 jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSProfile.java diff --git a/jdk/make/sun/cmm/lcms/mapfile-vers b/jdk/make/sun/cmm/lcms/mapfile-vers index 3d9074f746d..949ff9b5787 100644 --- a/jdk/make/sun/cmm/lcms/mapfile-vers +++ b/jdk/make/sun/cmm/lcms/mapfile-vers @@ -28,9 +28,8 @@ SUNWprivate_1.1 { global: Java_sun_java2d_cmm_lcms_LCMS_loadProfileNative; - Java_sun_java2d_cmm_lcms_LCMS_freeProfileNative; - Java_sun_java2d_cmm_lcms_LCMS_getProfileSize; - Java_sun_java2d_cmm_lcms_LCMS_getProfileData; + Java_sun_java2d_cmm_lcms_LCMS_getProfileSizeNative; + Java_sun_java2d_cmm_lcms_LCMS_getProfileDataNative; Java_sun_java2d_cmm_lcms_LCMS_getTagNative; Java_sun_java2d_cmm_lcms_LCMS_setTagDataNative; Java_sun_java2d_cmm_lcms_LCMS_colorConvert; diff --git a/jdk/makefiles/mapfiles/liblcms/mapfile-vers b/jdk/makefiles/mapfiles/liblcms/mapfile-vers index 024511423d3..2e63d68e5d4 100644 --- a/jdk/makefiles/mapfiles/liblcms/mapfile-vers +++ b/jdk/makefiles/mapfiles/liblcms/mapfile-vers @@ -28,9 +28,8 @@ SUNWprivate_1.1 { global: Java_sun_java2d_cmm_lcms_LCMS_loadProfileNative; - Java_sun_java2d_cmm_lcms_LCMS_freeProfileNative; - Java_sun_java2d_cmm_lcms_LCMS_getProfileSize; - Java_sun_java2d_cmm_lcms_LCMS_getProfileData; + Java_sun_java2d_cmm_lcms_LCMS_getProfileSizeNative; + Java_sun_java2d_cmm_lcms_LCMS_getProfileDataNative; Java_sun_java2d_cmm_lcms_LCMS_getTagNative; Java_sun_java2d_cmm_lcms_LCMS_setTagDataNative; Java_sun_java2d_cmm_lcms_LCMS_colorConvert; diff --git a/jdk/src/share/classes/java/awt/color/ICC_Profile.java b/jdk/src/share/classes/java/awt/color/ICC_Profile.java index c1534249f39..7e44947477d 100644 --- a/jdk/src/share/classes/java/awt/color/ICC_Profile.java +++ b/jdk/src/share/classes/java/awt/color/ICC_Profile.java @@ -37,6 +37,7 @@ package java.awt.color; import sun.java2d.cmm.PCMM; import sun.java2d.cmm.CMSManager; +import sun.java2d.cmm.Profile; import sun.java2d.cmm.ProfileDataVerifier; import sun.java2d.cmm.ProfileDeferralMgr; import sun.java2d.cmm.ProfileDeferralInfo; @@ -94,7 +95,7 @@ public class ICC_Profile implements Serializable { private static final long serialVersionUID = -3938515861990936766L; - transient long ID; + private transient Profile cmmProfile; private transient ProfileDeferralInfo deferralInfo; private transient ProfileActivator profileActivator; @@ -727,8 +728,8 @@ public class ICC_Profile implements Serializable { /** * Constructs an ICC_Profile object with a given ID. */ - ICC_Profile(long ID) { - this.ID = ID; + ICC_Profile(Profile p) { + this.cmmProfile = p; } @@ -751,8 +752,8 @@ public class ICC_Profile implements Serializable { * Frees the resources associated with an ICC_Profile object. */ protected void finalize () { - if (ID != 0) { - CMSManager.getModule().freeProfile(ID); + if (cmmProfile != null) { + CMSManager.getModule().freeProfile(cmmProfile); } else if (profileActivator != null) { ProfileDeferralMgr.unregisterDeferral(profileActivator); } @@ -770,7 +771,7 @@ public class ICC_Profile implements Serializable { public static ICC_Profile getInstance(byte[] data) { ICC_Profile thisProfile; - long theID; + Profile p = null; if (ProfileDeferralMgr.deferring) { ProfileDeferralMgr.activateProfiles(); @@ -779,32 +780,32 @@ public class ICC_Profile implements Serializable { ProfileDataVerifier.verify(data); try { - theID = CMSManager.getModule().loadProfile(data); + p = CMSManager.getModule().loadProfile(data); } catch (CMMException c) { throw new IllegalArgumentException("Invalid ICC Profile Data"); } try { - if ((getColorSpaceType (theID) == ColorSpace.TYPE_GRAY) && - (getData (theID, icSigMediaWhitePointTag) != null) && - (getData (theID, icSigGrayTRCTag) != null)) { - thisProfile = new ICC_ProfileGray (theID); + if ((getColorSpaceType (p) == ColorSpace.TYPE_GRAY) && + (getData (p, icSigMediaWhitePointTag) != null) && + (getData (p, icSigGrayTRCTag) != null)) { + thisProfile = new ICC_ProfileGray (p); } - else if ((getColorSpaceType (theID) == ColorSpace.TYPE_RGB) && - (getData (theID, icSigMediaWhitePointTag) != null) && - (getData (theID, icSigRedColorantTag) != null) && - (getData (theID, icSigGreenColorantTag) != null) && - (getData (theID, icSigBlueColorantTag) != null) && - (getData (theID, icSigRedTRCTag) != null) && - (getData (theID, icSigGreenTRCTag) != null) && - (getData (theID, icSigBlueTRCTag) != null)) { - thisProfile = new ICC_ProfileRGB (theID); + else if ((getColorSpaceType (p) == ColorSpace.TYPE_RGB) && + (getData (p, icSigMediaWhitePointTag) != null) && + (getData (p, icSigRedColorantTag) != null) && + (getData (p, icSigGreenColorantTag) != null) && + (getData (p, icSigBlueColorantTag) != null) && + (getData (p, icSigRedTRCTag) != null) && + (getData (p, icSigGreenTRCTag) != null) && + (getData (p, icSigBlueTRCTag) != null)) { + thisProfile = new ICC_ProfileRGB (p); } else { - thisProfile = new ICC_Profile (theID); + thisProfile = new ICC_Profile (p); } } catch (CMMException c) { - thisProfile = new ICC_Profile (theID); + thisProfile = new ICC_Profile (p); } return thisProfile; } @@ -1119,7 +1120,7 @@ public class ICC_Profile implements Serializable { fileName); } try { - ID = CMSManager.getModule().loadProfile(profileData); + cmmProfile = CMSManager.getModule().loadProfile(profileData); } catch (CMMException c) { ProfileDataException pde = new ProfileDataException("Invalid ICC Profile Data" + fileName); @@ -1229,14 +1230,14 @@ public class ICC_Profile implements Serializable { causing a deferred profile to be loaded */ } - return getColorSpaceType(ID); + return getColorSpaceType(cmmProfile); } - static int getColorSpaceType(long profileID) { + static int getColorSpaceType(Profile p) { byte[] theHeader; int theColorSpaceSig, theColorSpace; - theHeader = getData(profileID, icSigHead); + theHeader = getData(p, icSigHead); theColorSpaceSig = intFromBigEndian(theHeader, icHdrColorSpace); theColorSpace = iccCStoJCS (theColorSpaceSig); return theColorSpace; @@ -1258,15 +1259,15 @@ public class ICC_Profile implements Serializable { if (ProfileDeferralMgr.deferring) { ProfileDeferralMgr.activateProfiles(); } - return getPCSType(ID); + return getPCSType(cmmProfile); } - static int getPCSType(long profileID) { + static int getPCSType(Profile p) { byte[] theHeader; int thePCSSig, thePCS; - theHeader = getData(profileID, icSigHead); + theHeader = getData(p, icSigHead); thePCSSig = intFromBigEndian(theHeader, icHdrPcs); thePCS = iccCStoJCS(thePCSSig); return thePCS; @@ -1326,12 +1327,12 @@ public class ICC_Profile implements Serializable { PCMM mdl = CMSManager.getModule(); /* get the number of bytes needed for this profile */ - profileSize = mdl.getProfileSize(ID); + profileSize = mdl.getProfileSize(cmmProfile); profileData = new byte [profileSize]; /* get the data for the profile */ - mdl.getProfileData(ID, profileData); + mdl.getProfileData(cmmProfile, profileData); return profileData; } @@ -1358,11 +1359,11 @@ public class ICC_Profile implements Serializable { ProfileDeferralMgr.activateProfiles(); } - return getData(ID, tagSignature); + return getData(cmmProfile, tagSignature); } - static byte[] getData(long profileID, int tagSignature) { + static byte[] getData(Profile p, int tagSignature) { int tagSize; byte[] tagData; @@ -1370,12 +1371,12 @@ public class ICC_Profile implements Serializable { PCMM mdl = CMSManager.getModule(); /* get the number of bytes needed for this tag */ - tagSize = mdl.getTagSize(profileID, tagSignature); + tagSize = mdl.getTagSize(p, tagSignature); tagData = new byte[tagSize]; /* get an array for the tag */ /* get the tag's data */ - mdl.getTagData(profileID, tagSignature, tagData); + mdl.getTagData(p, tagSignature, tagData); } catch(CMMException c) { tagData = null; } @@ -1406,7 +1407,7 @@ public class ICC_Profile implements Serializable { ProfileDeferralMgr.activateProfiles(); } - CMSManager.getModule().setTagData(ID, tagSignature, tagData); + CMSManager.getModule().setTagData(cmmProfile, tagSignature, tagData); } /** diff --git a/jdk/src/share/classes/java/awt/color/ICC_ProfileGray.java b/jdk/src/share/classes/java/awt/color/ICC_ProfileGray.java index d9042266663..a868a6f50fc 100644 --- a/jdk/src/share/classes/java/awt/color/ICC_ProfileGray.java +++ b/jdk/src/share/classes/java/awt/color/ICC_ProfileGray.java @@ -35,7 +35,7 @@ package java.awt.color; -import java.awt.image.LookupTable; +import sun.java2d.cmm.Profile; import sun.java2d.cmm.ProfileDeferralInfo; /** @@ -76,8 +76,8 @@ extends ICC_Profile { /** * Constructs a new ICC_ProfileGray from a CMM ID. */ - ICC_ProfileGray(long ID) { - super(ID); + ICC_ProfileGray(Profile p) { + super(p); } /** diff --git a/jdk/src/share/classes/java/awt/color/ICC_ProfileRGB.java b/jdk/src/share/classes/java/awt/color/ICC_ProfileRGB.java index b0bad4d9a91..dcf65828650 100644 --- a/jdk/src/share/classes/java/awt/color/ICC_ProfileRGB.java +++ b/jdk/src/share/classes/java/awt/color/ICC_ProfileRGB.java @@ -35,7 +35,7 @@ package java.awt.color; -import java.awt.image.LookupTable; +import sun.java2d.cmm.Profile; import sun.java2d.cmm.ProfileDeferralInfo; /** @@ -114,8 +114,8 @@ extends ICC_Profile { * @param ID The CMM ID for the profile. * */ - ICC_ProfileRGB(long ID) { - super(ID); + ICC_ProfileRGB(Profile p) { + super(p); } /** diff --git a/jdk/src/share/classes/sun/java2d/cmm/CMSManager.java b/jdk/src/share/classes/sun/java2d/cmm/CMSManager.java index 1e24504b45a..fcaede43a94 100644 --- a/jdk/src/share/classes/sun/java2d/cmm/CMSManager.java +++ b/jdk/src/share/classes/sun/java2d/cmm/CMSManager.java @@ -104,53 +104,53 @@ public class CMSManager { cName = tcmm.getClass().getName(); } - public long loadProfile(byte[] data) { + public Profile loadProfile(byte[] data) { System.err.print(cName + ".loadProfile"); - long profileID = tcmm.loadProfile(data); - System.err.printf("(ID=%x)\n", profileID); - return profileID; + Profile p = tcmm.loadProfile(data); + System.err.printf("(ID=%s)\n", p.toString()); + return p; } - public void freeProfile(long profileID) { - System.err.printf(cName + ".freeProfile(ID=%x)\n", profileID); - tcmm.freeProfile(profileID); + public void freeProfile(Profile p) { + System.err.printf(cName + ".freeProfile(ID=%s)\n", p.toString()); + tcmm.freeProfile(p); } - public int getProfileSize(long profileID) { - System.err.print(cName + ".getProfileSize(ID=" + profileID + ")"); - int size = tcmm.getProfileSize(profileID); + public int getProfileSize(Profile p) { + System.err.print(cName + ".getProfileSize(ID=" + p + ")"); + int size = tcmm.getProfileSize(p); System.err.println("=" + size); return size; } - public void getProfileData(long profileID, byte[] data) { - System.err.print(cName + ".getProfileData(ID=" + profileID + ") "); + public void getProfileData(Profile p, byte[] data) { + System.err.print(cName + ".getProfileData(ID=" + p + ") "); System.err.println("requested " + data.length + " byte(s)"); - tcmm.getProfileData(profileID, data); + tcmm.getProfileData(p, data); } - public int getTagSize(long profileID, int tagSignature) { + public int getTagSize(Profile p, int tagSignature) { System.err.printf(cName + ".getTagSize(ID=%x, TagSig=%s)", - profileID, signatureToString(tagSignature)); - int size = tcmm.getTagSize(profileID, tagSignature); + p, signatureToString(tagSignature)); + int size = tcmm.getTagSize(p, tagSignature); System.err.println("=" + size); return size; } - public void getTagData(long profileID, int tagSignature, + public void getTagData(Profile p, int tagSignature, byte[] data) { System.err.printf(cName + ".getTagData(ID=%x, TagSig=%s)", - profileID, signatureToString(tagSignature)); + p, signatureToString(tagSignature)); System.err.println(" requested " + data.length + " byte(s)"); - tcmm.getTagData(profileID, tagSignature, data); + tcmm.getTagData(p, tagSignature, data); } - public void setTagData(long profileID, int tagSignature, + public void setTagData(Profile p, int tagSignature, byte[] data) { - System.err.print(cName + ".setTagData(ID=" + profileID + + System.err.print(cName + ".setTagData(ID=" + p + ", TagSig=" + tagSignature + ")"); System.err.println(" sending " + data.length + " byte(s)"); - tcmm.setTagData(profileID, tagSignature, data); + tcmm.setTagData(p, tagSignature, data); } /* methods for creating ColorTransforms */ diff --git a/jdk/src/share/classes/sun/java2d/cmm/PCMM.java b/jdk/src/share/classes/sun/java2d/cmm/PCMM.java index 6b6ce93546d..03f2fab6336 100644 --- a/jdk/src/share/classes/sun/java2d/cmm/PCMM.java +++ b/jdk/src/share/classes/sun/java2d/cmm/PCMM.java @@ -32,13 +32,13 @@ import java.awt.color.ICC_Profile; public interface PCMM { /* methods invoked from ICC_Profile */ - public long loadProfile(byte[] data); - public void freeProfile(long profileID); - public int getProfileSize(long profileID); - public void getProfileData(long profileID, byte[] data); - public void getTagData(long profileID, int tagSignature, byte[] data); - public int getTagSize(long profileID, int tagSignature); - public void setTagData(long profileID, int tagSignature, byte[] data); + public Profile loadProfile(byte[] data); + public void freeProfile(Profile p); + public int getProfileSize(Profile p); + public void getProfileData(Profile p, byte[] data); + public void getTagData(Profile p, int tagSignature, byte[] data); + public int getTagSize(Profile p, int tagSignature); + public void setTagData(Profile p, int tagSignature, byte[] data); /* methods for creating ColorTransforms */ public ColorTransform createTransform(ICC_Profile profile, int renderType, diff --git a/jdk/src/share/classes/sun/java2d/cmm/Profile.java b/jdk/src/share/classes/sun/java2d/cmm/Profile.java new file mode 100644 index 00000000000..5b766b5d079 --- /dev/null +++ b/jdk/src/share/classes/sun/java2d/cmm/Profile.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2013, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.java2d.cmm; + +import java.awt.color.CMMException; + +public class Profile { + private final long nativePtr; + + protected Profile(long ptr) { + nativePtr = ptr; + } + + protected final long getNativePtr() { + if (nativePtr == 0L) { + throw new CMMException("Invalid profile: ptr is null"); + } + return nativePtr; + } +} diff --git a/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMS.java b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMS.java index f7ecc0b67c9..d76d99638a9 100644 --- a/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMS.java +++ b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMS.java @@ -25,96 +25,139 @@ package sun.java2d.cmm.lcms; +import java.awt.color.CMMException; import java.awt.color.ICC_Profile; -import java.util.Arrays; -import java.util.HashMap; import sun.java2d.cmm.ColorTransform; import sun.java2d.cmm.PCMM; +import sun.java2d.cmm.Profile; +import sun.java2d.cmm.lcms.LCMSProfile.TagData; public class LCMS implements PCMM { /* methods invoked from ICC_Profile */ @Override - public long loadProfile(byte[] data) { - long id = loadProfileNative(data); + public Profile loadProfile(byte[] data) { + final Object disposerRef = new Object(); - if (id != 0L) { - if (profiles == null) { - profiles = new HashMap<>(); - } - profiles.put(id, new TagCache(id)); + final long ptr = loadProfileNative(data, disposerRef); + + if (ptr != 0L) { + return new LCMSProfile(ptr, disposerRef); } - return id; + return null; } - private native long loadProfileNative(byte[] data); + private native long loadProfileNative(byte[] data, Object ref); - @Override - public void freeProfile(long profileID) { - TagCache c = profiles.remove(profileID); - if (c != null) { - c.clear(); + private LCMSProfile getLcmsProfile(Profile p) { + if (p instanceof LCMSProfile) { + return (LCMSProfile)p; } - if (profiles.isEmpty()) { - profiles = null; - } - freeProfileNative(profileID); + throw new CMMException("Invalid profile: " + p); } - private native void freeProfileNative(long profileID); - - public native synchronized int getProfileSize(long profileID); - - public native synchronized void getProfileData(long profileID, byte[] data); @Override - public synchronized int getTagSize(long profileID, int tagSignature) { - TagCache cache = profiles.get(profileID); - - if (cache == null) { - cache = new TagCache(profileID); - profiles.put(profileID, cache); - } - - TagData t = cache.getTag(tagSignature); - return t == null ? 0 : t.getSize(); + public void freeProfile(Profile p) { + // we use disposer, so this method does nothing } - private static native byte[] getTagNative(long profileID, int signature); + @Override + public int getProfileSize(final Profile p) { + synchronized (p) { + return getProfileSizeNative(getLcmsProfile(p).getLcmsPtr()); + } + } + + private native int getProfileSizeNative(long ptr); @Override - public synchronized void getTagData(long profileID, int tagSignature, - byte[] data) + public void getProfileData(final Profile p, byte[] data) { + synchronized (p) { + getProfileDataNative(getLcmsProfile(p).getLcmsPtr(), data); + } + } + + private native void getProfileDataNative(long ptr, byte[] data); + + @Override + public int getTagSize(Profile p, int tagSignature) { + final LCMSProfile profile = getLcmsProfile(p); + + synchronized (profile) { + TagData t = profile.getTag(tagSignature); + return t == null ? 0 : t.getSize(); + } + } + + static native byte[] getTagNative(long profileID, int signature); + + @Override + public void getTagData(Profile p, int tagSignature, byte[] data) { - TagCache cache = profiles.get(profileID); + final LCMSProfile profile = getLcmsProfile(p); - if (cache == null) { - cache = new TagCache(profileID); - profiles.put(profileID, cache); - } - - TagData t = cache.getTag(tagSignature); - if (t != null) { - t.copyDataTo(data); + synchronized (profile) { + TagData t = profile.getTag(tagSignature); + if (t != null) { + t.copyDataTo(data); + } } } @Override - public synchronized void setTagData(long profileID, int tagSignature, byte[] data) { - TagCache cache = profiles.get(profileID); + public synchronized void setTagData(Profile p, int tagSignature, byte[] data) { + final LCMSProfile profile = getLcmsProfile(p); - if (cache != null) { - cache.clear(); + synchronized (profile) { + profile.clearTagCache(); + + // Now we are going to update the profile with new tag data + // In some cases, we may change the pointer to the native + // profile. + // + // If we fail to write tag data for any reason, the old pointer + // should be used. + setTagDataNative(profile.getLcmsPtr(), + tagSignature, data); } - setTagDataNative(profileID, tagSignature, data); } - private native synchronized void setTagDataNative(long profileID, int tagSignature, + /** + * Writes supplied data as a tag into the profile. + * Destroys old profile, if new one was successfully + * created. + * + * Returns valid pointer to new profile. + * + * Throws CMMException if operation fails, preserve old profile from + * destruction. + */ + private native void setTagDataNative(long ptr, int tagSignature, byte[] data); - public static native long getProfileID(ICC_Profile profile); + public synchronized static native LCMSProfile getProfileID(ICC_Profile profile); - public static native long createNativeTransform( + /* Helper method used from LCMSColorTransfrom */ + static long createTransform( + LCMSProfile[] profiles, int renderType, + int inFormatter, boolean isInIntPacked, + int outFormatter, boolean isOutIntPacked, + Object disposerRef) + { + long[] ptrs = new long[profiles.length]; + + for (int i = 0; i < profiles.length; i++) { + if (profiles[i] == null) throw new CMMException("Unknown profile ID"); + + ptrs[i] = profiles[i].getLcmsPtr(); + } + + return createNativeTransform(ptrs, renderType, inFormatter, + isInIntPacked, outFormatter, isOutIntPacked, disposerRef); + } + + private static native long createNativeTransform( long[] profileIDs, int renderType, int inFormatter, boolean isInIntPacked, int outFormatter, boolean isOutIntPacked, @@ -175,59 +218,4 @@ public class LCMS implements PCMM { return theLcms; } - - private static class TagData { - private int signature; - private byte[] data; - - TagData(int sig, byte[] data) { - this.signature = sig; - this.data = data; - } - - int getSize() { - return data.length; - } - - byte[] getData() { - return Arrays.copyOf(data, data.length); - } - - void copyDataTo(byte[] dst) { - System.arraycopy(data, 0, dst, 0, data.length); - } - - int getSignature() { - return signature; - } - } - - private static class TagCache { - private long profileID; - private HashMap tags; - - TagCache(long id) { - profileID = id; - - tags = new HashMap<>(); - } - - TagData getTag(int sig) { - TagData t = tags.get(sig); - if (t == null) { - byte[] tagData = getTagNative(profileID, sig); - if (tagData != null) { - t = new TagData(sig, tagData); - tags.put(sig, t); - } - } - return t; - } - - void clear() { - tags.clear(); - } - } - - private static HashMap profiles; } diff --git a/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSProfile.java b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSProfile.java new file mode 100644 index 00000000000..12810812416 --- /dev/null +++ b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSProfile.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2013, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.java2d.cmm.lcms; + +import java.awt.color.CMMException; +import java.util.Arrays; +import java.util.HashMap; +import sun.java2d.cmm.Profile; + +final class LCMSProfile extends Profile { + private final TagCache tagCache; + + private final Object disposerReferent; + + LCMSProfile(long ptr, Object ref) { + super(ptr); + + disposerReferent = ref; + + tagCache = new TagCache(this); + } + + final long getLcmsPtr() { + return this.getNativePtr(); + } + + TagData getTag(int sig) { + return tagCache.getTag(sig); + } + + void clearTagCache() { + tagCache.clear(); + } + + static class TagCache { + final LCMSProfile profile; + private HashMap tags; + + TagCache(LCMSProfile p) { + profile = p; + tags = new HashMap<>(); + } + + TagData getTag(int sig) { + TagData t = tags.get(sig); + if (t == null) { + byte[] tagData = LCMS.getTagNative(profile.getNativePtr(), sig); + if (tagData != null) { + t = new TagData(sig, tagData); + tags.put(sig, t); + } + } + return t; + } + + void clear() { + tags.clear(); + } + } + + static class TagData { + private int signature; + private byte[] data; + + TagData(int sig, byte[] data) { + this.signature = sig; + this.data = data; + } + + int getSize() { + return data.length; + } + + byte[] getData() { + return Arrays.copyOf(data, data.length); + } + + void copyDataTo(byte[] dst) { + System.arraycopy(data, 0, dst, 0, data.length); + } + + int getSignature() { + return signature; + } + } +} diff --git a/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java index d5ce5525989..9d6dfa9aac3 100644 --- a/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java +++ b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java @@ -62,7 +62,7 @@ public class LCMSTransform implements ColorTransform { private boolean isOutIntPacked = false; ICC_Profile[] profiles; - long [] profileIDs; + LCMSProfile[] lcmsProfiles; int renderType; int transformType; @@ -84,8 +84,8 @@ public class LCMSTransform implements ColorTransform { /* Actually, it is not a complete transform but just part of it */ profiles = new ICC_Profile[1]; profiles[0] = profile; - profileIDs = new long[1]; - profileIDs[0] = LCMS.getProfileID(profile); + lcmsProfiles = new LCMSProfile[1]; + lcmsProfiles[0] = LCMS.getProfileID(profile); this.renderType = (renderType == ColorTransform.Any)? ICC_Profile.icPerceptual : renderType; this.transformType = transformType; @@ -105,14 +105,14 @@ public class LCMSTransform implements ColorTransform { size+=((LCMSTransform)transforms[i]).profiles.length; } profiles = new ICC_Profile[size]; - profileIDs = new long[size]; + lcmsProfiles = new LCMSProfile[size]; int j = 0; for (int i=0; i < transforms.length; i++) { LCMSTransform curTrans = (LCMSTransform)transforms[i]; System.arraycopy(curTrans.profiles, 0, profiles, j, curTrans.profiles.length); - System.arraycopy(curTrans.profileIDs, 0, profileIDs, j, - curTrans.profileIDs.length); + System.arraycopy(curTrans.lcmsProfiles, 0, lcmsProfiles, j, + curTrans.lcmsProfiles.length); j += curTrans.profiles.length; } renderType = ((LCMSTransform)transforms[0]).renderType; @@ -152,7 +152,7 @@ public class LCMSTransform implements ColorTransform { outFormatter = out.pixelType; isOutIntPacked = out.isIntPacked; - ID = LCMS.createNativeTransform(profileIDs, renderType, + ID = LCMS.createTransform(lcmsProfiles, renderType, inFormatter, isInIntPacked, outFormatter, isOutIntPacked, disposerReferent); diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c b/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c index 1340c82a822..13030cc41d5 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c @@ -94,8 +94,12 @@ cmsInt32Number TransportValue32(cmsInt32Number Value) # endif #endif -typedef union storeID_s { /* store SProfile stuff in a Java Long */ +typedef struct lcmsProfile_s { cmsHPROFILE pf; +} lcmsProfile_t, *lcmsProfile_p; + +typedef union storeID_s { /* store SProfile stuff in a Java Long */ + lcmsProfile_p lcmsPf; cmsHTRANSFORM xf; jobject jobj; jlong j; @@ -106,7 +110,6 @@ typedef union { jint j; } TagSignature_t, *TagSignature_p; -static jfieldID Trans_profileIDs_fID; static jfieldID Trans_renderType_fID; static jfieldID Trans_ID_fID; static jfieldID IL_isIntPacked_fID; @@ -118,7 +121,6 @@ static jfieldID IL_nextRowOffset_fID; static jfieldID IL_width_fID; static jfieldID IL_height_fID; static jfieldID IL_imageAtOnce_fID; -static jfieldID PF_ID_fID; JavaVM *javaVM; @@ -145,6 +147,18 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) { return JNI_VERSION_1_6; } +void LCMS_freeProfile(JNIEnv *env, jlong ptr) { + storeID_t sProfile; + sProfile.j = ptr; + + if (sProfile.lcmsPf != NULL) { + if (sProfile.lcmsPf->pf != NULL) { + cmsCloseProfile(sProfile.lcmsPf->pf); + } + free(sProfile.lcmsPf); + } +} + void LCMS_freeTransform(JNIEnv *env, jlong ID) { storeID_t sTrans; @@ -170,7 +184,7 @@ JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_createNativeTransform jlong* ids; size = (*env)->GetArrayLength (env, profileIDs); - ids = (*env)->GetPrimitiveArrayCritical(env, profileIDs, 0); + ids = (*env)->GetLongArrayElements(env, profileIDs, 0); #ifdef _LITTLE_ENDIAN /* Reversing data packed into int for LE archs */ @@ -186,6 +200,8 @@ JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_createNativeTransform iccArray = (cmsHPROFILE*) malloc( size*2*sizeof(cmsHPROFILE)); if (iccArray == NULL) { + (*env)->ReleaseLongArrayElements(env, profileIDs, ids, 0); + J2dRlsTraceLn(J2D_TRACE_ERROR, "getXForm: iccArray == NULL"); return 0L; } @@ -197,7 +213,7 @@ JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_createNativeTransform cmsColorSpaceSignature cs; sTrans.j = ids[i]; - icc = sTrans.pf; + icc = sTrans.lcmsPf->pf; iccArray[j++] = icc; /* Middle non-abstract profiles should be doubled before passing to @@ -215,13 +231,15 @@ JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_createNativeTransform sTrans.xf = cmsCreateMultiprofileTransform(iccArray, j, inFormatter, outFormatter, renderType, 0); - (*env)->ReleasePrimitiveArrayCritical(env, profileIDs, ids, 0); + (*env)->ReleaseLongArrayElements(env, profileIDs, ids, 0); if (sTrans.xf == NULL) { J2dRlsTraceLn(J2D_TRACE_ERROR, "LCMS_createNativeTransform: " "sTrans.xf == NULL"); - JNU_ThrowByName(env, "java/awt/color/CMMException", - "Cannot get color transform"); + if ((*env)->ExceptionOccurred(env) == NULL) { + JNU_ThrowByName(env, "java/awt/color/CMMException", + "Cannot get color transform"); + } } else { Disposer_AddRecord(env, disposerRef, LCMS_freeTransform, sTrans.j); } @@ -236,20 +254,23 @@ JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_createNativeTransform /* * Class: sun_java2d_cmm_lcms_LCMS * Method: loadProfile - * Signature: ([B)J + * Signature: ([B,Lsun/java2d/cmm/lcms/LCMSProfile;)V */ JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_loadProfileNative - (JNIEnv *env, jobject obj, jbyteArray data) + (JNIEnv *env, jobject obj, jbyteArray data, jobject disposerRef) { jbyte* dataArray; jint dataSize; storeID_t sProf; + cmsHPROFILE pf; if (JNU_IsNull(env, data)) { JNU_ThrowIllegalArgumentException(env, "Invalid profile data"); return 0L; } + sProf.j = 0L; + dataArray = (*env)->GetByteArrayElements (env, data, 0); dataSize = (*env)->GetArrayLength (env, data); @@ -258,22 +279,37 @@ JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_loadProfileNative return 0L; } - sProf.pf = cmsOpenProfileFromMem((const void *)dataArray, + pf = cmsOpenProfileFromMem((const void *)dataArray, (cmsUInt32Number) dataSize); (*env)->ReleaseByteArrayElements (env, data, dataArray, 0); - if (sProf.pf == NULL) { + if (pf == NULL) { JNU_ThrowIllegalArgumentException(env, "Invalid profile data"); } else { /* Sanity check: try to save the profile in order * to force basic validation. */ cmsUInt32Number pfSize = 0; - if (!cmsSaveProfileToMem(sProf.pf, NULL, &pfSize) || + if (!cmsSaveProfileToMem(pf, NULL, &pfSize) || pfSize < sizeof(cmsICCHeader)) { JNU_ThrowIllegalArgumentException(env, "Invalid profile data"); + + cmsCloseProfile(pf); + pf = NULL; + } + } + + if (pf != NULL) { + // create profile holder + sProf.lcmsPf = (lcmsProfile_p)malloc(sizeof(lcmsProfile_t)); + if (sProf.lcmsPf != NULL) { + // register the disposer record + sProf.lcmsPf->pf = pf; + Disposer_AddRecord(env, disposerRef, LCMS_freeTransform, sProf.j); + } else { + cmsCloseProfile(pf); } } @@ -282,37 +318,17 @@ JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_loadProfileNative /* * Class: sun_java2d_cmm_lcms_LCMS - * Method: freeProfile - * Signature: (J)V - */ -JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_freeProfileNative - (JNIEnv *env, jobject obj, jlong id) -{ - storeID_t sProf; - - sProf.j = id; - if (cmsCloseProfile(sProf.pf) == 0) { - J2dRlsTraceLn1(J2D_TRACE_ERROR, "LCMS_freeProfile: cmsCloseProfile(%d)" - "== 0", id); - JNU_ThrowByName(env, "java/awt/color/CMMException", - "Cannot close profile"); - } - -} - -/* - * Class: sun_java2d_cmm_lcms_LCMS - * Method: getProfileSize + * Method: getProfileSizeNative * Signature: (J)I */ -JNIEXPORT jint JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileSize +JNIEXPORT jint JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileSizeNative (JNIEnv *env, jobject obj, jlong id) { storeID_t sProf; cmsUInt32Number pfSize = 0; sProf.j = id; - if (cmsSaveProfileToMem(sProf.pf, NULL, &pfSize) && ((jint)pfSize > 0)) { + if (cmsSaveProfileToMem(sProf.lcmsPf->pf, NULL, &pfSize) && ((jint)pfSize > 0)) { return (jint)pfSize; } else { JNU_ThrowByName(env, "java/awt/color/CMMException", @@ -323,10 +339,10 @@ JNIEXPORT jint JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileSize /* * Class: sun_java2d_cmm_lcms_LCMS - * Method: getProfileData + * Method: getProfileDataNative * Signature: (J[B)V */ -JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileData +JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileDataNative (JNIEnv *env, jobject obj, jlong id, jbyteArray data) { storeID_t sProf; @@ -338,7 +354,7 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileData sProf.j = id; // determine actual profile size - if (!cmsSaveProfileToMem(sProf.pf, NULL, &pfSize)) { + if (!cmsSaveProfileToMem(sProf.lcmsPf->pf, NULL, &pfSize)) { JNU_ThrowByName(env, "java/awt/color/CMMException", "Can not access specified profile."); return; @@ -354,7 +370,7 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileData dataArray = (*env)->GetByteArrayElements (env, data, 0); - status = cmsSaveProfileToMem(sProf.pf, dataArray, &pfSize); + status = cmsSaveProfileToMem(sProf.lcmsPf->pf, dataArray, &pfSize); (*env)->ReleaseByteArrayElements (env, data, dataArray, 0); @@ -368,7 +384,7 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileData /* Get profile header info */ static cmsBool _getHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize); static cmsBool _setHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize); -static cmsBool _writeCookedTag(cmsHPROFILE pfTarget, cmsTagSignature sig, jbyte *pData, jint size); +static cmsHPROFILE _writeCookedTag(cmsHPROFILE pfTarget, cmsTagSignature sig, jbyte *pData, jint size); /* @@ -412,7 +428,7 @@ JNIEXPORT jbyteArray JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagNative return NULL; } - status = _getHeaderInfo(sProf.pf, dataArray, bufSize); + status = _getHeaderInfo(sProf.lcmsPf->pf, dataArray, bufSize); (*env)->ReleaseByteArrayElements (env, data, dataArray, 0); @@ -425,8 +441,8 @@ JNIEXPORT jbyteArray JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagNative return data; } - if (cmsIsTag(sProf.pf, sig.cms)) { - tagSize = cmsReadRawTag(sProf.pf, sig.cms, NULL, 0); + if (cmsIsTag(sProf.lcmsPf->pf, sig.cms)) { + tagSize = cmsReadRawTag(sProf.lcmsPf->pf, sig.cms, NULL, 0); } else { JNU_ThrowByName(env, "java/awt/color/CMMException", "ICC profile tag not found"); @@ -449,7 +465,7 @@ JNIEXPORT jbyteArray JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagNative return NULL; } - bufSize = cmsReadRawTag(sProf.pf, sig.cms, dataArray, tagSize); + bufSize = cmsReadRawTag(sProf.lcmsPf->pf, sig.cms, dataArray, tagSize); (*env)->ReleaseByteArrayElements (env, data, dataArray, 0); @@ -470,8 +486,10 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_setTagDataNative (JNIEnv *env, jobject obj, jlong id, jint tagSig, jbyteArray data) { storeID_t sProf; + cmsHPROFILE pfReplace = NULL; + TagSignature_t sig; - cmsBool status; + cmsBool status = FALSE; jbyte* dataArray; int tagSize; @@ -493,15 +511,24 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_setTagDataNative } if (tagSig == SigHead) { - status = _setHeaderInfo(sProf.pf, dataArray, tagSize); + status = _setHeaderInfo(sProf.lcmsPf->pf, dataArray, tagSize); } else { - status = _writeCookedTag(sProf.pf, sig.cms, dataArray, tagSize); + /* + * New strategy for generic tags: create a place holder, + * dump all existing tags there, dump externally supplied + * tag, and return the new profile to the java. + */ + pfReplace = _writeCookedTag(sProf.lcmsPf->pf, sig.cms, dataArray, tagSize); + status = (pfReplace != NULL); } (*env)->ReleaseByteArrayElements(env, data, dataArray, 0); if (!status) { JNU_ThrowIllegalArgumentException(env, "Can not write tag data."); + } else if (pfReplace != NULL) { + cmsCloseProfile(sProf.lcmsPf->pf); + sProf.lcmsPf->pf = pfReplace; } } @@ -624,12 +651,27 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_colorConvert /* * Class: sun_java2d_cmm_lcms_LCMS * Method: getProfileID - * Signature: (Ljava/awt/color/ICC_Profile;)J + * Signature: (Ljava/awt/color/ICC_Profile;)Lsun/java2d/cmm/lcms/LCMSProfile */ -JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileID +JNIEXPORT jobject JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileID (JNIEnv *env, jclass cls, jobject pf) { - return (*env)->GetLongField (env, pf, PF_ID_fID); + jfieldID fid = (*env)->GetFieldID (env, + (*env)->GetObjectClass(env, pf), + "cmmProfile", "Lsun/java2d/cmm/Profile;"); + + jclass clsLcmsProfile = (*env)->FindClass(env, + "sun/java2d/cmm/lcms/LCMSProfile"); + + jobject cmmProfile = (*env)->GetObjectField (env, pf, fid); + + if (JNU_IsNull(env, cmmProfile)) { + return NULL; + } + if ((*env)->IsInstanceOf(env, cmmProfile, clsLcmsProfile)) { + return cmmProfile; + } + return NULL; } /* @@ -644,7 +686,6 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_initLCMS * corresponding classes to avoid problems with invalidating ids by class * unloading */ - Trans_profileIDs_fID = (*env)->GetFieldID (env, Trans, "profileIDs", "[J"); Trans_renderType_fID = (*env)->GetFieldID (env, Trans, "renderType", "I"); Trans_ID_fID = (*env)->GetFieldID (env, Trans, "ID", "J"); @@ -658,8 +699,6 @@ JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_initLCMS IL_offset_fID = (*env)->GetFieldID (env, IL, "offset", "I"); IL_imageAtOnce_fID = (*env)->GetFieldID (env, IL, "imageAtOnce", "Z"); IL_nextRowOffset_fID = (*env)->GetFieldID (env, IL, "nextRowOffset", "I"); - - PF_ID_fID = (*env)->GetFieldID (env, Pf, "ID", "J"); } static cmsBool _getHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize) @@ -714,76 +753,114 @@ static cmsBool _setHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize) return TRUE; } -static cmsBool _writeCookedTag(cmsHPROFILE pfTarget, - cmsTagSignature sig, +/* Returns new profile handler, if it was created successfully, + NULL otherwise. + */ +static cmsHPROFILE _writeCookedTag(const cmsHPROFILE pfTarget, + const cmsTagSignature sig, jbyte *pData, jint size) { - cmsBool status; cmsUInt32Number pfSize = 0; - cmsUInt8Number* pfBuffer = NULL; + const cmsInt32Number tagCount = cmsGetTagCount(pfTarget); + cmsInt32Number i; + cmsHPROFILE pfSanity = NULL; + + cmsICCHeader hdr = { 0 }; cmsHPROFILE p = cmsCreateProfilePlaceholder(NULL); - if (NULL != p) { - cmsICCHeader hdr = { 0 }; - /* Populate the placeholder's header according to target profile */ - hdr.flags = cmsGetHeaderFlags(pfTarget); - hdr.renderingIntent = cmsGetHeaderRenderingIntent(pfTarget); - hdr.manufacturer = cmsGetHeaderManufacturer(pfTarget); - hdr.model = cmsGetHeaderModel(pfTarget); - hdr.pcs = cmsGetPCS(pfTarget); - hdr.colorSpace = cmsGetColorSpace(pfTarget); - hdr.deviceClass = cmsGetDeviceClass(pfTarget); - hdr.version = cmsGetEncodedICCversion(pfTarget); - cmsGetHeaderAttributes(pfTarget, &hdr.attributes); - cmsGetHeaderProfileID(pfTarget, (cmsUInt8Number*)&hdr.profileID); + if (NULL == p) { + return NULL; + } - cmsSetHeaderFlags(p, hdr.flags); - cmsSetHeaderManufacturer(p, hdr.manufacturer); - cmsSetHeaderModel(p, hdr.model); - cmsSetHeaderAttributes(p, hdr.attributes); - cmsSetHeaderProfileID(p, (cmsUInt8Number*)&(hdr.profileID)); - cmsSetHeaderRenderingIntent(p, hdr.renderingIntent); - cmsSetPCS(p, hdr.pcs); - cmsSetColorSpace(p, hdr.colorSpace); - cmsSetDeviceClass(p, hdr.deviceClass); - cmsSetEncodedICCversion(p, hdr.version); + // Populate the placeholder's header according to target profile + hdr.flags = cmsGetHeaderFlags(pfTarget); + hdr.renderingIntent = cmsGetHeaderRenderingIntent(pfTarget); + hdr.manufacturer = cmsGetHeaderManufacturer(pfTarget); + hdr.model = cmsGetHeaderModel(pfTarget); + hdr.pcs = cmsGetPCS(pfTarget); + hdr.colorSpace = cmsGetColorSpace(pfTarget); + hdr.deviceClass = cmsGetDeviceClass(pfTarget); + hdr.version = cmsGetEncodedICCversion(pfTarget); + cmsGetHeaderAttributes(pfTarget, &hdr.attributes); + cmsGetHeaderProfileID(pfTarget, (cmsUInt8Number*)&hdr.profileID); + cmsSetHeaderFlags(p, hdr.flags); + cmsSetHeaderManufacturer(p, hdr.manufacturer); + cmsSetHeaderModel(p, hdr.model); + cmsSetHeaderAttributes(p, hdr.attributes); + cmsSetHeaderProfileID(p, (cmsUInt8Number*)&(hdr.profileID)); + cmsSetHeaderRenderingIntent(p, hdr.renderingIntent); + cmsSetPCS(p, hdr.pcs); + cmsSetColorSpace(p, hdr.colorSpace); + cmsSetDeviceClass(p, hdr.deviceClass); + cmsSetEncodedICCversion(p, hdr.version); - if (cmsWriteRawTag(p, sig, pData, size)) { - if (cmsSaveProfileToMem(p, NULL, &pfSize)) { - pfBuffer = malloc(pfSize); - if (pfBuffer != NULL) { - /* load raw profile data into the buffer */ - if (!cmsSaveProfileToMem(p, pfBuffer, &pfSize)) { - free(pfBuffer); - pfBuffer = NULL; - } + // now write the user supplied tag + if (size <= 0 || !cmsWriteRawTag(p, sig, pData, size)) { + cmsCloseProfile(p); + return NULL; + } + + // copy tags from the original profile + for (i = 0; i < tagCount; i++) { + cmsBool isTagReady = FALSE; + const cmsTagSignature s = cmsGetTagSignature(pfTarget, i); + const cmsInt32Number tagSize = cmsReadRawTag(pfTarget, s, NULL, 0); + + if (s == sig) { + // skip the user supplied tag + continue; + } + + // read raw tag from the original profile + if (tagSize > 0) { + cmsUInt8Number* buf = (cmsUInt8Number*)malloc(tagSize); + if (buf != NULL) { + if (tagSize == cmsReadRawTag(pfTarget, s, buf, tagSize)) { + // now we are ready to write the tag + isTagReady = cmsWriteRawTag(p, s, buf, tagSize); } + free(buf); } } - cmsCloseProfile(p); - } - if (pfBuffer == NULL) { - return FALSE; - } - - /* re-open the placeholder profile */ - p = cmsOpenProfileFromMem(pfBuffer, pfSize); - free(pfBuffer); - status = FALSE; - - if (p != NULL) { - /* Note that pCookedTag points to internal structures of the placeholder, - * so this data is valid only while the placeholder is open. - */ - void *pCookedTag = cmsReadTag(p, sig); - if (pCookedTag != NULL) { - status = cmsWriteTag(pfTarget, sig, pCookedTag); + if (!isTagReady) { + cmsCloseProfile(p); + return NULL; } - pCookedTag = NULL; - cmsCloseProfile(p); } - return status; + + // now we have all tags moved to the new profile. + // do some sanity checks: write it to a memory buffer and read again. + if (cmsSaveProfileToMem(p, NULL, &pfSize)) { + void* buf = malloc(pfSize); + if (buf != NULL) { + // load raw profile data into the buffer + if (cmsSaveProfileToMem(p, buf, &pfSize)) { + pfSanity = cmsOpenProfileFromMem(buf, pfSize); + } + free(buf); + } + } + + if (pfSanity == NULL) { + // for some reason, we failed to save and read the updated profile + // It likely indicates that the profile is not correct, so we report + // a failure here. + cmsCloseProfile(p); + p = NULL; + } else { + // do final check whether we can read and handle the the target tag. + const void* pTag = cmsReadTag(pfSanity, sig); + if (pTag == NULL) { + // the tag can not be cooked + cmsCloseProfile(p); + p = NULL; + } + cmsCloseProfile(pfSanity); + pfSanity = NULL; + } + + return p; } diff --git a/jdk/test/sun/java2d/cmm/ProfileOp/ReadWriteProfileTest.java b/jdk/test/sun/java2d/cmm/ProfileOp/ReadWriteProfileTest.java index bc14128fcee..f3fa0791d46 100644 --- a/jdk/test/sun/java2d/cmm/ProfileOp/ReadWriteProfileTest.java +++ b/jdk/test/sun/java2d/cmm/ProfileOp/ReadWriteProfileTest.java @@ -23,7 +23,7 @@ /** * @test - * @bug 6476665 6523403 6733501 7042594 + * @bug 6476665 6523403 6733501 7042594 7043064 * @summary Verifies reading and writing profiles and tags of the standard color * spaces * @run main ReadWriteProfileTest @@ -82,6 +82,7 @@ public class ReadWriteProfileTest implements Runnable { public void run() { for (int i = 0; i < cspaces.length; i++) { + System.out.println("Profile: " + csNames[i]); ICC_Profile pf = ICC_Profile.getInstance(cspaces[i]); byte [] data = pf.getData(); pf = ICC_Profile.getInstance(data); @@ -92,6 +93,10 @@ public class ReadWriteProfileTest implements Runnable { } for (int tagSig : tags[i].keySet()) { + String signature = SigToString(tagSig); + System.out.printf("Tag: %s\n", signature); + System.out.flush(); + byte [] tagData = pf.getData(tagSig); byte [] empty = new byte[tagData.length]; boolean emptyDataRejected = false; @@ -104,15 +109,23 @@ public class ReadWriteProfileTest implements Runnable { throw new RuntimeException("Test failed: empty tag data was not rejected."); } - pf.setData(tagSig, tagData); - + try { + pf.setData(tagSig, tagData); + } catch (IllegalArgumentException e) { + // let's ignore this exception for Kodak proprietary tags + if (isKodakExtention(signature)) { + System.out.println("Ignore Kodak tag: " + signature); + } else { + throw new RuntimeException("Test failed!", e); + } + } byte [] tagData1 = pf.getData(tagSig); if (!Arrays.equals(tagData1, tags[i].get(tagSig))) { System.err.println("Incorrect result of getData(int) with" + " tag " + - Integer.toHexString(tagSig) + + SigToString(tagSig) + " of " + csNames[i] + " profile"); throw new RuntimeException("Incorrect result of " + @@ -122,6 +135,19 @@ public class ReadWriteProfileTest implements Runnable { } } + private static boolean isKodakExtention(String signature) { + return signature.matches("K\\d\\d\\d"); + } + + private static String SigToString(int tagSig ) { + return String.format("%c%c%c%c", + (char)(0xff & (tagSig >> 24)), + (char)(0xff & (tagSig >> 16)), + (char)(0xff & (tagSig >> 8)), + (char)(0xff & (tagSig))); + + } + public static void main(String [] args) { ReadWriteProfileTest test = new ReadWriteProfileTest(); test.run(); From 5159f55769cb383f4297b3553acb5d6a6e5a25ff Mon Sep 17 00:00:00 2001 From: Clemens Eisserer Date: Wed, 4 Sep 2013 12:38:00 +0400 Subject: [PATCH 6/9] 7159455: Nimbus scrollbar rendering glitch with xrender enabled on i945GM Reviewed-by: prr, bae --- .../classes/sun/java2d/xr/XRPMBlitLoops.java | 92 +++++++++---------- 1 file changed, 43 insertions(+), 49 deletions(-) diff --git a/jdk/src/solaris/classes/sun/java2d/xr/XRPMBlitLoops.java b/jdk/src/solaris/classes/sun/java2d/xr/XRPMBlitLoops.java index aaa48af2e16..20f84fa8ba3 100644 --- a/jdk/src/solaris/classes/sun/java2d/xr/XRPMBlitLoops.java +++ b/jdk/src/solaris/classes/sun/java2d/xr/XRPMBlitLoops.java @@ -225,6 +225,9 @@ class XRPMScaledBlit extends ScaledBlit { * @author Clemens Eisserer */ class XRPMTransformedBlit extends TransformBlit { + final Rectangle compositeBounds = new Rectangle(); + final double[] srcCoords = new double[8]; + final double[] dstCoords = new double[8]; public XRPMTransformedBlit(SurfaceType srcType, SurfaceType dstType) { super(srcType, CompositeType.AnyAlpha, dstType); @@ -235,61 +238,68 @@ class XRPMTransformedBlit extends TransformBlit { * method is functionally equal to: Shape shp = * xform.createTransformedShape(rect); Rectangle bounds = shp.getBounds(); * but performs significantly better. + * Returns true if the destination shape is parallel to x/y axis */ - public Rectangle getCompositeBounds(AffineTransform tr, int dstx, int dsty, int width, int height) { - double[] compBounds = new double[8]; - compBounds[0] = dstx; - compBounds[1] = dsty; - compBounds[2] = dstx + width; - compBounds[3] = dsty; - compBounds[4] = dstx + width; - compBounds[5] = dsty + height; - compBounds[6] = dstx; - compBounds[7] = dsty + height; + protected boolean adjustCompositeBounds(AffineTransform tr, int dstx, int dsty, int width, int height) { + srcCoords[0] = dstx; + srcCoords[1] = dsty; + srcCoords[2] = dstx + width; + srcCoords[3] = dsty; + srcCoords[4] = dstx + width; + srcCoords[5] = dsty + height; + srcCoords[6] = dstx; + srcCoords[7] = dsty + height; - tr.transform(compBounds, 0, compBounds, 0, 4); + tr.transform(srcCoords, 0, dstCoords, 0, 4); - double minX = Math.min(compBounds[0], Math.min(compBounds[2], Math.min(compBounds[4], compBounds[6]))); - double minY = Math.min(compBounds[1], Math.min(compBounds[3], Math.min(compBounds[5], compBounds[7]))); - double maxX = Math.max(compBounds[0], Math.max(compBounds[2], Math.max(compBounds[4], compBounds[6]))); - double maxY = Math.max(compBounds[1], Math.max(compBounds[3], Math.max(compBounds[5], compBounds[7]))); + double minX = Math.min(dstCoords[0], Math.min(dstCoords[2], Math.min(dstCoords[4], dstCoords[6]))); + double minY = Math.min(dstCoords[1], Math.min(dstCoords[3], Math.min(dstCoords[5], dstCoords[7]))); + double maxX = Math.max(dstCoords[0], Math.max(dstCoords[2], Math.max(dstCoords[4], dstCoords[6]))); + double maxY = Math.max(dstCoords[1], Math.max(dstCoords[3], Math.max(dstCoords[5], dstCoords[7]))); - minX = Math.floor(minX); - minY = Math.floor(minY); - maxX = Math.ceil(maxX); - maxY = Math.ceil(maxY); + minX = Math.round(minX); + minY = Math.round(minY); + maxX = Math.round(maxX); + maxY = Math.round(maxY); - return new Rectangle((int) minX, (int) minY, (int) (maxX - minX), (int) (maxY - minY)); + compositeBounds.x = (int) minX; + compositeBounds.y = (int) minY; + compositeBounds.width = (int) (maxX - minX); + compositeBounds.height = (int) (maxY - minY); + + boolean is0or180 = (dstCoords[1] == dstCoords[3]) && (dstCoords[2] == dstCoords[4]); + boolean is90or270 = (dstCoords[0] == dstCoords[2]) && (dstCoords[3] == dstCoords[5]); + + return is0or180 || is90or270; } - public void Transform(SurfaceData src, SurfaceData dst, Composite comp, Region clip, AffineTransform xform, int hint, int srcx, int srcy, - int dstx, int dsty, int width, int height) { + public void Transform(SurfaceData src, SurfaceData dst, Composite comp, Region clip, AffineTransform xform, + int hint, int srcx, int srcy, int dstx, int dsty, int width, int height) { try { SunToolkit.awtLock(); - int filter = XRUtils.ATransOpToXRQuality(hint); - XRSurfaceData x11sdDst = (XRSurfaceData) dst; - x11sdDst.validateAsDestination(null, clip); XRSurfaceData x11sdSrc = (XRSurfaceData) src; + + int filter = XRUtils.ATransOpToXRQuality(hint); + boolean isAxisAligned = adjustCompositeBounds(xform, dstx, dsty, width, height); + + x11sdDst.validateAsDestination(null, clip); x11sdDst.maskBuffer.validateCompositeState(comp, null, null, null); - Rectangle bounds = getCompositeBounds(xform, dstx, dsty, width, height); - - AffineTransform trx = AffineTransform.getTranslateInstance((-bounds.x), (-bounds.y)); + AffineTransform trx = AffineTransform.getTranslateInstance(-compositeBounds.x, -compositeBounds.y); trx.concatenate(xform); AffineTransform maskTX = (AffineTransform) trx.clone(); - trx.translate(-srcx, -srcy); try { trx.invert(); } catch (NoninvertibleTransformException ex) { trx.setToIdentity(); - System.err.println("Reseted to identity!"); } - boolean omitMask = isMaskOmittable(trx, comp, filter); + boolean omitMask = (filter == XRUtils.FAST) + || (isAxisAligned && ((AlphaComposite) comp).getAlpha() == 1.0f); if (!omitMask) { XRMaskImage mask = x11sdSrc.maskBuffer.getMaskImage(); @@ -297,33 +307,17 @@ class XRPMTransformedBlit extends TransformBlit { x11sdSrc.validateAsSource(trx, XRUtils.RepeatPad, filter); int maskPicture = mask.prepareBlitMask(x11sdDst, maskTX, width, height); x11sdDst.maskBuffer.con.renderComposite(XRCompositeManager.getInstance(x11sdSrc).getCompRule(), x11sdSrc.picture, maskPicture, x11sdDst.picture, - 0, 0, 0, 0, bounds.x, bounds.y, bounds.width, bounds.height); + 0, 0, 0, 0, compositeBounds.x, compositeBounds.y, compositeBounds.width, compositeBounds.height); } else { int repeat = filter == XRUtils.FAST ? XRUtils.RepeatNone : XRUtils.RepeatPad; x11sdSrc.validateAsSource(trx, repeat, filter); - x11sdDst.maskBuffer.compositeBlit(x11sdSrc, x11sdDst, 0, 0, bounds.x, bounds.y, bounds.width, bounds.height); + x11sdDst.maskBuffer.compositeBlit(x11sdSrc, x11sdDst, 0, 0, compositeBounds.x, compositeBounds.y, compositeBounds.width, compositeBounds.height); } } finally { SunToolkit.awtUnlock(); } } - - /* TODO: Is mask ever omitable??? ... should be for 90 degree rotation and no shear, but we always need to use RepeatPad */ - protected static boolean isMaskOmittable(AffineTransform trx, Composite comp, int filter) { - return (filter == XRUtils.FAST || trx.getTranslateX() == (int) trx.getTranslateX() /* - * If - * translate - * is - * integer - * only - */ - && trx.getTranslateY() == (int) trx.getTranslateY() && (trx.getShearX() == 0 && trx.getShearY() == 0 // Only - // 90 degree - // rotation - || trx.getShearX() == -trx.getShearY())) && ((AlphaComposite) comp).getAlpha() == 1.0f; // No - // ExtraAlpha!=1 - } } class XrSwToPMBlit extends Blit { From d8b770b0cd7a1a52d39fd0f4407bd14e9232358a Mon Sep 17 00:00:00 2001 From: Clemens Eisserer Date: Thu, 5 Sep 2013 11:50:42 +0400 Subject: [PATCH 7/9] 8024261: xrender: improve performance of small fillRect operations Reviewed-by: prr, bae --- .../solaris/classes/sun/java2d/xr/XRCompositeManager.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/jdk/src/solaris/classes/sun/java2d/xr/XRCompositeManager.java b/jdk/src/solaris/classes/sun/java2d/xr/XRCompositeManager.java index b1c2ef08065..39b8642bb9d 100644 --- a/jdk/src/solaris/classes/sun/java2d/xr/XRCompositeManager.java +++ b/jdk/src/solaris/classes/sun/java2d/xr/XRCompositeManager.java @@ -285,7 +285,12 @@ public class XRCompositeManager { if (xorEnabled) { con.GCRectangles(dst.getXid(), dst.getGC(), rects); } else { - con.renderRectangles(dst.getPicture(), compRule, solidColor, rects); + if (rects.getSize() == 1) { + con.renderRectangle(dst.getPicture(), compRule, solidColor, + rects.getX(0), rects.getY(0), rects.getWidth(0), rects.getHeight(0)); + } else { + con.renderRectangles(dst.getPicture(), compRule, solidColor, rects); + } } } From 47f48cad92630ada6ccd34d7d7aa2b6191cb1bf9 Mon Sep 17 00:00:00 2001 From: Andrew Brygin Date: Tue, 10 Sep 2013 21:54:14 +0400 Subject: [PATCH 8/9] 8024511: Crash during color profile destruction Reviewed-by: vadim, prr --- .../share/native/sun/java2d/cmm/lcms/LCMS.c | 2 +- .../cmm/ProfileOp/DisposalCrashTest.java | 83 +++++++++++++++++++ 2 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 jdk/test/sun/java2d/cmm/ProfileOp/DisposalCrashTest.java diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c b/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c index 13030cc41d5..b2c4fce4229 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c @@ -307,7 +307,7 @@ JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_loadProfileNative if (sProf.lcmsPf != NULL) { // register the disposer record sProf.lcmsPf->pf = pf; - Disposer_AddRecord(env, disposerRef, LCMS_freeTransform, sProf.j); + Disposer_AddRecord(env, disposerRef, LCMS_freeProfile, sProf.j); } else { cmsCloseProfile(pf); } diff --git a/jdk/test/sun/java2d/cmm/ProfileOp/DisposalCrashTest.java b/jdk/test/sun/java2d/cmm/ProfileOp/DisposalCrashTest.java new file mode 100644 index 00000000000..ab8527d76da --- /dev/null +++ b/jdk/test/sun/java2d/cmm/ProfileOp/DisposalCrashTest.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2013, 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 8024511 + * @summary Verifies that instances of color profiles are destroyed correctly. + * A crash during profile destruction indicates failure. + * + * @run main DisposalCrashTest + */ + +import static java.awt.color.ColorSpace.*; +import java.awt.color.ICC_Profile; +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; +import java.util.Vector; + +public class DisposalCrashTest { + + static final ReferenceQueue queue = new ReferenceQueue<>(); + static final Vector> v = new Vector<>(); + + public static void main(String[] args) { + int[] ids = new int[]{ + CS_sRGB, CS_CIEXYZ, CS_GRAY, CS_LINEAR_RGB, CS_PYCC + }; + + for (int id : ids) { + ICC_Profile p = getCopyOf(id); + } + + while (!v.isEmpty()) { + System.gc(); + System.out.println("."); + try { + Thread.sleep(500); + } catch (InterruptedException e) {}; + + final Reference ref = queue.poll(); + System.out.println("Got reference: " + ref); + + v.remove(ref); + } + + System.out.println("Test PASSED."); + } + + private static ICC_Profile getCopyOf(int id) { + ICC_Profile std = ICC_Profile.getInstance(id); + + byte[] data = std.getData(); + + ICC_Profile p = ICC_Profile.getInstance(data); + + WeakReference ref = new WeakReference<>(p, queue); + + v.add(ref); + + return p; + } +} From e3016af23b88aa40523ced16d5af94a0c5c8627b Mon Sep 17 00:00:00 2001 From: Andrew Brygin Date: Fri, 13 Sep 2013 20:28:17 +0400 Subject: [PATCH 9/9] 8024697: Fix for 8020983 causes Xcheck:jni warnings Reviewed-by: prr, jchen --- .../native/sun/awt/image/jpeg/imageioJPEG.c | 18 +++++++++++------- .../plugins/jpeg/JpegWriterLeakTest.java | 2 +- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c b/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c index e0716b1835b..fce061d0fb8 100644 --- a/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c +++ b/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c @@ -930,9 +930,10 @@ imageio_fill_input_buffer(j_decompress_ptr cinfo) * Now fill a complete buffer, or as much of one as the stream * will give us if we are near the end. */ + RELEASE_ARRAYS(env, data, src->next_input_byte); + GET_IO_REF(input); - RELEASE_ARRAYS(env, data, src->next_input_byte); ret = (*env)->CallIntMethod(env, input, JPEGImageReader_readInputDataID, @@ -1017,9 +1018,11 @@ imageio_fill_suspended_buffer(j_decompress_ptr cinfo) memcpy(sb->buf, src->next_input_byte, offset); } - GET_IO_REF(input); RELEASE_ARRAYS(env, data, src->next_input_byte); + + GET_IO_REF(input); + buflen = sb->bufferLength - offset; if (buflen <= 0) { if (!GET_ARRAYS(env, data, &(src->next_input_byte))) { @@ -1121,9 +1124,10 @@ imageio_skip_input_data(j_decompress_ptr cinfo, long num_bytes) return; } + RELEASE_ARRAYS(env, data, src->next_input_byte); + GET_IO_REF(input); - RELEASE_ARRAYS(env, data, src->next_input_byte); ret = (*env)->CallLongMethod(env, input, JPEGImageReader_skipInputBytesID, @@ -2306,10 +2310,10 @@ imageio_empty_output_buffer (j_compress_ptr cinfo) JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); jobject output = NULL; - GET_IO_REF(output); - RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte)); + GET_IO_REF(output); + (*env)->CallVoidMethod(env, output, JPEGImageWriter_writeOutputDataID, @@ -2348,10 +2352,10 @@ imageio_term_destination (j_compress_ptr cinfo) if (datacount != 0) { jobject output = NULL; - GET_IO_REF(output); - RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte)); + GET_IO_REF(output); + (*env)->CallVoidMethod(env, output, JPEGImageWriter_writeOutputDataID, diff --git a/jdk/test/javax/imageio/plugins/jpeg/JpegWriterLeakTest.java b/jdk/test/javax/imageio/plugins/jpeg/JpegWriterLeakTest.java index ffb2b63b0b0..bb5fc06e99b 100644 --- a/jdk/test/javax/imageio/plugins/jpeg/JpegWriterLeakTest.java +++ b/jdk/test/javax/imageio/plugins/jpeg/JpegWriterLeakTest.java @@ -23,7 +23,7 @@ /** * @test - * @bug 8020983 + * @bug 8020983 8024697 * @summary Test verifies that jpeg writer instances are collected * even if destroy() or reset() methods is not invoked. *