Merge
diff --git a/make/CompileDemos.gmk b/make/CompileDemos.gmk
index 3b18391..36829b3 100644
--- a/make/CompileDemos.gmk
+++ b/make/CompileDemos.gmk
@@ -456,7 +456,7 @@
##################################################################################################
ifndef OPENJDK
- DB_DEMO_ZIPFILE := $(wildcard $(JDK_TOPDIR)/src/closed/share/db/*.zip)
+ DB_DEMO_ZIPFILE := $(wildcard $(JDK_TOPDIR)/src/closed/share/db/db-derby-*-bin.zip)
$(JDK_OUTPUTDIR)/demo/_the.db.unzipped: $(DB_DEMO_ZIPFILE)
$(MKDIR) -p $(@D)
diff --git a/make/Images.gmk b/make/Images.gmk
index 884dc4f..51d0c14 100644
--- a/make/Images.gmk
+++ b/make/Images.gmk
@@ -562,7 +562,7 @@
$(CAT) $< | $(SED) "s/XXXX/$(shell cat $(JDK_TOPDIR)/src/closed/share/db/COPYRIGHTYEAR)/" > $@
JDK_DB_TARGETS := $(patsubst $(JDK_TOPDIR)/src/closed/share/db/%, $(IMAGES_OUTPUTDIR)/_unzip/%.unzipped, \
- $(wildcard $(JDK_TOPDIR)/src/closed/share/db/*.zip)) \
+ $(wildcard $(JDK_TOPDIR)/src/closed/share/db/db-derby-*-bin.zip)) \
$(JDK_IMAGE_DIR)/db/README-JDK.html $(JDK_IMAGE_DIR)/db/3RDPARTY
endif
diff --git a/src/aix/classes/sun/awt/fontconfigs/aix.fontconfig.properties b/src/aix/classes/sun/awt/fontconfigs/aix.fontconfig.properties
index 29e7c7d..f203f75 100644
--- a/src/aix/classes/sun/awt/fontconfigs/aix.fontconfig.properties
+++ b/src/aix/classes/sun/awt/fontconfigs/aix.fontconfig.properties
@@ -24,9 +24,14 @@
# questions.
#
-# Minimal version for AIX using the standard Latin Type1 Fonts from the
-# package X11.fnt.iso_T1. These fonts are installed by default into
-# "/usr/lpp/X11/lib/X11/fonts/Type1" and sym-linked to "/usr/lib/X11/fonts/Type1"
+#
+# Portions Copyright (c) 2014 IBM Corporation
+#
+
+# This file references the standard Latin Type1 fonts from the AIX package
+# X11.fnt.iso_T1 and the Unicode TrueType fonts from X11.fnt.ucs.ttf. They
+# are located by default under "/usr/lpp/X11/lib/X11/fonts/{Type1,TrueType}"
+# and sym-linked to "/usr/lib/X11/fonts/".
# Version
@@ -34,44 +39,381 @@
# Component Font Mappings
-dialog.plain.latin-1=-*-helvetica-medium-r-normal--*-%d-100-100-p-*-iso10646-1
-dialog.bold.latin-1=-*-helvetica-bold-r-normal--*-%d-100-100-p-*-iso10646-1
-dialog.italic.latin-1=-*-helvetica-medium-o-normal--*-%d-100-100-p-*-iso10646-1
-dialog.bolditalic.latin-1=-*-helvetica-bold-o-normal--*-%d-100-100-p-*-iso10646-1
+allfonts.iso10646-extB=-monotype-sansmonowtextb-medium-r-normal--*-%d-75-75-m-*-unicode-2
-dialoginput.plain.latin-1=-*-courier-medium-r-normal--*-%d-100-100-m-*-iso10646-1
-dialoginput.bold.latin-1=-*-courier-bold-r-normal--*-%d-100-100-m-*-iso10646-1
-dialoginput.italic.latin-1=-*-courier-medium-o-normal--*-%d-100-100-m-*-iso10646-1
-dialoginput.bolditalic.latin-1=-*-courier-bold-o-normal--*-%d-100-100-m-*-iso10646-1
-sansserif.plain.latin-1=-*-helvetica-medium-r-normal--*-%d-100-100-p-*-iso10646-1
-sansserif.bold.latin-1=-*-helvetica-bold-r-normal--*-%d-100-100-p-*-iso10646-1
-sansserif.italic.latin-1=-*-helvetica-medium-o-normal--*-%d-100-100-p-*-iso10646-1
-sansserif.bolditalic.latin-1=-*-helvetica-bold-o-normal--*-%d-100-100-p-*-iso10646-1
+dialog.plain.latin-1=-*-helvetica-medium-r-normal--*-%d-100-100-p-*-iso8859-1
+dialog.plain.thai=-ibm-thaihelvetica-medium-r-normal--*-%d-75-75-p-*-ucs2.thai-0
+dialog.plain.ukranian-ibm1124=-*-*-medium-r-normal--*-%d-75-75-p-*-ucs2.i18n-0
+dialog.plain.japanese-x0208=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0
+dialog.plain.japanese-x0201=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0
+dialog.plain.japanese-udc=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp
+dialog.plain.japanese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0
+dialog.plain.korean=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0
+dialog.plain.korean-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0
+dialog.plain.chinese=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0
+dialog.plain.chinese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0
+dialog.plain.taiwanese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0
-serif.plain.latin-1=-*-times new roman-medium-r-normal--*-%d-100-100-p-*-iso10646-1
-serif.bold.latin-1=-*-times new roman-bold-r-normal--*-%d-100-100-p-*-iso10646-1
-serif.italic.latin-1=-*-times new roman-medium-i-normal--*-%d-100-100-p-*-iso10646-1
-serif.bolditalic.latin-1=-*-times new roman-bold-i-normal--*-%d-100-100-p-*-iso10646-1
+dialog.bold.latin-1=-*-helvetica-bold-r-normal--*-%d-100-100-p-*-iso8859-1
+dialog.bold.thai=-ibm-thaihelvetica-medium-r-normal--*-%d-75-75-p-*-ucs2.thai-0
+dialog.bold.ukranian-ibm1124=-*-*-bold-r-normal--*-%d-75-75-p-*-ucs2.i18n-0
+dialog.bold.japanese-x0208=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0
+dialog.bold.japanese-x0201=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0
+dialog.bold.japanese-udc=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp
+dialog.bold.japanese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0
+dialog.bold.korean=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0
+dialog.bold.korean-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0
+dialog.bold.chinese=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0
+dialog.bold.chinese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0
+dialog.bold.taiwanese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0
-monospaced.plain.latin-1=-*-courier-medium-r-normal--*-%d-100-100-m-*-iso10646-1
-monospaced.bold.latin-1=-*-courier-bold-r-normal--*-%d-100-100-m-*-iso10646-1
-monospaced.italic.latin-1=-*-courier-medium-o-normal--*-%d-100-100-m-*-iso10646-1
-monospaced.bolditalic.latin-1=-*-courier-bold-o-normal--*-%d-100-100-m-*-iso10646-1
+dialog.italic.latin-1=-*-helvetica-medium-o-normal--*-%d-100-100-p-*-iso8859-1
+dialog.italic.thai=-ibm-thaihelvetica-medium-r-normal--*-%d-75-75-p-*-ucs2.thai-0
+dialog.italic.ukranian-ibm1124=-*-*-medium-i-normal--*-%d-75-75-p-*-ucs2.i18n-0
+dialog.italic.japanese-x0208=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0
+dialog.italic.japanese-x0201=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0
+dialog.italic.japanese-udc=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp
+dialog.italic.japanese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0
+dialog.italic.korean=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0
+dialog.italic.korean-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0
+dialog.italic.chinese=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0
+dialog.italic.chinese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0
+dialog.italic.taiwanese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0
+
+dialog.bolditalic.latin-1=-*-helvetica-bold-o-normal--*-%d-100-100-p-*-iso8859-1
+dialog.bolditalic.thai=-ibm-thaihelvetica-medium-r-normal--*-%d-75-75-p-*-ucs2.thai-0
+dialog.bolditalic.ukranian-ibm1124=-*-*-medium-r-normal--*-%d-75-75-p-*-ucs2.i18n-0
+dialog.bolditalic.japanese-x0208=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0
+dialog.bolditalic.japanese-x0201=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0
+dialog.bolditalic.japanese-udc=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp
+dialog.bolditalic.japanese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0
+dialog.bolditalic.korean=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0
+dialog.bolditalic.korean-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0
+dialog.bolditalic.chinese=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0
+dialog.bolditalic.chinese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0
+dialog.bolditalic.taiwanese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0
+
+dialoginput.plain.latin-1=-*-courier-medium-r-normal--*-%d-100-100-m-*-iso8859-1
+dialoginput.plain.thai=-ibm-thaicourier-medium-r-normal--*-%d-75-75-m-*-ucs2.thai-0
+dialoginput.plain.ukranian-ibm1124=-*-*-medium-r-normal--*-%d-75-75-m-*-ucs2.i18n-0
+dialoginput.plain.japanese-x0208=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0
+dialoginput.plain.japanese-x0201=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0
+dialoginput.plain.japanese-udc=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp
+dialoginput.plain.japanese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0
+dialoginput.plain.korean=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0
+dialoginput.plain.korean-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0
+dialoginput.plain.chinese=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0
+dialoginput.plain.chinese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0
+dialoginput.plain.taiwanese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0
+
+dialoginput.bold.latin-1=-*-courier-bold-r-normal--*-%d-100-100-m-*-iso8859-1
+dialoginput.bold.thai=-ibm-thaicourier-medium-r-normal--*-%d-75-75-m-*-ucs2.thai-0
+dialoginput.bold.ukranian-ibm1124=-*-*-bold-r-normal--*-%d-75-75-m-*-ucs2.i18n-0
+dialoginput.bold.japanese-x0208=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0
+dialoginput.bold.japanese-x0201=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0
+dialoginput.bold.japanese-udc=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp
+dialoginput.bold.japanese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0
+dialoginput.bold.korean=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0
+dialoginput.bold.korean-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0
+dialoginput.bold.chinese=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0
+dialoginput.bold.chinese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0
+dialoginput.bold.taiwanese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0
+
+dialoginput.italic.latin-1=-*-courier-medium-o-normal--*-%d-100-100-m-*-iso8859-1
+dialoginput.italic.thai=-ibm-thaicourier-medium-r-normal--*-%d-75-75-m-*-ucs2.thai-0
+dialoginput.italic.ukranian-ibm1124=-*-*-medium-i-normal--*-%d-75-75-m-*-ucs2.i18n-0
+dialoginput.italic.japanese-x0208=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0
+dialoginput.italic.japanese-x0201=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0
+dialoginput.italic.japanese-udc=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp
+dialoginput.italic.japanese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0
+dialoginput.italic.korean=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0
+dialoginput.italic.korean-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0
+dialoginput.italic.chinese=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0
+dialoginput.italic.chinese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0
+dialoginput.italic.taiwanese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0
+
+dialoginput.bolditalic.latin-1=-*-courier-bold-o-normal--*-%d-100-100-m-*-iso8859-1
+dialoginput.bolditalic.thai=-ibm-thaicourier-medium-r-normal--*-%d-75-75-m-*-ucs2.thai-0
+dialoginput.bolditalic.ukranian-ibm1124=-*-*-medium-r-normal--*-%d-75-75-m-*-ucs2.i18n-0
+dialoginput.bolditalic.japanese-x0208=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0
+dialoginput.bolditalic.japanese-x0201=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0
+dialoginput.bolditalic.japanese-udc=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp
+dialoginput.bolditalic.japanese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0
+dialoginput.bolditalic.korean=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0
+dialoginput.bolditalic.korean-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0
+dialoginput.bolditalic.chinese=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0
+dialoginput.bolditalic.chinese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0
+dialoginput.bolditalic.taiwanese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0
+
+sansserif.plain.latin-1=-*-helvetica-medium-r-normal--*-%d-100-100-p-*-iso8859-1
+sansserif.plain.thai=-ibm-thaihelvetica-medium-r-normal--*-%d-75-75-p-*-ucs2.thai-0
+sansserif.plain.ukranian-ibm1124=-*-*-medium-r-normal--*-%d-75-75-p-*-ucs2.i18n-0
+sansserif.plain.japanese-x0208=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0
+sansserif.plain.japanese-x0201=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0
+sansserif.plain.japanese-udc=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp
+sansserif.plain.japanese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0
+sansserif.plain.korean=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0
+sansserif.plain.korean-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0
+sansserif.plain.chinese=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0
+sansserif.plain.chinese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0
+sansserif.plain.taiwanese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0
+
+sansserif.bold.latin-1=-*-helvetica-bold-r-normal--*-%d-100-100-p-*-iso8859-1
+sansserif.bold.thai=-ibm-thaihelvetica-medium-r-normal--*-%d-75-75-p-*-ucs2.thai-0
+sansserif.bold.ukranian-ibm1124=-*-*-bold-r-normal--*-%d-75-75-p-*-ucs2.i18n-0
+sansserif.bold.japanese-x0208=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0
+sansserif.bold.japanese-x0201=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0
+sansserif.bold.japanese-udc=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp
+sansserif.bold.japanese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0
+sansserif.bold.korean=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0
+sansserif.bold.korean-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0
+sansserif.bold.chinese=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0
+sansserif.bold.chinese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0
+sansserif.bold.taiwanese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0
+
+sansserif.italic.latin-1=-*-helvetica-medium-o-normal--*-%d-100-100-p-*-iso8859-1
+sansserif.italic.thai=-ibm-thaihelvetica-medium-r-normal--*-%d-75-75-p-*-ucs2.thai-0
+sansserif.italic.ukranian-ibm1124=-*-*-medium-i-normal--*-%d-75-75-p-*-ucs2.i18n-0
+sansserif.italic.japanese-x0208=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0
+sansserif.italic.japanese-x0201=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0
+sansserif.italic.japanese-udc=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp
+sansserif.italic.japanese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0
+sansserif.italic.korean=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0
+sansserif.italic.korean-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0
+sansserif.italic.chinese=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0
+sansserif.italic.chinese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0
+sansserif.italic.taiwanese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0
+
+sansserif.bolditalic.latin-1=-*-helvetica-bold-o-normal--*-%d-100-100-p-*-iso8859-1
+sansserif.bolditalic.thai=-ibm-thaihelvetica-medium-r-normal--*-%d-75-75-p-*-ucs2.thai-0
+sansserif.bolditalic.ukranian-ibm1124=-*-*-medium-r-normal--*-%d-75-75-p-*-ucs2.i18n-0
+sansserif.bolditalic.japanese-x0208=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0
+sansserif.bolditalic.japanese-x0201=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0
+sansserif.bolditalic.japanese-udc=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp
+sansserif.bolditalic.japanese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0
+sansserif.bolditalic.korean=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0
+sansserif.bolditalic.korean-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0
+sansserif.bolditalic.chinese=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0
+sansserif.bolditalic.chinese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0
+sansserif.bolditalic.taiwanese-iso10646=-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0
+
+serif.plain.latin-1=-*-times new roman-medium-r-normal--*-%d-100-100-p-*-iso8859-1
+serif.plain.thai=-ibm-thaitimes-medium-r-normal--*-%d-75-75-p-*-ucs2.thai-0
+serif.plain.ukranian-ibm1124=-*-*-medium-r-normal--*-%d-75-75-p-*-ucs2.i18n-0
+serif.plain.japanese-x0208=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0
+serif.plain.japanese-x0201=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0
+serif.plain.japanese-udc=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp
+serif.plain.japanese-iso10646=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0
+serif.plain.korean=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0
+serif.plain.korean-iso10646=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0
+serif.plain.chinese=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0
+serif.plain.chinese-iso10646=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0
+serif.plain.taiwanese-iso10646=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0
+
+serif.bold.latin-1=-*-times new roman-bold-r-normal--*-%d-100-100-p-*-iso8859-1
+serif.bold.thai=-ibm-thaitimes-medium-r-normal--*-%d-75-75-p-*-ucs2.thai-0
+serif.bold.ukranian-ibm1124=-*-*-bold-r-normal--*-%d-75-75-p-*-ucs2.i18n-0
+serif.bold.japanese-x0208=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0
+serif.bold.japanese-x0201=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0
+serif.bold.japanese-udc=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp
+serif.bold.japanese-iso10646=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0
+serif.bold.korean=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0
+serif.bold.korean-iso10646=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0
+serif.bold.chinese=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0
+serif.bold.chinese-iso10646=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0
+serif.bold.taiwanese-iso10646=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0
+
+
+serif.italic.latin-1=-*-times new roman-medium-i-normal--*-%d-100-100-p-*-iso8859-1
+serif.italic.thai=-ibm-thaitimes-medium-r-normal--*-%d-75-75-p-*-ucs2.thai-0
+serif.italic.ukranian-ibm1124=-*-*-medium-i-normal--*-%d-75-75-p-*-ucs2.i18n-0
+serif.italic.japanese-x0208=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0
+serif.italic.japanese-x0201=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0
+serif.italic.japanese-udc=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp
+serif.italic.japanese-iso10646=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0
+serif.italic.korean=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0
+serif.italic.korean-iso10646=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0
+serif.italic.chinese=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0
+serif.italic.chinese-iso10646=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0
+serif.italic.taiwanese-iso10646=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0
+
+serif.bolditalic.latin-1=-*-times new roman-bold-i-normal--*-%d-100-100-p-*-iso8859-1
+serif.bolditalic.thai=-ibm-thaitimes-medium-r-normal--*-%d-75-75-p-*-ucs2.thai-0
+serif.bolditalic.ukranian-ibm1124=-*-*-medium-r-normal--*-%d-75-75-p-*-ucs2.i18n-0
+serif.bolditalic.japanese-x0208=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0
+serif.bolditalic.japanese-x0201=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0
+serif.bolditalic.japanese-udc=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp
+serif.bolditalic.japanese-iso10646=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0
+serif.bolditalic.korean=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0
+serif.bolditalic.korean-iso10646=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0
+serif.bolditalic.chinese=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0
+serif.bolditalic.chinese-iso10646=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0
+serif.bolditalic.taiwanese-iso10646=-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0
+
+monospaced.plain.latin-1=-*-courier-medium-r-normal--*-%d-100-100-m-*-iso8859-1
+monospaced.plain.thai=-ibm-thaicourier-medium-r-normal--*-%d-75-75-m-*-ucs2.thai-0
+monospaced.plain.ukranian-ibm1124=-*-*-medium-r-normal--*-%d-75-75-m-*-ucs2.i18n-0
+monospaced.plain.japanese-x0208=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0
+monospaced.plain.japanese-x0201=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0
+monospaced.plain.japanese-udc=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp
+monospaced.plain.japanese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0
+monospaced.plain.korean=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0
+monospaced.plain.korean-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0
+monospaced.plain.chinese=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0
+monospaced.plain.chinese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0
+monospaced.plain.taiwanese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0
+
+monospaced.bold.latin-1=-*-courier-bold-r-normal--*-%d-100-100-m-*-iso8859-1
+monospaced.bold.thai=-ibm-thaicourier-medium-r-normal--*-%d-75-75-m-*-ucs2.thai-0
+monospaced.bold.ukranian-ibm1124=-*-*-bold-r-normal--*-%d-75-75-m-*-ucs2.i18n-0
+monospaced.bold.japanese-x0208=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0
+monospaced.bold.japanese-x0201=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0
+monospaced.bold.japanese-udc=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp
+monospaced.bold.japanese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0
+monospaced.bold.korean=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0
+monospaced.bold.korean-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0
+monospaced.bold.chinese=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0
+monospaced.bold.chinese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0
+monospaced.bold.taiwanese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0
+
+monospaced.italic.latin-1=-*-courier-medium-o-normal--*-%d-100-100-m-*-iso8859-1
+monospaced.italic.thai=-ibm-thaicourier-medium-r-normal--*-%d-75-75-m-*-ucs2.thai-0
+monospaced.italic.ukranian-ibm1124=-*-*-medium-i-normal--*-%d-75-75-m-*-ucs2.i18n-0
+monospaced.italic.japanese-x0208=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0
+monospaced.italic.japanese-x0201=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0
+monospaced.italic.japanese-udc=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp
+monospaced.italic.japanese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0
+monospaced.italic.korean=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0
+monospaced.italic.korean-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0
+monospaced.italic.chinese=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0
+monospaced.italic.chinese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0
+monospaced.italic.taiwanese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0
+
+monospaced.bolditalic.latin-1=-*-courier-bold-o-normal--*-%d-100-100-m-*-iso8859-1
+monospaced.bolditalic.thai=-ibm-thaicourier-medium-r-normal--*-%d-75-75-m-*-ucs2.thai-0
+monospaced.bolditalic.ukranian-ibm1124=-*-*-medium-r-normal--*-%d-75-75-m-*-ucs2.i18n-0
+monospaced.bolditalic.japanese-x0208=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0
+monospaced.bolditalic.japanese-x0201=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0
+monospaced.bolditalic.japanese-udc=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp
+monospaced.bolditalic.japanese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0
+monospaced.bolditalic.korean=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0
+monospaced.bolditalic.korean-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0
+monospaced.bolditalic.chinese=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0
+monospaced.bolditalic.chinese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0
+monospaced.bolditalic.taiwanese-iso10646=-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0
# Search Sequences
sequence.allfonts=latin-1
+sequence.allfonts.UTF-8=latin-1,japanese-iso10646
+# Uk_UA
+sequence.allfonts.x-IBM1124=latin-1,ukranian-ibm1124
+# Japanese
+sequence.allfonts.x-IBM943C=latin-1,japanese-x0201,japanese-x0208,japanese-udc
+sequence.allfonts.x-IBM29626C=latin-1,japanese-x0201,japanese-x0208,japanese-udc
+sequence.allfonts.UTF-8.ja=japanese-iso10646,latin-1,iso10646-extB
+# Chinese
+sequence.allfonts.x-EUC_CN=latin-1,chinese
+sequence.allfonts.GB18030=latin-1,chinese-iso10646,iso10646-extB
+sequence.allfonts.UTF-8.zh.CN=latin-1,chinese-iso10646,iso10646-extB
+# Taiwanese
+sequence.allfonts.x-IBM964=latin-1,taiwanese-iso10646
+sequence.allfonts.Big5=latin-1,taiwanese-iso10646
+sequence.allfonts.UTF-8.zh.TW=latin-1,taiwanese-iso10646
+# Korean
+sequence.allfonts.x-IBM970=latin-1,korean
+sequence.allfonts.UTF-8.ko=latin-1,korean-iso10646
+# Thai
+sequence.allfonts.TIS-620=latin-1,thai
+sequence.allfonts.UTF-8.th=latin-1,thai
+# fallback
+sequence.fallback=thai,chinese-iso10646,taiwanese-iso10646,japanese-iso10646,korean-iso10646,iso10646-extB
-filename.-*-courier-medium-r-normal--*-%d-100-100-m-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/cour.pfa
-filename.-*-courier-bold-r-normal--*-%d-100-100-m-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/courb.pfa
-filename.-*-courier-medium-o-normal--*-%d-100-100-m-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/couri.pfa
-filename.-*-courier-bold-o-normal--*-%d-100-100-m-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/courbi.pfa
-filename.-*-helvetica-medium-r-normal--*-%d-100-100-p-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/helv.pfa
-filename.-*-helvetica-bold-r-normal--*-%d-100-100-p-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/helvb.pfa
-filename.-*-helvetica-medium-o-normal--*-%d-100-100-p-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/helvi.pfa
-filename.-*-helvetica-bold-o-normal--*-%d-100-100-p-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/helvbi.pfa
-filename.-*-times_new_roman-medium-r-normal--*-%d-100-100-p-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/tnr.pfa
-filename.-*-times_new_roman-bold-r-normal--*-%d-100-100-p-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/tnrb.pfa
-filename.-*-times_new_roman-medium-i-normal--*-%d-100-100-p-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/tnri.pfa
-filename.-*-times_new_roman-bold-i-normal--*-%d-100-100-p-*-iso10646-1=/usr/lpp/X11/lib/X11/fonts/Type1/tnrbi.pfa
+# Exclusion Ranges
+exclusion.japanese-iso10646=0000-00ff
+
+# Font File Names
+filename.-*-courier-medium-r-normal--*-%d-100-100-m-*-iso8859-1=/usr/lpp/X11/lib/X11/fonts/Type1/cour.pfa
+filename.-*-courier-bold-r-normal--*-%d-100-100-m-*-iso8859-1=/usr/lpp/X11/lib/X11/fonts/Type1/courb.pfa
+filename.-*-courier-medium-o-normal--*-%d-100-100-m-*-iso8859-1=/usr/lpp/X11/lib/X11/fonts/Type1/couri.pfa
+filename.-*-courier-bold-o-normal--*-%d-100-100-m-*-iso8859-1=/usr/lpp/X11/lib/X11/fonts/Type1/courbi.pfa
+filename.-*-helvetica-medium-r-normal--*-%d-100-100-p-*-iso8859-1=/usr/lpp/X11/lib/X11/fonts/Type1/helv.pfa
+filename.-*-helvetica-bold-r-normal--*-%d-100-100-p-*-iso8859-1=/usr/lpp/X11/lib/X11/fonts/Type1/helvb.pfa
+filename.-*-helvetica-medium-o-normal--*-%d-100-100-p-*-iso8859-1=/usr/lpp/X11/lib/X11/fonts/Type1/helvi.pfa
+filename.-*-helvetica-bold-o-normal--*-%d-100-100-p-*-iso8859-1=/usr/lpp/X11/lib/X11/fonts/Type1/helvbi.pfa
+filename.-*-times_new_roman-medium-r-normal--*-%d-100-100-p-*-iso8859-1=/usr/lpp/X11/lib/X11/fonts/Type1/tnr.pfa
+filename.-*-times_new_roman-bold-r-normal--*-%d-100-100-p-*-iso8859-1=/usr/lpp/X11/lib/X11/fonts/Type1/tnrb.pfa
+filename.-*-times_new_roman-medium-i-normal--*-%d-100-100-p-*-iso8859-1=/usr/lpp/X11/lib/X11/fonts/Type1/tnri.pfa
+filename.-*-times_new_roman-bold-i-normal--*-%d-100-100-p-*-iso8859-1=/usr/lpp/X11/lib/X11/fonts/Type1/tnrbi.pfa
+
+
+filename.-monotype-sansmonowtextb-medium-r-normal--*-%d-75-75-m-*-unicode-2=/usr/lpp/X11/lib/X11/fonts/TrueType/MTSanXBA.ttf
+
+filename.-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_j.ttf
+filename.-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_j.ttf
+filename.-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_j.ttf
+filename.-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_j.ttf
+filename.-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_k.ttf
+filename.-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_k.ttf
+filename.-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_s.ttf
+filename.-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_s.ttf
+filename.-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_s.ttf
+filename.-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_s.ttf
+filename.-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_t.ttf
+
+filename.-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsansdj.ttf
+filename.-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsansdj.ttf
+filename.-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsansdj.ttf
+filename.-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsansdj.ttf
+filename.-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsansdk.ttf
+filename.-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsansdk.ttf
+filename.-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsansds.ttf
+filename.-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsansds.ttf
+filename.-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsansdt.ttf
+filename.-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0208.1983-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsans_j.ttf
+filename.-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-jisx0201.1976-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsans_j.ttf
+filename.-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ibm-udcjp=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsans_j.ttf
+filename.-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_japan-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsans_j.ttf
+filename.-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ksc5601.1987-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsans_k.ttf
+filename.-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_korea-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsans_k.ttf
+filename.-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-gb2312.1980-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsans_s.ttf
+filename.-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_china-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsans_s.ttf
+filename.-monotype-sanswt-medium-r-normal--*-%d-75-75-*-*-ucs2.cjk_taiwan-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsans_t.ttf
+
+filename.-monotype-timesnewromanwt-medium-r-normal--*-%d-75-75-*-*-iso8859-15=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_j.ttf
+filename.-monotype-sansmonowt-medium-r-normal--*-%d-75-75-*-*-iso8859-15=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsansdj.ttf
+
+filename.-ibm-thaicourier-medium-r-normal--*-%d-75-75-m-*-ucs2.thai-0=/usr/lpp/X11/lib/X11/fonts/TrueType/courth.ttf
+filename.-ibm-thaihelvetica-medium-r-normal--*-%d-75-75-p-*-ucs2.thai-0=/usr/lpp/X11/lib/X11/fonts/TrueType/helvth.ttf
+filename.-ibm-thaitimes-medium-r-normal--*-%d-75-75-p-*-ucs2.thai-0=/usr/lpp/X11/lib/X11/fonts/TrueType/timeth.ttf
+
+filename.-*-*-medium-r-normal--*-%d-*-*-p-*-ibm-1046=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_j.ttf
+filename.-*-*-bold-r-normal--*-%d-*-*-p-*-ibm-1046=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_j.ttf
+filename.-*-*-medium-i-normal--*-%d-*-*-p-*-ibm-1046=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_j.ttf
+filename.-*-*-bold-i-normal--*-%d-*-*-p-*-ibm-1046=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_j.ttf
+filename.-*-*-medium-r-normal--*-%d-*-*-m-*-ibm-1046=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsansdj.ttf
+filename.-*-*-bold-r-normal--*-%d-*-*-m-*-ibm-1046=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsansdj.ttf
+filename.-*-*-medium-i-normal--*-%d-*-*-m-*-ibm-1046=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsansdj.ttf
+filename.-*-*-bold-i-normal--*-%d-*-*-m-*-ibm-1046=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsansdj.ttf
+
+filename.-*-*-medium-r-normal--*-%d-75-75-p-*-ucs2.i18n-0=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_j.ttf
+filename.-*-*-bold-r-normal--*-%d-75-75-p-*-ucs2.i18n-0=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_j.ttf
+filename.-*-*-medium-i-normal--*-%d-75-75-p-*-ucs2.i18n-0=/usr/lpp/X11/lib/X11/fonts/TrueType/tnrwt_j.ttf
+filename.-*-*-medium-r-normal--*-%d-75-75-m-*-ucs2.i18n-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsansdj.ttf
+filename.-*-*-bold-r-normal--*-%d-75-75-m-*-ucs2.i18n-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsansdj.ttf
+filename.-*-*-medium-i-normal--*-%d-75-75-m-*-ucs2.i18n-0=/usr/lpp/X11/lib/X11/fonts/TrueType/mtsansdj.ttf
+
+# AWT font path
+awtfontpath.japanese-x0201=/usr/lpp/X11/lib/X11/fonts/TrueType
+awtfontpath.japanese-x0208=/usr/lpp/X11/lib/X11/fonts/TrueType
+awtfontpath.japanese-udc=/usr/lpp/X11/lib/X11/fonts/TrueType
+awtfontpath.japanese-iso10646=/usr/lpp/X11/lib/X11/fonts/TrueType
+awtfontpath.korean=/usr/lpp/X11/lib/X11/fonts/TrueType
+awtfontpath.korean-iso10646=/usr/lpp/X11/lib/X11/fonts/TrueType
+awtfontpath.chinese=/usr/lpp/X11/lib/X11/fonts/TrueType
+awtfontpath.chinese-iso10646=/usr/lpp/X11/lib/X11/fonts/TrueType
+awtfontpath.taiwanese-iso10646=/usr/lpp/X11/lib/X11/fonts/TrueType
+awtfontpath.thai=/usr/lpp/X11/lib/X11/fonts/TrueType
+awtfontpath.iso10646-extB=/usr/lpp/X11/lib/X11/fonts/TrueType
+
diff --git a/src/share/bin/java.c b/src/share/bin/java.c
index eb5c331..cc354eb 100644
--- a/src/share/bin/java.c
+++ b/src/share/bin/java.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2014, 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
@@ -1248,11 +1248,13 @@
(*env)->SetByteArrayRegion(env, ary, 0, len, (jbyte *)s);
if (!(*env)->ExceptionOccurred(env)) {
if (makePlatformStringMID == NULL) {
- NULL_CHECK0(makePlatformStringMID = (*env)->GetStaticMethodID(env,
+ CHECK_JNI_RETURN_0(
+ makePlatformStringMID = (*env)->GetStaticMethodID(env,
cls, "makePlatformString", "(Z[B)Ljava/lang/String;"));
}
- str = (*env)->CallStaticObjectMethod(env, cls,
- makePlatformStringMID, USE_STDERR, ary);
+ CHECK_JNI_RETURN_0(
+ str = (*env)->CallStaticObjectMethod(env, cls,
+ makePlatformStringMID, USE_STDERR, ary));
(*env)->DeleteLocalRef(env, ary);
return str;
}
@@ -1303,7 +1305,9 @@
"(ZILjava/lang/String;)Ljava/lang/Class;"));
str = NewPlatformString(env, name);
- result = (*env)->CallStaticObjectMethod(env, cls, mid, USE_STDERR, mode, str);
+ CHECK_JNI_RETURN_0(
+ result = (*env)->CallStaticObjectMethod(
+ env, cls, mid, USE_STDERR, mode, str));
if (JLI_IsTraceLauncher()) {
end = CounterGet();
diff --git a/src/share/bin/java.h b/src/share/bin/java.h
index 83e97e6..43450d8 100644
--- a/src/share/bin/java.h
+++ b/src/share/bin/java.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2014, 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
@@ -256,4 +256,47 @@
#define NULL_CHECK(NC_check_pointer) \
NULL_CHECK_RETURN_VALUE(NC_check_pointer, )
+/*
+ * For JNI calls :
+ * - check for thrown exceptions
+ * - check for null return
+ *
+ * JNI calls can return null and/or throw an exception. Check for these.
+ *
+ * : CHECK_JNI_RETURN_EXCEPTION()
+ * return the specified RETURNVALUE if exception was generated
+ * : CHECK_JNI_RETURN_0(JNISTATEMENT) : check if JNISTATEMENT was successful, return 0 if not
+ * : CHECK_JNI_RETURN_VOID(JNISTATEMENT) : check if JNISTATEMENT was successful, return void if not
+ * : CHECK_JNI_RETURN_VALUE(JNISTATEMENT,n) : check if JNISTATEMENT was successful, return n if not
+ *
+ * These macros need at least one parameter, the JNI statement [ JNISTATEMENT ].
+ *
+ * E.G.: check the JNI statement, and specify a value to return if a failure was detected.
+ *
+ * CHECK_JNI_RETURN_VALUE(str = (*env)->CallStaticObjectMethod(env, cls,
+ * makePlatformStringMID, USE_STDERR, ary), -1);
+ */
+
+#define RETURNVOID return
+#define RETURN0 return 0
+#define RETURN(N) return (N)
+
+#define CHECK_JNI_RETURN_EXCEPTION(RETURNVALUE) \
+ if ((((*env)->ExceptionOccurred(env))!=NULL)) { \
+ RETURNVALUE; \
+ }
+
+#define CHECK_JNI_RETURN_0(JNISTATEMENT) \
+ CHECK_JNI_RETURN_EXCEPTION(RETURN0); \
+ NULL_CHECK0(JNISTATEMENT);
+
+#define CHECK_JNI_RETURN_VOID(JNISTATEMENT) \
+ CHECK_JNI_RETURN_EXCEPTION(RETURNVOID); \
+ NULL_CHECK(JNISTATEMENT);
+
+#define CHECK_JNI_RETURN_VALUE(JNISTATEMENT, NCRV_return_value) \
+ CHECK_JNI_RETURN_EXCEPTION(RETURN(NCRV_return_value)); \
+ NULL_CHECK_RETURN_VALUE(JNISTATEMENT, NCRV_return_value);
+
+
#endif /* _JAVA_H_ */
diff --git a/src/share/classes/com/sun/java/swing/plaf/motif/MotifScrollPaneUI.java b/src/share/classes/com/sun/java/swing/plaf/motif/MotifScrollPaneUI.java
index 2a12ed8..52bc738 100644
--- a/src/share/classes/com/sun/java/swing/plaf/motif/MotifScrollPaneUI.java
+++ b/src/share/classes/com/sun/java/swing/plaf/motif/MotifScrollPaneUI.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, 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
@@ -56,19 +56,22 @@
private PropertyChangeListener propertyChangeHandler;
+ @Override
protected void installListeners(JScrollPane scrollPane) {
super.installListeners(scrollPane);
propertyChangeHandler = createPropertyChangeHandler();
scrollPane.addPropertyChangeListener(propertyChangeHandler);
}
- protected void uninstallListeners(JScrollPane scrollPane) {
+ @Override
+ protected void uninstallListeners(JComponent scrollPane) {
super.uninstallListeners(scrollPane);
scrollPane.removePropertyChangeListener(propertyChangeHandler);
}
private PropertyChangeListener createPropertyChangeHandler() {
return new PropertyChangeListener() {
+ @Override
public void propertyChange(PropertyChangeEvent e) {
String propertyName = e.getPropertyName();
@@ -92,6 +95,7 @@
}};
}
+ @Override
protected void installDefaults(JScrollPane scrollpane) {
super.installDefaults(scrollpane);
@@ -115,7 +119,7 @@
}
}
-
+ @Override
protected void uninstallDefaults(JScrollPane c) {
super.uninstallDefaults(c);
diff --git a/src/share/classes/java/awt/event/InputMethodEvent.java b/src/share/classes/java/awt/event/InputMethodEvent.java
index cd7122d..d90e5ec 100644
--- a/src/share/classes/java/awt/event/InputMethodEvent.java
+++ b/src/share/classes/java/awt/event/InputMethodEvent.java
@@ -417,7 +417,8 @@
private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException {
s.defaultReadObject();
if (when == 0) {
- when = getMostRecentEventTimeForSource(this.source);
+ // Can't use getMostRecentEventTimeForSource because source is always null during deserialization
+ when = EventQueue.getMostRecentEventTime();
}
}
diff --git a/src/share/classes/java/util/CurrencyData.properties b/src/share/classes/java/util/CurrencyData.properties
index a22ddd4..2b5a570 100644
--- a/src/share/classes/java/util/CurrencyData.properties
+++ b/src/share/classes/java/util/CurrencyData.properties
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2000, 2014, 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
@@ -28,7 +28,7 @@
# Version of the currency code information in this class.
# It is a serial number that accompanies with each amendment.
-dataVersion=156
+dataVersion=159
# List of all valid ISO 4217 currency codes.
# To ensure compatibility, do not remove codes.
@@ -332,7 +332,7 @@
# LIECHTENSTEIN
LI=CHF
# LITHUANIA
-LT=LTL
+LT=LTL;2014-12-31-22-00-00;EUR
# LUXEMBOURG
LU=EUR
# MACAU
diff --git a/src/share/classes/java/util/concurrent/CompletableFuture.java b/src/share/classes/java/util/concurrent/CompletableFuture.java
index 9e89169..8476dcc 100644
--- a/src/share/classes/java/util/concurrent/CompletableFuture.java
+++ b/src/share/classes/java/util/concurrent/CompletableFuture.java
@@ -50,7 +50,6 @@
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletionException;
import java.util.concurrent.CompletionStage;
-import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.LockSupport;
/**
@@ -77,9 +76,9 @@
* <li>All <em>async</em> methods without an explicit Executor
* argument are performed using the {@link ForkJoinPool#commonPool()}
* (unless it does not support a parallelism level of at least two, in
- * which case, a new Thread is used). To simplify monitoring,
- * debugging, and tracking, all generated asynchronous tasks are
- * instances of the marker interface {@link
+ * which case, a new Thread is created to run each task). To simplify
+ * monitoring, debugging, and tracking, all generated asynchronous
+ * tasks are instances of the marker interface {@link
* AsynchronousCompletionTask}. </li>
*
* <li>All CompletionStage methods are implemented independently of
@@ -113,141 +112,1556 @@
/*
* Overview:
*
- * 1. Non-nullness of field result (set via CAS) indicates done.
- * An AltResult is used to box null as a result, as well as to
- * hold exceptions. Using a single field makes completion fast
- * and simple to detect and trigger, at the expense of a lot of
- * encoding and decoding that infiltrates many methods. One minor
- * simplification relies on the (static) NIL (to box null results)
- * being the only AltResult with a null exception field, so we
- * don't usually need explicit comparisons with NIL. The CF
- * exception propagation mechanics surrounding decoding rely on
- * unchecked casts of decoded results really being unchecked,
- * where user type errors are caught at point of use, as is
- * currently the case in Java. These are highlighted by using
- * SuppressWarnings-annotated temporaries.
+ * A CompletableFuture may have dependent completion actions,
+ * collected in a linked stack. It atomically completes by CASing
+ * a result field, and then pops off and runs those actions. This
+ * applies across normal vs exceptional outcomes, sync vs async
+ * actions, binary triggers, and various forms of completions.
*
- * 2. Waiters are held in a Treiber stack similar to the one used
- * in FutureTask, Phaser, and SynchronousQueue. See their
- * internal documentation for algorithmic details.
+ * Non-nullness of field result (set via CAS) indicates done. An
+ * AltResult is used to box null as a result, as well as to hold
+ * exceptions. Using a single field makes completion simple to
+ * detect and trigger. Encoding and decoding is straightforward
+ * but adds to the sprawl of trapping and associating exceptions
+ * with targets. Minor simplifications rely on (static) NIL (to
+ * box null results) being the only AltResult with a null
+ * exception field, so we don't usually need explicit comparisons.
+ * Even though some of the generics casts are unchecked (see
+ * SuppressWarnings annotations), they are placed to be
+ * appropriate even if checked.
*
- * 3. Completions are also kept in a list/stack, and pulled off
- * and run when completion is triggered. (We could even use the
- * same stack as for waiters, but would give up the potential
- * parallelism obtained because woken waiters help release/run
- * others -- see method postComplete). Because post-processing
- * may race with direct calls, class Completion opportunistically
- * extends AtomicInteger so callers can claim the action via
- * compareAndSet(0, 1). The Completion.run methods are all
- * written a boringly similar uniform way (that sometimes includes
- * unnecessary-looking checks, kept to maintain uniformity).
- * There are enough dimensions upon which they differ that
- * attempts to factor commonalities while maintaining efficiency
- * require more lines of code than they would save.
+ * Dependent actions are represented by Completion objects linked
+ * as Treiber stacks headed by field "stack". There are Completion
+ * classes for each kind of action, grouped into single-input
+ * (UniCompletion), two-input (BiCompletion), projected
+ * (BiCompletions using either (not both) of two inputs), shared
+ * (CoCompletion, used by the second of two sources), zero-input
+ * source actions, and Signallers that unblock waiters. Class
+ * Completion extends ForkJoinTask to enable async execution
+ * (adding no space overhead because we exploit its "tag" methods
+ * to maintain claims). It is also declared as Runnable to allow
+ * usage with arbitrary executors.
*
- * 4. The exported then/and/or methods do support a bit of
- * factoring (see doThenApply etc). They must cope with the
- * intrinsic races surrounding addition of a dependent action
- * versus performing the action directly because the task is
- * already complete. For example, a CF may not be complete upon
- * entry, so a dependent completion is added, but by the time it
- * is added, the target CF is complete, so must be directly
- * executed. This is all done while avoiding unnecessary object
- * construction in safe-bypass cases.
+ * Support for each kind of CompletionStage relies on a separate
+ * class, along with two CompletableFuture methods:
+ *
+ * * A Completion class with name X corresponding to function,
+ * prefaced with "Uni", "Bi", or "Or". Each class contains
+ * fields for source(s), actions, and dependent. They are
+ * boringly similar, differing from others only with respect to
+ * underlying functional forms. We do this so that users don't
+ * encounter layers of adaptors in common usages. We also
+ * include "Relay" classes/methods that don't correspond to user
+ * methods; they copy results from one stage to another.
+ *
+ * * Boolean CompletableFuture method x(...) (for example
+ * uniApply) takes all of the arguments needed to check that an
+ * action is triggerable, and then either runs the action or
+ * arranges its async execution by executing its Completion
+ * argument, if present. The method returns true if known to be
+ * complete.
+ *
+ * * Completion method tryFire(int mode) invokes the associated x
+ * method with its held arguments, and on success cleans up.
+ * The mode argument allows tryFire to be called twice (SYNC,
+ * then ASYNC); the first to screen and trap exceptions while
+ * arranging to execute, and the second when called from a
+ * task. (A few classes are not used async so take slightly
+ * different forms.) The claim() callback suppresses function
+ * invocation if already claimed by another thread.
+ *
+ * * CompletableFuture method xStage(...) is called from a public
+ * stage method of CompletableFuture x. It screens user
+ * arguments and invokes and/or creates the stage object. If
+ * not async and x is already complete, the action is run
+ * immediately. Otherwise a Completion c is created, pushed to
+ * x's stack (unless done), and started or triggered via
+ * c.tryFire. This also covers races possible if x completes
+ * while pushing. Classes with two inputs (for example BiApply)
+ * deal with races across both while pushing actions. The
+ * second completion is a CoCompletion pointing to the first,
+ * shared so that at most one performs the action. The
+ * multiple-arity methods allOf and anyOf do this pairwise to
+ * form trees of completions.
+ *
+ * Note that the generic type parameters of methods vary according
+ * to whether "this" is a source, dependent, or completion.
+ *
+ * Method postComplete is called upon completion unless the target
+ * is guaranteed not to be observable (i.e., not yet returned or
+ * linked). Multiple threads can call postComplete, which
+ * atomically pops each dependent action, and tries to trigger it
+ * via method tryFire, in NESTED mode. Triggering can propagate
+ * recursively, so NESTED mode returns its completed dependent (if
+ * one exists) for further processing by its caller (see method
+ * postFire).
+ *
+ * Blocking methods get() and join() rely on Signaller Completions
+ * that wake up waiting threads. The mechanics are similar to
+ * Treiber stack wait-nodes used in FutureTask, Phaser, and
+ * SynchronousQueue. See their internal documentation for
+ * algorithmic details.
+ *
+ * Without precautions, CompletableFutures would be prone to
+ * garbage accumulation as chains of Completions build up, each
+ * pointing back to its sources. So we null out fields as soon as
+ * possible (see especially method Completion.detach). The
+ * screening checks needed anyway harmlessly ignore null arguments
+ * that may have been obtained during races with threads nulling
+ * out fields. We also try to unlink fired Completions from
+ * stacks that might never be popped (see method postFire).
+ * Completion fields need not be declared as final or volatile
+ * because they are only visible to other threads upon safe
+ * publication.
*/
- // preliminaries
+ volatile Object result; // Either the result or boxed AltResult
+ volatile Completion stack; // Top of Treiber stack of dependent actions
- static final class AltResult {
- final Throwable ex; // null only for NIL
- AltResult(Throwable ex) { this.ex = ex; }
+ final boolean internalComplete(Object r) { // CAS from null to r
+ return UNSAFE.compareAndSwapObject(this, RESULT, null, r);
}
+ final boolean casStack(Completion cmp, Completion val) {
+ return UNSAFE.compareAndSwapObject(this, STACK, cmp, val);
+ }
+
+ /** Returns true if successfully pushed c onto stack. */
+ final boolean tryPushStack(Completion c) {
+ Completion h = stack;
+ lazySetNext(c, h);
+ return UNSAFE.compareAndSwapObject(this, STACK, h, c);
+ }
+
+ /** Unconditionally pushes c onto stack, retrying if necessary. */
+ final void pushStack(Completion c) {
+ do {} while (!tryPushStack(c));
+ }
+
+ /* ------------- Encoding and decoding outcomes -------------- */
+
+ static final class AltResult { // See above
+ final Throwable ex; // null only for NIL
+ AltResult(Throwable x) { this.ex = x; }
+ }
+
+ /** The encoding of the null value. */
static final AltResult NIL = new AltResult(null);
- // Fields
+ /** Completes with the null value, unless already completed. */
+ final boolean completeNull() {
+ return UNSAFE.compareAndSwapObject(this, RESULT, null,
+ NIL);
+ }
- volatile Object result; // Either the result or boxed AltResult
- volatile WaitNode waiters; // Treiber stack of threads blocked on get()
- volatile CompletionNode completions; // list (Treiber stack) of completions
+ /** Returns the encoding of the given non-exceptional value. */
+ final Object encodeValue(T t) {
+ return (t == null) ? NIL : t;
+ }
- // Basic utilities for triggering and processing completions
+ /** Completes with a non-exceptional result, unless already completed. */
+ final boolean completeValue(T t) {
+ return UNSAFE.compareAndSwapObject(this, RESULT, null,
+ (t == null) ? NIL : t);
+ }
/**
- * Removes and signals all waiting threads and runs all completions.
+ * Returns the encoding of the given (non-null) exception as a
+ * wrapped CompletionException unless it is one already.
+ */
+ static AltResult encodeThrowable(Throwable x) {
+ return new AltResult((x instanceof CompletionException) ? x :
+ new CompletionException(x));
+ }
+
+ /** Completes with an exceptional result, unless already completed. */
+ final boolean completeThrowable(Throwable x) {
+ return UNSAFE.compareAndSwapObject(this, RESULT, null,
+ encodeThrowable(x));
+ }
+
+ /**
+ * Returns the encoding of the given (non-null) exception as a
+ * wrapped CompletionException unless it is one already. May
+ * return the given Object r (which must have been the result of a
+ * source future) if it is equivalent, i.e. if this is a simple
+ * relay of an existing CompletionException.
+ */
+ static Object encodeThrowable(Throwable x, Object r) {
+ if (!(x instanceof CompletionException))
+ x = new CompletionException(x);
+ else if (r instanceof AltResult && x == ((AltResult)r).ex)
+ return r;
+ return new AltResult(x);
+ }
+
+ /**
+ * Completes with the given (non-null) exceptional result as a
+ * wrapped CompletionException unless it is one already, unless
+ * already completed. May complete with the given Object r
+ * (which must have been the result of a source future) if it is
+ * equivalent, i.e. if this is a simple propagation of an
+ * existing CompletionException.
+ */
+ final boolean completeThrowable(Throwable x, Object r) {
+ return UNSAFE.compareAndSwapObject(this, RESULT, null,
+ encodeThrowable(x, r));
+ }
+
+ /**
+ * Returns the encoding of the given arguments: if the exception
+ * is non-null, encodes as AltResult. Otherwise uses the given
+ * value, boxed as NIL if null.
+ */
+ Object encodeOutcome(T t, Throwable x) {
+ return (x == null) ? (t == null) ? NIL : t : encodeThrowable(x);
+ }
+
+ /**
+ * Returns the encoding of a copied outcome; if exceptional,
+ * rewraps as a CompletionException, else returns argument.
+ */
+ static Object encodeRelay(Object r) {
+ Throwable x;
+ return (((r instanceof AltResult) &&
+ (x = ((AltResult)r).ex) != null &&
+ !(x instanceof CompletionException)) ?
+ new AltResult(new CompletionException(x)) : r);
+ }
+
+ /**
+ * Completes with r or a copy of r, unless already completed.
+ * If exceptional, r is first coerced to a CompletionException.
+ */
+ final boolean completeRelay(Object r) {
+ return UNSAFE.compareAndSwapObject(this, RESULT, null,
+ encodeRelay(r));
+ }
+
+ /**
+ * Reports result using Future.get conventions.
+ */
+ private static <T> T reportGet(Object r)
+ throws InterruptedException, ExecutionException {
+ if (r == null) // by convention below, null means interrupted
+ throw new InterruptedException();
+ if (r instanceof AltResult) {
+ Throwable x, cause;
+ if ((x = ((AltResult)r).ex) == null)
+ return null;
+ if (x instanceof CancellationException)
+ throw (CancellationException)x;
+ if ((x instanceof CompletionException) &&
+ (cause = x.getCause()) != null)
+ x = cause;
+ throw new ExecutionException(x);
+ }
+ @SuppressWarnings("unchecked") T t = (T) r;
+ return t;
+ }
+
+ /**
+ * Decodes outcome to return result or throw unchecked exception.
+ */
+ private static <T> T reportJoin(Object r) {
+ if (r instanceof AltResult) {
+ Throwable x;
+ if ((x = ((AltResult)r).ex) == null)
+ return null;
+ if (x instanceof CancellationException)
+ throw (CancellationException)x;
+ if (x instanceof CompletionException)
+ throw (CompletionException)x;
+ throw new CompletionException(x);
+ }
+ @SuppressWarnings("unchecked") T t = (T) r;
+ return t;
+ }
+
+ /* ------------- Async task preliminaries -------------- */
+
+ /**
+ * A marker interface identifying asynchronous tasks produced by
+ * {@code async} methods. This may be useful for monitoring,
+ * debugging, and tracking asynchronous activities.
+ *
+ * @since 1.8
+ */
+ public static interface AsynchronousCompletionTask {
+ }
+
+ private static final boolean useCommonPool =
+ (ForkJoinPool.getCommonPoolParallelism() > 1);
+
+ /**
+ * Default executor -- ForkJoinPool.commonPool() unless it cannot
+ * support parallelism.
+ */
+ private static final Executor asyncPool = useCommonPool ?
+ ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();
+
+ /** Fallback if ForkJoinPool.commonPool() cannot support parallelism */
+ static final class ThreadPerTaskExecutor implements Executor {
+ public void execute(Runnable r) { new Thread(r).start(); }
+ }
+
+ /**
+ * Null-checks user executor argument, and translates uses of
+ * commonPool to asyncPool in case parallelism disabled.
+ */
+ static Executor screenExecutor(Executor e) {
+ if (!useCommonPool && e == ForkJoinPool.commonPool())
+ return asyncPool;
+ if (e == null) throw new NullPointerException();
+ return e;
+ }
+
+ // Modes for Completion.tryFire. Signedness matters.
+ static final int SYNC = 0;
+ static final int ASYNC = 1;
+ static final int NESTED = -1;
+
+ /* ------------- Base Completion classes and operations -------------- */
+
+ @SuppressWarnings("serial")
+ abstract static class Completion extends ForkJoinTask<Void>
+ implements Runnable, AsynchronousCompletionTask {
+ volatile Completion next; // Treiber stack link
+
+ /**
+ * Performs completion action if triggered, returning a
+ * dependent that may need propagation, if one exists.
+ *
+ * @param mode SYNC, ASYNC, or NESTED
+ */
+ abstract CompletableFuture<?> tryFire(int mode);
+
+ /** Returns true if possibly still triggerable. Used by cleanStack. */
+ abstract boolean isLive();
+
+ public final void run() { tryFire(ASYNC); }
+ public final boolean exec() { tryFire(ASYNC); return true; }
+ public final Void getRawResult() { return null; }
+ public final void setRawResult(Void v) {}
+ }
+
+ static void lazySetNext(Completion c, Completion next) {
+ UNSAFE.putOrderedObject(c, NEXT, next);
+ }
+
+ /**
+ * Pops and tries to trigger all reachable dependents. Call only
+ * when known to be done.
*/
final void postComplete() {
- WaitNode q; Thread t;
- while ((q = waiters) != null) {
- if (UNSAFE.compareAndSwapObject(this, WAITERS, q, q.next) &&
- (t = q.thread) != null) {
- q.thread = null;
- LockSupport.unpark(t);
+ /*
+ * On each step, variable f holds current dependents to pop
+ * and run. It is extended along only one path at a time,
+ * pushing others to avoid unbounded recursion.
+ */
+ CompletableFuture<?> f = this; Completion h;
+ while ((h = f.stack) != null ||
+ (f != this && (h = (f = this).stack) != null)) {
+ CompletableFuture<?> d; Completion t;
+ if (f.casStack(h, t = h.next)) {
+ if (t != null) {
+ if (f != this) {
+ pushStack(h);
+ continue;
+ }
+ h.next = null; // detach
+ }
+ f = (d = h.tryFire(NESTED)) == null ? this : d;
}
}
+ }
- CompletionNode h; Completion c;
- while ((h = completions) != null) {
- if (UNSAFE.compareAndSwapObject(this, COMPLETIONS, h, h.next) &&
- (c = h.completion) != null)
- c.run();
+ /** Traverses stack and unlinks dead Completions. */
+ final void cleanStack() {
+ for (Completion p = null, q = stack; q != null;) {
+ Completion s = q.next;
+ if (q.isLive()) {
+ p = q;
+ q = s;
+ }
+ else if (p == null) {
+ casStack(q, s);
+ q = stack;
+ }
+ else {
+ p.next = s;
+ if (p.isLive())
+ q = s;
+ else {
+ p = null; // restart
+ q = stack;
+ }
+ }
+ }
+ }
+
+ /* ------------- One-input Completions -------------- */
+
+ /** A Completion with a source, dependent, and executor. */
+ @SuppressWarnings("serial")
+ abstract static class UniCompletion<T,V> extends Completion {
+ Executor executor; // executor to use (null if none)
+ CompletableFuture<V> dep; // the dependent to complete
+ CompletableFuture<T> src; // source for action
+
+ UniCompletion(Executor executor, CompletableFuture<V> dep,
+ CompletableFuture<T> src) {
+ this.executor = executor; this.dep = dep; this.src = src;
+ }
+
+ /**
+ * Returns true if action can be run. Call only when known to
+ * be triggerable. Uses FJ tag bit to ensure that only one
+ * thread claims ownership. If async, starts as task -- a
+ * later call to tryFire will run action.
+ */
+ final boolean claim() {
+ Executor e = executor;
+ if (compareAndSetForkJoinTaskTag((short)0, (short)1)) {
+ if (e == null)
+ return true;
+ executor = null; // disable
+ e.execute(this);
+ }
+ return false;
+ }
+
+ final boolean isLive() { return dep != null; }
+ }
+
+ /** Pushes the given completion (if it exists) unless done. */
+ final void push(UniCompletion<?,?> c) {
+ if (c != null) {
+ while (result == null && !tryPushStack(c))
+ lazySetNext(c, null); // clear on failure
}
}
/**
- * Triggers completion with the encoding of the given arguments:
- * if the exception is non-null, encodes it as a wrapped
- * CompletionException unless it is one already. Otherwise uses
- * the given result, boxed as NIL if null.
+ * Post-processing by dependent after successful UniCompletion
+ * tryFire. Tries to clean stack of source a, and then either runs
+ * postComplete or returns this to caller, depending on mode.
*/
- final void internalComplete(T v, Throwable ex) {
+ final CompletableFuture<T> postFire(CompletableFuture<?> a, int mode) {
+ if (a != null && a.stack != null) {
+ if (mode < 0 || a.result == null)
+ a.cleanStack();
+ else
+ a.postComplete();
+ }
+ if (result != null && stack != null) {
+ if (mode < 0)
+ return this;
+ else
+ postComplete();
+ }
+ return null;
+ }
+
+ @SuppressWarnings("serial")
+ static final class UniApply<T,V> extends UniCompletion<T,V> {
+ Function<? super T,? extends V> fn;
+ UniApply(Executor executor, CompletableFuture<V> dep,
+ CompletableFuture<T> src,
+ Function<? super T,? extends V> fn) {
+ super(executor, dep, src); this.fn = fn;
+ }
+ final CompletableFuture<V> tryFire(int mode) {
+ CompletableFuture<V> d; CompletableFuture<T> a;
+ if ((d = dep) == null ||
+ !d.uniApply(a = src, fn, mode > 0 ? null : this))
+ return null;
+ dep = null; src = null; fn = null;
+ return d.postFire(a, mode);
+ }
+ }
+
+ final <S> boolean uniApply(CompletableFuture<S> a,
+ Function<? super S,? extends T> f,
+ UniApply<S,T> c) {
+ Object r; Throwable x;
+ if (a == null || (r = a.result) == null || f == null)
+ return false;
+ tryComplete: if (result == null) {
+ if (r instanceof AltResult) {
+ if ((x = ((AltResult)r).ex) != null) {
+ completeThrowable(x, r);
+ break tryComplete;
+ }
+ r = null;
+ }
+ try {
+ if (c != null && !c.claim())
+ return false;
+ @SuppressWarnings("unchecked") S s = (S) r;
+ completeValue(f.apply(s));
+ } catch (Throwable ex) {
+ completeThrowable(ex);
+ }
+ }
+ return true;
+ }
+
+ private <V> CompletableFuture<V> uniApplyStage(
+ Executor e, Function<? super T,? extends V> f) {
+ if (f == null) throw new NullPointerException();
+ CompletableFuture<V> d = new CompletableFuture<V>();
+ if (e != null || !d.uniApply(this, f, null)) {
+ UniApply<T,V> c = new UniApply<T,V>(e, d, this, f);
+ push(c);
+ c.tryFire(SYNC);
+ }
+ return d;
+ }
+
+ @SuppressWarnings("serial")
+ static final class UniAccept<T> extends UniCompletion<T,Void> {
+ Consumer<? super T> fn;
+ UniAccept(Executor executor, CompletableFuture<Void> dep,
+ CompletableFuture<T> src, Consumer<? super T> fn) {
+ super(executor, dep, src); this.fn = fn;
+ }
+ final CompletableFuture<Void> tryFire(int mode) {
+ CompletableFuture<Void> d; CompletableFuture<T> a;
+ if ((d = dep) == null ||
+ !d.uniAccept(a = src, fn, mode > 0 ? null : this))
+ return null;
+ dep = null; src = null; fn = null;
+ return d.postFire(a, mode);
+ }
+ }
+
+ final <S> boolean uniAccept(CompletableFuture<S> a,
+ Consumer<? super S> f, UniAccept<S> c) {
+ Object r; Throwable x;
+ if (a == null || (r = a.result) == null || f == null)
+ return false;
+ tryComplete: if (result == null) {
+ if (r instanceof AltResult) {
+ if ((x = ((AltResult)r).ex) != null) {
+ completeThrowable(x, r);
+ break tryComplete;
+ }
+ r = null;
+ }
+ try {
+ if (c != null && !c.claim())
+ return false;
+ @SuppressWarnings("unchecked") S s = (S) r;
+ f.accept(s);
+ completeNull();
+ } catch (Throwable ex) {
+ completeThrowable(ex);
+ }
+ }
+ return true;
+ }
+
+ private CompletableFuture<Void> uniAcceptStage(Executor e,
+ Consumer<? super T> f) {
+ if (f == null) throw new NullPointerException();
+ CompletableFuture<Void> d = new CompletableFuture<Void>();
+ if (e != null || !d.uniAccept(this, f, null)) {
+ UniAccept<T> c = new UniAccept<T>(e, d, this, f);
+ push(c);
+ c.tryFire(SYNC);
+ }
+ return d;
+ }
+
+ @SuppressWarnings("serial")
+ static final class UniRun<T> extends UniCompletion<T,Void> {
+ Runnable fn;
+ UniRun(Executor executor, CompletableFuture<Void> dep,
+ CompletableFuture<T> src, Runnable fn) {
+ super(executor, dep, src); this.fn = fn;
+ }
+ final CompletableFuture<Void> tryFire(int mode) {
+ CompletableFuture<Void> d; CompletableFuture<T> a;
+ if ((d = dep) == null ||
+ !d.uniRun(a = src, fn, mode > 0 ? null : this))
+ return null;
+ dep = null; src = null; fn = null;
+ return d.postFire(a, mode);
+ }
+ }
+
+ final boolean uniRun(CompletableFuture<?> a, Runnable f, UniRun<?> c) {
+ Object r; Throwable x;
+ if (a == null || (r = a.result) == null || f == null)
+ return false;
+ if (result == null) {
+ if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
+ completeThrowable(x, r);
+ else
+ try {
+ if (c != null && !c.claim())
+ return false;
+ f.run();
+ completeNull();
+ } catch (Throwable ex) {
+ completeThrowable(ex);
+ }
+ }
+ return true;
+ }
+
+ private CompletableFuture<Void> uniRunStage(Executor e, Runnable f) {
+ if (f == null) throw new NullPointerException();
+ CompletableFuture<Void> d = new CompletableFuture<Void>();
+ if (e != null || !d.uniRun(this, f, null)) {
+ UniRun<T> c = new UniRun<T>(e, d, this, f);
+ push(c);
+ c.tryFire(SYNC);
+ }
+ return d;
+ }
+
+ @SuppressWarnings("serial")
+ static final class UniWhenComplete<T> extends UniCompletion<T,T> {
+ BiConsumer<? super T, ? super Throwable> fn;
+ UniWhenComplete(Executor executor, CompletableFuture<T> dep,
+ CompletableFuture<T> src,
+ BiConsumer<? super T, ? super Throwable> fn) {
+ super(executor, dep, src); this.fn = fn;
+ }
+ final CompletableFuture<T> tryFire(int mode) {
+ CompletableFuture<T> d; CompletableFuture<T> a;
+ if ((d = dep) == null ||
+ !d.uniWhenComplete(a = src, fn, mode > 0 ? null : this))
+ return null;
+ dep = null; src = null; fn = null;
+ return d.postFire(a, mode);
+ }
+ }
+
+ final boolean uniWhenComplete(CompletableFuture<T> a,
+ BiConsumer<? super T,? super Throwable> f,
+ UniWhenComplete<T> c) {
+ Object r; T t; Throwable x = null;
+ if (a == null || (r = a.result) == null || f == null)
+ return false;
+ if (result == null) {
+ try {
+ if (c != null && !c.claim())
+ return false;
+ if (r instanceof AltResult) {
+ x = ((AltResult)r).ex;
+ t = null;
+ } else {
+ @SuppressWarnings("unchecked") T tr = (T) r;
+ t = tr;
+ }
+ f.accept(t, x);
+ if (x == null) {
+ internalComplete(r);
+ return true;
+ }
+ } catch (Throwable ex) {
+ if (x == null)
+ x = ex;
+ }
+ completeThrowable(x, r);
+ }
+ return true;
+ }
+
+ private CompletableFuture<T> uniWhenCompleteStage(
+ Executor e, BiConsumer<? super T, ? super Throwable> f) {
+ if (f == null) throw new NullPointerException();
+ CompletableFuture<T> d = new CompletableFuture<T>();
+ if (e != null || !d.uniWhenComplete(this, f, null)) {
+ UniWhenComplete<T> c = new UniWhenComplete<T>(e, d, this, f);
+ push(c);
+ c.tryFire(SYNC);
+ }
+ return d;
+ }
+
+ @SuppressWarnings("serial")
+ static final class UniHandle<T,V> extends UniCompletion<T,V> {
+ BiFunction<? super T, Throwable, ? extends V> fn;
+ UniHandle(Executor executor, CompletableFuture<V> dep,
+ CompletableFuture<T> src,
+ BiFunction<? super T, Throwable, ? extends V> fn) {
+ super(executor, dep, src); this.fn = fn;
+ }
+ final CompletableFuture<V> tryFire(int mode) {
+ CompletableFuture<V> d; CompletableFuture<T> a;
+ if ((d = dep) == null ||
+ !d.uniHandle(a = src, fn, mode > 0 ? null : this))
+ return null;
+ dep = null; src = null; fn = null;
+ return d.postFire(a, mode);
+ }
+ }
+
+ final <S> boolean uniHandle(CompletableFuture<S> a,
+ BiFunction<? super S, Throwable, ? extends T> f,
+ UniHandle<S,T> c) {
+ Object r; S s; Throwable x;
+ if (a == null || (r = a.result) == null || f == null)
+ return false;
+ if (result == null) {
+ try {
+ if (c != null && !c.claim())
+ return false;
+ if (r instanceof AltResult) {
+ x = ((AltResult)r).ex;
+ s = null;
+ } else {
+ x = null;
+ @SuppressWarnings("unchecked") S ss = (S) r;
+ s = ss;
+ }
+ completeValue(f.apply(s, x));
+ } catch (Throwable ex) {
+ completeThrowable(ex);
+ }
+ }
+ return true;
+ }
+
+ private <V> CompletableFuture<V> uniHandleStage(
+ Executor e, BiFunction<? super T, Throwable, ? extends V> f) {
+ if (f == null) throw new NullPointerException();
+ CompletableFuture<V> d = new CompletableFuture<V>();
+ if (e != null || !d.uniHandle(this, f, null)) {
+ UniHandle<T,V> c = new UniHandle<T,V>(e, d, this, f);
+ push(c);
+ c.tryFire(SYNC);
+ }
+ return d;
+ }
+
+ @SuppressWarnings("serial")
+ static final class UniExceptionally<T> extends UniCompletion<T,T> {
+ Function<? super Throwable, ? extends T> fn;
+ UniExceptionally(CompletableFuture<T> dep, CompletableFuture<T> src,
+ Function<? super Throwable, ? extends T> fn) {
+ super(null, dep, src); this.fn = fn;
+ }
+ final CompletableFuture<T> tryFire(int mode) { // never ASYNC
+ // assert mode != ASYNC;
+ CompletableFuture<T> d; CompletableFuture<T> a;
+ if ((d = dep) == null || !d.uniExceptionally(a = src, fn, this))
+ return null;
+ dep = null; src = null; fn = null;
+ return d.postFire(a, mode);
+ }
+ }
+
+ final boolean uniExceptionally(CompletableFuture<T> a,
+ Function<? super Throwable, ? extends T> f,
+ UniExceptionally<T> c) {
+ Object r; Throwable x;
+ if (a == null || (r = a.result) == null || f == null)
+ return false;
+ if (result == null) {
+ try {
+ if (r instanceof AltResult && (x = ((AltResult)r).ex) != null) {
+ if (c != null && !c.claim())
+ return false;
+ completeValue(f.apply(x));
+ } else
+ internalComplete(r);
+ } catch (Throwable ex) {
+ completeThrowable(ex);
+ }
+ }
+ return true;
+ }
+
+ private CompletableFuture<T> uniExceptionallyStage(
+ Function<Throwable, ? extends T> f) {
+ if (f == null) throw new NullPointerException();
+ CompletableFuture<T> d = new CompletableFuture<T>();
+ if (!d.uniExceptionally(this, f, null)) {
+ UniExceptionally<T> c = new UniExceptionally<T>(d, this, f);
+ push(c);
+ c.tryFire(SYNC);
+ }
+ return d;
+ }
+
+ @SuppressWarnings("serial")
+ static final class UniRelay<T> extends UniCompletion<T,T> { // for Compose
+ UniRelay(CompletableFuture<T> dep, CompletableFuture<T> src) {
+ super(null, dep, src);
+ }
+ final CompletableFuture<T> tryFire(int mode) {
+ CompletableFuture<T> d; CompletableFuture<T> a;
+ if ((d = dep) == null || !d.uniRelay(a = src))
+ return null;
+ src = null; dep = null;
+ return d.postFire(a, mode);
+ }
+ }
+
+ final boolean uniRelay(CompletableFuture<T> a) {
+ Object r;
+ if (a == null || (r = a.result) == null)
+ return false;
+ if (result == null) // no need to claim
+ completeRelay(r);
+ return true;
+ }
+
+ @SuppressWarnings("serial")
+ static final class UniCompose<T,V> extends UniCompletion<T,V> {
+ Function<? super T, ? extends CompletionStage<V>> fn;
+ UniCompose(Executor executor, CompletableFuture<V> dep,
+ CompletableFuture<T> src,
+ Function<? super T, ? extends CompletionStage<V>> fn) {
+ super(executor, dep, src); this.fn = fn;
+ }
+ final CompletableFuture<V> tryFire(int mode) {
+ CompletableFuture<V> d; CompletableFuture<T> a;
+ if ((d = dep) == null ||
+ !d.uniCompose(a = src, fn, mode > 0 ? null : this))
+ return null;
+ dep = null; src = null; fn = null;
+ return d.postFire(a, mode);
+ }
+ }
+
+ final <S> boolean uniCompose(
+ CompletableFuture<S> a,
+ Function<? super S, ? extends CompletionStage<T>> f,
+ UniCompose<S,T> c) {
+ Object r; Throwable x;
+ if (a == null || (r = a.result) == null || f == null)
+ return false;
+ tryComplete: if (result == null) {
+ if (r instanceof AltResult) {
+ if ((x = ((AltResult)r).ex) != null) {
+ completeThrowable(x, r);
+ break tryComplete;
+ }
+ r = null;
+ }
+ try {
+ if (c != null && !c.claim())
+ return false;
+ @SuppressWarnings("unchecked") S s = (S) r;
+ CompletableFuture<T> g = f.apply(s).toCompletableFuture();
+ if (g.result == null || !uniRelay(g)) {
+ UniRelay<T> copy = new UniRelay<T>(this, g);
+ g.push(copy);
+ copy.tryFire(SYNC);
+ if (result == null)
+ return false;
+ }
+ } catch (Throwable ex) {
+ completeThrowable(ex);
+ }
+ }
+ return true;
+ }
+
+ private <V> CompletableFuture<V> uniComposeStage(
+ Executor e, Function<? super T, ? extends CompletionStage<V>> f) {
+ if (f == null) throw new NullPointerException();
+ Object r; Throwable x;
+ if (e == null && (r = result) != null) {
+ // try to return function result directly
+ if (r instanceof AltResult) {
+ if ((x = ((AltResult)r).ex) != null) {
+ return new CompletableFuture<V>(encodeThrowable(x, r));
+ }
+ r = null;
+ }
+ try {
+ @SuppressWarnings("unchecked") T t = (T) r;
+ return f.apply(t).toCompletableFuture();
+ } catch (Throwable ex) {
+ return new CompletableFuture<V>(encodeThrowable(ex));
+ }
+ }
+ CompletableFuture<V> d = new CompletableFuture<V>();
+ UniCompose<T,V> c = new UniCompose<T,V>(e, d, this, f);
+ push(c);
+ c.tryFire(SYNC);
+ return d;
+ }
+
+ /* ------------- Two-input Completions -------------- */
+
+ /** A Completion for an action with two sources */
+ @SuppressWarnings("serial")
+ abstract static class BiCompletion<T,U,V> extends UniCompletion<T,V> {
+ CompletableFuture<U> snd; // second source for action
+ BiCompletion(Executor executor, CompletableFuture<V> dep,
+ CompletableFuture<T> src, CompletableFuture<U> snd) {
+ super(executor, dep, src); this.snd = snd;
+ }
+ }
+
+ /** A Completion delegating to a BiCompletion */
+ @SuppressWarnings("serial")
+ static final class CoCompletion extends Completion {
+ BiCompletion<?,?,?> base;
+ CoCompletion(BiCompletion<?,?,?> base) { this.base = base; }
+ final CompletableFuture<?> tryFire(int mode) {
+ BiCompletion<?,?,?> c; CompletableFuture<?> d;
+ if ((c = base) == null || (d = c.tryFire(mode)) == null)
+ return null;
+ base = null; // detach
+ return d;
+ }
+ final boolean isLive() {
+ BiCompletion<?,?,?> c;
+ return (c = base) != null && c.dep != null;
+ }
+ }
+
+ /** Pushes completion to this and b unless both done. */
+ final void bipush(CompletableFuture<?> b, BiCompletion<?,?,?> c) {
+ if (c != null) {
+ Object r;
+ while ((r = result) == null && !tryPushStack(c))
+ lazySetNext(c, null); // clear on failure
+ if (b != null && b != this && b.result == null) {
+ Completion q = (r != null) ? c : new CoCompletion(c);
+ while (b.result == null && !b.tryPushStack(q))
+ lazySetNext(q, null); // clear on failure
+ }
+ }
+ }
+
+ /** Post-processing after successful BiCompletion tryFire. */
+ final CompletableFuture<T> postFire(CompletableFuture<?> a,
+ CompletableFuture<?> b, int mode) {
+ if (b != null && b.stack != null) { // clean second source
+ if (mode < 0 || b.result == null)
+ b.cleanStack();
+ else
+ b.postComplete();
+ }
+ return postFire(a, mode);
+ }
+
+ @SuppressWarnings("serial")
+ static final class BiApply<T,U,V> extends BiCompletion<T,U,V> {
+ BiFunction<? super T,? super U,? extends V> fn;
+ BiApply(Executor executor, CompletableFuture<V> dep,
+ CompletableFuture<T> src, CompletableFuture<U> snd,
+ BiFunction<? super T,? super U,? extends V> fn) {
+ super(executor, dep, src, snd); this.fn = fn;
+ }
+ final CompletableFuture<V> tryFire(int mode) {
+ CompletableFuture<V> d;
+ CompletableFuture<T> a;
+ CompletableFuture<U> b;
+ if ((d = dep) == null ||
+ !d.biApply(a = src, b = snd, fn, mode > 0 ? null : this))
+ return null;
+ dep = null; src = null; snd = null; fn = null;
+ return d.postFire(a, b, mode);
+ }
+ }
+
+ final <R,S> boolean biApply(CompletableFuture<R> a,
+ CompletableFuture<S> b,
+ BiFunction<? super R,? super S,? extends T> f,
+ BiApply<R,S,T> c) {
+ Object r, s; Throwable x;
+ if (a == null || (r = a.result) == null ||
+ b == null || (s = b.result) == null || f == null)
+ return false;
+ tryComplete: if (result == null) {
+ if (r instanceof AltResult) {
+ if ((x = ((AltResult)r).ex) != null) {
+ completeThrowable(x, r);
+ break tryComplete;
+ }
+ r = null;
+ }
+ if (s instanceof AltResult) {
+ if ((x = ((AltResult)s).ex) != null) {
+ completeThrowable(x, s);
+ break tryComplete;
+ }
+ s = null;
+ }
+ try {
+ if (c != null && !c.claim())
+ return false;
+ @SuppressWarnings("unchecked") R rr = (R) r;
+ @SuppressWarnings("unchecked") S ss = (S) s;
+ completeValue(f.apply(rr, ss));
+ } catch (Throwable ex) {
+ completeThrowable(ex);
+ }
+ }
+ return true;
+ }
+
+ private <U,V> CompletableFuture<V> biApplyStage(
+ Executor e, CompletionStage<U> o,
+ BiFunction<? super T,? super U,? extends V> f) {
+ CompletableFuture<U> b;
+ if (f == null || (b = o.toCompletableFuture()) == null)
+ throw new NullPointerException();
+ CompletableFuture<V> d = new CompletableFuture<V>();
+ if (e != null || !d.biApply(this, b, f, null)) {
+ BiApply<T,U,V> c = new BiApply<T,U,V>(e, d, this, b, f);
+ bipush(b, c);
+ c.tryFire(SYNC);
+ }
+ return d;
+ }
+
+ @SuppressWarnings("serial")
+ static final class BiAccept<T,U> extends BiCompletion<T,U,Void> {
+ BiConsumer<? super T,? super U> fn;
+ BiAccept(Executor executor, CompletableFuture<Void> dep,
+ CompletableFuture<T> src, CompletableFuture<U> snd,
+ BiConsumer<? super T,? super U> fn) {
+ super(executor, dep, src, snd); this.fn = fn;
+ }
+ final CompletableFuture<Void> tryFire(int mode) {
+ CompletableFuture<Void> d;
+ CompletableFuture<T> a;
+ CompletableFuture<U> b;
+ if ((d = dep) == null ||
+ !d.biAccept(a = src, b = snd, fn, mode > 0 ? null : this))
+ return null;
+ dep = null; src = null; snd = null; fn = null;
+ return d.postFire(a, b, mode);
+ }
+ }
+
+ final <R,S> boolean biAccept(CompletableFuture<R> a,
+ CompletableFuture<S> b,
+ BiConsumer<? super R,? super S> f,
+ BiAccept<R,S> c) {
+ Object r, s; Throwable x;
+ if (a == null || (r = a.result) == null ||
+ b == null || (s = b.result) == null || f == null)
+ return false;
+ tryComplete: if (result == null) {
+ if (r instanceof AltResult) {
+ if ((x = ((AltResult)r).ex) != null) {
+ completeThrowable(x, r);
+ break tryComplete;
+ }
+ r = null;
+ }
+ if (s instanceof AltResult) {
+ if ((x = ((AltResult)s).ex) != null) {
+ completeThrowable(x, s);
+ break tryComplete;
+ }
+ s = null;
+ }
+ try {
+ if (c != null && !c.claim())
+ return false;
+ @SuppressWarnings("unchecked") R rr = (R) r;
+ @SuppressWarnings("unchecked") S ss = (S) s;
+ f.accept(rr, ss);
+ completeNull();
+ } catch (Throwable ex) {
+ completeThrowable(ex);
+ }
+ }
+ return true;
+ }
+
+ private <U> CompletableFuture<Void> biAcceptStage(
+ Executor e, CompletionStage<U> o,
+ BiConsumer<? super T,? super U> f) {
+ CompletableFuture<U> b;
+ if (f == null || (b = o.toCompletableFuture()) == null)
+ throw new NullPointerException();
+ CompletableFuture<Void> d = new CompletableFuture<Void>();
+ if (e != null || !d.biAccept(this, b, f, null)) {
+ BiAccept<T,U> c = new BiAccept<T,U>(e, d, this, b, f);
+ bipush(b, c);
+ c.tryFire(SYNC);
+ }
+ return d;
+ }
+
+ @SuppressWarnings("serial")
+ static final class BiRun<T,U> extends BiCompletion<T,U,Void> {
+ Runnable fn;
+ BiRun(Executor executor, CompletableFuture<Void> dep,
+ CompletableFuture<T> src,
+ CompletableFuture<U> snd,
+ Runnable fn) {
+ super(executor, dep, src, snd); this.fn = fn;
+ }
+ final CompletableFuture<Void> tryFire(int mode) {
+ CompletableFuture<Void> d;
+ CompletableFuture<T> a;
+ CompletableFuture<U> b;
+ if ((d = dep) == null ||
+ !d.biRun(a = src, b = snd, fn, mode > 0 ? null : this))
+ return null;
+ dep = null; src = null; snd = null; fn = null;
+ return d.postFire(a, b, mode);
+ }
+ }
+
+ final boolean biRun(CompletableFuture<?> a, CompletableFuture<?> b,
+ Runnable f, BiRun<?,?> c) {
+ Object r, s; Throwable x;
+ if (a == null || (r = a.result) == null ||
+ b == null || (s = b.result) == null || f == null)
+ return false;
+ if (result == null) {
+ if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
+ completeThrowable(x, r);
+ else if (s instanceof AltResult && (x = ((AltResult)s).ex) != null)
+ completeThrowable(x, s);
+ else
+ try {
+ if (c != null && !c.claim())
+ return false;
+ f.run();
+ completeNull();
+ } catch (Throwable ex) {
+ completeThrowable(ex);
+ }
+ }
+ return true;
+ }
+
+ private CompletableFuture<Void> biRunStage(Executor e, CompletionStage<?> o,
+ Runnable f) {
+ CompletableFuture<?> b;
+ if (f == null || (b = o.toCompletableFuture()) == null)
+ throw new NullPointerException();
+ CompletableFuture<Void> d = new CompletableFuture<Void>();
+ if (e != null || !d.biRun(this, b, f, null)) {
+ BiRun<T,?> c = new BiRun<>(e, d, this, b, f);
+ bipush(b, c);
+ c.tryFire(SYNC);
+ }
+ return d;
+ }
+
+ @SuppressWarnings("serial")
+ static final class BiRelay<T,U> extends BiCompletion<T,U,Void> { // for And
+ BiRelay(CompletableFuture<Void> dep,
+ CompletableFuture<T> src,
+ CompletableFuture<U> snd) {
+ super(null, dep, src, snd);
+ }
+ final CompletableFuture<Void> tryFire(int mode) {
+ CompletableFuture<Void> d;
+ CompletableFuture<T> a;
+ CompletableFuture<U> b;
+ if ((d = dep) == null || !d.biRelay(a = src, b = snd))
+ return null;
+ src = null; snd = null; dep = null;
+ return d.postFire(a, b, mode);
+ }
+ }
+
+ boolean biRelay(CompletableFuture<?> a, CompletableFuture<?> b) {
+ Object r, s; Throwable x;
+ if (a == null || (r = a.result) == null ||
+ b == null || (s = b.result) == null)
+ return false;
+ if (result == null) {
+ if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
+ completeThrowable(x, r);
+ else if (s instanceof AltResult && (x = ((AltResult)s).ex) != null)
+ completeThrowable(x, s);
+ else
+ completeNull();
+ }
+ return true;
+ }
+
+ /** Recursively constructs a tree of completions. */
+ static CompletableFuture<Void> andTree(CompletableFuture<?>[] cfs,
+ int lo, int hi) {
+ CompletableFuture<Void> d = new CompletableFuture<Void>();
+ if (lo > hi) // empty
+ d.result = NIL;
+ else {
+ CompletableFuture<?> a, b;
+ int mid = (lo + hi) >>> 1;
+ if ((a = (lo == mid ? cfs[lo] :
+ andTree(cfs, lo, mid))) == null ||
+ (b = (lo == hi ? a : (hi == mid+1) ? cfs[hi] :
+ andTree(cfs, mid+1, hi))) == null)
+ throw new NullPointerException();
+ if (!d.biRelay(a, b)) {
+ BiRelay<?,?> c = new BiRelay<>(d, a, b);
+ a.bipush(b, c);
+ c.tryFire(SYNC);
+ }
+ }
+ return d;
+ }
+
+ /* ------------- Projected (Ored) BiCompletions -------------- */
+
+ /** Pushes completion to this and b unless either done. */
+ final void orpush(CompletableFuture<?> b, BiCompletion<?,?,?> c) {
+ if (c != null) {
+ while ((b == null || b.result == null) && result == null) {
+ if (tryPushStack(c)) {
+ if (b != null && b != this && b.result == null) {
+ Completion q = new CoCompletion(c);
+ while (result == null && b.result == null &&
+ !b.tryPushStack(q))
+ lazySetNext(q, null); // clear on failure
+ }
+ break;
+ }
+ lazySetNext(c, null); // clear on failure
+ }
+ }
+ }
+
+ @SuppressWarnings("serial")
+ static final class OrApply<T,U extends T,V> extends BiCompletion<T,U,V> {
+ Function<? super T,? extends V> fn;
+ OrApply(Executor executor, CompletableFuture<V> dep,
+ CompletableFuture<T> src,
+ CompletableFuture<U> snd,
+ Function<? super T,? extends V> fn) {
+ super(executor, dep, src, snd); this.fn = fn;
+ }
+ final CompletableFuture<V> tryFire(int mode) {
+ CompletableFuture<V> d;
+ CompletableFuture<T> a;
+ CompletableFuture<U> b;
+ if ((d = dep) == null ||
+ !d.orApply(a = src, b = snd, fn, mode > 0 ? null : this))
+ return null;
+ dep = null; src = null; snd = null; fn = null;
+ return d.postFire(a, b, mode);
+ }
+ }
+
+ final <R,S extends R> boolean orApply(CompletableFuture<R> a,
+ CompletableFuture<S> b,
+ Function<? super R, ? extends T> f,
+ OrApply<R,S,T> c) {
+ Object r; Throwable x;
+ if (a == null || b == null ||
+ ((r = a.result) == null && (r = b.result) == null) || f == null)
+ return false;
+ tryComplete: if (result == null) {
+ try {
+ if (c != null && !c.claim())
+ return false;
+ if (r instanceof AltResult) {
+ if ((x = ((AltResult)r).ex) != null) {
+ completeThrowable(x, r);
+ break tryComplete;
+ }
+ r = null;
+ }
+ @SuppressWarnings("unchecked") R rr = (R) r;
+ completeValue(f.apply(rr));
+ } catch (Throwable ex) {
+ completeThrowable(ex);
+ }
+ }
+ return true;
+ }
+
+ private <U extends T,V> CompletableFuture<V> orApplyStage(
+ Executor e, CompletionStage<U> o,
+ Function<? super T, ? extends V> f) {
+ CompletableFuture<U> b;
+ if (f == null || (b = o.toCompletableFuture()) == null)
+ throw new NullPointerException();
+ CompletableFuture<V> d = new CompletableFuture<V>();
+ if (e != null || !d.orApply(this, b, f, null)) {
+ OrApply<T,U,V> c = new OrApply<T,U,V>(e, d, this, b, f);
+ orpush(b, c);
+ c.tryFire(SYNC);
+ }
+ return d;
+ }
+
+ @SuppressWarnings("serial")
+ static final class OrAccept<T,U extends T> extends BiCompletion<T,U,Void> {
+ Consumer<? super T> fn;
+ OrAccept(Executor executor, CompletableFuture<Void> dep,
+ CompletableFuture<T> src,
+ CompletableFuture<U> snd,
+ Consumer<? super T> fn) {
+ super(executor, dep, src, snd); this.fn = fn;
+ }
+ final CompletableFuture<Void> tryFire(int mode) {
+ CompletableFuture<Void> d;
+ CompletableFuture<T> a;
+ CompletableFuture<U> b;
+ if ((d = dep) == null ||
+ !d.orAccept(a = src, b = snd, fn, mode > 0 ? null : this))
+ return null;
+ dep = null; src = null; snd = null; fn = null;
+ return d.postFire(a, b, mode);
+ }
+ }
+
+ final <R,S extends R> boolean orAccept(CompletableFuture<R> a,
+ CompletableFuture<S> b,
+ Consumer<? super R> f,
+ OrAccept<R,S> c) {
+ Object r; Throwable x;
+ if (a == null || b == null ||
+ ((r = a.result) == null && (r = b.result) == null) || f == null)
+ return false;
+ tryComplete: if (result == null) {
+ try {
+ if (c != null && !c.claim())
+ return false;
+ if (r instanceof AltResult) {
+ if ((x = ((AltResult)r).ex) != null) {
+ completeThrowable(x, r);
+ break tryComplete;
+ }
+ r = null;
+ }
+ @SuppressWarnings("unchecked") R rr = (R) r;
+ f.accept(rr);
+ completeNull();
+ } catch (Throwable ex) {
+ completeThrowable(ex);
+ }
+ }
+ return true;
+ }
+
+ private <U extends T> CompletableFuture<Void> orAcceptStage(
+ Executor e, CompletionStage<U> o, Consumer<? super T> f) {
+ CompletableFuture<U> b;
+ if (f == null || (b = o.toCompletableFuture()) == null)
+ throw new NullPointerException();
+ CompletableFuture<Void> d = new CompletableFuture<Void>();
+ if (e != null || !d.orAccept(this, b, f, null)) {
+ OrAccept<T,U> c = new OrAccept<T,U>(e, d, this, b, f);
+ orpush(b, c);
+ c.tryFire(SYNC);
+ }
+ return d;
+ }
+
+ @SuppressWarnings("serial")
+ static final class OrRun<T,U> extends BiCompletion<T,U,Void> {
+ Runnable fn;
+ OrRun(Executor executor, CompletableFuture<Void> dep,
+ CompletableFuture<T> src,
+ CompletableFuture<U> snd,
+ Runnable fn) {
+ super(executor, dep, src, snd); this.fn = fn;
+ }
+ final CompletableFuture<Void> tryFire(int mode) {
+ CompletableFuture<Void> d;
+ CompletableFuture<T> a;
+ CompletableFuture<U> b;
+ if ((d = dep) == null ||
+ !d.orRun(a = src, b = snd, fn, mode > 0 ? null : this))
+ return null;
+ dep = null; src = null; snd = null; fn = null;
+ return d.postFire(a, b, mode);
+ }
+ }
+
+ final boolean orRun(CompletableFuture<?> a, CompletableFuture<?> b,
+ Runnable f, OrRun<?,?> c) {
+ Object r; Throwable x;
+ if (a == null || b == null ||
+ ((r = a.result) == null && (r = b.result) == null) || f == null)
+ return false;
+ if (result == null) {
+ try {
+ if (c != null && !c.claim())
+ return false;
+ if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
+ completeThrowable(x, r);
+ else {
+ f.run();
+ completeNull();
+ }
+ } catch (Throwable ex) {
+ completeThrowable(ex);
+ }
+ }
+ return true;
+ }
+
+ private CompletableFuture<Void> orRunStage(Executor e, CompletionStage<?> o,
+ Runnable f) {
+ CompletableFuture<?> b;
+ if (f == null || (b = o.toCompletableFuture()) == null)
+ throw new NullPointerException();
+ CompletableFuture<Void> d = new CompletableFuture<Void>();
+ if (e != null || !d.orRun(this, b, f, null)) {
+ OrRun<T,?> c = new OrRun<>(e, d, this, b, f);
+ orpush(b, c);
+ c.tryFire(SYNC);
+ }
+ return d;
+ }
+
+ @SuppressWarnings("serial")
+ static final class OrRelay<T,U> extends BiCompletion<T,U,Object> { // for Or
+ OrRelay(CompletableFuture<Object> dep, CompletableFuture<T> src,
+ CompletableFuture<U> snd) {
+ super(null, dep, src, snd);
+ }
+ final CompletableFuture<Object> tryFire(int mode) {
+ CompletableFuture<Object> d;
+ CompletableFuture<T> a;
+ CompletableFuture<U> b;
+ if ((d = dep) == null || !d.orRelay(a = src, b = snd))
+ return null;
+ src = null; snd = null; dep = null;
+ return d.postFire(a, b, mode);
+ }
+ }
+
+ final boolean orRelay(CompletableFuture<?> a, CompletableFuture<?> b) {
+ Object r;
+ if (a == null || b == null ||
+ ((r = a.result) == null && (r = b.result) == null))
+ return false;
if (result == null)
- UNSAFE.compareAndSwapObject
- (this, RESULT, null,
- (ex == null) ? (v == null) ? NIL : v :
- new AltResult((ex instanceof CompletionException) ? ex :
- new CompletionException(ex)));
- postComplete(); // help out even if not triggered
+ completeRelay(r);
+ return true;
}
- /**
- * If triggered, helps release and/or process completions.
- */
- final void helpPostComplete() {
- if (result != null)
- postComplete();
+ /** Recursively constructs a tree of completions. */
+ static CompletableFuture<Object> orTree(CompletableFuture<?>[] cfs,
+ int lo, int hi) {
+ CompletableFuture<Object> d = new CompletableFuture<Object>();
+ if (lo <= hi) {
+ CompletableFuture<?> a, b;
+ int mid = (lo + hi) >>> 1;
+ if ((a = (lo == mid ? cfs[lo] :
+ orTree(cfs, lo, mid))) == null ||
+ (b = (lo == hi ? a : (hi == mid+1) ? cfs[hi] :
+ orTree(cfs, mid+1, hi))) == null)
+ throw new NullPointerException();
+ if (!d.orRelay(a, b)) {
+ OrRelay<?,?> c = new OrRelay<>(d, a, b);
+ a.orpush(b, c);
+ c.tryFire(SYNC);
+ }
+ }
+ return d;
}
- /* ------------- waiting for completions -------------- */
+ /* ------------- Zero-input Async forms -------------- */
- /** Number of processors, for spin control */
- static final int NCPU = Runtime.getRuntime().availableProcessors();
+ @SuppressWarnings("serial")
+ static final class AsyncSupply<T> extends ForkJoinTask<Void>
+ implements Runnable, AsynchronousCompletionTask {
+ CompletableFuture<T> dep; Supplier<T> fn;
+ AsyncSupply(CompletableFuture<T> dep, Supplier<T> fn) {
+ this.dep = dep; this.fn = fn;
+ }
+
+ public final Void getRawResult() { return null; }
+ public final void setRawResult(Void v) {}
+ public final boolean exec() { run(); return true; }
+
+ public void run() {
+ CompletableFuture<T> d; Supplier<T> f;
+ if ((d = dep) != null && (f = fn) != null) {
+ dep = null; fn = null;
+ if (d.result == null) {
+ try {
+ d.completeValue(f.get());
+ } catch (Throwable ex) {
+ d.completeThrowable(ex);
+ }
+ }
+ d.postComplete();
+ }
+ }
+ }
+
+ static <U> CompletableFuture<U> asyncSupplyStage(Executor e,
+ Supplier<U> f) {
+ if (f == null) throw new NullPointerException();
+ CompletableFuture<U> d = new CompletableFuture<U>();
+ e.execute(new AsyncSupply<U>(d, f));
+ return d;
+ }
+
+ @SuppressWarnings("serial")
+ static final class AsyncRun extends ForkJoinTask<Void>
+ implements Runnable, AsynchronousCompletionTask {
+ CompletableFuture<Void> dep; Runnable fn;
+ AsyncRun(CompletableFuture<Void> dep, Runnable fn) {
+ this.dep = dep; this.fn = fn;
+ }
+
+ public final Void getRawResult() { return null; }
+ public final void setRawResult(Void v) {}
+ public final boolean exec() { run(); return true; }
+
+ public void run() {
+ CompletableFuture<Void> d; Runnable f;
+ if ((d = dep) != null && (f = fn) != null) {
+ dep = null; fn = null;
+ if (d.result == null) {
+ try {
+ f.run();
+ d.completeNull();
+ } catch (Throwable ex) {
+ d.completeThrowable(ex);
+ }
+ }
+ d.postComplete();
+ }
+ }
+ }
+
+ static CompletableFuture<Void> asyncRunStage(Executor e, Runnable f) {
+ if (f == null) throw new NullPointerException();
+ CompletableFuture<Void> d = new CompletableFuture<Void>();
+ e.execute(new AsyncRun(d, f));
+ return d;
+ }
+
+ /* ------------- Signallers -------------- */
/**
- * Heuristic spin value for waitingGet() before blocking on
- * multiprocessors
+ * Completion for recording and releasing a waiting thread. This
+ * class implements ManagedBlocker to avoid starvation when
+ * blocking actions pile up in ForkJoinPools.
*/
- static final int SPINS = (NCPU > 1) ? 1 << 8 : 0;
-
- /**
- * Linked nodes to record waiting threads in a Treiber stack. See
- * other classes such as Phaser and SynchronousQueue for more
- * detailed explanation. This class implements ManagedBlocker to
- * avoid starvation when blocking actions pile up in
- * ForkJoinPools.
- */
- static final class WaitNode implements ForkJoinPool.ManagedBlocker {
- long nanos; // wait time if timed
- final long deadline; // non-zero if timed
+ @SuppressWarnings("serial")
+ static final class Signaller extends Completion
+ implements ForkJoinPool.ManagedBlocker {
+ long nanos; // wait time if timed
+ final long deadline; // non-zero if timed
volatile int interruptControl; // > 0: interruptible, < 0: interrupted
volatile Thread thread;
- volatile WaitNode next;
- WaitNode(boolean interruptible, long nanos, long deadline) {
+
+ Signaller(boolean interruptible, long nanos, long deadline) {
this.thread = Thread.currentThread();
this.interruptControl = interruptible ? 1 : 0;
this.nanos = nanos;
this.deadline = deadline;
}
+ final CompletableFuture<?> tryFire(int ignore) {
+ Thread w; // no need to atomically claim
+ if ((w = thread) != null) {
+ thread = null;
+ LockSupport.unpark(w);
+ }
+ return null;
+ }
public boolean isReleasable() {
if (thread == null)
return true;
@@ -273,6 +1687,7 @@
LockSupport.parkNanos(this, nanos);
return isReleasable();
}
+ final boolean isLive() { return thread != null; }
}
/**
@@ -280,1832 +1695,89 @@
* interrupted.
*/
private Object waitingGet(boolean interruptible) {
- WaitNode q = null;
+ Signaller q = null;
boolean queued = false;
- int spins = SPINS;
- for (Object r;;) {
- if ((r = result) != null) {
- if (q != null) { // suppress unpark
- q.thread = null;
- if (q.interruptControl < 0) {
- if (interruptible) {
- removeWaiter(q);
- return null;
- }
- Thread.currentThread().interrupt();
- }
- }
- postComplete(); // help release others
- return r;
- }
+ int spins = -1;
+ Object r;
+ while ((r = result) == null) {
+ if (spins < 0)
+ spins = (Runtime.getRuntime().availableProcessors() > 1) ?
+ 1 << 8 : 0; // Use brief spin-wait on multiprocessors
else if (spins > 0) {
- int rnd = ThreadLocalRandom.nextSecondarySeed();
- if (rnd == 0)
- rnd = ThreadLocalRandom.current().nextInt();
- if (rnd >= 0)
+ if (ThreadLocalRandom.nextSecondarySeed() >= 0)
--spins;
}
else if (q == null)
- q = new WaitNode(interruptible, 0L, 0L);
+ q = new Signaller(interruptible, 0L, 0L);
else if (!queued)
- queued = UNSAFE.compareAndSwapObject(this, WAITERS,
- q.next = waiters, q);
+ queued = tryPushStack(q);
else if (interruptible && q.interruptControl < 0) {
- removeWaiter(q);
+ q.thread = null;
+ cleanStack();
return null;
}
else if (q.thread != null && result == null) {
try {
ForkJoinPool.managedBlock(q);
- } catch (InterruptedException ex) {
+ } catch (InterruptedException ie) {
q.interruptControl = -1;
}
}
}
+ if (q != null) {
+ q.thread = null;
+ if (q.interruptControl < 0) {
+ if (interruptible)
+ r = null; // report interruption
+ else
+ Thread.currentThread().interrupt();
+ }
+ }
+ postComplete();
+ return r;
}
/**
- * Awaits completion or aborts on interrupt or timeout.
- *
- * @param nanos time to wait
- * @return raw result
+ * Returns raw result after waiting, or null if interrupted, or
+ * throws TimeoutException on timeout.
*/
- private Object timedAwaitDone(long nanos)
- throws InterruptedException, TimeoutException {
- WaitNode q = null;
+ private Object timedGet(long nanos) throws TimeoutException {
+ if (Thread.interrupted())
+ return null;
+ if (nanos <= 0L)
+ throw new TimeoutException();
+ long d = System.nanoTime() + nanos;
+ Signaller q = new Signaller(true, nanos, d == 0L ? 1L : d); // avoid 0
boolean queued = false;
- for (Object r;;) {
- if ((r = result) != null) {
- if (q != null) {
- q.thread = null;
- if (q.interruptControl < 0) {
- removeWaiter(q);
- throw new InterruptedException();
- }
- }
- postComplete();
- return r;
- }
- else if (q == null) {
- if (nanos <= 0L)
- throw new TimeoutException();
- long d = System.nanoTime() + nanos;
- q = new WaitNode(true, nanos, d == 0L ? 1L : d); // avoid 0
- }
- else if (!queued)
- queued = UNSAFE.compareAndSwapObject(this, WAITERS,
- q.next = waiters, q);
- else if (q.interruptControl < 0) {
- removeWaiter(q);
- throw new InterruptedException();
- }
- else if (q.nanos <= 0L) {
- if (result == null) {
- removeWaiter(q);
- throw new TimeoutException();
- }
+ Object r;
+ // We intentionally don't spin here (as waitingGet does) because
+ // the call to nanoTime() above acts much like a spin.
+ while ((r = result) == null) {
+ if (!queued)
+ queued = tryPushStack(q);
+ else if (q.interruptControl < 0 || q.nanos <= 0L) {
+ q.thread = null;
+ cleanStack();
+ if (q.interruptControl < 0)
+ return null;
+ throw new TimeoutException();
}
else if (q.thread != null && result == null) {
try {
ForkJoinPool.managedBlock(q);
- } catch (InterruptedException ex) {
+ } catch (InterruptedException ie) {
q.interruptControl = -1;
}
}
}
+ if (q.interruptControl < 0)
+ r = null;
+ q.thread = null;
+ postComplete();
+ return r;
}
- /**
- * Tries to unlink a timed-out or interrupted wait node to avoid
- * accumulating garbage. Internal nodes are simply unspliced
- * without CAS since it is harmless if they are traversed anyway
- * by releasers. To avoid effects of unsplicing from already
- * removed nodes, the list is retraversed in case of an apparent
- * race. This is slow when there are a lot of nodes, but we don't
- * expect lists to be long enough to outweigh higher-overhead
- * schemes.
- */
- private void removeWaiter(WaitNode node) {
- if (node != null) {
- node.thread = null;
- retry:
- for (;;) { // restart on removeWaiter race
- for (WaitNode pred = null, q = waiters, s; q != null; q = s) {
- s = q.next;
- if (q.thread != null)
- pred = q;
- else if (pred != null) {
- pred.next = s;
- if (pred.thread == null) // check for race
- continue retry;
- }
- else if (!UNSAFE.compareAndSwapObject(this, WAITERS, q, s))
- continue retry;
- }
- break;
- }
- }
- }
-
- /* ------------- Async tasks -------------- */
-
- /**
- * A marker interface identifying asynchronous tasks produced by
- * {@code async} methods. This may be useful for monitoring,
- * debugging, and tracking asynchronous activities.
- *
- * @since 1.8
- */
- public static interface AsynchronousCompletionTask {
- }
-
- /** Base class can act as either FJ or plain Runnable */
- @SuppressWarnings("serial")
- abstract static class Async extends ForkJoinTask<Void>
- implements Runnable, AsynchronousCompletionTask {
- public final Void getRawResult() { return null; }
- public final void setRawResult(Void v) { }
- public final void run() { exec(); }
- }
-
- /**
- * Starts the given async task using the given executor, unless
- * the executor is ForkJoinPool.commonPool and it has been
- * disabled, in which case starts a new thread.
- */
- static void execAsync(Executor e, Async r) {
- if (e == ForkJoinPool.commonPool() &&
- ForkJoinPool.getCommonPoolParallelism() <= 1)
- new Thread(r).start();
- else
- e.execute(r);
- }
-
- static final class AsyncRun extends Async {
- final Runnable fn;
- final CompletableFuture<Void> dst;
- AsyncRun(Runnable fn, CompletableFuture<Void> dst) {
- this.fn = fn; this.dst = dst;
- }
- public final boolean exec() {
- CompletableFuture<Void> d; Throwable ex;
- if ((d = this.dst) != null && d.result == null) {
- try {
- fn.run();
- ex = null;
- } catch (Throwable rex) {
- ex = rex;
- }
- d.internalComplete(null, ex);
- }
- return true;
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class AsyncSupply<U> extends Async {
- final Supplier<U> fn;
- final CompletableFuture<U> dst;
- AsyncSupply(Supplier<U> fn, CompletableFuture<U> dst) {
- this.fn = fn; this.dst = dst;
- }
- public final boolean exec() {
- CompletableFuture<U> d; U u; Throwable ex;
- if ((d = this.dst) != null && d.result == null) {
- try {
- u = fn.get();
- ex = null;
- } catch (Throwable rex) {
- ex = rex;
- u = null;
- }
- d.internalComplete(u, ex);
- }
- return true;
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class AsyncApply<T,U> extends Async {
- final T arg;
- final Function<? super T,? extends U> fn;
- final CompletableFuture<U> dst;
- AsyncApply(T arg, Function<? super T,? extends U> fn,
- CompletableFuture<U> dst) {
- this.arg = arg; this.fn = fn; this.dst = dst;
- }
- public final boolean exec() {
- CompletableFuture<U> d; U u; Throwable ex;
- if ((d = this.dst) != null && d.result == null) {
- try {
- u = fn.apply(arg);
- ex = null;
- } catch (Throwable rex) {
- ex = rex;
- u = null;
- }
- d.internalComplete(u, ex);
- }
- return true;
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class AsyncCombine<T,U,V> extends Async {
- final T arg1;
- final U arg2;
- final BiFunction<? super T,? super U,? extends V> fn;
- final CompletableFuture<V> dst;
- AsyncCombine(T arg1, U arg2,
- BiFunction<? super T,? super U,? extends V> fn,
- CompletableFuture<V> dst) {
- this.arg1 = arg1; this.arg2 = arg2; this.fn = fn; this.dst = dst;
- }
- public final boolean exec() {
- CompletableFuture<V> d; V v; Throwable ex;
- if ((d = this.dst) != null && d.result == null) {
- try {
- v = fn.apply(arg1, arg2);
- ex = null;
- } catch (Throwable rex) {
- ex = rex;
- v = null;
- }
- d.internalComplete(v, ex);
- }
- return true;
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class AsyncAccept<T> extends Async {
- final T arg;
- final Consumer<? super T> fn;
- final CompletableFuture<?> dst;
- AsyncAccept(T arg, Consumer<? super T> fn,
- CompletableFuture<?> dst) {
- this.arg = arg; this.fn = fn; this.dst = dst;
- }
- public final boolean exec() {
- CompletableFuture<?> d; Throwable ex;
- if ((d = this.dst) != null && d.result == null) {
- try {
- fn.accept(arg);
- ex = null;
- } catch (Throwable rex) {
- ex = rex;
- }
- d.internalComplete(null, ex);
- }
- return true;
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class AsyncAcceptBoth<T,U> extends Async {
- final T arg1;
- final U arg2;
- final BiConsumer<? super T,? super U> fn;
- final CompletableFuture<?> dst;
- AsyncAcceptBoth(T arg1, U arg2,
- BiConsumer<? super T,? super U> fn,
- CompletableFuture<?> dst) {
- this.arg1 = arg1; this.arg2 = arg2; this.fn = fn; this.dst = dst;
- }
- public final boolean exec() {
- CompletableFuture<?> d; Throwable ex;
- if ((d = this.dst) != null && d.result == null) {
- try {
- fn.accept(arg1, arg2);
- ex = null;
- } catch (Throwable rex) {
- ex = rex;
- }
- d.internalComplete(null, ex);
- }
- return true;
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class AsyncCompose<T,U> extends Async {
- final T arg;
- final Function<? super T, ? extends CompletionStage<U>> fn;
- final CompletableFuture<U> dst;
- AsyncCompose(T arg,
- Function<? super T, ? extends CompletionStage<U>> fn,
- CompletableFuture<U> dst) {
- this.arg = arg; this.fn = fn; this.dst = dst;
- }
- public final boolean exec() {
- CompletableFuture<U> d, fr; U u; Throwable ex;
- if ((d = this.dst) != null && d.result == null) {
- try {
- CompletionStage<U> cs = fn.apply(arg);
- fr = (cs == null) ? null : cs.toCompletableFuture();
- ex = (fr == null) ? new NullPointerException() : null;
- } catch (Throwable rex) {
- ex = rex;
- fr = null;
- }
- if (ex != null)
- u = null;
- else {
- Object r = fr.result;
- if (r == null)
- r = fr.waitingGet(false);
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- u = null;
- }
- else {
- @SuppressWarnings("unchecked") U ur = (U) r;
- u = ur;
- }
- }
- d.internalComplete(u, ex);
- }
- return true;
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class AsyncWhenComplete<T> extends Async {
- final T arg1;
- final Throwable arg2;
- final BiConsumer<? super T,? super Throwable> fn;
- final CompletableFuture<T> dst;
- AsyncWhenComplete(T arg1, Throwable arg2,
- BiConsumer<? super T,? super Throwable> fn,
- CompletableFuture<T> dst) {
- this.arg1 = arg1; this.arg2 = arg2; this.fn = fn; this.dst = dst;
- }
- public final boolean exec() {
- CompletableFuture<T> d;
- if ((d = this.dst) != null && d.result == null) {
- Throwable ex = arg2;
- try {
- fn.accept(arg1, ex);
- } catch (Throwable rex) {
- if (ex == null)
- ex = rex;
- }
- d.internalComplete(arg1, ex);
- }
- return true;
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- /* ------------- Completions -------------- */
-
- /**
- * Simple linked list nodes to record completions, used in
- * basically the same way as WaitNodes. (We separate nodes from
- * the Completions themselves mainly because for the And and Or
- * methods, the same Completion object resides in two lists.)
- */
- static final class CompletionNode {
- final Completion completion;
- volatile CompletionNode next;
- CompletionNode(Completion completion) { this.completion = completion; }
- }
-
- // Opportunistically subclass AtomicInteger to use compareAndSet to claim.
- @SuppressWarnings("serial")
- abstract static class Completion extends AtomicInteger implements Runnable {
- }
-
- static final class ThenApply<T,U> extends Completion {
- final CompletableFuture<? extends T> src;
- final Function<? super T,? extends U> fn;
- final CompletableFuture<U> dst;
- final Executor executor;
- ThenApply(CompletableFuture<? extends T> src,
- Function<? super T,? extends U> fn,
- CompletableFuture<U> dst,
- Executor executor) {
- this.src = src; this.fn = fn; this.dst = dst;
- this.executor = executor;
- }
- public final void run() {
- final CompletableFuture<? extends T> a;
- final Function<? super T,? extends U> fn;
- final CompletableFuture<U> dst;
- Object r; T t; Throwable ex;
- if ((dst = this.dst) != null &&
- (fn = this.fn) != null &&
- (a = this.src) != null &&
- (r = a.result) != null &&
- compareAndSet(0, 1)) {
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- Executor e = executor;
- U u = null;
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncApply<T,U>(t, fn, dst));
- else
- u = fn.apply(t);
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(u, ex);
- }
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class ThenAccept<T> extends Completion {
- final CompletableFuture<? extends T> src;
- final Consumer<? super T> fn;
- final CompletableFuture<?> dst;
- final Executor executor;
- ThenAccept(CompletableFuture<? extends T> src,
- Consumer<? super T> fn,
- CompletableFuture<?> dst,
- Executor executor) {
- this.src = src; this.fn = fn; this.dst = dst;
- this.executor = executor;
- }
- public final void run() {
- final CompletableFuture<? extends T> a;
- final Consumer<? super T> fn;
- final CompletableFuture<?> dst;
- Object r; T t; Throwable ex;
- if ((dst = this.dst) != null &&
- (fn = this.fn) != null &&
- (a = this.src) != null &&
- (r = a.result) != null &&
- compareAndSet(0, 1)) {
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- Executor e = executor;
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncAccept<T>(t, fn, dst));
- else
- fn.accept(t);
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(null, ex);
- }
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class ThenRun extends Completion {
- final CompletableFuture<?> src;
- final Runnable fn;
- final CompletableFuture<Void> dst;
- final Executor executor;
- ThenRun(CompletableFuture<?> src,
- Runnable fn,
- CompletableFuture<Void> dst,
- Executor executor) {
- this.src = src; this.fn = fn; this.dst = dst;
- this.executor = executor;
- }
- public final void run() {
- final CompletableFuture<?> a;
- final Runnable fn;
- final CompletableFuture<Void> dst;
- Object r; Throwable ex;
- if ((dst = this.dst) != null &&
- (fn = this.fn) != null &&
- (a = this.src) != null &&
- (r = a.result) != null &&
- compareAndSet(0, 1)) {
- if (r instanceof AltResult)
- ex = ((AltResult)r).ex;
- else
- ex = null;
- Executor e = executor;
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncRun(fn, dst));
- else
- fn.run();
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(null, ex);
- }
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class ThenCombine<T,U,V> extends Completion {
- final CompletableFuture<? extends T> src;
- final CompletableFuture<? extends U> snd;
- final BiFunction<? super T,? super U,? extends V> fn;
- final CompletableFuture<V> dst;
- final Executor executor;
- ThenCombine(CompletableFuture<? extends T> src,
- CompletableFuture<? extends U> snd,
- BiFunction<? super T,? super U,? extends V> fn,
- CompletableFuture<V> dst,
- Executor executor) {
- this.src = src; this.snd = snd;
- this.fn = fn; this.dst = dst;
- this.executor = executor;
- }
- public final void run() {
- final CompletableFuture<? extends T> a;
- final CompletableFuture<? extends U> b;
- final BiFunction<? super T,? super U,? extends V> fn;
- final CompletableFuture<V> dst;
- Object r, s; T t; U u; Throwable ex;
- if ((dst = this.dst) != null &&
- (fn = this.fn) != null &&
- (a = this.src) != null &&
- (r = a.result) != null &&
- (b = this.snd) != null &&
- (s = b.result) != null &&
- compareAndSet(0, 1)) {
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- if (ex != null)
- u = null;
- else if (s instanceof AltResult) {
- ex = ((AltResult)s).ex;
- u = null;
- }
- else {
- @SuppressWarnings("unchecked") U us = (U) s;
- u = us;
- }
- Executor e = executor;
- V v = null;
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncCombine<T,U,V>(t, u, fn, dst));
- else
- v = fn.apply(t, u);
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(v, ex);
- }
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class ThenAcceptBoth<T,U> extends Completion {
- final CompletableFuture<? extends T> src;
- final CompletableFuture<? extends U> snd;
- final BiConsumer<? super T,? super U> fn;
- final CompletableFuture<Void> dst;
- final Executor executor;
- ThenAcceptBoth(CompletableFuture<? extends T> src,
- CompletableFuture<? extends U> snd,
- BiConsumer<? super T,? super U> fn,
- CompletableFuture<Void> dst,
- Executor executor) {
- this.src = src; this.snd = snd;
- this.fn = fn; this.dst = dst;
- this.executor = executor;
- }
- public final void run() {
- final CompletableFuture<? extends T> a;
- final CompletableFuture<? extends U> b;
- final BiConsumer<? super T,? super U> fn;
- final CompletableFuture<Void> dst;
- Object r, s; T t; U u; Throwable ex;
- if ((dst = this.dst) != null &&
- (fn = this.fn) != null &&
- (a = this.src) != null &&
- (r = a.result) != null &&
- (b = this.snd) != null &&
- (s = b.result) != null &&
- compareAndSet(0, 1)) {
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- if (ex != null)
- u = null;
- else if (s instanceof AltResult) {
- ex = ((AltResult)s).ex;
- u = null;
- }
- else {
- @SuppressWarnings("unchecked") U us = (U) s;
- u = us;
- }
- Executor e = executor;
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncAcceptBoth<T,U>(t, u, fn, dst));
- else
- fn.accept(t, u);
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(null, ex);
- }
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class RunAfterBoth extends Completion {
- final CompletableFuture<?> src;
- final CompletableFuture<?> snd;
- final Runnable fn;
- final CompletableFuture<Void> dst;
- final Executor executor;
- RunAfterBoth(CompletableFuture<?> src,
- CompletableFuture<?> snd,
- Runnable fn,
- CompletableFuture<Void> dst,
- Executor executor) {
- this.src = src; this.snd = snd;
- this.fn = fn; this.dst = dst;
- this.executor = executor;
- }
- public final void run() {
- final CompletableFuture<?> a;
- final CompletableFuture<?> b;
- final Runnable fn;
- final CompletableFuture<Void> dst;
- Object r, s; Throwable ex;
- if ((dst = this.dst) != null &&
- (fn = this.fn) != null &&
- (a = this.src) != null &&
- (r = a.result) != null &&
- (b = this.snd) != null &&
- (s = b.result) != null &&
- compareAndSet(0, 1)) {
- if (r instanceof AltResult)
- ex = ((AltResult)r).ex;
- else
- ex = null;
- if (ex == null && (s instanceof AltResult))
- ex = ((AltResult)s).ex;
- Executor e = executor;
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncRun(fn, dst));
- else
- fn.run();
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(null, ex);
- }
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class AndCompletion extends Completion {
- final CompletableFuture<?> src;
- final CompletableFuture<?> snd;
- final CompletableFuture<Void> dst;
- AndCompletion(CompletableFuture<?> src,
- CompletableFuture<?> snd,
- CompletableFuture<Void> dst) {
- this.src = src; this.snd = snd; this.dst = dst;
- }
- public final void run() {
- final CompletableFuture<?> a;
- final CompletableFuture<?> b;
- final CompletableFuture<Void> dst;
- Object r, s; Throwable ex;
- if ((dst = this.dst) != null &&
- (a = this.src) != null &&
- (r = a.result) != null &&
- (b = this.snd) != null &&
- (s = b.result) != null &&
- compareAndSet(0, 1)) {
- if (r instanceof AltResult)
- ex = ((AltResult)r).ex;
- else
- ex = null;
- if (ex == null && (s instanceof AltResult))
- ex = ((AltResult)s).ex;
- dst.internalComplete(null, ex);
- }
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class ApplyToEither<T,U> extends Completion {
- final CompletableFuture<? extends T> src;
- final CompletableFuture<? extends T> snd;
- final Function<? super T,? extends U> fn;
- final CompletableFuture<U> dst;
- final Executor executor;
- ApplyToEither(CompletableFuture<? extends T> src,
- CompletableFuture<? extends T> snd,
- Function<? super T,? extends U> fn,
- CompletableFuture<U> dst,
- Executor executor) {
- this.src = src; this.snd = snd;
- this.fn = fn; this.dst = dst;
- this.executor = executor;
- }
- public final void run() {
- final CompletableFuture<? extends T> a;
- final CompletableFuture<? extends T> b;
- final Function<? super T,? extends U> fn;
- final CompletableFuture<U> dst;
- Object r; T t; Throwable ex;
- if ((dst = this.dst) != null &&
- (fn = this.fn) != null &&
- (((a = this.src) != null && (r = a.result) != null) ||
- ((b = this.snd) != null && (r = b.result) != null)) &&
- compareAndSet(0, 1)) {
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- Executor e = executor;
- U u = null;
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncApply<T,U>(t, fn, dst));
- else
- u = fn.apply(t);
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(u, ex);
- }
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class AcceptEither<T> extends Completion {
- final CompletableFuture<? extends T> src;
- final CompletableFuture<? extends T> snd;
- final Consumer<? super T> fn;
- final CompletableFuture<Void> dst;
- final Executor executor;
- AcceptEither(CompletableFuture<? extends T> src,
- CompletableFuture<? extends T> snd,
- Consumer<? super T> fn,
- CompletableFuture<Void> dst,
- Executor executor) {
- this.src = src; this.snd = snd;
- this.fn = fn; this.dst = dst;
- this.executor = executor;
- }
- public final void run() {
- final CompletableFuture<? extends T> a;
- final CompletableFuture<? extends T> b;
- final Consumer<? super T> fn;
- final CompletableFuture<Void> dst;
- Object r; T t; Throwable ex;
- if ((dst = this.dst) != null &&
- (fn = this.fn) != null &&
- (((a = this.src) != null && (r = a.result) != null) ||
- ((b = this.snd) != null && (r = b.result) != null)) &&
- compareAndSet(0, 1)) {
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- Executor e = executor;
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncAccept<T>(t, fn, dst));
- else
- fn.accept(t);
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(null, ex);
- }
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class RunAfterEither extends Completion {
- final CompletableFuture<?> src;
- final CompletableFuture<?> snd;
- final Runnable fn;
- final CompletableFuture<Void> dst;
- final Executor executor;
- RunAfterEither(CompletableFuture<?> src,
- CompletableFuture<?> snd,
- Runnable fn,
- CompletableFuture<Void> dst,
- Executor executor) {
- this.src = src; this.snd = snd;
- this.fn = fn; this.dst = dst;
- this.executor = executor;
- }
- public final void run() {
- final CompletableFuture<?> a;
- final CompletableFuture<?> b;
- final Runnable fn;
- final CompletableFuture<Void> dst;
- Object r; Throwable ex;
- if ((dst = this.dst) != null &&
- (fn = this.fn) != null &&
- (((a = this.src) != null && (r = a.result) != null) ||
- ((b = this.snd) != null && (r = b.result) != null)) &&
- compareAndSet(0, 1)) {
- if (r instanceof AltResult)
- ex = ((AltResult)r).ex;
- else
- ex = null;
- Executor e = executor;
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncRun(fn, dst));
- else
- fn.run();
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(null, ex);
- }
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class OrCompletion extends Completion {
- final CompletableFuture<?> src;
- final CompletableFuture<?> snd;
- final CompletableFuture<Object> dst;
- OrCompletion(CompletableFuture<?> src,
- CompletableFuture<?> snd,
- CompletableFuture<Object> dst) {
- this.src = src; this.snd = snd; this.dst = dst;
- }
- public final void run() {
- final CompletableFuture<?> a;
- final CompletableFuture<?> b;
- final CompletableFuture<Object> dst;
- Object r, t; Throwable ex;
- if ((dst = this.dst) != null &&
- (((a = this.src) != null && (r = a.result) != null) ||
- ((b = this.snd) != null && (r = b.result) != null)) &&
- compareAndSet(0, 1)) {
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- t = r;
- }
- dst.internalComplete(t, ex);
- }
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class ExceptionCompletion<T> extends Completion {
- final CompletableFuture<? extends T> src;
- final Function<? super Throwable, ? extends T> fn;
- final CompletableFuture<T> dst;
- ExceptionCompletion(CompletableFuture<? extends T> src,
- Function<? super Throwable, ? extends T> fn,
- CompletableFuture<T> dst) {
- this.src = src; this.fn = fn; this.dst = dst;
- }
- public final void run() {
- final CompletableFuture<? extends T> a;
- final Function<? super Throwable, ? extends T> fn;
- final CompletableFuture<T> dst;
- Object r; T t = null; Throwable ex, dx = null;
- if ((dst = this.dst) != null &&
- (fn = this.fn) != null &&
- (a = this.src) != null &&
- (r = a.result) != null &&
- compareAndSet(0, 1)) {
- if ((r instanceof AltResult) &&
- (ex = ((AltResult)r).ex) != null) {
- try {
- t = fn.apply(ex);
- } catch (Throwable rex) {
- dx = rex;
- }
- }
- else {
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- dst.internalComplete(t, dx);
- }
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class WhenCompleteCompletion<T> extends Completion {
- final CompletableFuture<? extends T> src;
- final BiConsumer<? super T, ? super Throwable> fn;
- final CompletableFuture<T> dst;
- final Executor executor;
- WhenCompleteCompletion(CompletableFuture<? extends T> src,
- BiConsumer<? super T, ? super Throwable> fn,
- CompletableFuture<T> dst,
- Executor executor) {
- this.src = src; this.fn = fn; this.dst = dst;
- this.executor = executor;
- }
- public final void run() {
- final CompletableFuture<? extends T> a;
- final BiConsumer<? super T, ? super Throwable> fn;
- final CompletableFuture<T> dst;
- Object r; T t; Throwable ex;
- if ((dst = this.dst) != null &&
- (fn = this.fn) != null &&
- (a = this.src) != null &&
- (r = a.result) != null &&
- compareAndSet(0, 1)) {
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- Executor e = executor;
- Throwable dx = null;
- try {
- if (e != null)
- execAsync(e, new AsyncWhenComplete<T>(t, ex, fn, dst));
- else
- fn.accept(t, ex);
- } catch (Throwable rex) {
- dx = rex;
- }
- if (e == null || dx != null)
- dst.internalComplete(t, ex != null ? ex : dx);
- }
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class ThenCopy<T> extends Completion {
- final CompletableFuture<?> src;
- final CompletableFuture<T> dst;
- ThenCopy(CompletableFuture<?> src,
- CompletableFuture<T> dst) {
- this.src = src; this.dst = dst;
- }
- public final void run() {
- final CompletableFuture<?> a;
- final CompletableFuture<T> dst;
- Object r; T t; Throwable ex;
- if ((dst = this.dst) != null &&
- (a = this.src) != null &&
- (r = a.result) != null &&
- compareAndSet(0, 1)) {
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- dst.internalComplete(t, ex);
- }
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- // version of ThenCopy for CompletableFuture<Void> dst
- static final class ThenPropagate extends Completion {
- final CompletableFuture<?> src;
- final CompletableFuture<Void> dst;
- ThenPropagate(CompletableFuture<?> src,
- CompletableFuture<Void> dst) {
- this.src = src; this.dst = dst;
- }
- public final void run() {
- final CompletableFuture<?> a;
- final CompletableFuture<Void> dst;
- Object r; Throwable ex;
- if ((dst = this.dst) != null &&
- (a = this.src) != null &&
- (r = a.result) != null &&
- compareAndSet(0, 1)) {
- if (r instanceof AltResult)
- ex = ((AltResult)r).ex;
- else
- ex = null;
- dst.internalComplete(null, ex);
- }
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class HandleCompletion<T,U> extends Completion {
- final CompletableFuture<? extends T> src;
- final BiFunction<? super T, Throwable, ? extends U> fn;
- final CompletableFuture<U> dst;
- final Executor executor;
- HandleCompletion(CompletableFuture<? extends T> src,
- BiFunction<? super T, Throwable, ? extends U> fn,
- CompletableFuture<U> dst,
- Executor executor) {
- this.src = src; this.fn = fn; this.dst = dst;
- this.executor = executor;
- }
- public final void run() {
- final CompletableFuture<? extends T> a;
- final BiFunction<? super T, Throwable, ? extends U> fn;
- final CompletableFuture<U> dst;
- Object r; T t; Throwable ex;
- if ((dst = this.dst) != null &&
- (fn = this.fn) != null &&
- (a = this.src) != null &&
- (r = a.result) != null &&
- compareAndSet(0, 1)) {
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- Executor e = executor;
- U u = null;
- Throwable dx = null;
- try {
- if (e != null)
- execAsync(e, new AsyncCombine<T,Throwable,U>(t, ex, fn, dst));
- else
- u = fn.apply(t, ex);
- } catch (Throwable rex) {
- dx = rex;
- }
- if (e == null || dx != null)
- dst.internalComplete(u, dx);
- }
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- static final class ThenCompose<T,U> extends Completion {
- final CompletableFuture<? extends T> src;
- final Function<? super T, ? extends CompletionStage<U>> fn;
- final CompletableFuture<U> dst;
- final Executor executor;
- ThenCompose(CompletableFuture<? extends T> src,
- Function<? super T, ? extends CompletionStage<U>> fn,
- CompletableFuture<U> dst,
- Executor executor) {
- this.src = src; this.fn = fn; this.dst = dst;
- this.executor = executor;
- }
- public final void run() {
- final CompletableFuture<? extends T> a;
- final Function<? super T, ? extends CompletionStage<U>> fn;
- final CompletableFuture<U> dst;
- Object r; T t; Throwable ex; Executor e;
- if ((dst = this.dst) != null &&
- (fn = this.fn) != null &&
- (a = this.src) != null &&
- (r = a.result) != null &&
- compareAndSet(0, 1)) {
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- CompletableFuture<U> c = null;
- U u = null;
- boolean complete = false;
- if (ex == null) {
- if ((e = executor) != null)
- execAsync(e, new AsyncCompose<T,U>(t, fn, dst));
- else {
- try {
- CompletionStage<U> cs = fn.apply(t);
- c = (cs == null) ? null : cs.toCompletableFuture();
- if (c == null)
- ex = new NullPointerException();
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- }
- if (c != null) {
- ThenCopy<U> d = null;
- Object s;
- if ((s = c.result) == null) {
- CompletionNode p = new CompletionNode
- (d = new ThenCopy<U>(c, dst));
- while ((s = c.result) == null) {
- if (UNSAFE.compareAndSwapObject
- (c, COMPLETIONS, p.next = c.completions, p))
- break;
- }
- }
- if (s != null && (d == null || d.compareAndSet(0, 1))) {
- complete = true;
- if (s instanceof AltResult) {
- ex = ((AltResult)s).ex; // no rewrap
- u = null;
- }
- else {
- @SuppressWarnings("unchecked") U us = (U) s;
- u = us;
- }
- }
- }
- if (complete || ex != null)
- dst.internalComplete(u, ex);
- if (c != null)
- c.helpPostComplete();
- }
- }
- private static final long serialVersionUID = 5232453952276885070L;
- }
-
- // Implementations of stage methods with (plain, async, Executor) forms
-
- private <U> CompletableFuture<U> doThenApply
- (Function<? super T,? extends U> fn,
- Executor e) {
- if (fn == null) throw new NullPointerException();
- CompletableFuture<U> dst = new CompletableFuture<U>();
- ThenApply<T,U> d = null;
- Object r;
- if ((r = result) == null) {
- CompletionNode p = new CompletionNode
- (d = new ThenApply<T,U>(this, fn, dst, e));
- while ((r = result) == null) {
- if (UNSAFE.compareAndSwapObject
- (this, COMPLETIONS, p.next = completions, p))
- break;
- }
- }
- if (r != null && (d == null || d.compareAndSet(0, 1))) {
- T t; Throwable ex;
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- U u = null;
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncApply<T,U>(t, fn, dst));
- else
- u = fn.apply(t);
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(u, ex);
- }
- helpPostComplete();
- return dst;
- }
-
- private CompletableFuture<Void> doThenAccept(Consumer<? super T> fn,
- Executor e) {
- if (fn == null) throw new NullPointerException();
- CompletableFuture<Void> dst = new CompletableFuture<Void>();
- ThenAccept<T> d = null;
- Object r;
- if ((r = result) == null) {
- CompletionNode p = new CompletionNode
- (d = new ThenAccept<T>(this, fn, dst, e));
- while ((r = result) == null) {
- if (UNSAFE.compareAndSwapObject
- (this, COMPLETIONS, p.next = completions, p))
- break;
- }
- }
- if (r != null && (d == null || d.compareAndSet(0, 1))) {
- T t; Throwable ex;
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncAccept<T>(t, fn, dst));
- else
- fn.accept(t);
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(null, ex);
- }
- helpPostComplete();
- return dst;
- }
-
- private CompletableFuture<Void> doThenRun(Runnable action,
- Executor e) {
- if (action == null) throw new NullPointerException();
- CompletableFuture<Void> dst = new CompletableFuture<Void>();
- ThenRun d = null;
- Object r;
- if ((r = result) == null) {
- CompletionNode p = new CompletionNode
- (d = new ThenRun(this, action, dst, e));
- while ((r = result) == null) {
- if (UNSAFE.compareAndSwapObject
- (this, COMPLETIONS, p.next = completions, p))
- break;
- }
- }
- if (r != null && (d == null || d.compareAndSet(0, 1))) {
- Throwable ex;
- if (r instanceof AltResult)
- ex = ((AltResult)r).ex;
- else
- ex = null;
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncRun(action, dst));
- else
- action.run();
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(null, ex);
- }
- helpPostComplete();
- return dst;
- }
-
- private <U,V> CompletableFuture<V> doThenCombine
- (CompletableFuture<? extends U> other,
- BiFunction<? super T,? super U,? extends V> fn,
- Executor e) {
- if (other == null || fn == null) throw new NullPointerException();
- CompletableFuture<V> dst = new CompletableFuture<V>();
- ThenCombine<T,U,V> d = null;
- Object r, s = null;
- if ((r = result) == null || (s = other.result) == null) {
- d = new ThenCombine<T,U,V>(this, other, fn, dst, e);
- CompletionNode q = null, p = new CompletionNode(d);
- while ((r == null && (r = result) == null) ||
- (s == null && (s = other.result) == null)) {
- if (q != null) {
- if (s != null ||
- UNSAFE.compareAndSwapObject
- (other, COMPLETIONS, q.next = other.completions, q))
- break;
- }
- else if (r != null ||
- UNSAFE.compareAndSwapObject
- (this, COMPLETIONS, p.next = completions, p)) {
- if (s != null)
- break;
- q = new CompletionNode(d);
- }
- }
- }
- if (r != null && s != null && (d == null || d.compareAndSet(0, 1))) {
- T t; U u; Throwable ex;
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- if (ex != null)
- u = null;
- else if (s instanceof AltResult) {
- ex = ((AltResult)s).ex;
- u = null;
- }
- else {
- @SuppressWarnings("unchecked") U us = (U) s;
- u = us;
- }
- V v = null;
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncCombine<T,U,V>(t, u, fn, dst));
- else
- v = fn.apply(t, u);
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(v, ex);
- }
- helpPostComplete();
- other.helpPostComplete();
- return dst;
- }
-
- private <U> CompletableFuture<Void> doThenAcceptBoth
- (CompletableFuture<? extends U> other,
- BiConsumer<? super T,? super U> fn,
- Executor e) {
- if (other == null || fn == null) throw new NullPointerException();
- CompletableFuture<Void> dst = new CompletableFuture<Void>();
- ThenAcceptBoth<T,U> d = null;
- Object r, s = null;
- if ((r = result) == null || (s = other.result) == null) {
- d = new ThenAcceptBoth<T,U>(this, other, fn, dst, e);
- CompletionNode q = null, p = new CompletionNode(d);
- while ((r == null && (r = result) == null) ||
- (s == null && (s = other.result) == null)) {
- if (q != null) {
- if (s != null ||
- UNSAFE.compareAndSwapObject
- (other, COMPLETIONS, q.next = other.completions, q))
- break;
- }
- else if (r != null ||
- UNSAFE.compareAndSwapObject
- (this, COMPLETIONS, p.next = completions, p)) {
- if (s != null)
- break;
- q = new CompletionNode(d);
- }
- }
- }
- if (r != null && s != null && (d == null || d.compareAndSet(0, 1))) {
- T t; U u; Throwable ex;
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- if (ex != null)
- u = null;
- else if (s instanceof AltResult) {
- ex = ((AltResult)s).ex;
- u = null;
- }
- else {
- @SuppressWarnings("unchecked") U us = (U) s;
- u = us;
- }
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncAcceptBoth<T,U>(t, u, fn, dst));
- else
- fn.accept(t, u);
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(null, ex);
- }
- helpPostComplete();
- other.helpPostComplete();
- return dst;
- }
-
- private CompletableFuture<Void> doRunAfterBoth(CompletableFuture<?> other,
- Runnable action,
- Executor e) {
- if (other == null || action == null) throw new NullPointerException();
- CompletableFuture<Void> dst = new CompletableFuture<Void>();
- RunAfterBoth d = null;
- Object r, s = null;
- if ((r = result) == null || (s = other.result) == null) {
- d = new RunAfterBoth(this, other, action, dst, e);
- CompletionNode q = null, p = new CompletionNode(d);
- while ((r == null && (r = result) == null) ||
- (s == null && (s = other.result) == null)) {
- if (q != null) {
- if (s != null ||
- UNSAFE.compareAndSwapObject
- (other, COMPLETIONS, q.next = other.completions, q))
- break;
- }
- else if (r != null ||
- UNSAFE.compareAndSwapObject
- (this, COMPLETIONS, p.next = completions, p)) {
- if (s != null)
- break;
- q = new CompletionNode(d);
- }
- }
- }
- if (r != null && s != null && (d == null || d.compareAndSet(0, 1))) {
- Throwable ex;
- if (r instanceof AltResult)
- ex = ((AltResult)r).ex;
- else
- ex = null;
- if (ex == null && (s instanceof AltResult))
- ex = ((AltResult)s).ex;
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncRun(action, dst));
- else
- action.run();
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(null, ex);
- }
- helpPostComplete();
- other.helpPostComplete();
- return dst;
- }
-
- private <U> CompletableFuture<U> doApplyToEither
- (CompletableFuture<? extends T> other,
- Function<? super T, U> fn,
- Executor e) {
- if (other == null || fn == null) throw new NullPointerException();
- CompletableFuture<U> dst = new CompletableFuture<U>();
- ApplyToEither<T,U> d = null;
- Object r;
- if ((r = result) == null && (r = other.result) == null) {
- d = new ApplyToEither<T,U>(this, other, fn, dst, e);
- CompletionNode q = null, p = new CompletionNode(d);
- while ((r = result) == null && (r = other.result) == null) {
- if (q != null) {
- if (UNSAFE.compareAndSwapObject
- (other, COMPLETIONS, q.next = other.completions, q))
- break;
- }
- else if (UNSAFE.compareAndSwapObject
- (this, COMPLETIONS, p.next = completions, p))
- q = new CompletionNode(d);
- }
- }
- if (r != null && (d == null || d.compareAndSet(0, 1))) {
- T t; Throwable ex;
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- U u = null;
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncApply<T,U>(t, fn, dst));
- else
- u = fn.apply(t);
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(u, ex);
- }
- helpPostComplete();
- other.helpPostComplete();
- return dst;
- }
-
- private CompletableFuture<Void> doAcceptEither
- (CompletableFuture<? extends T> other,
- Consumer<? super T> fn,
- Executor e) {
- if (other == null || fn == null) throw new NullPointerException();
- CompletableFuture<Void> dst = new CompletableFuture<Void>();
- AcceptEither<T> d = null;
- Object r;
- if ((r = result) == null && (r = other.result) == null) {
- d = new AcceptEither<T>(this, other, fn, dst, e);
- CompletionNode q = null, p = new CompletionNode(d);
- while ((r = result) == null && (r = other.result) == null) {
- if (q != null) {
- if (UNSAFE.compareAndSwapObject
- (other, COMPLETIONS, q.next = other.completions, q))
- break;
- }
- else if (UNSAFE.compareAndSwapObject
- (this, COMPLETIONS, p.next = completions, p))
- q = new CompletionNode(d);
- }
- }
- if (r != null && (d == null || d.compareAndSet(0, 1))) {
- T t; Throwable ex;
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncAccept<T>(t, fn, dst));
- else
- fn.accept(t);
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(null, ex);
- }
- helpPostComplete();
- other.helpPostComplete();
- return dst;
- }
-
- private CompletableFuture<Void> doRunAfterEither
- (CompletableFuture<?> other,
- Runnable action,
- Executor e) {
- if (other == null || action == null) throw new NullPointerException();
- CompletableFuture<Void> dst = new CompletableFuture<Void>();
- RunAfterEither d = null;
- Object r;
- if ((r = result) == null && (r = other.result) == null) {
- d = new RunAfterEither(this, other, action, dst, e);
- CompletionNode q = null, p = new CompletionNode(d);
- while ((r = result) == null && (r = other.result) == null) {
- if (q != null) {
- if (UNSAFE.compareAndSwapObject
- (other, COMPLETIONS, q.next = other.completions, q))
- break;
- }
- else if (UNSAFE.compareAndSwapObject
- (this, COMPLETIONS, p.next = completions, p))
- q = new CompletionNode(d);
- }
- }
- if (r != null && (d == null || d.compareAndSet(0, 1))) {
- Throwable ex;
- if (r instanceof AltResult)
- ex = ((AltResult)r).ex;
- else
- ex = null;
- if (ex == null) {
- try {
- if (e != null)
- execAsync(e, new AsyncRun(action, dst));
- else
- action.run();
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- if (e == null || ex != null)
- dst.internalComplete(null, ex);
- }
- helpPostComplete();
- other.helpPostComplete();
- return dst;
- }
-
- private <U> CompletableFuture<U> doThenCompose
- (Function<? super T, ? extends CompletionStage<U>> fn,
- Executor e) {
- if (fn == null) throw new NullPointerException();
- CompletableFuture<U> dst = null;
- ThenCompose<T,U> d = null;
- Object r;
- if ((r = result) == null) {
- dst = new CompletableFuture<U>();
- CompletionNode p = new CompletionNode
- (d = new ThenCompose<T,U>(this, fn, dst, e));
- while ((r = result) == null) {
- if (UNSAFE.compareAndSwapObject
- (this, COMPLETIONS, p.next = completions, p))
- break;
- }
- }
- if (r != null && (d == null || d.compareAndSet(0, 1))) {
- T t; Throwable ex;
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- if (ex == null) {
- if (e != null) {
- if (dst == null)
- dst = new CompletableFuture<U>();
- execAsync(e, new AsyncCompose<T,U>(t, fn, dst));
- }
- else {
- try {
- CompletionStage<U> cs = fn.apply(t);
- if (cs == null ||
- (dst = cs.toCompletableFuture()) == null)
- ex = new NullPointerException();
- } catch (Throwable rex) {
- ex = rex;
- }
- }
- }
- if (dst == null)
- dst = new CompletableFuture<U>();
- if (ex != null)
- dst.internalComplete(null, ex);
- }
- helpPostComplete();
- dst.helpPostComplete();
- return dst;
- }
-
- private CompletableFuture<T> doWhenComplete
- (BiConsumer<? super T, ? super Throwable> fn,
- Executor e) {
- if (fn == null) throw new NullPointerException();
- CompletableFuture<T> dst = new CompletableFuture<T>();
- WhenCompleteCompletion<T> d = null;
- Object r;
- if ((r = result) == null) {
- CompletionNode p =
- new CompletionNode(d = new WhenCompleteCompletion<T>
- (this, fn, dst, e));
- while ((r = result) == null) {
- if (UNSAFE.compareAndSwapObject(this, COMPLETIONS,
- p.next = completions, p))
- break;
- }
- }
- if (r != null && (d == null || d.compareAndSet(0, 1))) {
- T t; Throwable ex;
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- Throwable dx = null;
- try {
- if (e != null)
- execAsync(e, new AsyncWhenComplete<T>(t, ex, fn, dst));
- else
- fn.accept(t, ex);
- } catch (Throwable rex) {
- dx = rex;
- }
- if (e == null || dx != null)
- dst.internalComplete(t, ex != null ? ex : dx);
- }
- helpPostComplete();
- return dst;
- }
-
- private <U> CompletableFuture<U> doHandle
- (BiFunction<? super T, Throwable, ? extends U> fn,
- Executor e) {
- if (fn == null) throw new NullPointerException();
- CompletableFuture<U> dst = new CompletableFuture<U>();
- HandleCompletion<T,U> d = null;
- Object r;
- if ((r = result) == null) {
- CompletionNode p =
- new CompletionNode(d = new HandleCompletion<T,U>
- (this, fn, dst, e));
- while ((r = result) == null) {
- if (UNSAFE.compareAndSwapObject(this, COMPLETIONS,
- p.next = completions, p))
- break;
- }
- }
- if (r != null && (d == null || d.compareAndSet(0, 1))) {
- T t; Throwable ex;
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- U u = null;
- Throwable dx = null;
- try {
- if (e != null)
- execAsync(e, new AsyncCombine<T,Throwable,U>(t, ex, fn, dst));
- else {
- u = fn.apply(t, ex);
- dx = null;
- }
- } catch (Throwable rex) {
- dx = rex;
- u = null;
- }
- if (e == null || dx != null)
- dst.internalComplete(u, dx);
- }
- helpPostComplete();
- return dst;
- }
-
-
- // public methods
+ /* ------------- public methods -------------- */
/**
* Creates a new incomplete CompletableFuture.
@@ -2114,6 +1786,13 @@
}
/**
+ * Creates a new complete CompletableFuture with given encoded result.
+ */
+ private CompletableFuture(Object r) {
+ this.result = r;
+ }
+
+ /**
* Returns a new CompletableFuture that is asynchronously completed
* by a task running in the {@link ForkJoinPool#commonPool()} with
* the value obtained by calling the given Supplier.
@@ -2124,10 +1803,7 @@
* @return the new CompletableFuture
*/
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
- if (supplier == null) throw new NullPointerException();
- CompletableFuture<U> f = new CompletableFuture<U>();
- execAsync(ForkJoinPool.commonPool(), new AsyncSupply<U>(supplier, f));
- return f;
+ return asyncSupplyStage(asyncPool, supplier);
}
/**
@@ -2143,11 +1819,7 @@
*/
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,
Executor executor) {
- if (executor == null || supplier == null)
- throw new NullPointerException();
- CompletableFuture<U> f = new CompletableFuture<U>();
- execAsync(executor, new AsyncSupply<U>(supplier, f));
- return f;
+ return asyncSupplyStage(screenExecutor(executor), supplier);
}
/**
@@ -2160,10 +1832,7 @@
* @return the new CompletableFuture
*/
public static CompletableFuture<Void> runAsync(Runnable runnable) {
- if (runnable == null) throw new NullPointerException();
- CompletableFuture<Void> f = new CompletableFuture<Void>();
- execAsync(ForkJoinPool.commonPool(), new AsyncRun(runnable, f));
- return f;
+ return asyncRunStage(asyncPool, runnable);
}
/**
@@ -2178,11 +1847,7 @@
*/
public static CompletableFuture<Void> runAsync(Runnable runnable,
Executor executor) {
- if (executor == null || runnable == null)
- throw new NullPointerException();
- CompletableFuture<Void> f = new CompletableFuture<Void>();
- execAsync(executor, new AsyncRun(runnable, f));
- return f;
+ return asyncRunStage(screenExecutor(executor), runnable);
}
/**
@@ -2194,9 +1859,7 @@
* @return the completed CompletableFuture
*/
public static <U> CompletableFuture<U> completedFuture(U value) {
- CompletableFuture<U> f = new CompletableFuture<U>();
- f.result = (value == null) ? NIL : value;
- return f;
+ return new CompletableFuture<U>((value == null) ? NIL : value);
}
/**
@@ -2220,21 +1883,8 @@
* while waiting
*/
public T get() throws InterruptedException, ExecutionException {
- Object r; Throwable ex, cause;
- if ((r = result) == null && (r = waitingGet(true)) == null)
- throw new InterruptedException();
- if (!(r instanceof AltResult)) {
- @SuppressWarnings("unchecked") T tr = (T) r;
- return tr;
- }
- if ((ex = ((AltResult)r).ex) == null)
- return null;
- if (ex instanceof CancellationException)
- throw (CancellationException)ex;
- if ((ex instanceof CompletionException) &&
- (cause = ex.getCause()) != null)
- ex = cause;
- throw new ExecutionException(ex);
+ Object r;
+ return reportGet((r = result) == null ? waitingGet(true) : r);
}
/**
@@ -2252,24 +1902,9 @@
*/
public T get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
- Object r; Throwable ex, cause;
+ Object r;
long nanos = unit.toNanos(timeout);
- if (Thread.interrupted())
- throw new InterruptedException();
- if ((r = result) == null)
- r = timedAwaitDone(nanos);
- if (!(r instanceof AltResult)) {
- @SuppressWarnings("unchecked") T tr = (T) r;
- return tr;
- }
- if ((ex = ((AltResult)r).ex) == null)
- return null;
- if (ex instanceof CancellationException)
- throw (CancellationException)ex;
- if ((ex instanceof CompletionException) &&
- (cause = ex.getCause()) != null)
- ex = cause;
- throw new ExecutionException(ex);
+ return reportGet((r = result) == null ? timedGet(nanos) : r);
}
/**
@@ -2287,20 +1922,8 @@
* exceptionally or a completion computation threw an exception
*/
public T join() {
- Object r; Throwable ex;
- if ((r = result) == null)
- r = waitingGet(false);
- if (!(r instanceof AltResult)) {
- @SuppressWarnings("unchecked") T tr = (T) r;
- return tr;
- }
- if ((ex = ((AltResult)r).ex) == null)
- return null;
- if (ex instanceof CancellationException)
- throw (CancellationException)ex;
- if (ex instanceof CompletionException)
- throw (CompletionException)ex;
- throw new CompletionException(ex);
+ Object r;
+ return reportJoin((r = result) == null ? waitingGet(false) : r);
}
/**
@@ -2314,20 +1937,8 @@
* exceptionally or a completion computation threw an exception
*/
public T getNow(T valueIfAbsent) {
- Object r; Throwable ex;
- if ((r = result) == null)
- return valueIfAbsent;
- if (!(r instanceof AltResult)) {
- @SuppressWarnings("unchecked") T tr = (T) r;
- return tr;
- }
- if ((ex = ((AltResult)r).ex) == null)
- return null;
- if (ex instanceof CancellationException)
- throw (CancellationException)ex;
- if (ex instanceof CompletionException)
- throw (CompletionException)ex;
- throw new CompletionException(ex);
+ Object r;
+ return ((r = result) == null) ? valueIfAbsent : reportJoin(r);
}
/**
@@ -2339,9 +1950,7 @@
* to transition to a completed state, else {@code false}
*/
public boolean complete(T value) {
- boolean triggered = result == null &&
- UNSAFE.compareAndSwapObject(this, RESULT, null,
- value == null ? NIL : value);
+ boolean triggered = completeValue(value);
postComplete();
return triggered;
}
@@ -2356,244 +1965,200 @@
*/
public boolean completeExceptionally(Throwable ex) {
if (ex == null) throw new NullPointerException();
- boolean triggered = result == null &&
- UNSAFE.compareAndSwapObject(this, RESULT, null, new AltResult(ex));
+ boolean triggered = internalComplete(new AltResult(ex));
postComplete();
return triggered;
}
- // CompletionStage methods
-
- public <U> CompletableFuture<U> thenApply
- (Function<? super T,? extends U> fn) {
- return doThenApply(fn, null);
+ public <U> CompletableFuture<U> thenApply(
+ Function<? super T,? extends U> fn) {
+ return uniApplyStage(null, fn);
}
- public <U> CompletableFuture<U> thenApplyAsync
- (Function<? super T,? extends U> fn) {
- return doThenApply(fn, ForkJoinPool.commonPool());
+ public <U> CompletableFuture<U> thenApplyAsync(
+ Function<? super T,? extends U> fn) {
+ return uniApplyStage(asyncPool, fn);
}
- public <U> CompletableFuture<U> thenApplyAsync
- (Function<? super T,? extends U> fn,
- Executor executor) {
- if (executor == null) throw new NullPointerException();
- return doThenApply(fn, executor);
+ public <U> CompletableFuture<U> thenApplyAsync(
+ Function<? super T,? extends U> fn, Executor executor) {
+ return uniApplyStage(screenExecutor(executor), fn);
}
- public CompletableFuture<Void> thenAccept
- (Consumer<? super T> action) {
- return doThenAccept(action, null);
+ public CompletableFuture<Void> thenAccept(Consumer<? super T> action) {
+ return uniAcceptStage(null, action);
}
- public CompletableFuture<Void> thenAcceptAsync
- (Consumer<? super T> action) {
- return doThenAccept(action, ForkJoinPool.commonPool());
+ public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action) {
+ return uniAcceptStage(asyncPool, action);
}
- public CompletableFuture<Void> thenAcceptAsync
- (Consumer<? super T> action,
- Executor executor) {
- if (executor == null) throw new NullPointerException();
- return doThenAccept(action, executor);
+ public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action,
+ Executor executor) {
+ return uniAcceptStage(screenExecutor(executor), action);
}
- public CompletableFuture<Void> thenRun
- (Runnable action) {
- return doThenRun(action, null);
+ public CompletableFuture<Void> thenRun(Runnable action) {
+ return uniRunStage(null, action);
}
- public CompletableFuture<Void> thenRunAsync
- (Runnable action) {
- return doThenRun(action, ForkJoinPool.commonPool());
+ public CompletableFuture<Void> thenRunAsync(Runnable action) {
+ return uniRunStage(asyncPool, action);
}
- public CompletableFuture<Void> thenRunAsync
- (Runnable action,
- Executor executor) {
- if (executor == null) throw new NullPointerException();
- return doThenRun(action, executor);
+ public CompletableFuture<Void> thenRunAsync(Runnable action,
+ Executor executor) {
+ return uniRunStage(screenExecutor(executor), action);
}
- public <U,V> CompletableFuture<V> thenCombine
- (CompletionStage<? extends U> other,
- BiFunction<? super T,? super U,? extends V> fn) {
- return doThenCombine(other.toCompletableFuture(), fn, null);
+ public <U,V> CompletableFuture<V> thenCombine(
+ CompletionStage<? extends U> other,
+ BiFunction<? super T,? super U,? extends V> fn) {
+ return biApplyStage(null, other, fn);
}
- public <U,V> CompletableFuture<V> thenCombineAsync
- (CompletionStage<? extends U> other,
- BiFunction<? super T,? super U,? extends V> fn) {
- return doThenCombine(other.toCompletableFuture(), fn,
- ForkJoinPool.commonPool());
+ public <U,V> CompletableFuture<V> thenCombineAsync(
+ CompletionStage<? extends U> other,
+ BiFunction<? super T,? super U,? extends V> fn) {
+ return biApplyStage(asyncPool, other, fn);
}
- public <U,V> CompletableFuture<V> thenCombineAsync
- (CompletionStage<? extends U> other,
- BiFunction<? super T,? super U,? extends V> fn,
- Executor executor) {
- if (executor == null) throw new NullPointerException();
- return doThenCombine(other.toCompletableFuture(), fn, executor);
+ public <U,V> CompletableFuture<V> thenCombineAsync(
+ CompletionStage<? extends U> other,
+ BiFunction<? super T,? super U,? extends V> fn, Executor executor) {
+ return biApplyStage(screenExecutor(executor), other, fn);
}
- public <U> CompletableFuture<Void> thenAcceptBoth
- (CompletionStage<? extends U> other,
- BiConsumer<? super T, ? super U> action) {
- return doThenAcceptBoth(other.toCompletableFuture(), action, null);
+ public <U> CompletableFuture<Void> thenAcceptBoth(
+ CompletionStage<? extends U> other,
+ BiConsumer<? super T, ? super U> action) {
+ return biAcceptStage(null, other, action);
}
- public <U> CompletableFuture<Void> thenAcceptBothAsync
- (CompletionStage<? extends U> other,
- BiConsumer<? super T, ? super U> action) {
- return doThenAcceptBoth(other.toCompletableFuture(), action,
- ForkJoinPool.commonPool());
+ public <U> CompletableFuture<Void> thenAcceptBothAsync(
+ CompletionStage<? extends U> other,
+ BiConsumer<? super T, ? super U> action) {
+ return biAcceptStage(asyncPool, other, action);
}
- public <U> CompletableFuture<Void> thenAcceptBothAsync
- (CompletionStage<? extends U> other,
- BiConsumer<? super T, ? super U> action,
- Executor executor) {
- if (executor == null) throw new NullPointerException();
- return doThenAcceptBoth(other.toCompletableFuture(), action, executor);
+ public <U> CompletableFuture<Void> thenAcceptBothAsync(
+ CompletionStage<? extends U> other,
+ BiConsumer<? super T, ? super U> action, Executor executor) {
+ return biAcceptStage(screenExecutor(executor), other, action);
}
- public CompletableFuture<Void> runAfterBoth
- (CompletionStage<?> other,
- Runnable action) {
- return doRunAfterBoth(other.toCompletableFuture(), action, null);
+ public CompletableFuture<Void> runAfterBoth(CompletionStage<?> other,
+ Runnable action) {
+ return biRunStage(null, other, action);
}
- public CompletableFuture<Void> runAfterBothAsync
- (CompletionStage<?> other,
- Runnable action) {
- return doRunAfterBoth(other.toCompletableFuture(), action,
- ForkJoinPool.commonPool());
+ public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,
+ Runnable action) {
+ return biRunStage(asyncPool, other, action);
}
- public CompletableFuture<Void> runAfterBothAsync
- (CompletionStage<?> other,
- Runnable action,
- Executor executor) {
- if (executor == null) throw new NullPointerException();
- return doRunAfterBoth(other.toCompletableFuture(), action, executor);
+ public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,
+ Runnable action,
+ Executor executor) {
+ return biRunStage(screenExecutor(executor), other, action);
}
-
- public <U> CompletableFuture<U> applyToEither
- (CompletionStage<? extends T> other,
- Function<? super T, U> fn) {
- return doApplyToEither(other.toCompletableFuture(), fn, null);
+ public <U> CompletableFuture<U> applyToEither(
+ CompletionStage<? extends T> other, Function<? super T, U> fn) {
+ return orApplyStage(null, other, fn);
}
- public <U> CompletableFuture<U> applyToEitherAsync
- (CompletionStage<? extends T> other,
- Function<? super T, U> fn) {
- return doApplyToEither(other.toCompletableFuture(), fn,
- ForkJoinPool.commonPool());
+ public <U> CompletableFuture<U> applyToEitherAsync(
+ CompletionStage<? extends T> other, Function<? super T, U> fn) {
+ return orApplyStage(asyncPool, other, fn);
}
- public <U> CompletableFuture<U> applyToEitherAsync
- (CompletionStage<? extends T> other,
- Function<? super T, U> fn,
- Executor executor) {
- if (executor == null) throw new NullPointerException();
- return doApplyToEither(other.toCompletableFuture(), fn, executor);
+ public <U> CompletableFuture<U> applyToEitherAsync(
+ CompletionStage<? extends T> other, Function<? super T, U> fn,
+ Executor executor) {
+ return orApplyStage(screenExecutor(executor), other, fn);
}
- public CompletableFuture<Void> acceptEither
- (CompletionStage<? extends T> other,
- Consumer<? super T> action) {
- return doAcceptEither(other.toCompletableFuture(), action, null);
+ public CompletableFuture<Void> acceptEither(
+ CompletionStage<? extends T> other, Consumer<? super T> action) {
+ return orAcceptStage(null, other, action);
}
- public CompletableFuture<Void> acceptEitherAsync
- (CompletionStage<? extends T> other,
- Consumer<? super T> action) {
- return doAcceptEither(other.toCompletableFuture(), action,
- ForkJoinPool.commonPool());
+ public CompletableFuture<Void> acceptEitherAsync(
+ CompletionStage<? extends T> other, Consumer<? super T> action) {
+ return orAcceptStage(asyncPool, other, action);
}
- public CompletableFuture<Void> acceptEitherAsync
- (CompletionStage<? extends T> other,
- Consumer<? super T> action,
- Executor executor) {
- if (executor == null) throw new NullPointerException();
- return doAcceptEither(other.toCompletableFuture(), action, executor);
+ public CompletableFuture<Void> acceptEitherAsync(
+ CompletionStage<? extends T> other, Consumer<? super T> action,
+ Executor executor) {
+ return orAcceptStage(screenExecutor(executor), other, action);
}
public CompletableFuture<Void> runAfterEither(CompletionStage<?> other,
Runnable action) {
- return doRunAfterEither(other.toCompletableFuture(), action, null);
+ return orRunStage(null, other, action);
}
- public CompletableFuture<Void> runAfterEitherAsync
- (CompletionStage<?> other,
- Runnable action) {
- return doRunAfterEither(other.toCompletableFuture(), action,
- ForkJoinPool.commonPool());
+ public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,
+ Runnable action) {
+ return orRunStage(asyncPool, other, action);
}
- public CompletableFuture<Void> runAfterEitherAsync
- (CompletionStage<?> other,
- Runnable action,
- Executor executor) {
- if (executor == null) throw new NullPointerException();
- return doRunAfterEither(other.toCompletableFuture(), action, executor);
+ public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,
+ Runnable action,
+ Executor executor) {
+ return orRunStage(screenExecutor(executor), other, action);
}
- public <U> CompletableFuture<U> thenCompose
- (Function<? super T, ? extends CompletionStage<U>> fn) {
- return doThenCompose(fn, null);
+ public <U> CompletableFuture<U> thenCompose(
+ Function<? super T, ? extends CompletionStage<U>> fn) {
+ return uniComposeStage(null, fn);
}
- public <U> CompletableFuture<U> thenComposeAsync
- (Function<? super T, ? extends CompletionStage<U>> fn) {
- return doThenCompose(fn, ForkJoinPool.commonPool());
+ public <U> CompletableFuture<U> thenComposeAsync(
+ Function<? super T, ? extends CompletionStage<U>> fn) {
+ return uniComposeStage(asyncPool, fn);
}
- public <U> CompletableFuture<U> thenComposeAsync
- (Function<? super T, ? extends CompletionStage<U>> fn,
- Executor executor) {
- if (executor == null) throw new NullPointerException();
- return doThenCompose(fn, executor);
+ public <U> CompletableFuture<U> thenComposeAsync(
+ Function<? super T, ? extends CompletionStage<U>> fn,
+ Executor executor) {
+ return uniComposeStage(screenExecutor(executor), fn);
}
- public CompletableFuture<T> whenComplete
- (BiConsumer<? super T, ? super Throwable> action) {
- return doWhenComplete(action, null);
+ public CompletableFuture<T> whenComplete(
+ BiConsumer<? super T, ? super Throwable> action) {
+ return uniWhenCompleteStage(null, action);
}
- public CompletableFuture<T> whenCompleteAsync
- (BiConsumer<? super T, ? super Throwable> action) {
- return doWhenComplete(action, ForkJoinPool.commonPool());
+ public CompletableFuture<T> whenCompleteAsync(
+ BiConsumer<? super T, ? super Throwable> action) {
+ return uniWhenCompleteStage(asyncPool, action);
}
- public CompletableFuture<T> whenCompleteAsync
- (BiConsumer<? super T, ? super Throwable> action,
- Executor executor) {
- if (executor == null) throw new NullPointerException();
- return doWhenComplete(action, executor);
+ public CompletableFuture<T> whenCompleteAsync(
+ BiConsumer<? super T, ? super Throwable> action, Executor executor) {
+ return uniWhenCompleteStage(screenExecutor(executor), action);
}
- public <U> CompletableFuture<U> handle
- (BiFunction<? super T, Throwable, ? extends U> fn) {
- return doHandle(fn, null);
+ public <U> CompletableFuture<U> handle(
+ BiFunction<? super T, Throwable, ? extends U> fn) {
+ return uniHandleStage(null, fn);
}
- public <U> CompletableFuture<U> handleAsync
- (BiFunction<? super T, Throwable, ? extends U> fn) {
- return doHandle(fn, ForkJoinPool.commonPool());
+ public <U> CompletableFuture<U> handleAsync(
+ BiFunction<? super T, Throwable, ? extends U> fn) {
+ return uniHandleStage(asyncPool, fn);
}
- public <U> CompletableFuture<U> handleAsync
- (BiFunction<? super T, Throwable, ? extends U> fn,
- Executor executor) {
- if (executor == null) throw new NullPointerException();
- return doHandle(fn, executor);
+ public <U> CompletableFuture<U> handleAsync(
+ BiFunction<? super T, Throwable, ? extends U> fn, Executor executor) {
+ return uniHandleStage(screenExecutor(executor), fn);
}
/**
- * Returns this CompletableFuture
+ * Returns this CompletableFuture.
*
* @return this CompletableFuture
*/
@@ -2618,52 +2183,13 @@
* exceptionally
* @return the new CompletableFuture
*/
- public CompletableFuture<T> exceptionally
- (Function<Throwable, ? extends T> fn) {
- if (fn == null) throw new NullPointerException();
- CompletableFuture<T> dst = new CompletableFuture<T>();
- ExceptionCompletion<T> d = null;
- Object r;
- if ((r = result) == null) {
- CompletionNode p =
- new CompletionNode(d = new ExceptionCompletion<T>
- (this, fn, dst));
- while ((r = result) == null) {
- if (UNSAFE.compareAndSwapObject(this, COMPLETIONS,
- p.next = completions, p))
- break;
- }
- }
- if (r != null && (d == null || d.compareAndSet(0, 1))) {
- T t = null; Throwable ex, dx = null;
- if (r instanceof AltResult) {
- if ((ex = ((AltResult)r).ex) != null) {
- try {
- t = fn.apply(ex);
- } catch (Throwable rex) {
- dx = rex;
- }
- }
- }
- else {
- @SuppressWarnings("unchecked") T tr = (T) r;
- t = tr;
- }
- dst.internalComplete(t, dx);
- }
- helpPostComplete();
- return dst;
+ public CompletableFuture<T> exceptionally(
+ Function<Throwable, ? extends T> fn) {
+ return uniExceptionallyStage(fn);
}
/* ------------- Arbitrary-arity constructions -------------- */
- /*
- * The basic plan of attack is to recursively form binary
- * completion trees of elements. This can be overkill for small
- * sets, but scales nicely. The And/All vs Or/Any forms use the
- * same idea, but details differ.
- */
-
/**
* Returns a new CompletableFuture that is completed when all of
* the given CompletableFutures complete. If any of the given
@@ -2688,82 +2214,7 @@
* {@code null}
*/
public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs) {
- int len = cfs.length; // Directly handle empty and singleton cases
- if (len > 1)
- return allTree(cfs, 0, len - 1);
- else {
- CompletableFuture<Void> dst = new CompletableFuture<Void>();
- CompletableFuture<?> f;
- if (len == 0)
- dst.result = NIL;
- else if ((f = cfs[0]) == null)
- throw new NullPointerException();
- else {
- ThenPropagate d = null;
- CompletionNode p = null;
- Object r;
- while ((r = f.result) == null) {
- if (d == null)
- d = new ThenPropagate(f, dst);
- else if (p == null)
- p = new CompletionNode(d);
- else if (UNSAFE.compareAndSwapObject
- (f, COMPLETIONS, p.next = f.completions, p))
- break;
- }
- if (r != null && (d == null || d.compareAndSet(0, 1)))
- dst.internalComplete(null, (r instanceof AltResult) ?
- ((AltResult)r).ex : null);
- f.helpPostComplete();
- }
- return dst;
- }
- }
-
- /**
- * Recursively constructs an And'ed tree of CompletableFutures.
- * Called only when array known to have at least two elements.
- */
- private static CompletableFuture<Void> allTree(CompletableFuture<?>[] cfs,
- int lo, int hi) {
- CompletableFuture<?> fst, snd;
- int mid = (lo + hi) >>> 1;
- if ((fst = (lo == mid ? cfs[lo] : allTree(cfs, lo, mid))) == null ||
- (snd = (hi == mid+1 ? cfs[hi] : allTree(cfs, mid+1, hi))) == null)
- throw new NullPointerException();
- CompletableFuture<Void> dst = new CompletableFuture<Void>();
- AndCompletion d = null;
- CompletionNode p = null, q = null;
- Object r = null, s = null;
- while ((r = fst.result) == null || (s = snd.result) == null) {
- if (d == null)
- d = new AndCompletion(fst, snd, dst);
- else if (p == null)
- p = new CompletionNode(d);
- else if (q == null) {
- if (UNSAFE.compareAndSwapObject
- (fst, COMPLETIONS, p.next = fst.completions, p))
- q = new CompletionNode(d);
- }
- else if (UNSAFE.compareAndSwapObject
- (snd, COMPLETIONS, q.next = snd.completions, q))
- break;
- }
- if ((r != null || (r = fst.result) != null) &&
- (s != null || (s = snd.result) != null) &&
- (d == null || d.compareAndSet(0, 1))) {
- Throwable ex;
- if (r instanceof AltResult)
- ex = ((AltResult)r).ex;
- else
- ex = null;
- if (ex == null && (s instanceof AltResult))
- ex = ((AltResult)s).ex;
- dst.internalComplete(null, ex);
- }
- fst.helpPostComplete();
- snd.helpPostComplete();
- return dst;
+ return andTree(cfs, 0, cfs.length - 1);
}
/**
@@ -2782,92 +2233,7 @@
* {@code null}
*/
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs) {
- int len = cfs.length; // Same idea as allOf
- if (len > 1)
- return anyTree(cfs, 0, len - 1);
- else {
- CompletableFuture<Object> dst = new CompletableFuture<Object>();
- CompletableFuture<?> f;
- if (len == 0)
- ; // skip
- else if ((f = cfs[0]) == null)
- throw new NullPointerException();
- else {
- ThenCopy<Object> d = null;
- CompletionNode p = null;
- Object r;
- while ((r = f.result) == null) {
- if (d == null)
- d = new ThenCopy<Object>(f, dst);
- else if (p == null)
- p = new CompletionNode(d);
- else if (UNSAFE.compareAndSwapObject
- (f, COMPLETIONS, p.next = f.completions, p))
- break;
- }
- if (r != null && (d == null || d.compareAndSet(0, 1))) {
- Throwable ex; Object t;
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- t = r;
- }
- dst.internalComplete(t, ex);
- }
- f.helpPostComplete();
- }
- return dst;
- }
- }
-
- /**
- * Recursively constructs an Or'ed tree of CompletableFutures.
- */
- private static CompletableFuture<Object> anyTree(CompletableFuture<?>[] cfs,
- int lo, int hi) {
- CompletableFuture<?> fst, snd;
- int mid = (lo + hi) >>> 1;
- if ((fst = (lo == mid ? cfs[lo] : anyTree(cfs, lo, mid))) == null ||
- (snd = (hi == mid+1 ? cfs[hi] : anyTree(cfs, mid+1, hi))) == null)
- throw new NullPointerException();
- CompletableFuture<Object> dst = new CompletableFuture<Object>();
- OrCompletion d = null;
- CompletionNode p = null, q = null;
- Object r;
- while ((r = fst.result) == null && (r = snd.result) == null) {
- if (d == null)
- d = new OrCompletion(fst, snd, dst);
- else if (p == null)
- p = new CompletionNode(d);
- else if (q == null) {
- if (UNSAFE.compareAndSwapObject
- (fst, COMPLETIONS, p.next = fst.completions, p))
- q = new CompletionNode(d);
- }
- else if (UNSAFE.compareAndSwapObject
- (snd, COMPLETIONS, q.next = snd.completions, q))
- break;
- }
- if ((r != null || (r = fst.result) != null ||
- (r = snd.result) != null) &&
- (d == null || d.compareAndSet(0, 1))) {
- Throwable ex; Object t;
- if (r instanceof AltResult) {
- ex = ((AltResult)r).ex;
- t = null;
- }
- else {
- ex = null;
- t = r;
- }
- dst.internalComplete(t, ex);
- }
- fst.helpPostComplete();
- snd.helpPostComplete();
- return dst;
+ return orTree(cfs, 0, cfs.length - 1);
}
/* ------------- Control and status methods -------------- */
@@ -2887,8 +2253,7 @@
*/
public boolean cancel(boolean mayInterruptIfRunning) {
boolean cancelled = (result == null) &&
- UNSAFE.compareAndSwapObject
- (this, RESULT, null, new AltResult(new CancellationException()));
+ internalComplete(new AltResult(new CancellationException()));
postComplete();
return cancelled || isCancelled();
}
@@ -2940,11 +2305,12 @@
* Forcibly causes subsequent invocations of method {@link #get()}
* and related methods to throw the given exception, whether or
* not already completed. This method is designed for use only in
- * recovery actions, and even in such situations may result in
- * ongoing dependent completions using established versus
+ * error recovery actions, and even in such situations may result
+ * in ongoing dependent completions using established versus
* overwritten outcomes.
*
* @param ex the exception
+ * @throws NullPointerException if the exception is null
*/
public void obtrudeException(Throwable ex) {
if (ex == null) throw new NullPointerException();
@@ -2962,7 +2328,7 @@
*/
public int getNumberOfDependents() {
int count = 0;
- for (CompletionNode p = completions; p != null; p = p.next)
+ for (Completion p = stack; p != null; p = p.next)
++count;
return count;
}
@@ -2993,20 +2359,19 @@
// Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE;
private static final long RESULT;
- private static final long WAITERS;
- private static final long COMPLETIONS;
+ private static final long STACK;
+ private static final long NEXT;
static {
try {
- UNSAFE = sun.misc.Unsafe.getUnsafe();
+ final sun.misc.Unsafe u;
+ UNSAFE = u = sun.misc.Unsafe.getUnsafe();
Class<?> k = CompletableFuture.class;
- RESULT = UNSAFE.objectFieldOffset
- (k.getDeclaredField("result"));
- WAITERS = UNSAFE.objectFieldOffset
- (k.getDeclaredField("waiters"));
- COMPLETIONS = UNSAFE.objectFieldOffset
- (k.getDeclaredField("completions"));
- } catch (Exception e) {
- throw new Error(e);
+ RESULT = u.objectFieldOffset(k.getDeclaredField("result"));
+ STACK = u.objectFieldOffset(k.getDeclaredField("stack"));
+ NEXT = u.objectFieldOffset
+ (Completion.class.getDeclaredField("next"));
+ } catch (Exception x) {
+ throw new Error(x);
}
}
}
diff --git a/src/share/classes/java/util/concurrent/CompletionStage.java b/src/share/classes/java/util/concurrent/CompletionStage.java
index 6de6098..304ede5 100644
--- a/src/share/classes/java/util/concurrent/CompletionStage.java
+++ b/src/share/classes/java/util/concurrent/CompletionStage.java
@@ -407,7 +407,7 @@
/**
* Returns a new CompletionStage that, when this and the other
* given stage complete normally, executes the given action using
- * the supplied executor
+ * the supplied executor.
*
* See the {@link CompletionStage} documentation for rules
* covering exceptional completion.
@@ -569,7 +569,7 @@
/**
* Returns a new CompletionStage that, when either this or the
* other given stage complete normally, executes the given action
- * using supplied executor.
+ * using the supplied executor.
*
* See the {@link CompletionStage} documentation for rules
* covering exceptional completion.
@@ -649,10 +649,15 @@
(Function<Throwable, ? extends T> fn);
/**
- * Returns a new CompletionStage with the same result or exception
- * as this stage, and when this stage completes, executes the
- * given action with the result (or {@code null} if none) and the
- * exception (or {@code null} if none) of this stage.
+ * Returns a new CompletionStage with the same result or exception as
+ * this stage, that executes the given action when this stage completes.
+ *
+ * <p>When this stage is complete, the given action is invoked with the
+ * result (or {@code null} if none) and the exception (or {@code null}
+ * if none) of this stage as arguments. The returned stage is completed
+ * when the action returns. If the supplied action itself encounters an
+ * exception, then the returned stage exceptionally completes with this
+ * exception unless this stage also completed exceptionally.
*
* @param action the action to perform
* @return the new CompletionStage
@@ -661,12 +666,16 @@
(BiConsumer<? super T, ? super Throwable> action);
/**
- * Returns a new CompletionStage with the same result or exception
- * as this stage, and when this stage completes, executes the
- * given action executes the given action using this stage's
- * default asynchronous execution facility, with the result (or
- * {@code null} if none) and the exception (or {@code null} if
- * none) of this stage as arguments.
+ * Returns a new CompletionStage with the same result or exception as
+ * this stage, that executes the given action using this stage's
+ * default asynchronous execution facility when this stage completes.
+ *
+ * <p>When this stage is complete, the given action is invoked with the
+ * result (or {@code null} if none) and the exception (or {@code null}
+ * if none) of this stage as arguments. The returned stage is completed
+ * when the action returns. If the supplied action itself encounters an
+ * exception, then the returned stage exceptionally completes with this
+ * exception unless this stage also completed exceptionally.
*
* @param action the action to perform
* @return the new CompletionStage
@@ -675,11 +684,16 @@
(BiConsumer<? super T, ? super Throwable> action);
/**
- * Returns a new CompletionStage with the same result or exception
- * as this stage, and when this stage completes, executes using
- * the supplied Executor, the given action with the result (or
- * {@code null} if none) and the exception (or {@code null} if
- * none) of this stage as arguments.
+ * Returns a new CompletionStage with the same result or exception as
+ * this stage, that executes the given action using the supplied
+ * Executor when this stage completes.
+ *
+ * <p>When this stage is complete, the given action is invoked with the
+ * result (or {@code null} if none) and the exception (or {@code null}
+ * if none) of this stage as arguments. The returned stage is completed
+ * when the action returns. If the supplied action itself encounters an
+ * exception, then the returned stage exceptionally completes with this
+ * exception unless this stage also completed exceptionally.
*
* @param action the action to perform
* @param executor the executor to use for asynchronous execution
@@ -693,9 +707,11 @@
* Returns a new CompletionStage that, when this stage completes
* either normally or exceptionally, is executed with this stage's
* result and exception as arguments to the supplied function.
- * The given function is invoked with the result (or {@code null}
- * if none) and the exception (or {@code null} if none) of this
- * stage when complete as arguments.
+ *
+ * <p>When this stage is complete, the given function is invoked
+ * with the result (or {@code null} if none) and the exception (or
+ * {@code null} if none) of this stage as arguments, and the
+ * function's result is used to complete the returned stage.
*
* @param fn the function to use to compute the value of the
* returned CompletionStage
@@ -710,9 +726,11 @@
* either normally or exceptionally, is executed using this stage's
* default asynchronous execution facility, with this stage's
* result and exception as arguments to the supplied function.
- * The given function is invoked with the result (or {@code null}
- * if none) and the exception (or {@code null} if none) of this
- * stage when complete as arguments.
+ *
+ * <p>When this stage is complete, the given function is invoked
+ * with the result (or {@code null} if none) and the exception (or
+ * {@code null} if none) of this stage as arguments, and the
+ * function's result is used to complete the returned stage.
*
* @param fn the function to use to compute the value of the
* returned CompletionStage
@@ -726,10 +744,12 @@
* Returns a new CompletionStage that, when this stage completes
* either normally or exceptionally, is executed using the
* supplied executor, with this stage's result and exception as
- * arguments to the supplied function. The given function is
- * invoked with the result (or {@code null} if none) and the
- * exception (or {@code null} if none) of this stage when complete
- * as arguments.
+ * arguments to the supplied function.
+ *
+ * <p>When this stage is complete, the given function is invoked
+ * with the result (or {@code null} if none) and the exception (or
+ * {@code null} if none) of this stage as arguments, and the
+ * function's result is used to complete the returned stage.
*
* @param fn the function to use to compute the value of the
* returned CompletionStage
diff --git a/src/share/classes/java/util/logging/FileHandler.java b/src/share/classes/java/util/logging/FileHandler.java
index 4d63b77..9699b72 100644
--- a/src/share/classes/java/util/logging/FileHandler.java
+++ b/src/share/classes/java/util/logging/FileHandler.java
@@ -25,6 +25,7 @@
package java.util.logging;
+import static java.nio.file.StandardOpenOption.APPEND;
import static java.nio.file.StandardOpenOption.CREATE_NEW;
import static java.nio.file.StandardOpenOption.WRITE;
@@ -34,10 +35,17 @@
import java.io.IOException;
import java.io.OutputStream;
import java.nio.channels.FileChannel;
+import java.nio.channels.OverlappingFileLockException;
import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.AccessController;
import java.security.PrivilegedAction;
+import java.util.HashSet;
+import java.util.Set;
/**
* Simple file logging <tt>Handler</tt>.
@@ -149,7 +157,7 @@
private FileChannel lockFileChannel;
private File files[];
private static final int MAX_LOCKS = 100;
- private static final java.util.HashMap<String, String> locks = new java.util.HashMap<>();
+ private static final Set<String> locks = new HashSet<>();
/**
* A metered stream is a subclass of OutputStream that
@@ -428,34 +436,80 @@
// between processes (and not within a process), we first check
// if we ourself already have the file locked.
synchronized(locks) {
- if (locks.get(lockFileName) != null) {
+ if (locks.contains(lockFileName)) {
// We already own this lock, for a different FileHandler
// object. Try again.
continue;
}
- try {
- lockFileChannel = FileChannel.open(Paths.get(lockFileName),
- CREATE_NEW, WRITE);
- } catch (FileAlreadyExistsException ix) {
- // try the next lock file name in the sequence
- continue;
+ final Path lockFilePath = Paths.get(lockFileName);
+ FileChannel channel = null;
+ int retries = -1;
+ boolean fileCreated = false;
+ while (channel == null && retries++ < 1) {
+ try {
+ channel = FileChannel.open(lockFilePath,
+ CREATE_NEW, WRITE);
+ fileCreated = true;
+ } catch (FileAlreadyExistsException ix) {
+ // This may be a zombie file left over by a previous
+ // execution. Reuse it - but only if we can actually
+ // write to its directory.
+ // Note that this is a situation that may happen,
+ // but not too frequently.
+ if (Files.isRegularFile(lockFilePath, LinkOption.NOFOLLOW_LINKS)
+ && Files.isWritable(lockFilePath.getParent())) {
+ try {
+ channel = FileChannel.open(lockFilePath,
+ WRITE, APPEND);
+ } catch (NoSuchFileException x) {
+ // Race condition - retry once, and if that
+ // fails again just try the next name in
+ // the sequence.
+ continue;
+ } catch(IOException x) {
+ // the file may not be writable for us.
+ // try the next name in the sequence
+ break;
+ }
+ } else {
+ // at this point channel should still be null.
+ // break and try the next name in the sequence.
+ break;
+ }
+ }
}
+ if (channel == null) continue; // try the next name;
+ lockFileChannel = channel;
+
boolean available;
try {
available = lockFileChannel.tryLock() != null;
// We got the lock OK.
+ // At this point we could call File.deleteOnExit().
+ // However, this could have undesirable side effects
+ // as indicated by JDK-4872014. So we will instead
+ // rely on the fact that close() will remove the lock
+ // file and that whoever is creating FileHandlers should
+ // be responsible for closing them.
} catch (IOException ix) {
// We got an IOException while trying to get the lock.
// This normally indicates that locking is not supported
// on the target directory. We have to proceed without
- // getting a lock. Drop through.
- available = true;
+ // getting a lock. Drop through, but only if we did
+ // create the file...
+ available = fileCreated;
+ } catch (OverlappingFileLockException x) {
+ // someone already locked this file in this VM, through
+ // some other channel - that is - using something else
+ // than new FileHandler(...);
+ // continue searching for an available lock.
+ available = false;
}
if (available) {
// We got the lock. Remember it.
- locks.put(lockFileName, lockFileName);
+ locks.add(lockFileName);
break;
}
diff --git a/src/share/classes/javax/swing/JDesktopPane.java b/src/share/classes/javax/swing/JDesktopPane.java
index b5945dd..0f05f79 100644
--- a/src/share/classes/javax/swing/JDesktopPane.java
+++ b/src/share/classes/javax/swing/JDesktopPane.java
@@ -43,6 +43,7 @@
import java.beans.PropertyVetoException;
import java.util.Set;
import java.util.TreeSet;
+import java.util.LinkedHashSet;
/**
* A container used to create a multiple-document interface or a virtual desktop.
* You create <code>JInternalFrame</code> objects and add them to the
@@ -266,7 +267,7 @@
private static Collection<JInternalFrame> getAllFrames(Container parent) {
int i, count;
- Collection<JInternalFrame> results = new ArrayList<JInternalFrame>();
+ Collection<JInternalFrame> results = new LinkedHashSet<>();
count = parent.getComponentCount();
for (i = 0; i < count; i++) {
Component next = parent.getComponent(i);
diff --git a/src/share/classes/sun/util/resources/lt/CurrencyNames_lt_LT.properties b/src/share/classes/sun/util/resources/lt/CurrencyNames_lt_LT.properties
index f727521..a0884fa 100644
--- a/src/share/classes/sun/util/resources/lt/CurrencyNames_lt_LT.properties
+++ b/src/share/classes/sun/util/resources/lt/CurrencyNames_lt_LT.properties
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2005, 2014, 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
@@ -35,4 +35,5 @@
# This notice and attribution to Taligent may not be removed.
# Taligent is a registered trademark of Taligent, Inc.
+EUR=\u20AC
LTL=Lt
diff --git a/src/share/native/sun/java2d/cmm/lcms/cmscam02.c b/src/share/native/sun/java2d/cmm/lcms/cmscam02.c
index 38d164a..86ec167 100644
--- a/src/share/native/sun/java2d/cmm/lcms/cmscam02.c
+++ b/src/share/native/sun/java2d/cmm/lcms/cmscam02.c
@@ -467,11 +467,12 @@
CAM02COLOR clr;
cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel;
- memset(&clr, 0, sizeof(clr));
_cmsAssert(lpMod != NULL);
_cmsAssert(pIn != NULL);
_cmsAssert(pOut != NULL);
+ memset(&clr, 0, sizeof(clr));
+
clr.XYZ[0] = pIn ->X;
clr.XYZ[1] = pIn ->Y;
clr.XYZ[2] = pIn ->Z;
@@ -492,11 +493,12 @@
CAM02COLOR clr;
cmsCIECAM02* lpMod = (cmsCIECAM02*) hModel;
- memset(&clr, 0, sizeof(clr));
_cmsAssert(lpMod != NULL);
_cmsAssert(pIn != NULL);
_cmsAssert(pOut != NULL);
+ memset(&clr, 0, sizeof(clr));
+
clr.J = pIn -> J;
clr.C = pIn -> C;
clr.h = pIn -> h;
@@ -511,4 +513,3 @@
pOut ->Y = clr.XYZ[1];
pOut ->Z = clr.XYZ[2];
}
-
diff --git a/src/share/native/sun/java2d/cmm/lcms/cmscgats.c b/src/share/native/sun/java2d/cmm/lcms/cmscgats.c
index 11fe36e..4610a23 100644
--- a/src/share/native/sun/java2d/cmm/lcms/cmscgats.c
+++ b/src/share/native/sun/java2d/cmm/lcms/cmscgats.c
@@ -2179,9 +2179,9 @@
if (cmsstrcasecmp(Fld, "SAMPLE_ID") == 0) {
- t -> SampleID = idField;
+ t -> SampleID = idField;
- for (i=0; i < t -> nPatches; i++) {
+ for (i=0; i < t -> nPatches; i++) {
char *Data = GetData(it8, i, idField);
if (Data) {
@@ -2196,7 +2196,7 @@
SetData(it8, i, idField, Buffer);
}
- }
+ }
}
diff --git a/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c b/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c
index cea3b8b..bc2b0da 100644
--- a/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c
+++ b/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c
@@ -137,15 +137,68 @@
// A pointer to the begining of the list
-static cmsIntentsList *Intents = DefaultIntents;
+_cmsIntentsPluginChunkType _cmsIntentsPluginChunk = { NULL };
+
+// Duplicates the zone of memory used by the plug-in in the new context
+static
+void DupPluginIntentsList(struct _cmsContext_struct* ctx,
+ const struct _cmsContext_struct* src)
+{
+ _cmsIntentsPluginChunkType newHead = { NULL };
+ cmsIntentsList* entry;
+ cmsIntentsList* Anterior = NULL;
+ _cmsIntentsPluginChunkType* head = (_cmsIntentsPluginChunkType*) src->chunks[IntentPlugin];
+
+ // Walk the list copying all nodes
+ for (entry = head->Intents;
+ entry != NULL;
+ entry = entry ->Next) {
+
+ cmsIntentsList *newEntry = ( cmsIntentsList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(cmsIntentsList));
+
+ if (newEntry == NULL)
+ return;
+
+ // We want to keep the linked list order, so this is a little bit tricky
+ newEntry -> Next = NULL;
+ if (Anterior)
+ Anterior -> Next = newEntry;
+
+ Anterior = newEntry;
+
+ if (newHead.Intents == NULL)
+ newHead.Intents = newEntry;
+ }
+
+ ctx ->chunks[IntentPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsIntentsPluginChunkType));
+}
+
+void _cmsAllocIntentsPluginChunk(struct _cmsContext_struct* ctx,
+ const struct _cmsContext_struct* src)
+{
+ if (src != NULL) {
+
+ // Copy all linked list
+ DupPluginIntentsList(ctx, src);
+ }
+ else {
+ static _cmsIntentsPluginChunkType IntentsPluginChunkType = { NULL };
+ ctx ->chunks[IntentPlugin] = _cmsSubAllocDup(ctx ->MemPool, &IntentsPluginChunkType, sizeof(_cmsIntentsPluginChunkType));
+ }
+}
+
// Search the list for a suitable intent. Returns NULL if not found
static
-cmsIntentsList* SearchIntent(cmsUInt32Number Intent)
+cmsIntentsList* SearchIntent(cmsContext ContextID, cmsUInt32Number Intent)
{
+ _cmsIntentsPluginChunkType* ctx = ( _cmsIntentsPluginChunkType*) _cmsContextGetClientChunk(ContextID, IntentPlugin);
cmsIntentsList* pt;
- for (pt = Intents; pt != NULL; pt = pt -> Next)
+ for (pt = ctx -> Intents; pt != NULL; pt = pt -> Next)
+ if (pt ->Intent == Intent) return pt;
+
+ for (pt = DefaultIntents; pt != NULL; pt = pt -> Next)
if (pt ->Intent == Intent) return pt;
return NULL;
@@ -1031,7 +1084,7 @@
// this case would present some issues if the custom intent tries to do things like
// preserve primaries. This solution is not perfect, but works well on most cases.
- Intent = SearchIntent(TheIntents[0]);
+ Intent = SearchIntent(ContextID, TheIntents[0]);
if (Intent == NULL) {
cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported intent '%d'", TheIntents[0]);
return NULL;
@@ -1046,12 +1099,14 @@
// Get information about available intents. nMax is the maximum space for the supplied "Codes"
// and "Descriptions" the function returns the total number of intents, which may be greater
// than nMax, although the matrices are not populated beyond this level.
-cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions)
+cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID, cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions)
{
+ _cmsIntentsPluginChunkType* ctx = ( _cmsIntentsPluginChunkType*) _cmsContextGetClientChunk(ContextID, IntentPlugin);
cmsIntentsList* pt;
cmsUInt32Number nIntents;
- for (nIntents=0, pt = Intents; pt != NULL; pt = pt -> Next)
+
+ for (nIntents=0, pt = ctx->Intents; pt != NULL; pt = pt -> Next)
{
if (nIntents < nMax) {
if (Codes != NULL)
@@ -1064,37 +1119,52 @@
nIntents++;
}
+ for (nIntents=0, pt = DefaultIntents; pt != NULL; pt = pt -> Next)
+ {
+ if (nIntents < nMax) {
+ if (Codes != NULL)
+ Codes[nIntents] = pt ->Intent;
+
+ if (Descriptions != NULL)
+ Descriptions[nIntents] = pt ->Description;
+ }
+
+ nIntents++;
+ }
return nIntents;
}
+cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions)
+{
+ return cmsGetSupportedIntentsTHR(NULL, nMax, Codes, Descriptions);
+}
+
// The plug-in registration. User can add new intents or override default routines
cmsBool _cmsRegisterRenderingIntentPlugin(cmsContext id, cmsPluginBase* Data)
{
+ _cmsIntentsPluginChunkType* ctx = ( _cmsIntentsPluginChunkType*) _cmsContextGetClientChunk(id, IntentPlugin);
cmsPluginRenderingIntent* Plugin = (cmsPluginRenderingIntent*) Data;
cmsIntentsList* fl;
- // Do we have to reset the intents?
+ // Do we have to reset the custom intents?
if (Data == NULL) {
- Intents = DefaultIntents;
- return TRUE;
+ ctx->Intents = NULL;
+ return TRUE;
}
- fl = SearchIntent(Plugin ->Intent);
+ fl = (cmsIntentsList*) _cmsPluginMalloc(id, sizeof(cmsIntentsList));
+ if (fl == NULL) return FALSE;
- if (fl == NULL) {
- fl = (cmsIntentsList*) _cmsPluginMalloc(id, sizeof(cmsIntentsList));
- if (fl == NULL) return FALSE;
- }
fl ->Intent = Plugin ->Intent;
- strncpy(fl ->Description, Plugin ->Description, 255);
- fl ->Description[255] = 0;
+ strncpy(fl ->Description, Plugin ->Description, sizeof(fl ->Description)-1);
+ fl ->Description[sizeof(fl ->Description)-1] = 0;
fl ->Link = Plugin ->Link;
- fl ->Next = Intents;
- Intents = fl;
+ fl ->Next = ctx ->Intents;
+ ctx ->Intents = fl;
return TRUE;
}
diff --git a/src/share/native/sun/java2d/cmm/lcms/cmserr.c b/src/share/native/sun/java2d/cmm/lcms/cmserr.c
index bf1e260..306d036 100644
--- a/src/share/native/sun/java2d/cmm/lcms/cmserr.c
+++ b/src/share/native/sun/java2d/cmm/lcms/cmserr.c
@@ -60,13 +60,14 @@
// compare two strings ignoring case
int CMSEXPORT cmsstrcasecmp(const char* s1, const char* s2)
{
- register const unsigned char *us1 = (const unsigned char *)s1,
- *us2 = (const unsigned char *)s2;
+ register const unsigned char *us1 = (const unsigned char *)s1,
+ *us2 = (const unsigned char *)s2;
- while (toupper(*us1) == toupper(*us2++))
- if (*us1++ == '\0')
- return (0);
- return (toupper(*us1) - toupper(*--us2));
+ while (toupper(*us1) == toupper(*us2++))
+ if (*us1++ == '\0')
+ return 0;
+
+ return (toupper(*us1) - toupper(*--us2));
}
// long int because C99 specifies ftell in such way (7.19.9.2)
@@ -91,9 +92,8 @@
//
// This is the interface to low-level memory management routines. By default a simple
// wrapping to malloc/free/realloc is provided, although there is a limit on the max
-// amount of memoy that can be reclaimed. This is mostly as a safety feature to
-// prevent bogus or malintentionated code to allocate huge blocks that otherwise lcms
-// would never need.
+// amount of memoy that can be reclaimed. This is mostly as a safety feature to prevent
+// bogus or evil code to allocate huge blocks that otherwise lcms would never need.
#define MAX_MEMORY_FOR_ALLOC ((cmsUInt32Number)(1024U*1024U*512U))
@@ -103,7 +103,7 @@
// required to be implemented: malloc, realloc and free, although the user may want to
// replace the optional mallocZero, calloc and dup as well.
-cmsBool _cmsRegisterMemHandlerPlugin(cmsPluginBase* Plugin);
+cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase* Plugin);
// *********************************************************************************
@@ -143,7 +143,7 @@
cmsUNUSED_PARAMETER(ContextID);
}
-// The default realloc function. Again it check for exploits. If Ptr is NULL,
+// The default realloc function. Again it checks for exploits. If Ptr is NULL,
// realloc behaves the same way as malloc and allocates a new block of size bytes.
static
void* _cmsReallocDefaultFn(cmsContext ContextID, void* Ptr, cmsUInt32Number size)
@@ -196,28 +196,73 @@
return mem;
}
-// Pointers to malloc and _cmsFree functions in current environment
-static void * (* MallocPtr)(cmsContext ContextID, cmsUInt32Number size) = _cmsMallocDefaultFn;
-static void * (* MallocZeroPtr)(cmsContext ContextID, cmsUInt32Number size) = _cmsMallocZeroDefaultFn;
-static void (* FreePtr)(cmsContext ContextID, void *Ptr) = _cmsFreeDefaultFn;
-static void * (* ReallocPtr)(cmsContext ContextID, void *Ptr, cmsUInt32Number NewSize) = _cmsReallocDefaultFn;
-static void * (* CallocPtr)(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size)= _cmsCallocDefaultFn;
-static void * (* DupPtr)(cmsContext ContextID, const void* Org, cmsUInt32Number size) = _cmsDupDefaultFn;
+
+// Pointers to memory manager functions in Context0
+_cmsMemPluginChunkType _cmsMemPluginChunk = { _cmsMallocDefaultFn, _cmsMallocZeroDefaultFn, _cmsFreeDefaultFn,
+ _cmsReallocDefaultFn, _cmsCallocDefaultFn, _cmsDupDefaultFn
+ };
+
+
+// Reset and duplicate memory manager
+void _cmsAllocMemPluginChunk(struct _cmsContext_struct* ctx, const struct _cmsContext_struct* src)
+{
+ _cmsAssert(ctx != NULL);
+
+ if (src != NULL) {
+
+ // Duplicate
+ ctx ->chunks[MemPlugin] = _cmsSubAllocDup(ctx ->MemPool, src ->chunks[MemPlugin], sizeof(_cmsMemPluginChunkType));
+ }
+ else {
+
+ // To reset it, we use the default allocators, which cannot be overriden
+ ctx ->chunks[MemPlugin] = &ctx ->DefaultMemoryManager;
+ }
+}
+
+// Auxiliar to fill memory management functions from plugin (or context 0 defaults)
+void _cmsInstallAllocFunctions(cmsPluginMemHandler* Plugin, _cmsMemPluginChunkType* ptr)
+{
+ if (Plugin == NULL) {
+
+ memcpy(ptr, &_cmsMemPluginChunk, sizeof(_cmsMemPluginChunk));
+ }
+ else {
+
+ ptr ->MallocPtr = Plugin -> MallocPtr;
+ ptr ->FreePtr = Plugin -> FreePtr;
+ ptr ->ReallocPtr = Plugin -> ReallocPtr;
+
+ // Make sure we revert to defaults
+ ptr ->MallocZeroPtr= _cmsMallocZeroDefaultFn;
+ ptr ->CallocPtr = _cmsCallocDefaultFn;
+ ptr ->DupPtr = _cmsDupDefaultFn;
+
+ if (Plugin ->MallocZeroPtr != NULL) ptr ->MallocZeroPtr = Plugin -> MallocZeroPtr;
+ if (Plugin ->CallocPtr != NULL) ptr ->CallocPtr = Plugin -> CallocPtr;
+ if (Plugin ->DupPtr != NULL) ptr ->DupPtr = Plugin -> DupPtr;
+
+ }
+}
+
// Plug-in replacement entry
-cmsBool _cmsRegisterMemHandlerPlugin(cmsPluginBase *Data)
+cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase *Data)
{
cmsPluginMemHandler* Plugin = (cmsPluginMemHandler*) Data;
+ _cmsMemPluginChunkType* ptr;
- // NULL forces to reset to defaults
+ // NULL forces to reset to defaults. In this special case, the defaults are stored in the context structure.
+ // Remaining plug-ins does NOT have any copy in the context structure, but this is somehow special as the
+ // context internal data should be malloce'd by using those functions.
if (Data == NULL) {
- MallocPtr = _cmsMallocDefaultFn;
- MallocZeroPtr= _cmsMallocZeroDefaultFn;
- FreePtr = _cmsFreeDefaultFn;
- ReallocPtr = _cmsReallocDefaultFn;
- CallocPtr = _cmsCallocDefaultFn;
- DupPtr = _cmsDupDefaultFn;
+ struct _cmsContext_struct* ctx = ( struct _cmsContext_struct*) ContextID;
+
+ // Return to the default allocators
+ if (ContextID != NULL) {
+ ctx->chunks[MemPlugin] = (void*) &ctx->DefaultMemoryManager;
+ }
return TRUE;
}
@@ -227,51 +272,56 @@
Plugin -> ReallocPtr == NULL) return FALSE;
// Set replacement functions
- MallocPtr = Plugin -> MallocPtr;
- FreePtr = Plugin -> FreePtr;
- ReallocPtr = Plugin -> ReallocPtr;
+ ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin);
+ if (ptr == NULL)
+ return FALSE;
- if (Plugin ->MallocZeroPtr != NULL) MallocZeroPtr = Plugin ->MallocZeroPtr;
- if (Plugin ->CallocPtr != NULL) CallocPtr = Plugin -> CallocPtr;
- if (Plugin ->DupPtr != NULL) DupPtr = Plugin -> DupPtr;
-
+ _cmsInstallAllocFunctions(Plugin, ptr);
return TRUE;
}
// Generic allocate
void* CMSEXPORT _cmsMalloc(cmsContext ContextID, cmsUInt32Number size)
{
- return MallocPtr(ContextID, size);
+ _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin);
+ return ptr ->MallocPtr(ContextID, size);
}
// Generic allocate & zero
void* CMSEXPORT _cmsMallocZero(cmsContext ContextID, cmsUInt32Number size)
{
- return MallocZeroPtr(ContextID, size);
+ _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin);
+ return ptr->MallocZeroPtr(ContextID, size);
}
// Generic calloc
void* CMSEXPORT _cmsCalloc(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size)
{
- return CallocPtr(ContextID, num, size);
+ _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin);
+ return ptr->CallocPtr(ContextID, num, size);
}
// Generic reallocate
void* CMSEXPORT _cmsRealloc(cmsContext ContextID, void* Ptr, cmsUInt32Number size)
{
- return ReallocPtr(ContextID, Ptr, size);
+ _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin);
+ return ptr->ReallocPtr(ContextID, Ptr, size);
}
// Generic free memory
void CMSEXPORT _cmsFree(cmsContext ContextID, void* Ptr)
{
- if (Ptr != NULL) FreePtr(ContextID, Ptr);
+ if (Ptr != NULL) {
+ _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin);
+ ptr ->FreePtr(ContextID, Ptr);
+ }
}
// Generic block duplication
void* CMSEXPORT _cmsDupMem(cmsContext ContextID, const void* Org, cmsUInt32Number size)
{
- return DupPtr(ContextID, Org, size);
+ _cmsMemPluginChunkType* ptr = (_cmsMemPluginChunkType*) _cmsContextGetClientChunk(ContextID, MemPlugin);
+ return ptr ->DupPtr(ContextID, Org, size);
}
// ********************************************************************************************
@@ -380,6 +430,26 @@
return (void*) ptr;
}
+// Duplicate in pool
+void* _cmsSubAllocDup(_cmsSubAllocator* s, const void *ptr, cmsUInt32Number size)
+{
+ void *NewPtr;
+
+ // Dup of null pointer is also NULL
+ if (ptr == NULL)
+ return NULL;
+
+ NewPtr = _cmsSubAlloc(s, size);
+
+ if (ptr != NULL && NewPtr != NULL) {
+ memcpy(NewPtr, ptr, size);
+ }
+
+ return NewPtr;
+}
+
+
+
// Error logging ******************************************************************
// There is no error handling at all. When a funtion fails, it returns proper value.
@@ -401,8 +471,26 @@
// This is our default log error
static void DefaultLogErrorHandlerFunction(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text);
-// The current handler in actual environment
-static cmsLogErrorHandlerFunction LogErrorHandler = DefaultLogErrorHandlerFunction;
+// Context0 storage, which is global
+_cmsLogErrorChunkType _cmsLogErrorChunk = { DefaultLogErrorHandlerFunction };
+
+// Allocates and inits error logger container for a given context. If src is NULL, only initializes the value
+// to the default. Otherwise, it duplicates the value. The interface is standard across all context clients
+void _cmsAllocLogErrorChunk(struct _cmsContext_struct* ctx,
+ const struct _cmsContext_struct* src)
+{
+ static _cmsLogErrorChunkType LogErrorChunk = { DefaultLogErrorHandlerFunction };
+ void* from;
+
+ if (src != NULL) {
+ from = src ->chunks[Logger];
+ }
+ else {
+ from = &LogErrorChunk;
+ }
+
+ ctx ->chunks[Logger] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsLogErrorChunkType));
+}
// The default error logger does nothing.
static
@@ -416,13 +504,24 @@
cmsUNUSED_PARAMETER(Text);
}
-// Change log error
+// Change log error, context based
+void CMSEXPORT cmsSetLogErrorHandlerTHR(cmsContext ContextID, cmsLogErrorHandlerFunction Fn)
+{
+ _cmsLogErrorChunkType* lhg = (_cmsLogErrorChunkType*) _cmsContextGetClientChunk(ContextID, Logger);
+
+ if (lhg != NULL) {
+
+ if (Fn == NULL)
+ lhg -> LogErrorHandler = DefaultLogErrorHandlerFunction;
+ else
+ lhg -> LogErrorHandler = Fn;
+ }
+}
+
+// Change log error, legacy
void CMSEXPORT cmsSetLogErrorHandler(cmsLogErrorHandlerFunction Fn)
{
- if (Fn == NULL)
- LogErrorHandler = DefaultLogErrorHandlerFunction;
- else
- LogErrorHandler = Fn;
+ cmsSetLogErrorHandlerTHR(NULL, Fn);
}
// Log an error
@@ -431,13 +530,18 @@
{
va_list args;
char Buffer[MAX_ERROR_MESSAGE_LEN];
+ _cmsLogErrorChunkType* lhg;
+
va_start(args, ErrorText);
vsnprintf(Buffer, MAX_ERROR_MESSAGE_LEN-1, ErrorText, args);
va_end(args);
- // Call handler
- LogErrorHandler(ContextID, ErrorCode, Buffer);
+ // Check for the context, if specified go there. If not, go for the global
+ lhg = (_cmsLogErrorChunkType*) _cmsContextGetClientChunk(ContextID, Logger);
+ if (lhg ->LogErrorHandler) {
+ lhg ->LogErrorHandler(ContextID, ErrorCode, Buffer);
+ }
}
// Utility function to print signatures
@@ -455,3 +559,125 @@
String[4] = 0;
}
+//--------------------------------------------------------------------------------------------------
+
+
+static
+void* defMtxCreate(cmsContext id)
+{
+ _cmsMutex* ptr_mutex = (_cmsMutex*) _cmsMalloc(id, sizeof(_cmsMutex));
+ _cmsInitMutexPrimitive(ptr_mutex);
+ return (void*) ptr_mutex;
+}
+
+static
+void defMtxDestroy(cmsContext id, void* mtx)
+{
+ _cmsDestroyMutexPrimitive((_cmsMutex *) mtx);
+ _cmsFree(id, mtx);
+}
+
+static
+cmsBool defMtxLock(cmsContext id, void* mtx)
+{
+ cmsUNUSED_PARAMETER(id);
+ return _cmsLockPrimitive((_cmsMutex *) mtx) == 0;
+}
+
+static
+void defMtxUnlock(cmsContext id, void* mtx)
+{
+ cmsUNUSED_PARAMETER(id);
+ _cmsUnlockPrimitive((_cmsMutex *) mtx);
+}
+
+
+
+// Pointers to memory manager functions in Context0
+_cmsMutexPluginChunkType _cmsMutexPluginChunk = { defMtxCreate, defMtxDestroy, defMtxLock, defMtxUnlock };
+
+// Allocate and init mutex container.
+void _cmsAllocMutexPluginChunk(struct _cmsContext_struct* ctx,
+ const struct _cmsContext_struct* src)
+{
+ static _cmsMutexPluginChunkType MutexChunk = {defMtxCreate, defMtxDestroy, defMtxLock, defMtxUnlock };
+ void* from;
+
+ if (src != NULL) {
+ from = src ->chunks[MutexPlugin];
+ }
+ else {
+ from = &MutexChunk;
+ }
+
+ ctx ->chunks[MutexPlugin] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsMutexPluginChunkType));
+}
+
+// Register new ways to transform
+cmsBool _cmsRegisterMutexPlugin(cmsContext ContextID, cmsPluginBase* Data)
+{
+ cmsPluginMutex* Plugin = (cmsPluginMutex*) Data;
+ _cmsMutexPluginChunkType* ctx = ( _cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin);
+
+ if (Data == NULL) {
+
+ // No lock routines
+ ctx->CreateMutexPtr = NULL;
+ ctx->DestroyMutexPtr = NULL;
+ ctx->LockMutexPtr = NULL;
+ ctx ->UnlockMutexPtr = NULL;
+ return TRUE;
+ }
+
+ // Factory callback is required
+ if (Plugin ->CreateMutexPtr == NULL || Plugin ->DestroyMutexPtr == NULL ||
+ Plugin ->LockMutexPtr == NULL || Plugin ->UnlockMutexPtr == NULL) return FALSE;
+
+
+ ctx->CreateMutexPtr = Plugin->CreateMutexPtr;
+ ctx->DestroyMutexPtr = Plugin ->DestroyMutexPtr;
+ ctx ->LockMutexPtr = Plugin ->LockMutexPtr;
+ ctx ->UnlockMutexPtr = Plugin ->UnlockMutexPtr;
+
+ // All is ok
+ return TRUE;
+}
+
+// Generic Mutex fns
+void* CMSEXPORT _cmsCreateMutex(cmsContext ContextID)
+{
+ _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin);
+
+ if (ptr ->CreateMutexPtr == NULL) return NULL;
+
+ return ptr ->CreateMutexPtr(ContextID);
+}
+
+void CMSEXPORT _cmsDestroyMutex(cmsContext ContextID, void* mtx)
+{
+ _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin);
+
+ if (ptr ->DestroyMutexPtr != NULL) {
+
+ ptr ->DestroyMutexPtr(ContextID, mtx);
+ }
+}
+
+cmsBool CMSEXPORT _cmsLockMutex(cmsContext ContextID, void* mtx)
+{
+ _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin);
+
+ if (ptr ->LockMutexPtr == NULL) return TRUE;
+
+ return ptr ->LockMutexPtr(ContextID, mtx);
+}
+
+void CMSEXPORT _cmsUnlockMutex(cmsContext ContextID, void* mtx)
+{
+ _cmsMutexPluginChunkType* ptr = (_cmsMutexPluginChunkType*) _cmsContextGetClientChunk(ContextID, MutexPlugin);
+
+ if (ptr ->UnlockMutexPtr != NULL) {
+
+ ptr ->UnlockMutexPtr(ContextID, mtx);
+ }
+}
diff --git a/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c b/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c
index 79affb0..e68f258 100644
--- a/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c
+++ b/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c
@@ -82,7 +82,6 @@
} _cmsParametricCurvesCollection;
-
// This is the default (built-in) evaluator
static cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Number Params[], cmsFloat64Number R);
@@ -95,22 +94,77 @@
NULL // Next in chain
};
+// Duplicates the zone of memory used by the plug-in in the new context
+static
+void DupPluginCurvesList(struct _cmsContext_struct* ctx,
+ const struct _cmsContext_struct* src)
+{
+ _cmsCurvesPluginChunkType newHead = { NULL };
+ _cmsParametricCurvesCollection* entry;
+ _cmsParametricCurvesCollection* Anterior = NULL;
+ _cmsCurvesPluginChunkType* head = (_cmsCurvesPluginChunkType*) src->chunks[CurvesPlugin];
+
+ _cmsAssert(head != NULL);
+
+ // Walk the list copying all nodes
+ for (entry = head->ParametricCurves;
+ entry != NULL;
+ entry = entry ->Next) {
+
+ _cmsParametricCurvesCollection *newEntry = ( _cmsParametricCurvesCollection *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsParametricCurvesCollection));
+
+ if (newEntry == NULL)
+ return;
+
+ // We want to keep the linked list order, so this is a little bit tricky
+ newEntry -> Next = NULL;
+ if (Anterior)
+ Anterior -> Next = newEntry;
+
+ Anterior = newEntry;
+
+ if (newHead.ParametricCurves == NULL)
+ newHead.ParametricCurves = newEntry;
+ }
+
+ ctx ->chunks[CurvesPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsCurvesPluginChunkType));
+}
+
+// The allocator have to follow the chain
+void _cmsAllocCurvesPluginChunk(struct _cmsContext_struct* ctx,
+ const struct _cmsContext_struct* src)
+{
+ _cmsAssert(ctx != NULL);
+
+ if (src != NULL) {
+
+ // Copy all linked list
+ DupPluginCurvesList(ctx, src);
+ }
+ else {
+ static _cmsCurvesPluginChunkType CurvesPluginChunk = { NULL };
+ ctx ->chunks[CurvesPlugin] = _cmsSubAllocDup(ctx ->MemPool, &CurvesPluginChunk, sizeof(_cmsCurvesPluginChunkType));
+ }
+}
+
+
// The linked list head
-static _cmsParametricCurvesCollection* ParametricCurves = &DefaultCurves;
+_cmsCurvesPluginChunkType _cmsCurvesPluginChunk = { NULL };
// As a way to install new parametric curves
-cmsBool _cmsRegisterParametricCurvesPlugin(cmsContext id, cmsPluginBase* Data)
+cmsBool _cmsRegisterParametricCurvesPlugin(cmsContext ContextID, cmsPluginBase* Data)
{
+ _cmsCurvesPluginChunkType* ctx = ( _cmsCurvesPluginChunkType*) _cmsContextGetClientChunk(ContextID, CurvesPlugin);
cmsPluginParametricCurves* Plugin = (cmsPluginParametricCurves*) Data;
_cmsParametricCurvesCollection* fl;
if (Data == NULL) {
- ParametricCurves = &DefaultCurves;
+ ctx -> ParametricCurves = NULL;
return TRUE;
}
- fl = (_cmsParametricCurvesCollection*) _cmsPluginMalloc(id, sizeof(_cmsParametricCurvesCollection));
+ fl = (_cmsParametricCurvesCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsParametricCurvesCollection));
if (fl == NULL) return FALSE;
// Copy the parameters
@@ -126,8 +180,8 @@
memmove(fl->ParameterCount, Plugin ->ParameterCount, fl->nFunctions * sizeof(cmsUInt32Number));
// Keep linked list
- fl ->Next = ParametricCurves;
- ParametricCurves = fl;
+ fl ->Next = ctx->ParametricCurves;
+ ctx->ParametricCurves = fl;
// All is ok
return TRUE;
@@ -149,12 +203,24 @@
// Search for the collection which contains a specific type
static
-_cmsParametricCurvesCollection *GetParametricCurveByType(int Type, int* index)
+_cmsParametricCurvesCollection *GetParametricCurveByType(cmsContext ContextID, int Type, int* index)
{
_cmsParametricCurvesCollection* c;
int Position;
+ _cmsCurvesPluginChunkType* ctx = ( _cmsCurvesPluginChunkType*) _cmsContextGetClientChunk(ContextID, CurvesPlugin);
- for (c = ParametricCurves; c != NULL; c = c ->Next) {
+ for (c = ctx->ParametricCurves; c != NULL; c = c ->Next) {
+
+ Position = IsInSet(Type, c);
+
+ if (Position != -1) {
+ if (index != NULL)
+ *index = Position;
+ return c;
+ }
+ }
+ // If none found, revert for defaults
+ for (c = &DefaultCurves; c != NULL; c = c ->Next) {
Position = IsInSet(Type, c);
@@ -251,7 +317,7 @@
p ->Segments[i].SampledPoints = NULL;
- c = GetParametricCurveByType(Segments[i].Type, NULL);
+ c = GetParametricCurveByType(ContextID, Segments[i].Type, NULL);
if (c != NULL)
p ->Evals[i] = c ->Evaluator;
}
@@ -677,12 +743,12 @@
cmsCurveSegment Seg0;
int Pos = 0;
cmsUInt32Number size;
- _cmsParametricCurvesCollection* c = GetParametricCurveByType(Type, &Pos);
+ _cmsParametricCurvesCollection* c = GetParametricCurveByType(ContextID, Type, &Pos);
_cmsAssert(Params != NULL);
if (c == NULL) {
- cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Invalid parametric curve type %d", Type);
+ cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Invalid parametric curve type %d", Type);
return NULL;
}
@@ -872,7 +938,10 @@
_cmsAssert(InCurve != NULL);
// Try to reverse it analytically whatever possible
- if (InCurve ->nSegments == 1 && InCurve ->Segments[0].Type > 0 && InCurve -> Segments[0].Type <= 5) {
+
+ if (InCurve ->nSegments == 1 && InCurve ->Segments[0].Type > 0 &&
+ /* InCurve -> Segments[0].Type <= 5 */
+ GetParametricCurveByType(InCurve ->InterpParams->ContextID, InCurve ->Segments[0].Type, NULL) != NULL) {
return cmsBuildParametricToneCurve(InCurve ->InterpParams->ContextID,
-(InCurve -> Segments[0].Type),
diff --git a/src/share/native/sun/java2d/cmm/lcms/cmsgmt.c b/src/share/native/sun/java2d/cmm/lcms/cmsgmt.c
index 8ace203..0be9173 100644
--- a/src/share/native/sun/java2d/cmm/lcms/cmsgmt.c
+++ b/src/share/native/sun/java2d/cmm/lcms/cmsgmt.c
@@ -191,7 +191,7 @@
out = ComputeKToLstar(ContextID, nPoints, 1,
Intents + (nProfiles - 1),
- hProfiles + (nProfiles - 1),
+ &hProfiles [nProfiles - 1],
BPC + (nProfiles - 1),
AdaptationStates + (nProfiles - 1),
dwFlags);
diff --git a/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c b/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c
index ad971b5..e57e6ea 100644
--- a/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c
+++ b/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c
@@ -62,31 +62,57 @@
static cmsInterpFunction DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels, cmsUInt32Number nOutputChannels, cmsUInt32Number dwFlags);
// This is the default factory
-static cmsInterpFnFactory Interpolators = DefaultInterpolatorsFactory;
+_cmsInterpPluginChunkType _cmsInterpPluginChunk = { NULL };
+
+// The interpolation plug-in memory chunk allocator/dup
+void _cmsAllocInterpPluginChunk(struct _cmsContext_struct* ctx, const struct _cmsContext_struct* src)
+{
+ void* from;
+
+ _cmsAssert(ctx != NULL);
+
+ if (src != NULL) {
+ from = src ->chunks[InterpPlugin];
+ }
+ else {
+ static _cmsInterpPluginChunkType InterpPluginChunk = { NULL };
+
+ from = &InterpPluginChunk;
+ }
+
+ _cmsAssert(from != NULL);
+ ctx ->chunks[InterpPlugin] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsInterpPluginChunkType));
+}
// Main plug-in entry
-cmsBool _cmsRegisterInterpPlugin(cmsPluginBase* Data)
+cmsBool _cmsRegisterInterpPlugin(cmsContext ContextID, cmsPluginBase* Data)
{
cmsPluginInterpolation* Plugin = (cmsPluginInterpolation*) Data;
+ _cmsInterpPluginChunkType* ptr = (_cmsInterpPluginChunkType*) _cmsContextGetClientChunk(ContextID, InterpPlugin);
if (Data == NULL) {
- Interpolators = DefaultInterpolatorsFactory;
+ ptr ->Interpolators = NULL;
return TRUE;
}
// Set replacement functions
- Interpolators = Plugin ->InterpolatorsFactory;
+ ptr ->Interpolators = Plugin ->InterpolatorsFactory;
return TRUE;
}
// Set the interpolation method
-cmsBool _cmsSetInterpolationRoutine(cmsInterpParams* p)
+cmsBool _cmsSetInterpolationRoutine(cmsContext ContextID, cmsInterpParams* p)
{
- // Invoke factory, possibly in the Plug-in
- p ->Interpolation = Interpolators(p -> nInputs, p ->nOutputs, p ->dwFlags);
+ _cmsInterpPluginChunkType* ptr = (_cmsInterpPluginChunkType*) _cmsContextGetClientChunk(ContextID, InterpPlugin);
+
+ p ->Interpolation.Lerp16 = NULL;
+
+ // Invoke factory, possibly in the Plug-in
+ if (ptr ->Interpolators != NULL)
+ p ->Interpolation = ptr->Interpolators(p -> nInputs, p ->nOutputs, p ->dwFlags);
// If unsupported by the plug-in, go for the LittleCMS default.
// If happens only if an extern plug-in is being used
@@ -97,6 +123,7 @@
if (p ->Interpolation.Lerp16 == NULL) {
return FALSE;
}
+
return TRUE;
}
@@ -141,7 +168,7 @@
p ->opta[i] = p ->opta[i-1] * nSamples[InputChan-i];
- if (!_cmsSetInterpolationRoutine(p)) {
+ if (!_cmsSetInterpolationRoutine(ContextID, p)) {
cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported interpolation (%d->%d channels)", InputChan, OutputChan);
_cmsFree(ContextID, p);
return NULL;
diff --git a/src/share/native/sun/java2d/cmm/lcms/cmsio0.c b/src/share/native/sun/java2d/cmm/lcms/cmsio0.c
index 8f421c2..d4dc1b0 100644
--- a/src/share/native/sun/java2d/cmm/lcms/cmsio0.c
+++ b/src/share/native/sun/java2d/cmm/lcms/cmsio0.c
@@ -229,15 +229,14 @@
if (ResData == NULL) return FALSE; // Housekeeping
// Check for available space. Clip.
- if (iohandler ->UsedSpace + size > ResData->Size) {
- size = ResData ->Size - iohandler ->UsedSpace;
+ if (ResData->Pointer + size > ResData->Size) {
+ size = ResData ->Size - ResData->Pointer;
}
if (size == 0) return TRUE; // Write zero bytes is ok, but does nothing
memmove(ResData ->Block + ResData ->Pointer, Ptr, size);
ResData ->Pointer += size;
- iohandler->UsedSpace += size;
if (ResData ->Pointer > iohandler->UsedSpace)
iohandler->UsedSpace = ResData ->Pointer;
@@ -371,7 +370,7 @@
static
cmsUInt32Number FileTell(cmsIOHANDLER* iohandler)
{
- return ftell((FILE*)iohandler ->stream);
+ return (cmsUInt32Number) ftell((FILE*)iohandler ->stream);
}
// Writes data to stream, also keeps used space for further reference. Returns TRUE on success, FALSE on error
@@ -414,7 +413,7 @@
cmsSignalError(ContextID, cmsERROR_FILE, "File '%s' not found", FileName);
return NULL;
}
- iohandler -> ReportedSize = cmsfilelength(fm);
+ iohandler -> ReportedSize = (cmsUInt32Number) cmsfilelength(fm);
break;
case 'w':
@@ -461,7 +460,7 @@
iohandler -> ContextID = ContextID;
iohandler -> stream = (void*) Stream;
iohandler -> UsedSpace = 0;
- iohandler -> ReportedSize = cmsfilelength(Stream);
+ iohandler -> ReportedSize = (cmsUInt32Number) cmsfilelength(Stream);
iohandler -> PhysicalFile[0] = 0;
iohandler ->Read = FileRead;
@@ -501,6 +500,9 @@
// Set creation date/time
memmove(&Icc ->Created, gmtime(&now), sizeof(Icc ->Created));
+ // Create a mutex if the user provided proper plugin. NULL otherwise
+ Icc ->UsrMutex = _cmsCreateMutex(ContextID);
+
// Return the handle
return (cmsHPROFILE) Icc;
}
@@ -579,9 +581,39 @@
return n;
}
+// Deletes a tag entry
-// Create a new tag entry
+static
+void _cmsDeleteTagByPos(_cmsICCPROFILE* Icc, int i)
+{
+ _cmsAssert(Icc != NULL);
+ _cmsAssert(i >= 0);
+
+ if (Icc -> TagPtrs[i] != NULL) {
+
+ // Free previous version
+ if (Icc ->TagSaveAsRaw[i]) {
+ _cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]);
+ }
+ else {
+ cmsTagTypeHandler* TypeHandler = Icc ->TagTypeHandlers[i];
+
+ if (TypeHandler != NULL) {
+
+ cmsTagTypeHandler LocalTypeHandler = *TypeHandler;
+ LocalTypeHandler.ContextID = Icc ->ContextID; // As an additional parameter
+ LocalTypeHandler.ICCVersion = Icc ->Version;
+ LocalTypeHandler.FreePtr(&LocalTypeHandler, Icc -> TagPtrs[i]);
+ Icc ->TagPtrs[i] = NULL;
+ }
+ }
+
+ }
+}
+
+
+// Creates a new tag entry
static
cmsBool _cmsNewTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, int* NewPos)
{
@@ -589,15 +621,15 @@
// Search for the tag
i = _cmsSearchTag(Icc, sig, FALSE);
-
- // Now let's do it easy. If the tag has been already written, that's an error
if (i >= 0) {
- cmsSignalError(Icc ->ContextID, cmsERROR_ALREADY_DEFINED, "Tag '%x' already exists", sig);
- return FALSE;
+
+ // Already exists? delete it
+ _cmsDeleteTagByPos(Icc, i);
+ *NewPos = i;
}
else {
- // New one
+ // No, make a new one
if (Icc -> TagCount >= MAX_TABLE_TAG) {
cmsSignalError(Icc ->ContextID, cmsERROR_RANGE, "Too many tags (%d)", MAX_TABLE_TAG);
@@ -979,7 +1011,7 @@
// 4.2 -> 0x4200000
- Icc -> Version = BaseToBase((cmsUInt32Number) floor(Version * 100.0), 10, 16) << 16;
+ Icc -> Version = BaseToBase((cmsUInt32Number) floor(Version * 100.0 + 0.5), 10, 16) << 16;
}
cmsFloat64Number CMSEXPORT cmsGetProfileVersion(cmsHPROFILE hProfile)
@@ -1011,6 +1043,32 @@
return NULL;
}
+// Create profile from IOhandler
+cmsHPROFILE CMSEXPORT cmsOpenProfileFromIOhandler2THR(cmsContext ContextID, cmsIOHANDLER* io, cmsBool write)
+{
+ _cmsICCPROFILE* NewIcc;
+ cmsHPROFILE hEmpty = cmsCreateProfilePlaceholder(ContextID);
+
+ if (hEmpty == NULL) return NULL;
+
+ NewIcc = (_cmsICCPROFILE*) hEmpty;
+
+ NewIcc ->IOhandler = io;
+ if (write) {
+
+ NewIcc -> IsWrite = TRUE;
+ return hEmpty;
+ }
+
+ if (!_cmsReadHeader(NewIcc)) goto Error;
+ return hEmpty;
+
+Error:
+ cmsCloseProfile(hEmpty);
+ return NULL;
+}
+
+
// Create profile from disk file
cmsHPROFILE CMSEXPORT cmsOpenProfileFromFileTHR(cmsContext ContextID, const char *lpFileName, const char *sAccess)
{
@@ -1202,7 +1260,7 @@
else {
// Search for support on this tag
- TagDescriptor = _cmsGetTagDescriptor(Icc -> TagNames[i]);
+ TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, Icc -> TagNames[i]);
if (TagDescriptor == NULL) continue; // Unsupported, ignore it
if (TagDescriptor ->DecideType != NULL) {
@@ -1214,7 +1272,7 @@
Type = TagDescriptor ->SupportedTypes[0];
}
- TypeHandler = _cmsGetTagTypeHandler(Type);
+ TypeHandler = _cmsGetTagTypeHandler(Icc->ContextID, Type);
if (TypeHandler == NULL) {
cmsSignalError(Icc ->ContextID, cmsERROR_INTERNAL, "(Internal) no handler for tag %x", Icc -> TagNames[i]);
@@ -1282,10 +1340,12 @@
{
_cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
_cmsICCPROFILE Keep;
- cmsIOHANDLER* PrevIO;
+ cmsIOHANDLER* PrevIO = NULL;
cmsUInt32Number UsedSpace;
cmsContext ContextID;
+ _cmsAssert(hProfile != NULL);
+
memmove(&Keep, Icc, sizeof(_cmsICCPROFILE));
ContextID = cmsGetProfileContextID(hProfile);
@@ -1294,18 +1354,19 @@
// Pass #1 does compute offsets
- if (!_cmsWriteHeader(Icc, 0)) return 0;
- if (!SaveTags(Icc, &Keep)) return 0;
+ if (!_cmsWriteHeader(Icc, 0)) goto Error;
+ if (!SaveTags(Icc, &Keep)) goto Error;
UsedSpace = PrevIO ->UsedSpace;
// Pass #2 does save to iohandler
if (io != NULL) {
+
Icc ->IOhandler = io;
- if (!SetLinks(Icc)) goto CleanUp;
- if (!_cmsWriteHeader(Icc, UsedSpace)) goto CleanUp;
- if (!SaveTags(Icc, &Keep)) goto CleanUp;
+ if (!SetLinks(Icc)) goto Error;
+ if (!_cmsWriteHeader(Icc, UsedSpace)) goto Error;
+ if (!SaveTags(Icc, &Keep)) goto Error;
}
memmove(Icc, &Keep, sizeof(_cmsICCPROFILE));
@@ -1314,7 +1375,7 @@
return UsedSpace;
-CleanUp:
+Error:
cmsCloseIOhandler(PrevIO);
memmove(Icc, &Keep, sizeof(_cmsICCPROFILE));
return 0;
@@ -1362,11 +1423,13 @@
cmsIOHANDLER* io;
cmsContext ContextID = cmsGetProfileContextID(hProfile);
+ _cmsAssert(BytesNeeded != NULL);
+
// Should we just calculate the needed space?
if (MemPtr == NULL) {
*BytesNeeded = cmsSaveProfileToIOhandler(hProfile, NULL);
- return (*BytesNeeded == 0 ? FALSE : TRUE);
+ return (*BytesNeeded == 0) ? FALSE : TRUE;
}
// That is a real write operation
@@ -1419,6 +1482,8 @@
rc &= cmsCloseIOhandler(Icc->IOhandler);
}
+ _cmsDestroyMutex(Icc->ContextID, Icc->UsrMutex);
+
_cmsFree(Icc ->ContextID, Icc); // Free placeholder memory
return rc;
@@ -1459,14 +1524,18 @@
cmsUInt32Number ElemCount;
int n;
+ if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return NULL;
+
n = _cmsSearchTag(Icc, sig, TRUE);
- if (n < 0) return NULL; // Not found, return NULL
+ if (n < 0) goto Error; // Not found, return NULL
// If the element is already in memory, return the pointer
if (Icc -> TagPtrs[n]) {
- if (Icc ->TagSaveAsRaw[n]) return NULL; // We don't support read raw tags as cooked
+ if (Icc ->TagSaveAsRaw[n]) goto Error; // We don't support read raw tags as cooked
+
+ _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
return Icc -> TagPtrs[n];
}
@@ -1476,23 +1545,32 @@
// Seek to its location
if (!io -> Seek(io, Offset))
- return NULL;
+ goto Error;
// Search for support on this tag
- TagDescriptor = _cmsGetTagDescriptor(sig);
- if (TagDescriptor == NULL) return NULL; // Unsupported.
+ TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, sig);
+ if (TagDescriptor == NULL) {
+
+ char String[5];
+
+ _cmsTagSignature2String(String, sig);
+
+ // An unknown element was found.
+ cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown tag type '%s' found.", String);
+ goto Error; // Unsupported.
+ }
// if supported, get type and check if in list
BaseType = _cmsReadTypeBase(io);
- if (BaseType == 0) return NULL;
+ if (BaseType == 0) goto Error;
- if (!IsTypeSupported(TagDescriptor, BaseType)) return NULL;
+ if (!IsTypeSupported(TagDescriptor, BaseType)) goto Error;
TagSize -= 8; // Alredy read by the type base logic
// Get type handler
- TypeHandler = _cmsGetTagTypeHandler(BaseType);
- if (TypeHandler == NULL) return NULL;
+ TypeHandler = _cmsGetTagTypeHandler(Icc ->ContextID, BaseType);
+ if (TypeHandler == NULL) goto Error;
LocalTypeHandler = *TypeHandler;
@@ -1511,7 +1589,7 @@
_cmsTagSignature2String(String, sig);
cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "Corrupted tag '%s'", String);
- return NULL;
+ goto Error;
}
// This is a weird error that may be a symptom of something more serious, the number of
@@ -1527,7 +1605,14 @@
// Return the data
+ _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
return Icc -> TagPtrs[n];
+
+
+ // Return error and unlock tha data
+Error:
+ _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
+ return NULL;
}
@@ -1561,49 +1646,26 @@
cmsFloat64Number Version;
char TypeString[5], SigString[5];
+ if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return FALSE;
+ // To delete tags.
if (data == NULL) {
+ // Delete the tag
i = _cmsSearchTag(Icc, sig, FALSE);
- if (i >= 0)
+ if (i >= 0) {
+
+ // Use zero as a mark of deleted
+ _cmsDeleteTagByPos(Icc, i);
Icc ->TagNames[i] = (cmsTagSignature) 0;
- // Unsupported by now, reserved for future ampliations (delete)
- return FALSE;
+ _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
+ return TRUE;
+ }
+ // Didn't find the tag
+ goto Error;
}
- i = _cmsSearchTag(Icc, sig, FALSE);
- if (i >=0) {
-
- if (Icc -> TagPtrs[i] != NULL) {
-
- // Already exists. Free previous version
- if (Icc ->TagSaveAsRaw[i]) {
- _cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]);
- }
- else {
- TypeHandler = Icc ->TagTypeHandlers[i];
-
- if (TypeHandler != NULL) {
-
- LocalTypeHandler = *TypeHandler;
- LocalTypeHandler.ContextID = Icc ->ContextID; // As an additional parameter
- LocalTypeHandler.ICCVersion = Icc ->Version;
- LocalTypeHandler.FreePtr(&LocalTypeHandler, Icc -> TagPtrs[i]);
- }
- }
- }
- }
- else {
- // New one
- i = Icc -> TagCount;
-
- if (i >= MAX_TABLE_TAG) {
- cmsSignalError(Icc ->ContextID, cmsERROR_RANGE, "Too many tags (%d)", MAX_TABLE_TAG);
- return FALSE;
- }
-
- Icc -> TagCount++;
- }
+ if (!_cmsNewTag(Icc, sig, &i)) goto Error;
// This is not raw
Icc ->TagSaveAsRaw[i] = FALSE;
@@ -1612,10 +1674,10 @@
Icc ->TagLinked[i] = (cmsTagSignature) 0;
// Get information about the TAG.
- TagDescriptor = _cmsGetTagDescriptor(sig);
+ TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, sig);
if (TagDescriptor == NULL){
cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported tag '%x'", sig);
- return FALSE;
+ goto Error;
}
@@ -1633,7 +1695,6 @@
}
else {
-
Type = TagDescriptor ->SupportedTypes[0];
}
@@ -1644,18 +1705,18 @@
_cmsTagSignature2String(SigString, sig);
cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported type '%s' for tag '%s'", TypeString, SigString);
- return FALSE;
+ goto Error;
}
// Does we have a handler for this type?
- TypeHandler = _cmsGetTagTypeHandler(Type);
+ TypeHandler = _cmsGetTagTypeHandler(Icc->ContextID, Type);
if (TypeHandler == NULL) {
_cmsTagSignature2String(TypeString, (cmsTagSignature) Type);
_cmsTagSignature2String(SigString, sig);
cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported type '%s' for tag '%s'", TypeString, SigString);
- return FALSE; // Should never happen
+ goto Error; // Should never happen
}
@@ -1668,7 +1729,7 @@
LocalTypeHandler = *TypeHandler;
LocalTypeHandler.ContextID = Icc ->ContextID;
LocalTypeHandler.ICCVersion = Icc ->Version;
- Icc ->TagPtrs[i] = LocalTypeHandler.DupPtr(&LocalTypeHandler, data, TagDescriptor ->ElemCount);
+ Icc ->TagPtrs[i] = LocalTypeHandler.DupPtr(&LocalTypeHandler, data, TagDescriptor ->ElemCount);
if (Icc ->TagPtrs[i] == NULL) {
@@ -1676,10 +1737,16 @@
_cmsTagSignature2String(SigString, sig);
cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "Malformed struct in type '%s' for tag '%s'", TypeString, SigString);
- return FALSE;
+ goto Error;
}
+ _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
return TRUE;
+
+Error:
+ _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
+ return FALSE;
+
}
// Read and write raw data. The only way those function would work and keep consistence with normal read and write
@@ -1700,9 +1767,11 @@
cmsUInt32Number rc;
cmsUInt32Number Offset, TagSize;
+ if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return 0;
+
// Search for given tag in ICC profile directory
i = _cmsSearchTag(Icc, sig, TRUE);
- if (i < 0) return 0; // Not found, return 0
+ if (i < 0) goto Error; // Not found,
// It is already read?
if (Icc -> TagPtrs[i] == NULL) {
@@ -1717,12 +1786,14 @@
if (BufferSize < TagSize)
TagSize = BufferSize;
- if (!Icc ->IOhandler ->Seek(Icc ->IOhandler, Offset)) return 0;
- if (!Icc ->IOhandler ->Read(Icc ->IOhandler, data, 1, TagSize)) return 0;
+ if (!Icc ->IOhandler ->Seek(Icc ->IOhandler, Offset)) goto Error;
+ if (!Icc ->IOhandler ->Read(Icc ->IOhandler, data, 1, TagSize)) goto Error;
+ _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
return TagSize;
}
+ _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
return Icc ->TagSizes[i];
}
@@ -1738,16 +1809,22 @@
memmove(data, Icc ->TagPtrs[i], TagSize);
+ _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
return TagSize;
}
+ _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
return Icc ->TagSizes[i];
}
// Already readed, or previously set by cmsWriteTag(). We need to serialize that
// data to raw in order to maintain consistency.
+
+ _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
Object = cmsReadTag(hProfile, sig);
- if (Object == NULL) return 0;
+ if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return 0;
+
+ if (Object == NULL) goto Error;
// Now we need to serialize to a memory block: just use a memory iohandler
@@ -1756,17 +1833,18 @@
} else{
MemIO = cmsOpenIOhandlerFromMem(cmsGetProfileContextID(hProfile), data, BufferSize, "w");
}
- if (MemIO == NULL) return 0;
+ if (MemIO == NULL) goto Error;
// Obtain type handling for the tag
TypeHandler = Icc ->TagTypeHandlers[i];
- TagDescriptor = _cmsGetTagDescriptor(sig);
+ TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, sig);
if (TagDescriptor == NULL) {
cmsCloseIOhandler(MemIO);
- return 0;
+ goto Error;
}
- // FIXME: No handling for TypeHandler == NULL here?
+ if (TypeHandler == NULL) goto Error;
+
// Serialize
LocalTypeHandler = *TypeHandler;
LocalTypeHandler.ContextID = Icc ->ContextID;
@@ -1774,19 +1852,24 @@
if (!_cmsWriteTypeBase(MemIO, TypeHandler ->Signature)) {
cmsCloseIOhandler(MemIO);
- return 0;
+ goto Error;
}
if (!LocalTypeHandler.WritePtr(&LocalTypeHandler, MemIO, Object, TagDescriptor ->ElemCount)) {
cmsCloseIOhandler(MemIO);
- return 0;
+ goto Error;
}
// Get Size and close
rc = MemIO ->Tell(MemIO);
cmsCloseIOhandler(MemIO); // Ignore return code this time
+ _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
return rc;
+
+Error:
+ _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
+ return 0;
}
// Similar to the anterior. This function allows to write directly to the ICC profile any data, without
@@ -1798,7 +1881,12 @@
_cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
int i;
- if (!_cmsNewTag(Icc, sig, &i)) return FALSE;
+ if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return 0;
+
+ if (!_cmsNewTag(Icc, sig, &i)) {
+ _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
+ return FALSE;
+ }
// Mark the tag as being written as RAW
Icc ->TagSaveAsRaw[i] = TRUE;
@@ -1809,6 +1897,7 @@
Icc ->TagPtrs[i] = _cmsDupMem(Icc ->ContextID, data, Size);
Icc ->TagSizes[i] = Size;
+ _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
return TRUE;
}
@@ -1818,7 +1907,12 @@
_cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
int i;
- if (!_cmsNewTag(Icc, sig, &i)) return FALSE;
+ if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return FALSE;
+
+ if (!_cmsNewTag(Icc, sig, &i)) {
+ _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
+ return FALSE;
+ }
// Keep necessary information
Icc ->TagSaveAsRaw[i] = FALSE;
@@ -1829,6 +1923,7 @@
Icc ->TagSizes[i] = 0;
Icc ->TagOffsets[i] = 0;
+ _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
return TRUE;
}
diff --git a/src/share/native/sun/java2d/cmm/lcms/cmsio1.c b/src/share/native/sun/java2d/cmm/lcms/cmsio1.c
index efdc6bf..61c2ca5 100644
--- a/src/share/native/sun/java2d/cmm/lcms/cmsio1.c
+++ b/src/share/native/sun/java2d/cmm/lcms/cmsio1.c
@@ -334,7 +334,8 @@
// Read and create a BRAND NEW MPE LUT from a given profile. All stuff dependent of version, etc
-// is adjusted here in order to create a LUT that takes care of all those details
+// is adjusted here in order to create a LUT that takes care of all those details.
+// We add intent = -1 as a way to read matrix shaper always, no matter of other LUT
cmsPipeline* _cmsReadInputLUT(cmsHPROFILE hProfile, int Intent)
{
cmsTagTypeSignature OriginalType;
@@ -364,49 +365,54 @@
return Lut;
}
- if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence
+ // This is an attempt to reuse this funtion to retrieve the matrix-shaper as pipeline no
+ // matter other LUT are present and have precedence. Intent = -1 means just this.
+ if (Intent != -1) {
- // Floating point LUT are always V4, but the encoding range is no
- // longer 0..1.0, so we need to add an stage depending on the color space
- return _cmsReadFloatInputTag(hProfile, tagFloat);
- }
+ if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence
- // Revert to perceptual if no tag is found
- if (!cmsIsTag(hProfile, tag16)) {
- tag16 = Device2PCS16[0];
- }
+ // Floating point LUT are always V4, but the encoding range is no
+ // longer 0..1.0, so we need to add an stage depending on the color space
+ return _cmsReadFloatInputTag(hProfile, tagFloat);
+ }
- if (cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table?
+ // Revert to perceptual if no tag is found
+ if (!cmsIsTag(hProfile, tag16)) {
+ tag16 = Device2PCS16[0];
+ }
- // Check profile version and LUT type. Do the necessary adjustments if needed
+ if (cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table?
- // First read the tag
- cmsPipeline* Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16);
- if (Lut == NULL) return NULL;
+ // Check profile version and LUT type. Do the necessary adjustments if needed
- // After reading it, we have now info about the original type
- OriginalType = _cmsGetTagTrueType(hProfile, tag16);
+ // First read the tag
+ cmsPipeline* Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16);
+ if (Lut == NULL) return NULL;
- // The profile owns the Lut, so we need to copy it
- Lut = cmsPipelineDup(Lut);
+ // After reading it, we have now info about the original type
+ OriginalType = _cmsGetTagTrueType(hProfile, tag16);
- // We need to adjust data only for Lab16 on output
- if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData)
+ // The profile owns the Lut, so we need to copy it
+ Lut = cmsPipelineDup(Lut);
+
+ // We need to adjust data only for Lab16 on output
+ if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData)
+ return Lut;
+
+ // If the input is Lab, add also a conversion at the begin
+ if (cmsGetColorSpace(hProfile) == cmsSigLabData &&
+ !cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID)))
+ goto Error;
+
+ // Add a matrix for conversion V2 to V4 Lab PCS
+ if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID)))
+ goto Error;
+
return Lut;
-
- // If the input is Lab, add also a conversion at the begin
- if (cmsGetColorSpace(hProfile) == cmsSigLabData &&
- !cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID)))
- goto Error;
-
- // Add a matrix for conversion V2 to V4 Lab PCS
- if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID)))
- goto Error;
-
- return Lut;
Error:
- cmsPipelineFree(Lut);
- return NULL;
+ cmsPipelineFree(Lut);
+ return NULL;
+ }
}
// Lut was not found, try to create a matrix-shaper
@@ -551,7 +557,7 @@
_cmsStageCLutData* CLUT = (_cmsStageCLutData*) Stage ->Data;
CLUT ->Params->dwFlags |= CMS_LERP_FLAGS_TRILINEAR;
- _cmsSetInterpolationRoutine(CLUT ->Params);
+ _cmsSetInterpolationRoutine(Lut->ContextID, CLUT ->Params);
}
}
}
@@ -609,54 +615,58 @@
cmsTagSignature tagFloat = PCS2DeviceFloat[Intent];
cmsContext ContextID = cmsGetProfileContextID(hProfile);
- if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence
- // Floating point LUT are always V4
- return _cmsReadFloatOutputTag(hProfile, tagFloat);
- }
+ if (Intent != -1) {
- // Revert to perceptual if no tag is found
- if (!cmsIsTag(hProfile, tag16)) {
- tag16 = PCS2Device16[0];
- }
+ if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence
- if (cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table?
+ // Floating point LUT are always V4
+ return _cmsReadFloatOutputTag(hProfile, tagFloat);
+ }
- // Check profile version and LUT type. Do the necessary adjustments if needed
+ // Revert to perceptual if no tag is found
+ if (!cmsIsTag(hProfile, tag16)) {
+ tag16 = PCS2Device16[0];
+ }
- // First read the tag
- cmsPipeline* Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16);
- if (Lut == NULL) return NULL;
+ if (cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table?
- // After reading it, we have info about the original type
- OriginalType = _cmsGetTagTrueType(hProfile, tag16);
+ // Check profile version and LUT type. Do the necessary adjustments if needed
- // The profile owns the Lut, so we need to copy it
- Lut = cmsPipelineDup(Lut);
- if (Lut == NULL) return NULL;
+ // First read the tag
+ cmsPipeline* Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16);
+ if (Lut == NULL) return NULL;
- // Now it is time for a controversial stuff. I found that for 3D LUTS using
- // Lab used as indexer space, trilinear interpolation should be used
- if (cmsGetPCS(hProfile) == cmsSigLabData)
- ChangeInterpolationToTrilinear(Lut);
+ // After reading it, we have info about the original type
+ OriginalType = _cmsGetTagTrueType(hProfile, tag16);
- // We need to adjust data only for Lab and Lut16 type
- if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData)
- return Lut;
+ // The profile owns the Lut, so we need to copy it
+ Lut = cmsPipelineDup(Lut);
+ if (Lut == NULL) return NULL;
- // Add a matrix for conversion V4 to V2 Lab PCS
- if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID)))
- goto Error;
+ // Now it is time for a controversial stuff. I found that for 3D LUTS using
+ // Lab used as indexer space, trilinear interpolation should be used
+ if (cmsGetPCS(hProfile) == cmsSigLabData)
+ ChangeInterpolationToTrilinear(Lut);
- // If the output is Lab, add also a conversion at the end
- if (cmsGetColorSpace(hProfile) == cmsSigLabData)
- if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID)))
+ // We need to adjust data only for Lab and Lut16 type
+ if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData)
+ return Lut;
+
+ // Add a matrix for conversion V4 to V2 Lab PCS
+ if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID)))
goto Error;
- return Lut;
+ // If the output is Lab, add also a conversion at the end
+ if (cmsGetColorSpace(hProfile) == cmsSigLabData)
+ if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID)))
+ goto Error;
+
+ return Lut;
Error:
- cmsPipelineFree(Lut);
- return NULL;
+ cmsPipelineFree(Lut);
+ return NULL;
+ }
}
// Lut not found, try to create a matrix-shaper
@@ -782,7 +792,7 @@
// Now it is time for a controversial stuff. I found that for 3D LUTS using
// Lab used as indexer space, trilinear interpolation should be used
- if (cmsGetColorSpace(hProfile) == cmsSigLabData)
+ if (cmsGetPCS(hProfile) == cmsSigLabData)
ChangeInterpolationToTrilinear(Lut);
// After reading it, we have info about the original type
@@ -793,12 +803,12 @@
// Here it is possible to get Lab on both sides
- if (cmsGetPCS(hProfile) == cmsSigLabData) {
+ if (cmsGetColorSpace(hProfile) == cmsSigLabData) {
if(!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID)))
goto Error2;
}
- if (cmsGetColorSpace(hProfile) == cmsSigLabData) {
+ if (cmsGetPCS(hProfile) == cmsSigLabData) {
if(!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID)))
goto Error2;
}
diff --git a/src/share/native/sun/java2d/cmm/lcms/cmsopt.c b/src/share/native/sun/java2d/cmm/lcms/cmsopt.c
index d184ed7..b9d6951 100644
--- a/src/share/native/sun/java2d/cmm/lcms/cmsopt.c
+++ b/src/share/native/sun/java2d/cmm/lcms/cmsopt.c
@@ -542,11 +542,13 @@
cmsToneCurve* InversePostLin = cmsReverseToneCurve(Curves[i]);
if (InversePostLin == NULL) {
- WhiteOut[i] = 0;
- continue;
+ WhiteOut[i] = WhitePointOut[i];
+
+ } else {
+
+ WhiteOut[i] = cmsEvalToneCurve16(InversePostLin, WhitePointOut[i]);
+ cmsFreeToneCurve(InversePostLin);
}
- WhiteOut[i] = cmsEvalToneCurve16(InversePostLin, WhitePointOut[i]);
- cmsFreeToneCurve(InversePostLin);
}
}
else {
@@ -1666,44 +1668,102 @@
};
// The linked list head
-static _cmsOptimizationCollection* OptimizationCollection = DefaultOptimization;
+_cmsOptimizationPluginChunkType _cmsOptimizationPluginChunk = { NULL };
+
+
+// Duplicates the zone of memory used by the plug-in in the new context
+static
+void DupPluginOptimizationList(struct _cmsContext_struct* ctx,
+ const struct _cmsContext_struct* src)
+{
+ _cmsOptimizationPluginChunkType newHead = { NULL };
+ _cmsOptimizationCollection* entry;
+ _cmsOptimizationCollection* Anterior = NULL;
+ _cmsOptimizationPluginChunkType* head = (_cmsOptimizationPluginChunkType*) src->chunks[OptimizationPlugin];
+
+ _cmsAssert(ctx != NULL);
+ _cmsAssert(head != NULL);
+
+ // Walk the list copying all nodes
+ for (entry = head->OptimizationCollection;
+ entry != NULL;
+ entry = entry ->Next) {
+
+ _cmsOptimizationCollection *newEntry = ( _cmsOptimizationCollection *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsOptimizationCollection));
+
+ if (newEntry == NULL)
+ return;
+
+ // We want to keep the linked list order, so this is a little bit tricky
+ newEntry -> Next = NULL;
+ if (Anterior)
+ Anterior -> Next = newEntry;
+
+ Anterior = newEntry;
+
+ if (newHead.OptimizationCollection == NULL)
+ newHead.OptimizationCollection = newEntry;
+ }
+
+ ctx ->chunks[OptimizationPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsOptimizationPluginChunkType));
+}
+
+void _cmsAllocOptimizationPluginChunk(struct _cmsContext_struct* ctx,
+ const struct _cmsContext_struct* src)
+{
+ if (src != NULL) {
+
+ // Copy all linked list
+ DupPluginOptimizationList(ctx, src);
+ }
+ else {
+ static _cmsOptimizationPluginChunkType OptimizationPluginChunkType = { NULL };
+ ctx ->chunks[OptimizationPlugin] = _cmsSubAllocDup(ctx ->MemPool, &OptimizationPluginChunkType, sizeof(_cmsOptimizationPluginChunkType));
+ }
+}
+
// Register new ways to optimize
-cmsBool _cmsRegisterOptimizationPlugin(cmsContext id, cmsPluginBase* Data)
+cmsBool _cmsRegisterOptimizationPlugin(cmsContext ContextID, cmsPluginBase* Data)
{
cmsPluginOptimization* Plugin = (cmsPluginOptimization*) Data;
+ _cmsOptimizationPluginChunkType* ctx = ( _cmsOptimizationPluginChunkType*) _cmsContextGetClientChunk(ContextID, OptimizationPlugin);
_cmsOptimizationCollection* fl;
if (Data == NULL) {
- OptimizationCollection = DefaultOptimization;
+ ctx->OptimizationCollection = NULL;
return TRUE;
}
// Optimizer callback is required
if (Plugin ->OptimizePtr == NULL) return FALSE;
- fl = (_cmsOptimizationCollection*) _cmsPluginMalloc(id, sizeof(_cmsOptimizationCollection));
+ fl = (_cmsOptimizationCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsOptimizationCollection));
if (fl == NULL) return FALSE;
// Copy the parameters
fl ->OptimizePtr = Plugin ->OptimizePtr;
// Keep linked list
- fl ->Next = OptimizationCollection;
- OptimizationCollection = fl;
+ fl ->Next = ctx->OptimizationCollection;
+
+ // Set the head
+ ctx ->OptimizationCollection = fl;
// All is ok
return TRUE;
}
// The entry point for LUT optimization
-cmsBool _cmsOptimizePipeline(cmsPipeline** PtrLut,
+cmsBool _cmsOptimizePipeline(cmsContext ContextID,
+ cmsPipeline** PtrLut,
int Intent,
cmsUInt32Number* InputFormat,
cmsUInt32Number* OutputFormat,
cmsUInt32Number* dwFlags)
{
+ _cmsOptimizationPluginChunkType* ctx = ( _cmsOptimizationPluginChunkType*) _cmsContextGetClientChunk(ContextID, OptimizationPlugin);
_cmsOptimizationCollection* Opts;
cmsBool AnySuccess = FALSE;
@@ -1733,8 +1793,8 @@
if (*dwFlags & cmsFLAGS_NOOPTIMIZE)
return FALSE;
- // Try built-in optimizations and plug-in
- for (Opts = OptimizationCollection;
+ // Try plug-in optimizations
+ for (Opts = ctx->OptimizationCollection;
Opts != NULL;
Opts = Opts ->Next) {
@@ -1745,6 +1805,17 @@
}
}
+ // Try built-in optimizations
+ for (Opts = DefaultOptimization;
+ Opts != NULL;
+ Opts = Opts ->Next) {
+
+ if (Opts ->OptimizePtr(PtrLut, Intent, InputFormat, OutputFormat, dwFlags)) {
+
+ return TRUE;
+ }
+ }
+
// Only simple optimizations succeeded
return AnySuccess;
}
diff --git a/src/share/native/sun/java2d/cmm/lcms/cmspack.c b/src/share/native/sun/java2d/cmm/lcms/cmspack.c
index b89830c..6659774 100644
--- a/src/share/native/sun/java2d/cmm/lcms/cmspack.c
+++ b/src/share/native/sun/java2d/cmm/lcms/cmspack.c
@@ -883,6 +883,42 @@
}
}
+// This is a conversion of XYZ float to 16 bits
+static
+cmsUInt8Number* UnrollXYZFloatTo16(register _cmsTRANSFORM* info,
+ register cmsUInt16Number wIn[],
+ register cmsUInt8Number* accum,
+ register cmsUInt32Number Stride)
+{
+ if (T_PLANAR(info -> InputFormat)) {
+
+ cmsFloat32Number* Pt = (cmsFloat32Number*) accum;
+ cmsCIEXYZ XYZ;
+
+ XYZ.X = Pt[0];
+ XYZ.Y = Pt[Stride];
+ XYZ.Z = Pt[Stride*2];
+ cmsFloat2XYZEncoded(wIn, &XYZ);
+
+ return accum + sizeof(cmsFloat32Number);
+
+ }
+
+ else {
+ cmsFloat32Number* Pt = (cmsFloat32Number*) accum;
+ cmsCIEXYZ XYZ;
+
+ XYZ.X = Pt[0];
+ XYZ.Y = Pt[1];
+ XYZ.Z = Pt[2];
+ cmsFloat2XYZEncoded(wIn, &XYZ);
+
+ accum += 3 * sizeof(cmsFloat32Number) + T_EXTRA(info ->InputFormat) * sizeof(cmsFloat32Number);
+
+ return accum;
+ }
+}
+
// Check if space is marked as ink
cmsINLINE cmsBool IsInkSpace(cmsUInt32Number Type)
{
@@ -2334,6 +2370,39 @@
}
static
+cmsUInt8Number* PackXYZFloatFrom16(register _cmsTRANSFORM* Info,
+ register cmsUInt16Number wOut[],
+ register cmsUInt8Number* output,
+ register cmsUInt32Number Stride)
+{
+ if (T_PLANAR(Info -> OutputFormat)) {
+
+ cmsCIEXYZ XYZ;
+ cmsFloat32Number* Out = (cmsFloat32Number*) output;
+ cmsXYZEncoded2Float(&XYZ, wOut);
+
+ Out[0] = (cmsFloat32Number) XYZ.X;
+ Out[Stride] = (cmsFloat32Number) XYZ.Y;
+ Out[Stride*2] = (cmsFloat32Number) XYZ.Z;
+
+ return output + sizeof(cmsFloat32Number);
+
+ }
+ else {
+
+ cmsCIEXYZ XYZ;
+ cmsFloat32Number* Out = (cmsFloat32Number*) output;
+ cmsXYZEncoded2Float(&XYZ, wOut);
+
+ Out[0] = (cmsFloat32Number) XYZ.X;
+ Out[1] = (cmsFloat32Number) XYZ.Y;
+ Out[2] = (cmsFloat32Number) XYZ.Z;
+
+ return output + (3 * sizeof(cmsFloat32Number) + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat32Number));
+ }
+}
+
+static
cmsUInt8Number* PackDoubleFrom16(register _cmsTRANSFORM* info,
register cmsUInt16Number wOut[],
register cmsUInt8Number* output,
@@ -2893,6 +2962,7 @@
{ TYPE_Lab_DBL, ANYPLANAR|ANYEXTRA, UnrollLabDoubleTo16},
{ TYPE_XYZ_DBL, ANYPLANAR|ANYEXTRA, UnrollXYZDoubleTo16},
{ TYPE_Lab_FLT, ANYPLANAR|ANYEXTRA, UnrollLabFloatTo16},
+ { TYPE_XYZ_FLT, ANYPLANAR|ANYEXTRA, UnrollXYZFloatTo16},
{ TYPE_GRAY_DBL, 0, UnrollDouble1Chan},
{ FLOAT_SH(1)|BYTES_SH(0), ANYCHANNELS|ANYPLANAR|ANYSWAPFIRST|ANYFLAVOR|
ANYSWAP|ANYEXTRA|ANYSPACE, UnrollDoubleTo16},
@@ -3027,6 +3097,7 @@
{ TYPE_XYZ_DBL, ANYPLANAR|ANYEXTRA, PackXYZDoubleFrom16},
{ TYPE_Lab_FLT, ANYPLANAR|ANYEXTRA, PackLabFloatFrom16},
+ { TYPE_XYZ_FLT, ANYPLANAR|ANYEXTRA, PackXYZFloatFrom16},
{ FLOAT_SH(1)|BYTES_SH(0), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|
ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE, PackDoubleFrom16},
@@ -3182,40 +3253,98 @@
} cmsFormattersFactoryList;
-static cmsFormattersFactoryList* FactoryList = NULL;
+_cmsFormattersPluginChunkType _cmsFormattersPluginChunk = { NULL };
+
+
+// Duplicates the zone of memory used by the plug-in in the new context
+static
+void DupFormatterFactoryList(struct _cmsContext_struct* ctx,
+ const struct _cmsContext_struct* src)
+{
+ _cmsFormattersPluginChunkType newHead = { NULL };
+ cmsFormattersFactoryList* entry;
+ cmsFormattersFactoryList* Anterior = NULL;
+ _cmsFormattersPluginChunkType* head = (_cmsFormattersPluginChunkType*) src->chunks[FormattersPlugin];
+
+ _cmsAssert(head != NULL);
+
+ // Walk the list copying all nodes
+ for (entry = head->FactoryList;
+ entry != NULL;
+ entry = entry ->Next) {
+
+ cmsFormattersFactoryList *newEntry = ( cmsFormattersFactoryList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(cmsFormattersFactoryList));
+
+ if (newEntry == NULL)
+ return;
+
+ // We want to keep the linked list order, so this is a little bit tricky
+ newEntry -> Next = NULL;
+ if (Anterior)
+ Anterior -> Next = newEntry;
+
+ Anterior = newEntry;
+
+ if (newHead.FactoryList == NULL)
+ newHead.FactoryList = newEntry;
+ }
+
+ ctx ->chunks[FormattersPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsFormattersPluginChunkType));
+}
+
+// The interpolation plug-in memory chunk allocator/dup
+void _cmsAllocFormattersPluginChunk(struct _cmsContext_struct* ctx,
+ const struct _cmsContext_struct* src)
+{
+ _cmsAssert(ctx != NULL);
+
+ if (src != NULL) {
+
+ // Duplicate the LIST
+ DupFormatterFactoryList(ctx, src);
+ }
+ else {
+ static _cmsFormattersPluginChunkType FormattersPluginChunk = { NULL };
+ ctx ->chunks[FormattersPlugin] = _cmsSubAllocDup(ctx ->MemPool, &FormattersPluginChunk, sizeof(_cmsFormattersPluginChunkType));
+ }
+}
+
// Formatters management
-cmsBool _cmsRegisterFormattersPlugin(cmsContext id, cmsPluginBase* Data)
+cmsBool _cmsRegisterFormattersPlugin(cmsContext ContextID, cmsPluginBase* Data)
{
+ _cmsFormattersPluginChunkType* ctx = ( _cmsFormattersPluginChunkType*) _cmsContextGetClientChunk(ContextID, FormattersPlugin);
cmsPluginFormatters* Plugin = (cmsPluginFormatters*) Data;
cmsFormattersFactoryList* fl ;
- // Reset
+ // Reset to built-in defaults
if (Data == NULL) {
- FactoryList = NULL;
+ ctx ->FactoryList = NULL;
return TRUE;
}
- fl = (cmsFormattersFactoryList*) _cmsPluginMalloc(id, sizeof(cmsFormattersFactoryList));
+ fl = (cmsFormattersFactoryList*) _cmsPluginMalloc(ContextID, sizeof(cmsFormattersFactoryList));
if (fl == NULL) return FALSE;
fl ->Factory = Plugin ->FormattersFactory;
- fl ->Next = FactoryList;
- FactoryList = fl;
+ fl ->Next = ctx -> FactoryList;
+ ctx ->FactoryList = fl;
return TRUE;
}
-cmsFormatter _cmsGetFormatter(cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8
+cmsFormatter _cmsGetFormatter(cmsContext ContextID,
+ cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8
cmsFormatterDirection Dir,
cmsUInt32Number dwFlags)
{
+ _cmsFormattersPluginChunkType* ctx = ( _cmsFormattersPluginChunkType*) _cmsContextGetClientChunk(ContextID, FormattersPlugin);
cmsFormattersFactoryList* f;
- for (f = FactoryList; f != NULL; f = f ->Next) {
+ for (f =ctx->FactoryList; f != NULL; f = f ->Next) {
cmsFormatter fn = f ->Factory(Type, Dir, dwFlags);
if (fn.Fmt16 != NULL) return fn;
diff --git a/src/share/native/sun/java2d/cmm/lcms/cmsplugin.c b/src/share/native/sun/java2d/cmm/lcms/cmsplugin.c
index 3d43485..ef75e13 100644
--- a/src/share/native/sun/java2d/cmm/lcms/cmsplugin.c
+++ b/src/share/native/sun/java2d/cmm/lcms/cmsplugin.c
@@ -544,22 +544,31 @@
// Plugin memory management -------------------------------------------------------------------------------------------------
-static _cmsSubAllocator* PluginPool = NULL;
-
// Specialized malloc for plug-ins, that is freed upon exit.
-void* _cmsPluginMalloc(cmsContext id, cmsUInt32Number size)
+void* _cmsPluginMalloc(cmsContext ContextID, cmsUInt32Number size)
{
- if (PluginPool == NULL)
- PluginPool = _cmsCreateSubAlloc(id, 4*1024);
+ struct _cmsContext_struct* ctx = _cmsGetContext(ContextID);
- return _cmsSubAlloc(PluginPool, size);
+ if (ctx ->MemPool == NULL) {
+
+ if (ContextID == NULL) {
+
+ ctx->MemPool = _cmsCreateSubAlloc(0, 2*1024);
+ }
+ else {
+ cmsSignalError(ContextID, cmsERROR_CORRUPTION_DETECTED, "NULL memory pool on context");
+ return NULL;
+ }
+ }
+
+ return _cmsSubAlloc(ctx->MemPool, size);
}
// Main plug-in dispatcher
cmsBool CMSEXPORT cmsPlugin(void* Plug_in)
{
- return cmsPluginTHR(NULL, Plug_in);
+ return cmsPluginTHR(NULL, Plug_in);
}
cmsBool CMSEXPORT cmsPluginTHR(cmsContext id, void* Plug_in)
@@ -571,12 +580,12 @@
Plugin = Plugin -> Next) {
if (Plugin -> Magic != cmsPluginMagicNumber) {
- cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin");
+ cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin");
return FALSE;
}
if (Plugin ->ExpectedVersion > LCMS_VERSION) {
- cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "plugin needs Little CMS %d, current version is %d",
+ cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "plugin needs Little CMS %d, current version is %d",
Plugin ->ExpectedVersion, LCMS_VERSION);
return FALSE;
}
@@ -584,11 +593,11 @@
switch (Plugin -> Type) {
case cmsPluginMemHandlerSig:
- if (!_cmsRegisterMemHandlerPlugin(Plugin)) return FALSE;
+ if (!_cmsRegisterMemHandlerPlugin(id, Plugin)) return FALSE;
break;
case cmsPluginInterpolationSig:
- if (!_cmsRegisterInterpPlugin(Plugin)) return FALSE;
+ if (!_cmsRegisterInterpPlugin(id, Plugin)) return FALSE;
break;
case cmsPluginTagTypeSig:
@@ -623,8 +632,12 @@
if (!_cmsRegisterTransformPlugin(id, Plugin)) return FALSE;
break;
+ case cmsPluginMutexSig:
+ if (!_cmsRegisterMutexPlugin(id, Plugin)) return FALSE;
+ break;
+
default:
- cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin type '%X'", Plugin -> Type);
+ cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin type '%X'", Plugin -> Type);
return FALSE;
}
}
@@ -637,19 +650,337 @@
// Revert all plug-ins to default
void CMSEXPORT cmsUnregisterPlugins(void)
{
- _cmsRegisterMemHandlerPlugin(NULL);
- _cmsRegisterInterpPlugin(NULL);
- _cmsRegisterTagTypePlugin(NULL, NULL);
- _cmsRegisterTagPlugin(NULL, NULL);
- _cmsRegisterFormattersPlugin(NULL, NULL);
- _cmsRegisterRenderingIntentPlugin(NULL, NULL);
- _cmsRegisterParametricCurvesPlugin(NULL, NULL);
- _cmsRegisterMultiProcessElementPlugin(NULL, NULL);
- _cmsRegisterOptimizationPlugin(NULL, NULL);
- _cmsRegisterTransformPlugin(NULL, NULL);
-
- if (PluginPool != NULL)
- _cmsSubAllocDestroy(PluginPool);
-
- PluginPool = NULL;
+ cmsUnregisterPluginsTHR(NULL);
}
+
+
+// The Global storage for system context. This is the one and only global variable
+// pointers structure. All global vars are referenced here.
+static struct _cmsContext_struct globalContext = {
+
+ NULL, // Not in the linked list
+ NULL, // No suballocator
+ {
+ NULL, // UserPtr,
+ &_cmsLogErrorChunk, // Logger,
+ &_cmsAlarmCodesChunk, // AlarmCodes,
+ &_cmsAdaptationStateChunk, // AdaptationState,
+ &_cmsMemPluginChunk, // MemPlugin,
+ &_cmsInterpPluginChunk, // InterpPlugin,
+ &_cmsCurvesPluginChunk, // CurvesPlugin,
+ &_cmsFormattersPluginChunk, // FormattersPlugin,
+ &_cmsTagTypePluginChunk, // TagTypePlugin,
+ &_cmsTagPluginChunk, // TagPlugin,
+ &_cmsIntentsPluginChunk, // IntentPlugin,
+ &_cmsMPETypePluginChunk, // MPEPlugin,
+ &_cmsOptimizationPluginChunk, // OptimizationPlugin,
+ &_cmsTransformPluginChunk, // TransformPlugin,
+ &_cmsMutexPluginChunk // MutexPlugin
+ },
+
+ { NULL, NULL, NULL, NULL, NULL, NULL } // The default memory allocator is not used for context 0
+};
+
+
+// The context pool (linked list head)
+static _cmsMutex _cmsContextPoolHeadMutex = CMS_MUTEX_INITIALIZER;
+static struct _cmsContext_struct* _cmsContextPoolHead = NULL;
+
+// Internal, get associated pointer, with guessing. Never returns NULL.
+struct _cmsContext_struct* _cmsGetContext(cmsContext ContextID)
+{
+ struct _cmsContext_struct* id = (struct _cmsContext_struct*) ContextID;
+ struct _cmsContext_struct* ctx;
+
+
+ // On 0, use global settings
+ if (id == NULL)
+ return &globalContext;
+
+ // Search
+ for (ctx = _cmsContextPoolHead;
+ ctx != NULL;
+ ctx = ctx ->Next) {
+
+ // Found it?
+ if (id == ctx)
+ return ctx; // New-style context,
+ }
+
+ return &globalContext;
+}
+
+
+// Internal: get the memory area associanted with each context client
+// Returns the block assigned to the specific zone.
+void* _cmsContextGetClientChunk(cmsContext ContextID, _cmsMemoryClient mc)
+{
+ struct _cmsContext_struct* ctx;
+ void *ptr;
+
+ if (mc < 0 || mc >= MemoryClientMax) {
+ cmsSignalError(ContextID, cmsERROR_RANGE, "Bad context client");
+ return NULL;
+ }
+
+ ctx = _cmsGetContext(ContextID);
+ ptr = ctx ->chunks[mc];
+
+ if (ptr != NULL)
+ return ptr;
+
+ // A null ptr means no special settings for that context, and this
+ // reverts to Context0 globals
+ return globalContext.chunks[mc];
+}
+
+
+// This function returns the given context its default pristine state,
+// as no plug-ins were declared. There is no way to unregister a single
+// plug-in, as a single call to cmsPluginTHR() function may register
+// many different plug-ins simultaneously, then there is no way to
+// identify which plug-in to unregister.
+void CMSEXPORT cmsUnregisterPluginsTHR(cmsContext ContextID)
+{
+ _cmsRegisterMemHandlerPlugin(ContextID, NULL);
+ _cmsRegisterInterpPlugin(ContextID, NULL);
+ _cmsRegisterTagTypePlugin(ContextID, NULL);
+ _cmsRegisterTagPlugin(ContextID, NULL);
+ _cmsRegisterFormattersPlugin(ContextID, NULL);
+ _cmsRegisterRenderingIntentPlugin(ContextID, NULL);
+ _cmsRegisterParametricCurvesPlugin(ContextID, NULL);
+ _cmsRegisterMultiProcessElementPlugin(ContextID, NULL);
+ _cmsRegisterOptimizationPlugin(ContextID, NULL);
+ _cmsRegisterTransformPlugin(ContextID, NULL);
+ _cmsRegisterMutexPlugin(ContextID, NULL);
+}
+
+
+// Returns the memory manager plug-in, if any, from the Plug-in bundle
+static
+cmsPluginMemHandler* _cmsFindMemoryPlugin(void* PluginBundle)
+{
+ cmsPluginBase* Plugin;
+
+ for (Plugin = (cmsPluginBase*) PluginBundle;
+ Plugin != NULL;
+ Plugin = Plugin -> Next) {
+
+ if (Plugin -> Magic == cmsPluginMagicNumber &&
+ Plugin -> ExpectedVersion <= LCMS_VERSION &&
+ Plugin -> Type == cmsPluginMemHandlerSig) {
+
+ // Found!
+ return (cmsPluginMemHandler*) Plugin;
+ }
+ }
+
+ // Nope, revert to defaults
+ return NULL;
+}
+
+
+// Creates a new context with optional associated plug-ins. Caller may also specify an optional pointer to user-defined
+// data that will be forwarded to plug-ins and logger.
+cmsContext CMSEXPORT cmsCreateContext(void* Plugin, void* UserData)
+{
+ struct _cmsContext_struct* ctx;
+ struct _cmsContext_struct fakeContext;
+
+ _cmsInstallAllocFunctions(_cmsFindMemoryPlugin(Plugin), &fakeContext.DefaultMemoryManager);
+
+ fakeContext.chunks[UserPtr] = UserData;
+ fakeContext.chunks[MemPlugin] = &fakeContext.DefaultMemoryManager;
+
+ // Create the context structure.
+ ctx = (struct _cmsContext_struct*) _cmsMalloc(&fakeContext, sizeof(struct _cmsContext_struct));
+ if (ctx == NULL)
+ return NULL; // Something very wrong happened!
+
+ // Init the structure and the memory manager
+ memset(ctx, 0, sizeof(struct _cmsContext_struct));
+
+ // Keep memory manager
+ memcpy(&ctx->DefaultMemoryManager, &fakeContext.DefaultMemoryManager, sizeof(_cmsMemPluginChunk));
+
+ // Maintain the linked list (with proper locking)
+ _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
+ ctx ->Next = _cmsContextPoolHead;
+ _cmsContextPoolHead = ctx;
+ _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
+
+ ctx ->chunks[UserPtr] = UserData;
+ ctx ->chunks[MemPlugin] = &ctx->DefaultMemoryManager;
+
+ // Now we can allocate the pool by using default memory manager
+ ctx ->MemPool = _cmsCreateSubAlloc(ctx, 22 * sizeof(void*)); // default size about 32 pointers
+ if (ctx ->MemPool == NULL) {
+
+ cmsDeleteContext(ctx);
+ return NULL;
+ }
+
+ _cmsAllocLogErrorChunk(ctx, NULL);
+ _cmsAllocAlarmCodesChunk(ctx, NULL);
+ _cmsAllocAdaptationStateChunk(ctx, NULL);
+ _cmsAllocMemPluginChunk(ctx, NULL);
+ _cmsAllocInterpPluginChunk(ctx, NULL);
+ _cmsAllocCurvesPluginChunk(ctx, NULL);
+ _cmsAllocFormattersPluginChunk(ctx, NULL);
+ _cmsAllocTagTypePluginChunk(ctx, NULL);
+ _cmsAllocMPETypePluginChunk(ctx, NULL);
+ _cmsAllocTagPluginChunk(ctx, NULL);
+ _cmsAllocIntentsPluginChunk(ctx, NULL);
+ _cmsAllocOptimizationPluginChunk(ctx, NULL);
+ _cmsAllocTransformPluginChunk(ctx, NULL);
+ _cmsAllocMutexPluginChunk(ctx, NULL);
+
+ // Setup the plug-ins
+ if (!cmsPluginTHR(ctx, Plugin)) {
+
+ cmsDeleteContext(ctx);
+ return NULL;
+ }
+
+ return (cmsContext) ctx;
+}
+
+// Duplicates a context with all associated plug-ins.
+// Caller may specify an optional pointer to user-defined
+// data that will be forwarded to plug-ins and logger.
+cmsContext CMSEXPORT cmsDupContext(cmsContext ContextID, void* NewUserData)
+{
+ int i;
+ struct _cmsContext_struct* ctx;
+ const struct _cmsContext_struct* src = _cmsGetContext(ContextID);
+
+ void* userData = (NewUserData != NULL) ? NewUserData : src -> chunks[UserPtr];
+
+
+ ctx = (struct _cmsContext_struct*) _cmsMalloc(ContextID, sizeof(struct _cmsContext_struct));
+ if (ctx == NULL)
+ return NULL; // Something very wrong happened
+
+ // Setup default memory allocators
+ memcpy(&ctx->DefaultMemoryManager, &src->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager));
+
+ // Maintain the linked list
+ _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
+ ctx ->Next = _cmsContextPoolHead;
+ _cmsContextPoolHead = ctx;
+ _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
+
+ ctx ->chunks[UserPtr] = userData;
+ ctx ->chunks[MemPlugin] = &ctx->DefaultMemoryManager;
+
+ ctx ->MemPool = _cmsCreateSubAlloc(ctx, 22 * sizeof(void*));
+ if (ctx ->MemPool == NULL) {
+
+ cmsDeleteContext(ctx);
+ return NULL;
+ }
+
+ // Allocate all required chunks.
+ _cmsAllocLogErrorChunk(ctx, src);
+ _cmsAllocAlarmCodesChunk(ctx, src);
+ _cmsAllocAdaptationStateChunk(ctx, src);
+ _cmsAllocMemPluginChunk(ctx, src);
+ _cmsAllocInterpPluginChunk(ctx, src);
+ _cmsAllocCurvesPluginChunk(ctx, src);
+ _cmsAllocFormattersPluginChunk(ctx, src);
+ _cmsAllocTagTypePluginChunk(ctx, src);
+ _cmsAllocMPETypePluginChunk(ctx, src);
+ _cmsAllocTagPluginChunk(ctx, src);
+ _cmsAllocIntentsPluginChunk(ctx, src);
+ _cmsAllocOptimizationPluginChunk(ctx, src);
+ _cmsAllocTransformPluginChunk(ctx, src);
+ _cmsAllocMutexPluginChunk(ctx, src);
+
+ // Make sure no one failed
+ for (i=Logger; i < MemoryClientMax; i++) {
+
+ if (src ->chunks[i] == NULL) {
+ cmsDeleteContext((cmsContext) ctx);
+ return NULL;
+ }
+ }
+
+ return (cmsContext) ctx;
+}
+
+
+
+static
+struct _cmsContext_struct* FindPrev(struct _cmsContext_struct* id)
+{
+ struct _cmsContext_struct* prev;
+
+ // Search for previous
+ for (prev = _cmsContextPoolHead;
+ prev != NULL;
+ prev = prev ->Next)
+ {
+ if (prev ->Next == id)
+ return prev;
+ }
+
+ return NULL; // List is empty or only one element!
+}
+
+// Frees any resources associated with the given context,
+// and destroys the context placeholder.
+// The ContextID can no longer be used in any THR operation.
+void CMSEXPORT cmsDeleteContext(cmsContext ContextID)
+{
+ if (ContextID != NULL) {
+
+ struct _cmsContext_struct* ctx = (struct _cmsContext_struct*) ContextID;
+ struct _cmsContext_struct fakeContext;
+ struct _cmsContext_struct* prev;
+
+ memcpy(&fakeContext.DefaultMemoryManager, &ctx->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager));
+
+ fakeContext.chunks[UserPtr] = ctx ->chunks[UserPtr];
+ fakeContext.chunks[MemPlugin] = &fakeContext.DefaultMemoryManager;
+
+ // Get rid of plugins
+ cmsUnregisterPluginsTHR(ContextID);
+
+ // Since all memory is allocated in the private pool, all what we need to do is destroy the pool
+ if (ctx -> MemPool != NULL)
+ _cmsSubAllocDestroy(ctx ->MemPool);
+ ctx -> MemPool = NULL;
+
+ // Maintain list
+ _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
+ if (_cmsContextPoolHead == ctx) {
+
+ _cmsContextPoolHead = ctx->Next;
+ }
+ else {
+
+ // Search for previous
+ for (prev = _cmsContextPoolHead;
+ prev != NULL;
+ prev = prev ->Next)
+ {
+ if (prev -> Next == ctx) {
+ prev -> Next = ctx ->Next;
+ break;
+ }
+ }
+ }
+ _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex);
+
+ // free the memory block itself
+ _cmsFree(&fakeContext, ctx);
+ }
+}
+
+// Returns the user data associated to the given ContextID, or NULL if no user data was attached on context creation
+void* CMSEXPORT cmsGetContextUserData(cmsContext ContextID)
+{
+ return _cmsContextGetClientChunk(ContextID, UserPtr);
+}
+
+
diff --git a/src/share/native/sun/java2d/cmm/lcms/cmsps2.c b/src/share/native/sun/java2d/cmm/lcms/cmsps2.c
index 2da5a2b..22089d0 100644
--- a/src/share/native/sun/java2d/cmm/lcms/cmsps2.c
+++ b/src/share/native/sun/java2d/cmm/lcms/cmsps2.c
@@ -942,7 +942,7 @@
if (DeviceLink == NULL) return 0;
dwFlags |= cmsFLAGS_FORCE_CLUT;
- _cmsOptimizePipeline(&DeviceLink, Intent, &InputFormat, &OutFrm, &dwFlags);
+ _cmsOptimizePipeline(m->ContextID, &DeviceLink, Intent, &InputFormat, &OutFrm, &dwFlags);
rc = EmitCIEBasedDEF(m, DeviceLink, Intent, &BlackPointAdaptedToD50);
cmsPipelineFree(DeviceLink);
@@ -1359,7 +1359,7 @@
// We need a CLUT
dwFlags |= cmsFLAGS_FORCE_CLUT;
- _cmsOptimizePipeline(&DeviceLink, RelativeEncodingIntent, &InFrm, &OutputFormat, &dwFlags);
+ _cmsOptimizePipeline(m->ContextID, &DeviceLink, RelativeEncodingIntent, &InFrm, &OutputFormat, &dwFlags);
_cmsIOPrintf(m, "<<\n");
_cmsIOPrintf(m, "/ColorRenderingType 1\n");
diff --git a/src/share/native/sun/java2d/cmm/lcms/cmstypes.c b/src/share/native/sun/java2d/cmm/lcms/cmstypes.c
index f434cfd..08cad5e 100644
--- a/src/share/native/sun/java2d/cmm/lcms/cmstypes.c
+++ b/src/share/native/sun/java2d/cmm/lcms/cmstypes.c
@@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2011 Marti Maria Saguer
+// Copyright (c) 1998-2014 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -61,7 +61,7 @@
// are no profiles holding them. The programmer can also extend this list by defining his own types
// by using the appropiate plug-in. There are three types of plug ins regarding that. First type
// allows to define new tags using any existing type. Next plug-in type allows to define new types
-// and the third one is very specific: allows to extend the number of elements in the multiprofile
+// and the third one is very specific: allows to extend the number of elements in the multiprocessing
// elements special type.
//--------------------------------------------------------------------------------------------------
@@ -89,54 +89,49 @@
// Helper macro to define a MPE handler. Callbacks do have a fixed naming convention
#define TYPE_MPE_HANDLER(t, x) { (t), READ_FN(x), WRITE_FN(x), GenericMPEdup, GenericMPEfree, NULL, 0 }
-// Register a new type handler. This routine is shared between normal types and MPE
+// Register a new type handler. This routine is shared between normal types and MPE. LinkedList points to the optional list head
static
-cmsBool RegisterTypesPlugin(cmsContext id, cmsPluginBase* Data, _cmsTagTypeLinkedList* LinkedList, cmsUInt32Number DefaultListCount)
+cmsBool RegisterTypesPlugin(cmsContext id, cmsPluginBase* Data, _cmsMemoryClient pos)
{
cmsPluginTagType* Plugin = (cmsPluginTagType*) Data;
- _cmsTagTypeLinkedList *pt, *Anterior = NULL;
+ _cmsTagTypePluginChunkType* ctx = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(id, pos);
+ _cmsTagTypeLinkedList *pt;
// Calling the function with NULL as plug-in would unregister the plug in.
if (Data == NULL) {
- LinkedList[DefaultListCount-1].Next = NULL;
+ // There is no need to set free the memory, as pool is destroyed as a whole.
+ ctx ->TagTypes = NULL;
return TRUE;
}
- pt = Anterior = LinkedList;
- while (pt != NULL) {
-
- if (Plugin->Handler.Signature == pt -> Handler.Signature) {
- pt ->Handler = Plugin ->Handler; // Replace old behaviour.
- // Note that since no memory is allocated, unregister does not
- // reset this action.
- return TRUE;
- }
-
- Anterior = pt;
- pt = pt ->Next;
- }
-
- // Registering happens in plug-in memory pool
+ // Registering happens in plug-in memory pool.
pt = (_cmsTagTypeLinkedList*) _cmsPluginMalloc(id, sizeof(_cmsTagTypeLinkedList));
if (pt == NULL) return FALSE;
pt ->Handler = Plugin ->Handler;
- pt ->Next = NULL;
+ pt ->Next = ctx ->TagTypes;
- if (Anterior)
- Anterior -> Next = pt;
+ ctx ->TagTypes = pt;
return TRUE;
}
-// Return handler for a given type or NULL if not found. Shared between normal types and MPE
+// Return handler for a given type or NULL if not found. Shared between normal types and MPE. It first tries the additons
+// made by plug-ins and then the built-in defaults.
static
-cmsTagTypeHandler* GetHandler(cmsTagTypeSignature sig, _cmsTagTypeLinkedList* LinkedList)
+cmsTagTypeHandler* GetHandler(cmsTagTypeSignature sig, _cmsTagTypeLinkedList* PluginLinkedList, _cmsTagTypeLinkedList* DefaultLinkedList)
{
_cmsTagTypeLinkedList* pt;
- for (pt = LinkedList;
+ for (pt = PluginLinkedList;
+ pt != NULL;
+ pt = pt ->Next) {
+
+ if (sig == pt -> Handler.Signature) return &pt ->Handler;
+ }
+
+ for (pt = DefaultLinkedList;
pt != NULL;
pt = pt ->Next) {
@@ -163,6 +158,7 @@
return TRUE;
}
+// Auxiliar to read an array of wchar_t
static
cmsBool _cmsReadWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, wchar_t* Array)
{
@@ -777,6 +773,8 @@
// Create memory
Text = (char*) _cmsMalloc(self ->ContextID, size);
+ if (Text == NULL) return FALSE;
+
cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text, size);
// Write it, including separator
@@ -1783,7 +1781,6 @@
if (!_cmsReadUInt8Number(io, NULL)) goto Error;
// Do some checking
-
if (InputChannels > cmsMAXCHANNELS) goto Error;
if (OutputChannels > cmsMAXCHANNELS) goto Error;
@@ -1824,9 +1821,16 @@
if (T == NULL) goto Error;
Temp = (cmsUInt8Number*) _cmsMalloc(self ->ContextID, nTabSize);
- if (Temp == NULL) goto Error;
+ if (Temp == NULL) {
+ _cmsFree(self ->ContextID, T);
+ goto Error;
+ }
- if (io ->Read(io, Temp, nTabSize, 1) != 1) goto Error;
+ if (io ->Read(io, Temp, nTabSize, 1) != 1) {
+ _cmsFree(self ->ContextID, T);
+ _cmsFree(self ->ContextID, Temp);
+ goto Error;
+ }
for (i = 0; i < nTabSize; i++) {
@@ -2371,27 +2375,30 @@
// Precision can be 1 or 2 bytes
if (Precision == 1) {
- cmsUInt8Number v;
+ cmsUInt8Number v;
for (i=0; i < Data ->nEntries; i++) {
- if (io ->Read(io, &v, sizeof(cmsUInt8Number), 1) != 1) return NULL;
- Data ->Tab.T[i] = FROM_8_TO_16(v);
+ if (io ->Read(io, &v, sizeof(cmsUInt8Number), 1) != 1) return NULL;
+ Data ->Tab.T[i] = FROM_8_TO_16(v);
}
}
else
if (Precision == 2) {
- if (!_cmsReadUInt16Array(io, Data->nEntries, Data ->Tab.T)) return NULL;
- }
- else {
- cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision);
- return NULL;
- }
+ if (!_cmsReadUInt16Array(io, Data->nEntries, Data ->Tab.T)) {
+ cmsStageFree(CLUT);
+ return NULL;
+ }
+ }
+ else {
+ cmsStageFree(CLUT);
+ cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision);
+ return NULL;
+ }
-
- return CLUT;
+ return CLUT;
}
static
@@ -4374,7 +4381,7 @@
{TYPE_MPE_HANDLER((cmsTagTypeSignature) cmsSigCLutElemType, MPEclut), NULL },
};
-#define DEFAULT_MPE_TYPE_COUNT (sizeof(SupportedMPEtypes) / sizeof(_cmsTagTypeLinkedList))
+_cmsTagTypePluginChunkType _cmsMPETypePluginChunk = { NULL };
static
cmsBool ReadMPEElem(struct _cms_typehandler_struct* self,
@@ -4387,6 +4394,8 @@
cmsTagTypeHandler* TypeHandler;
cmsUInt32Number nItems;
cmsPipeline *NewLUT = (cmsPipeline *) Cargo;
+ _cmsTagTypePluginChunkType* MPETypePluginChunk = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(self->ContextID, MPEPlugin);
+
// Take signature and channels for each element.
if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) return FALSE;
@@ -4395,7 +4404,7 @@
if (!_cmsReadUInt32Number(io, NULL)) return FALSE;
// Read diverse MPE types
- TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, SupportedMPEtypes);
+ TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, MPETypePluginChunk ->TagTypes, SupportedMPEtypes);
if (TypeHandler == NULL) {
char String[5];
@@ -4472,6 +4481,7 @@
cmsPipeline* Lut = (cmsPipeline*) Ptr;
cmsStage* Elem = Lut ->Elements;
cmsTagTypeHandler* TypeHandler;
+ _cmsTagTypePluginChunkType* MPETypePluginChunk = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(self->ContextID, MPEPlugin);
BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
@@ -4505,7 +4515,7 @@
ElementSig = Elem ->Type;
- TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, SupportedMPEtypes);
+ TypeHandler = GetHandler((cmsTagTypeSignature) ElementSig, MPETypePluginChunk->TagTypes, SupportedMPEtypes);
if (TypeHandler == NULL) {
char String[5];
@@ -5125,7 +5135,7 @@
}
else {
- rc = cmsDictAddEntry(hDict, NameWCS, ValueWCS, DisplayNameMLU, DisplayValueMLU);
+ rc = cmsDictAddEntry(hDict, NameWCS, ValueWCS, DisplayNameMLU, DisplayValueMLU);
}
if (NameWCS != NULL) _cmsFree(self ->ContextID, NameWCS);
@@ -5282,24 +5292,95 @@
{TYPE_HANDLER(cmsSigVcgtType, vcgt), NULL }
};
-#define DEFAULT_TAG_TYPE_COUNT (sizeof(SupportedTagTypes) / sizeof(_cmsTagTypeLinkedList))
+
+_cmsTagTypePluginChunkType _cmsTagTypePluginChunk = { NULL };
+
+
+
+// Duplicates the zone of memory used by the plug-in in the new context
+static
+void DupTagTypeList(struct _cmsContext_struct* ctx,
+ const struct _cmsContext_struct* src,
+ int loc)
+{
+ _cmsTagTypePluginChunkType newHead = { NULL };
+ _cmsTagTypeLinkedList* entry;
+ _cmsTagTypeLinkedList* Anterior = NULL;
+ _cmsTagTypePluginChunkType* head = (_cmsTagTypePluginChunkType*) src->chunks[loc];
+
+ // Walk the list copying all nodes
+ for (entry = head->TagTypes;
+ entry != NULL;
+ entry = entry ->Next) {
+
+ _cmsTagTypeLinkedList *newEntry = ( _cmsTagTypeLinkedList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTagTypeLinkedList));
+
+ if (newEntry == NULL)
+ return;
+
+ // We want to keep the linked list order, so this is a little bit tricky
+ newEntry -> Next = NULL;
+ if (Anterior)
+ Anterior -> Next = newEntry;
+
+ Anterior = newEntry;
+
+ if (newHead.TagTypes == NULL)
+ newHead.TagTypes = newEntry;
+ }
+
+ ctx ->chunks[loc] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTagTypePluginChunkType));
+}
+
+
+void _cmsAllocTagTypePluginChunk(struct _cmsContext_struct* ctx,
+ const struct _cmsContext_struct* src)
+{
+ if (src != NULL) {
+
+ // Duplicate the LIST
+ DupTagTypeList(ctx, src, TagTypePlugin);
+ }
+ else {
+ static _cmsTagTypePluginChunkType TagTypePluginChunk = { NULL };
+ ctx ->chunks[TagTypePlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagTypePluginChunk, sizeof(_cmsTagTypePluginChunkType));
+ }
+}
+
+void _cmsAllocMPETypePluginChunk(struct _cmsContext_struct* ctx,
+ const struct _cmsContext_struct* src)
+{
+ if (src != NULL) {
+
+ // Duplicate the LIST
+ DupTagTypeList(ctx, src, MPEPlugin);
+ }
+ else {
+ static _cmsTagTypePluginChunkType TagTypePluginChunk = { NULL };
+ ctx ->chunks[MPEPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagTypePluginChunk, sizeof(_cmsTagTypePluginChunkType));
+ }
+
+}
+
// Both kind of plug-ins share same structure
cmsBool _cmsRegisterTagTypePlugin(cmsContext id, cmsPluginBase* Data)
{
- return RegisterTypesPlugin(id, Data, SupportedTagTypes, DEFAULT_TAG_TYPE_COUNT);
+ return RegisterTypesPlugin(id, Data, TagTypePlugin);
}
cmsBool _cmsRegisterMultiProcessElementPlugin(cmsContext id, cmsPluginBase* Data)
{
- return RegisterTypesPlugin(id, Data, SupportedMPEtypes, DEFAULT_MPE_TYPE_COUNT);
+ return RegisterTypesPlugin(id, Data,MPEPlugin);
}
// Wrapper for tag types
-cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsTagTypeSignature sig)
+cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsContext ContextID, cmsTagTypeSignature sig)
{
- return GetHandler(sig, SupportedTagTypes);
+ _cmsTagTypePluginChunkType* ctx = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(ContextID, TagTypePlugin);
+
+ return GetHandler(sig, ctx->TagTypes, SupportedTagTypes);
}
// ********************************************************************************
@@ -5414,48 +5495,94 @@
cmsSigDeviceSettingsTag ==> Deprecated, useless
*/
-#define DEFAULT_TAG_COUNT (sizeof(SupportedTags) / sizeof(_cmsTagLinkedList))
+
+_cmsTagPluginChunkType _cmsTagPluginChunk = { NULL };
+
+
+// Duplicates the zone of memory used by the plug-in in the new context
+static
+void DupTagList(struct _cmsContext_struct* ctx,
+ const struct _cmsContext_struct* src)
+{
+ _cmsTagPluginChunkType newHead = { NULL };
+ _cmsTagLinkedList* entry;
+ _cmsTagLinkedList* Anterior = NULL;
+ _cmsTagPluginChunkType* head = (_cmsTagPluginChunkType*) src->chunks[TagPlugin];
+
+ // Walk the list copying all nodes
+ for (entry = head->Tag;
+ entry != NULL;
+ entry = entry ->Next) {
+
+ _cmsTagLinkedList *newEntry = ( _cmsTagLinkedList *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTagLinkedList));
+
+ if (newEntry == NULL)
+ return;
+
+ // We want to keep the linked list order, so this is a little bit tricky
+ newEntry -> Next = NULL;
+ if (Anterior)
+ Anterior -> Next = newEntry;
+
+ Anterior = newEntry;
+
+ if (newHead.Tag == NULL)
+ newHead.Tag = newEntry;
+ }
+
+ ctx ->chunks[TagPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTagPluginChunkType));
+}
+
+void _cmsAllocTagPluginChunk(struct _cmsContext_struct* ctx,
+ const struct _cmsContext_struct* src)
+{
+ if (src != NULL) {
+
+ DupTagList(ctx, src);
+ }
+ else {
+ static _cmsTagPluginChunkType TagPluginChunk = { NULL };
+ ctx ->chunks[TagPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TagPluginChunk, sizeof(_cmsTagPluginChunkType));
+ }
+
+}
cmsBool _cmsRegisterTagPlugin(cmsContext id, cmsPluginBase* Data)
{
cmsPluginTag* Plugin = (cmsPluginTag*) Data;
- _cmsTagLinkedList *pt, *Anterior;
-
+ _cmsTagLinkedList *pt;
+ _cmsTagPluginChunkType* TagPluginChunk = ( _cmsTagPluginChunkType*) _cmsContextGetClientChunk(id, TagPlugin);
if (Data == NULL) {
- SupportedTags[DEFAULT_TAG_COUNT-1].Next = NULL;
+ TagPluginChunk->Tag = NULL;
return TRUE;
}
- pt = Anterior = SupportedTags;
- while (pt != NULL) {
-
- if (Plugin->Signature == pt -> Signature) {
- pt ->Descriptor = Plugin ->Descriptor; // Replace old behaviour
- return TRUE;
- }
-
- Anterior = pt;
- pt = pt ->Next;
- }
-
pt = (_cmsTagLinkedList*) _cmsPluginMalloc(id, sizeof(_cmsTagLinkedList));
if (pt == NULL) return FALSE;
pt ->Signature = Plugin ->Signature;
pt ->Descriptor = Plugin ->Descriptor;
- pt ->Next = NULL;
+ pt ->Next = TagPluginChunk ->Tag;
- if (Anterior != NULL) Anterior -> Next = pt;
+ TagPluginChunk ->Tag = pt;
return TRUE;
}
// Return a descriptor for a given tag or NULL
-cmsTagDescriptor* _cmsGetTagDescriptor(cmsTagSignature sig)
+cmsTagDescriptor* _cmsGetTagDescriptor(cmsContext ContextID, cmsTagSignature sig)
{
_cmsTagLinkedList* pt;
+ _cmsTagPluginChunkType* TagPluginChunk = ( _cmsTagPluginChunkType*) _cmsContextGetClientChunk(ContextID, TagPlugin);
+
+ for (pt = TagPluginChunk->Tag;
+ pt != NULL;
+ pt = pt ->Next) {
+
+ if (sig == pt -> Signature) return &pt ->Descriptor;
+ }
for (pt = SupportedTags;
pt != NULL;
diff --git a/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c b/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c
index 699abcc..3598751 100644
--- a/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c
+++ b/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c
@@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2011 Marti Maria Saguer
+// Copyright (c) 1998-2014 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -1019,7 +1019,7 @@
static const cmsAllowedLUT AllowedLUTTypes[] = {
- { FALSE, 0, cmsSigLut16Type, 4, { cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}},
+ { FALSE, 0, cmsSigLut16Type, 4, { cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}},
{ FALSE, 0, cmsSigLut16Type, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}},
{ FALSE, 0, cmsSigLut16Type, 2, { cmsSigCurveSetElemType, cmsSigCLutElemType}},
{ TRUE , 0, cmsSigLutAtoBType, 1, { cmsSigCurveSetElemType }},
@@ -1150,7 +1150,7 @@
if (AllowedLUT == NULL) {
// Try to optimize
- _cmsOptimizePipeline(&LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags);
+ _cmsOptimizePipeline(ContextID, &LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags);
AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag);
}
@@ -1159,7 +1159,7 @@
if (AllowedLUT == NULL) {
dwFlags |= cmsFLAGS_FORCE_CLUT;
- _cmsOptimizePipeline(&LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags);
+ _cmsOptimizePipeline(ContextID, &LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags);
// Put identity curves if needed
if (cmsPipelineGetPtrToFirstStage(LUT) ->Type != cmsSigCurveSetElemType)
diff --git a/src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c b/src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c
index 71fb765..1eb9a87 100644
--- a/src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c
+++ b/src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c
@@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2012 Marti Maria Saguer
+// Copyright (c) 1998-2014 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
diff --git a/src/share/native/sun/java2d/cmm/lcms/cmsxform.c b/src/share/native/sun/java2d/cmm/lcms/cmsxform.c
index 879056f..3e244c3 100644
--- a/src/share/native/sun/java2d/cmm/lcms/cmsxform.c
+++ b/src/share/native/sun/java2d/cmm/lcms/cmsxform.c
@@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2011 Marti Maria Saguer
+// Copyright (c) 1998-2014 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -58,44 +58,120 @@
// Transformations stuff
// -----------------------------------------------------------------------
-// Alarm codes for 16-bit transformations, because the fixed range of containers there are
-// no values left to mark out of gamut. volatile is C99 per 6.2.5
-static volatile cmsUInt16Number Alarm[cmsMAXCHANNELS] = { 0x7F00, 0x7F00, 0x7F00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-static volatile cmsFloat64Number GlobalAdaptationState = 1;
+#define DEFAULT_OBSERVER_ADAPTATION_STATE 1.0
+
+// The Context0 observer adaptation state.
+_cmsAdaptationStateChunkType _cmsAdaptationStateChunk = { DEFAULT_OBSERVER_ADAPTATION_STATE };
+
+// Init and duplicate observer adaptation state
+void _cmsAllocAdaptationStateChunk(struct _cmsContext_struct* ctx,
+ const struct _cmsContext_struct* src)
+{
+ static _cmsAdaptationStateChunkType AdaptationStateChunk = { DEFAULT_OBSERVER_ADAPTATION_STATE };
+ void* from;
+
+ if (src != NULL) {
+ from = src ->chunks[AdaptationStateContext];
+ }
+ else {
+ from = &AdaptationStateChunk;
+ }
+
+ ctx ->chunks[AdaptationStateContext] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsAdaptationStateChunkType));
+}
+
+
+// Sets adaptation state for absolute colorimetric intent in the given context. Adaptation state applies on all
+// but cmsCreateExtendedTransformTHR(). Little CMS can handle incomplete adaptation states.
+cmsFloat64Number CMSEXPORT cmsSetAdaptationStateTHR(cmsContext ContextID, cmsFloat64Number d)
+{
+ cmsFloat64Number prev;
+ _cmsAdaptationStateChunkType* ptr = (_cmsAdaptationStateChunkType*) _cmsContextGetClientChunk(ContextID, AdaptationStateContext);
+
+ // Get previous value for return
+ prev = ptr ->AdaptationState;
+
+ // Set the value if d is positive or zero
+ if (d >= 0.0) {
+
+ ptr ->AdaptationState = d;
+ }
+
+ // Always return previous value
+ return prev;
+}
+
// The adaptation state may be defaulted by this function. If you don't like it, use the extended transform routine
cmsFloat64Number CMSEXPORT cmsSetAdaptationState(cmsFloat64Number d)
{
- cmsFloat64Number OldVal = GlobalAdaptationState;
-
- if (d >= 0)
- GlobalAdaptationState = d;
-
- return OldVal;
+ return cmsSetAdaptationStateTHR(NULL, d);
}
-// Alarm codes are always global
-void CMSEXPORT cmsSetAlarmCodes(cmsUInt16Number NewAlarm[cmsMAXCHANNELS])
-{
- int i;
+// -----------------------------------------------------------------------
+// Alarm codes for 16-bit transformations, because the fixed range of containers there are
+// no values left to mark out of gamut.
+
+#define DEFAULT_ALARM_CODES_VALUE {0x7F00, 0x7F00, 0x7F00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+
+_cmsAlarmCodesChunkType _cmsAlarmCodesChunk = { DEFAULT_ALARM_CODES_VALUE };
+
+// Sets the codes used to mark out-out-gamut on Proofing transforms for a given context. Values are meant to be
+// encoded in 16 bits.
+void CMSEXPORT cmsSetAlarmCodesTHR(cmsContext ContextID, const cmsUInt16Number AlarmCodesP[cmsMAXCHANNELS])
+{
+ _cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(ContextID, AlarmCodesContext);
+
+ _cmsAssert(ContextAlarmCodes != NULL); // Can't happen
+
+ memcpy(ContextAlarmCodes->AlarmCodes, AlarmCodesP, sizeof(ContextAlarmCodes->AlarmCodes));
+}
+
+// Gets the current codes used to mark out-out-gamut on Proofing transforms for the given context.
+// Values are meant to be encoded in 16 bits.
+void CMSEXPORT cmsGetAlarmCodesTHR(cmsContext ContextID, cmsUInt16Number AlarmCodesP[cmsMAXCHANNELS])
+{
+ _cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(ContextID, AlarmCodesContext);
+
+ _cmsAssert(ContextAlarmCodes != NULL); // Can't happen
+
+ memcpy(AlarmCodesP, ContextAlarmCodes->AlarmCodes, sizeof(ContextAlarmCodes->AlarmCodes));
+}
+
+void CMSEXPORT cmsSetAlarmCodes(const cmsUInt16Number NewAlarm[cmsMAXCHANNELS])
+{
_cmsAssert(NewAlarm != NULL);
- for (i=0; i < cmsMAXCHANNELS; i++)
- Alarm[i] = NewAlarm[i];
+ cmsSetAlarmCodesTHR(NULL, NewAlarm);
}
-// You can get the codes cas well
void CMSEXPORT cmsGetAlarmCodes(cmsUInt16Number OldAlarm[cmsMAXCHANNELS])
{
- int i;
-
_cmsAssert(OldAlarm != NULL);
-
- for (i=0; i < cmsMAXCHANNELS; i++)
- OldAlarm[i] = Alarm[i];
+ cmsGetAlarmCodesTHR(NULL, OldAlarm);
}
+
+// Init and duplicate alarm codes
+void _cmsAllocAlarmCodesChunk(struct _cmsContext_struct* ctx,
+ const struct _cmsContext_struct* src)
+{
+ static _cmsAlarmCodesChunkType AlarmCodesChunk = { DEFAULT_ALARM_CODES_VALUE };
+ void* from;
+
+ if (src != NULL) {
+ from = src ->chunks[AlarmCodesContext];
+ }
+ else {
+ from = &AlarmCodesChunk;
+ }
+
+ ctx ->chunks[AlarmCodesContext] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsAlarmCodesChunkType));
+}
+
+// -----------------------------------------------------------------------
+
// Get rid of transform resources
void CMSEXPORT cmsDeleteTransform(cmsHTRANSFORM hTransform)
{
@@ -202,6 +278,30 @@
}
}
+
+static
+void NullFloatXFORM(_cmsTRANSFORM* p,
+ const void* in,
+ void* out,
+ cmsUInt32Number Size,
+ cmsUInt32Number Stride)
+{
+ cmsUInt8Number* accum;
+ cmsUInt8Number* output;
+ cmsFloat32Number fIn[cmsMAXCHANNELS];
+ cmsUInt32Number i, n;
+
+ accum = (cmsUInt8Number*) in;
+ output = (cmsUInt8Number*) out;
+ n = Size;
+
+ for (i=0; i < n; i++) {
+
+ accum = p -> FromInputFloat(p, fIn, accum, Stride);
+ output = p -> ToOutputFloat(p, fIn, output, Stride);
+ }
+}
+
// 16 bit precision -----------------------------------------------------------------------------------------------------------
// Null transformation, only applies formatters. No caché
@@ -252,7 +352,7 @@
}
-// Auxiliar: Handle precalculated gamut check
+// Auxiliar: Handle precalculated gamut check. The retrieval of context may be alittle bit slow, but this function is not critical.
static
void TransformOnePixelWithGamutCheck(_cmsTRANSFORM* p,
const cmsUInt16Number wIn[],
@@ -264,9 +364,12 @@
if (wOutOfGamut >= 1) {
cmsUInt16Number i;
+ _cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(p->ContextID, AlarmCodesContext);
- for (i=0; i < p ->Lut->OutputChannels; i++)
- wOut[i] = Alarm[i];
+ for (i=0; i < p ->Lut->OutputChannels; i++) {
+
+ wOut[i] = ContextAlarmCodes ->AlarmCodes[i];
+ }
}
else
p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data);
@@ -393,34 +496,86 @@
} _cmsTransformCollection;
// The linked list head
-static _cmsTransformCollection* TransformCollection = NULL;
+_cmsTransformPluginChunkType _cmsTransformPluginChunk = { NULL };
+
+
+// Duplicates the zone of memory used by the plug-in in the new context
+static
+void DupPluginTransformList(struct _cmsContext_struct* ctx,
+ const struct _cmsContext_struct* src)
+{
+ _cmsTransformPluginChunkType newHead = { NULL };
+ _cmsTransformCollection* entry;
+ _cmsTransformCollection* Anterior = NULL;
+ _cmsTransformPluginChunkType* head = (_cmsTransformPluginChunkType*) src->chunks[TransformPlugin];
+
+ // Walk the list copying all nodes
+ for (entry = head->TransformCollection;
+ entry != NULL;
+ entry = entry ->Next) {
+
+ _cmsTransformCollection *newEntry = ( _cmsTransformCollection *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTransformCollection));
+
+ if (newEntry == NULL)
+ return;
+
+ // We want to keep the linked list order, so this is a little bit tricky
+ newEntry -> Next = NULL;
+ if (Anterior)
+ Anterior -> Next = newEntry;
+
+ Anterior = newEntry;
+
+ if (newHead.TransformCollection == NULL)
+ newHead.TransformCollection = newEntry;
+ }
+
+ ctx ->chunks[TransformPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTransformPluginChunkType));
+}
+
+void _cmsAllocTransformPluginChunk(struct _cmsContext_struct* ctx,
+ const struct _cmsContext_struct* src)
+{
+ if (src != NULL) {
+
+ // Copy all linked list
+ DupPluginTransformList(ctx, src);
+ }
+ else {
+ static _cmsTransformPluginChunkType TransformPluginChunkType = { NULL };
+ ctx ->chunks[TransformPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TransformPluginChunkType, sizeof(_cmsTransformPluginChunkType));
+ }
+}
+
+
// Register new ways to transform
-cmsBool _cmsRegisterTransformPlugin(cmsContext id, cmsPluginBase* Data)
+cmsBool _cmsRegisterTransformPlugin(cmsContext ContextID, cmsPluginBase* Data)
{
cmsPluginTransform* Plugin = (cmsPluginTransform*) Data;
_cmsTransformCollection* fl;
+ _cmsTransformPluginChunkType* ctx = ( _cmsTransformPluginChunkType*) _cmsContextGetClientChunk(ContextID,TransformPlugin);
- if (Data == NULL) {
+ if (Data == NULL) {
// Free the chain. Memory is safely freed at exit
- TransformCollection = NULL;
+ ctx->TransformCollection = NULL;
return TRUE;
}
// Factory callback is required
- if (Plugin ->Factory == NULL) return FALSE;
+ if (Plugin ->Factory == NULL) return FALSE;
- fl = (_cmsTransformCollection*) _cmsPluginMalloc(id, sizeof(_cmsTransformCollection));
+ fl = (_cmsTransformCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsTransformCollection));
if (fl == NULL) return FALSE;
- // Copy the parameters
+ // Copy the parameters
fl ->Factory = Plugin ->Factory;
// Keep linked list
- fl ->Next = TransformCollection;
- TransformCollection = fl;
+ fl ->Next = ctx->TransformCollection;
+ ctx->TransformCollection = fl;
// All is ok
return TRUE;
@@ -463,6 +618,7 @@
_cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut,
cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags)
{
+ _cmsTransformPluginChunkType* ctx = ( _cmsTransformPluginChunkType*) _cmsContextGetClientChunk(ContextID, TransformPlugin);
_cmsTransformCollection* Plugin;
// Allocate needed memory
@@ -473,7 +629,7 @@
p ->Lut = lut;
// Let's see if any plug-in want to do the transform by itself
- for (Plugin = TransformCollection;
+ for (Plugin = ctx ->TransformCollection;
Plugin != NULL;
Plugin = Plugin ->Next) {
@@ -493,10 +649,10 @@
// Fill the formatters just in case the optimized routine is interested.
// No error is thrown if the formatter doesn't exist. It is up to the optimization
// factory to decide what to do in those cases.
- p ->FromInput = _cmsGetFormatter(*InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
- p ->ToOutput = _cmsGetFormatter(*OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
- p ->FromInputFloat = _cmsGetFormatter(*InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
- p ->ToOutputFloat = _cmsGetFormatter(*OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
+ p ->FromInput = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
+ p ->ToOutput = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
+ p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
+ p ->ToOutputFloat = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
return p;
}
@@ -504,14 +660,14 @@
// Not suitable for the transform plug-in, let's check the pipeline plug-in
if (p ->Lut != NULL)
- _cmsOptimizePipeline(&p->Lut, Intent, InputFormat, OutputFormat, dwFlags);
+ _cmsOptimizePipeline(ContextID, &p->Lut, Intent, InputFormat, OutputFormat, dwFlags);
// Check whatever this is a true floating point transform
if (_cmsFormatterIsFloat(*InputFormat) && _cmsFormatterIsFloat(*OutputFormat)) {
// Get formatter function always return a valid union, but the contents of this union may be NULL.
- p ->FromInputFloat = _cmsGetFormatter(*InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
- p ->ToOutputFloat = _cmsGetFormatter(*OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
+ p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
+ p ->ToOutputFloat = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
*dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
if (p ->FromInputFloat == NULL || p ->ToOutputFloat == NULL) {
@@ -521,8 +677,15 @@
return NULL;
}
- // Float transforms don't use caché, always are non-NULL
- p ->xform = FloatXFORM;
+ if (*dwFlags & cmsFLAGS_NULLTRANSFORM) {
+
+ p ->xform = NullFloatXFORM;
+ }
+ else {
+ // Float transforms don't use caché, always are non-NULL
+ p ->xform = FloatXFORM;
+ }
+
}
else {
@@ -534,8 +697,8 @@
int BytesPerPixelInput;
- p ->FromInput = _cmsGetFormatter(*InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
- p ->ToOutput = _cmsGetFormatter(*OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
+ p ->FromInput = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
+ p ->ToOutput = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
if (p ->FromInput == NULL || p ->ToOutput == NULL) {
@@ -727,6 +890,7 @@
// Check channel count
if ((cmsChannelsOf(EntryColorSpace) != cmsPipelineInputChannels(Lut)) ||
(cmsChannelsOf(ExitColorSpace) != cmsPipelineOutputChannels(Lut))) {
+ cmsPipelineFree(Lut);
cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Channel count doesn't match. Profile is corrupted");
return NULL;
}
@@ -829,7 +993,7 @@
for (i=0; i < nProfiles; i++) {
BPC[i] = dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION ? TRUE : FALSE;
Intents[i] = Intent;
- AdaptationStates[i] = GlobalAdaptationState;
+ AdaptationStates[i] = cmsSetAdaptationStateTHR(ContextID, -1);
}
@@ -909,7 +1073,7 @@
Intents[0] = nIntent; Intents[1] = nIntent; Intents[2] = INTENT_RELATIVE_COLORIMETRIC; Intents[3] = ProofingIntent;
BPC[0] = DoBPC; BPC[1] = DoBPC; BPC[2] = 0; BPC[3] = 0;
- Adaptation[0] = Adaptation[1] = Adaptation[2] = Adaptation[3] = GlobalAdaptationState;
+ Adaptation[0] = Adaptation[1] = Adaptation[2] = Adaptation[3] = cmsSetAdaptationStateTHR(ContextID, -1);
if (!(dwFlags & (cmsFLAGS_SOFTPROOFING|cmsFLAGS_GAMUTCHECK)))
return cmsCreateTransformTHR(ContextID, InputProfile, InputFormat, OutputProfile, OutputFormat, nIntent, dwFlags);
@@ -984,8 +1148,8 @@
return FALSE;
}
- FromInput = _cmsGetFormatter(InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
- ToOutput = _cmsGetFormatter(OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
+ FromInput = _cmsGetFormatter(xform->ContextID, InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
+ ToOutput = _cmsGetFormatter(xform->ContextID, OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
if (FromInput == NULL || ToOutput == NULL) {
diff --git a/src/share/native/sun/java2d/cmm/lcms/lcms2.h b/src/share/native/sun/java2d/cmm/lcms/lcms2.h
index c6c35b1..2fd2b56 100644
--- a/src/share/native/sun/java2d/cmm/lcms/lcms2.h
+++ b/src/share/native/sun/java2d/cmm/lcms/lcms2.h
@@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2013 Marti Maria Saguer
+// Copyright (c) 1998-2014 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -52,7 +52,7 @@
//
//---------------------------------------------------------------------------------
//
-// Version 2.5
+// Version 2.6
//
#ifndef _lcms2_H
@@ -84,6 +84,9 @@
// Uncomment to get rid of the tables for "half" float support
// #define CMS_NO_HALF_SUPPORT 1
+// Uncomment to get rid of pthreads/windows dependency
+// #define CMS_NO_PTHREADS 1
+
// ********** End of configuration toggles ******************************
// Needed for streams
@@ -101,7 +104,7 @@
#endif
// Version/release
-#define LCMS_VERSION 2050
+#define LCMS_VERSION 2060
// I will give the chance of redefining basic types for compilers that are not fully C99 compliant
#ifndef CMS_BASIC_TYPES_ALREADY_DEFINED
@@ -202,28 +205,42 @@
// Try to detect big endian platforms. This list can be endless, so only some checks are performed over here.
// you can pass this toggle to the compiler by using -DCMS_USE_BIG_ENDIAN or something similar
+#if defined(__sgi__) || defined(__sgi) || defined(sparc)
+# define CMS_USE_BIG_ENDIAN 1
+#endif
+
+#if defined(__s390__) || defined(__s390x__)
+# define CMS_USE_BIG_ENDIAN 1
+#endif
+
+# ifdef TARGET_CPU_PPC
+# if TARGET_CPU_PPC
+# define CMS_USE_BIG_ENDIAN 1
+# endif
+# endif
+
+#if defined(__powerpc__) || defined(__ppc__) || defined(TARGET_CPU_PPC)
+# define CMS_USE_BIG_ENDIAN 1
+# if defined (__GNUC__) && defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN)
+# if __BYTE_ORDER == __LITTLE_ENDIAN
+// // Don't use big endian for PowerPC little endian mode
+# undef CMS_USE_BIG_ENDIAN
+# endif
+# endif
+#endif
+
+// WORDS_BIGENDIAN takes precedence
#if defined(_HOST_BIG_ENDIAN) || defined(__BIG_ENDIAN__) || defined(WORDS_BIGENDIAN)
# define CMS_USE_BIG_ENDIAN 1
#endif
-#if defined(__sgi__) || defined(__sgi) || defined(__powerpc__) || defined(sparc)
-# define CMS_USE_BIG_ENDIAN 1
-#endif
-
-#if defined(__ppc__) || defined(__s390__) || defined(__s390x__)
-# define CMS_USE_BIG_ENDIAN 1
-#endif
-
-#ifdef TARGET_CPU_PPC
-# if TARGET_CPU_PPC
-# define CMS_USE_BIG_ENDIAN 1
-# endif
-#endif
-
#ifdef macintosh
# ifdef __BIG_ENDIAN__
# define CMS_USE_BIG_ENDIAN 1
# endif
+# ifdef __LITTLE_ENDIAN__
+# undef CMS_USE_BIG_ENDIAN
+# endif
#endif
// Calling convention -- this is hardly platform and compiler dependent
@@ -249,6 +266,14 @@
# define CMSAPI
#endif
+#ifdef HasTHREADS
+# if HasTHREADS == 1
+# undef CMS_NO_PTHREADS
+# else
+# define CMS_NO_PTHREADS 1
+# endif
+#endif
+
// Some common definitions
#define cmsMAX_PATH 256
@@ -642,7 +667,6 @@
// Little CMS specific typedefs
-typedef void* cmsContext; // Context identifier for multithreaded environments
typedef void* cmsHANDLE ; // Generic handle
typedef void* cmsHPROFILE; // Opaque typedefs to hide internals
typedef void* cmsHTRANSFORM;
@@ -1012,11 +1036,25 @@
CMSAPI int CMSEXPORT cmsstrcasecmp(const char* s1, const char* s2);
CMSAPI long int CMSEXPORT cmsfilelength(FILE* f);
-// Plug-In registering ---------------------------------------------------------------------------------------------------
+
+// Context handling --------------------------------------------------------------------------------------------------------
+
+// Each context holds its owns globals and its own plug-ins. There is a global context with the id = 0 for lecacy compatibility
+// though using the global context is not recomended. Proper context handling makes lcms more thread-safe.
+
+typedef struct _cmsContext_struct* cmsContext;
+
+CMSAPI cmsContext CMSEXPORT cmsCreateContext(void* Plugin, void* UserData);
+CMSAPI void CMSEXPORT cmsDeleteContext(cmsContext ContexID);
+CMSAPI cmsContext CMSEXPORT cmsDupContext(cmsContext ContextID, void* NewUserData);
+CMSAPI void* CMSEXPORT cmsGetContextUserData(cmsContext ContextID);
+
+// Plug-In registering --------------------------------------------------------------------------------------------------
CMSAPI cmsBool CMSEXPORT cmsPlugin(void* Plugin);
CMSAPI cmsBool CMSEXPORT cmsPluginTHR(cmsContext ContextID, void* Plugin);
CMSAPI void CMSEXPORT cmsUnregisterPlugins(void);
+CMSAPI void CMSEXPORT cmsUnregisterPluginsTHR(cmsContext ContextID);
// Error logging ----------------------------------------------------------------------------------------------------------
@@ -1053,6 +1091,7 @@
// Allows user to set any specific logger
CMSAPI void CMSEXPORT cmsSetLogErrorHandler(cmsLogErrorHandlerFunction Fn);
+CMSAPI void CMSEXPORT cmsSetLogErrorHandlerTHR(cmsContext ContextID, cmsLogErrorHandlerFunction Fn);
// Conversions --------------------------------------------------------------------------------------------------------------
@@ -1514,6 +1553,7 @@
CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromMem(const void * MemPtr, cmsUInt32Number dwSize);
CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromMemTHR(cmsContext ContextID, const void * MemPtr, cmsUInt32Number dwSize);
CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromIOhandlerTHR(cmsContext ContextID, cmsIOHANDLER* io);
+CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromIOhandler2THR(cmsContext ContextID, cmsIOHANDLER* io, cmsBool write);
CMSAPI cmsBool CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile);
CMSAPI cmsBool CMSEXPORT cmsSaveProfileToFile(cmsHPROFILE hProfile, const char* FileName);
@@ -1604,6 +1644,7 @@
// Call with NULL as parameters to get the intent count
CMSAPI cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions);
+CMSAPI cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID, cmsUInt32Number nMax, cmsUInt32Number* Codes, char** Descriptions);
// Flags
@@ -1715,11 +1756,22 @@
cmsUInt32Number Stride);
-CMSAPI void CMSEXPORT cmsSetAlarmCodes(cmsUInt16Number NewAlarm[cmsMAXCHANNELS]);
+CMSAPI void CMSEXPORT cmsSetAlarmCodes(const cmsUInt16Number NewAlarm[cmsMAXCHANNELS]);
CMSAPI void CMSEXPORT cmsGetAlarmCodes(cmsUInt16Number NewAlarm[cmsMAXCHANNELS]);
+
+CMSAPI void CMSEXPORT cmsSetAlarmCodesTHR(cmsContext ContextID,
+ const cmsUInt16Number AlarmCodes[cmsMAXCHANNELS]);
+CMSAPI void CMSEXPORT cmsGetAlarmCodesTHR(cmsContext ContextID,
+ cmsUInt16Number AlarmCodes[cmsMAXCHANNELS]);
+
+
+
// Adaptation state for absolute colorimetric intent
CMSAPI cmsFloat64Number CMSEXPORT cmsSetAdaptationState(cmsFloat64Number d);
+CMSAPI cmsFloat64Number CMSEXPORT cmsSetAdaptationStateTHR(cmsContext ContextID, cmsFloat64Number d);
+
+
// Grab the ContextID from an open transform. Returns NULL if a NULL transform is passed
CMSAPI cmsContext CMSEXPORT cmsGetTransformContextID(cmsHTRANSFORM hTransform);
diff --git a/src/share/native/sun/java2d/cmm/lcms/lcms2_internal.h b/src/share/native/sun/java2d/cmm/lcms/lcms2_internal.h
index 6fbbb95..7f28f3d 100644
--- a/src/share/native/sun/java2d/cmm/lcms/lcms2_internal.h
+++ b/src/share/native/sun/java2d/cmm/lcms/lcms2_internal.h
@@ -30,7 +30,7 @@
//
// Little Color Management System
-// Copyright (c) 1998-2011 Marti Maria Saguer
+// Copyright (c) 1998-2014 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -193,16 +193,171 @@
return _cmsQuickFloorWord(d);
}
-// Plug-In registering ---------------------------------------------------------------
+
+// Pthread support --------------------------------------------------------------------
+#ifndef CMS_NO_PTHREADS
+
+// This is the threading support. Unfortunately, it has to be platform-dependent because
+// windows does not support pthreads.
+
+#ifdef CMS_IS_WINDOWS_
+
+#define WIN32_LEAN_AND_MEAN 1
+#include <windows.h>
+
+
+// From: http://locklessinc.com/articles/pthreads_on_windows/
+// The pthreads API has an initialization macro that has no correspondence to anything in
+// the windows API. By investigating the internal definition of the critical section type,
+// one may work out how to initialize one without calling InitializeCriticalSection().
+// The trick here is that InitializeCriticalSection() is not allowed to fail. It tries
+// to allocate a critical section debug object, but if no memory is available, it sets
+// the pointer to a specific value. (One would expect that value to be NULL, but it is
+// actually (void *)-1 for some reason.) Thus we can use this special value for that
+// pointer, and the critical section code will work.
+
+// The other important part of the critical section type to initialize is the number
+// of waiters. This controls whether or not the mutex is locked. Fortunately, this
+// part of the critical section is unlikely to change. Apparently, many programs
+// already test critical sections to see if they are locked using this value, so
+// Microsoft felt that it was necessary to keep it set at -1 for an unlocked critical
+// section, even when they changed the underlying algorithm to be more scalable.
+// The final parts of the critical section object are unimportant, and can be set
+// to zero for their defaults. This yields an initialization macro:
+
+typedef CRITICAL_SECTION _cmsMutex;
+
+#define CMS_MUTEX_INITIALIZER {(void*) -1,-1,0,0,0,0}
+
+cmsINLINE int _cmsLockPrimitive(_cmsMutex *m)
+{
+ EnterCriticalSection(m);
+ return 0;
+}
+
+cmsINLINE int _cmsUnlockPrimitive(_cmsMutex *m)
+{
+ LeaveCriticalSection(m);
+ return 0;
+}
+
+cmsINLINE int _cmsInitMutexPrimitive(_cmsMutex *m)
+{
+ InitializeCriticalSection(m);
+ return 0;
+}
+
+cmsINLINE int _cmsDestroyMutexPrimitive(_cmsMutex *m)
+{
+ DeleteCriticalSection(m);
+ return 0;
+}
+
+cmsINLINE int _cmsEnterCriticalSectionPrimitive(_cmsMutex *m)
+{
+ EnterCriticalSection(m);
+ return 0;
+}
+
+cmsINLINE int _cmsLeaveCriticalSectionPrimitive(_cmsMutex *m)
+{
+ LeaveCriticalSection(m);
+ return 0;
+}
+
+#else
+
+// Rest of the wide world
+#include <pthread.h>
+
+#define CMS_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+typedef pthread_mutex_t _cmsMutex;
+
+
+cmsINLINE int _cmsLockPrimitive(_cmsMutex *m)
+{
+ return pthread_mutex_lock(m);
+}
+
+cmsINLINE int _cmsUnlockPrimitive(_cmsMutex *m)
+{
+ return pthread_mutex_unlock(m);
+}
+
+cmsINLINE int _cmsInitMutexPrimitive(_cmsMutex *m)
+{
+ return pthread_mutex_init(m, NULL);
+}
+
+cmsINLINE int _cmsDestroyMutexPrimitive(_cmsMutex *m)
+{
+ return pthread_mutex_destroy(m);
+}
+
+cmsINLINE int _cmsEnterCriticalSectionPrimitive(_cmsMutex *m)
+{
+ return pthread_mutex_lock(m);
+}
+
+cmsINLINE int _cmsLeaveCriticalSectionPrimitive(_cmsMutex *m)
+{
+ return pthread_mutex_unlock(m);
+}
+
+#endif
+#else
+
+#define CMS_MUTEX_INITIALIZER 0
+typedef int _cmsMutex;
+
+
+cmsINLINE int _cmsLockPrimitive(_cmsMutex *m)
+{
+ return 0;
+ cmsUNUSED_PARAMETER(m);
+}
+
+cmsINLINE int _cmsUnlockPrimitive(_cmsMutex *m)
+{
+ return 0;
+ cmsUNUSED_PARAMETER(m);
+}
+
+cmsINLINE int _cmsInitMutexPrimitive(_cmsMutex *m)
+{
+ return 0;
+ cmsUNUSED_PARAMETER(m);
+}
+
+cmsINLINE int _cmsDestroyMutexPrimitive(_cmsMutex *m)
+{
+ return 0;
+ cmsUNUSED_PARAMETER(m);
+}
+
+cmsINLINE int _cmsEnterCriticalSectionPrimitive(_cmsMutex *m)
+{
+ return 0;
+ cmsUNUSED_PARAMETER(m);
+}
+
+cmsINLINE int _cmsLeaveCriticalSectionPrimitive(_cmsMutex *m)
+{
+ return 0;
+ cmsUNUSED_PARAMETER(m);
+}
+#endif
+
+// Plug-In registration ---------------------------------------------------------------
// Specialized function for plug-in memory management. No pairing free() since whole pool is freed at once.
void* _cmsPluginMalloc(cmsContext ContextID, cmsUInt32Number size);
// Memory management
-cmsBool _cmsRegisterMemHandlerPlugin(cmsPluginBase* Plugin);
+cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase* Plugin);
// Interpolation
-cmsBool _cmsRegisterInterpPlugin(cmsPluginBase* Plugin);
+cmsBool _cmsRegisterInterpPlugin(cmsContext ContextID, cmsPluginBase* Plugin);
// Parametric curves
cmsBool _cmsRegisterParametricCurvesPlugin(cmsContext ContextID, cmsPluginBase* Plugin);
@@ -228,9 +383,12 @@
// Transform
cmsBool _cmsRegisterTransformPlugin(cmsContext ContextID, cmsPluginBase* Plugin);
+// Mutex
+cmsBool _cmsRegisterMutexPlugin(cmsContext ContextID, cmsPluginBase* Plugin);
+
// ---------------------------------------------------------------------------------------------------------
-// Suballocators. Those are blocks of memory that is freed at the end on whole block.
+// Suballocators.
typedef struct _cmsSubAllocator_chunk_st {
cmsUInt8Number* Block;
@@ -253,9 +411,264 @@
_cmsSubAllocator* _cmsCreateSubAlloc(cmsContext ContextID, cmsUInt32Number Initial);
void _cmsSubAllocDestroy(_cmsSubAllocator* s);
void* _cmsSubAlloc(_cmsSubAllocator* s, cmsUInt32Number size);
+void* _cmsSubAllocDup(_cmsSubAllocator* s, const void *ptr, cmsUInt32Number size);
// ----------------------------------------------------------------------------------
+// The context clients.
+typedef enum {
+
+ UserPtr, // User-defined pointer
+ Logger,
+ AlarmCodesContext,
+ AdaptationStateContext,
+ MemPlugin,
+ InterpPlugin,
+ CurvesPlugin,
+ FormattersPlugin,
+ TagTypePlugin,
+ TagPlugin,
+ IntentPlugin,
+ MPEPlugin,
+ OptimizationPlugin,
+ TransformPlugin,
+ MutexPlugin,
+
+ // Last in list
+ MemoryClientMax
+
+} _cmsMemoryClient;
+
+
+// Container for memory management plug-in.
+typedef struct {
+
+ _cmsMallocFnPtrType MallocPtr;
+ _cmsMalloZerocFnPtrType MallocZeroPtr;
+ _cmsFreeFnPtrType FreePtr;
+ _cmsReallocFnPtrType ReallocPtr;
+ _cmsCallocFnPtrType CallocPtr;
+ _cmsDupFnPtrType DupPtr;
+
+} _cmsMemPluginChunkType;
+
+// Copy memory management function pointers from plug-in to chunk, taking care of missing routines
+void _cmsInstallAllocFunctions(cmsPluginMemHandler* Plugin, _cmsMemPluginChunkType* ptr);
+
+// Internal structure for context
+struct _cmsContext_struct {
+
+ struct _cmsContext_struct* Next; // Points to next context in the new style
+ _cmsSubAllocator* MemPool; // The memory pool that stores context data
+
+ void* chunks[MemoryClientMax]; // array of pointers to client chunks. Memory itself is hold in the suballocator.
+ // If NULL, then it reverts to global Context0
+
+ _cmsMemPluginChunkType DefaultMemoryManager; // The allocators used for creating the context itself. Cannot be overriden
+};
+
+// Returns a pointer to a valid context structure, including the global one if id is zero.
+// Verifies the magic number.
+struct _cmsContext_struct* _cmsGetContext(cmsContext ContextID);
+
+// Returns the block assigned to the specific zone.
+void* _cmsContextGetClientChunk(cmsContext id, _cmsMemoryClient mc);
+
+
+// Chunks of context memory by plug-in client -------------------------------------------------------
+
+// Those structures encapsulates all variables needed by the several context clients (mostly plug-ins)
+
+// Container for error logger -- not a plug-in
+typedef struct {
+
+ cmsLogErrorHandlerFunction LogErrorHandler; // Set to NULL for Context0 fallback
+
+} _cmsLogErrorChunkType;
+
+// The global Context0 storage for error logger
+extern _cmsLogErrorChunkType _cmsLogErrorChunk;
+
+// Allocate and init error logger container.
+void _cmsAllocLogErrorChunk(struct _cmsContext_struct* ctx,
+ const struct _cmsContext_struct* src);
+
+// Container for alarm codes -- not a plug-in
+typedef struct {
+
+ cmsUInt16Number AlarmCodes[cmsMAXCHANNELS];
+
+} _cmsAlarmCodesChunkType;
+
+// The global Context0 storage for alarm codes
+extern _cmsAlarmCodesChunkType _cmsAlarmCodesChunk;
+
+// Allocate and init alarm codes container.
+void _cmsAllocAlarmCodesChunk(struct _cmsContext_struct* ctx,
+ const struct _cmsContext_struct* src);
+
+// Container for adaptation state -- not a plug-in
+typedef struct {
+
+ cmsFloat64Number AdaptationState;
+
+} _cmsAdaptationStateChunkType;
+
+// The global Context0 storage for adaptation state
+extern _cmsAdaptationStateChunkType _cmsAdaptationStateChunk;
+
+// Allocate and init adaptation state container.
+void _cmsAllocAdaptationStateChunk(struct _cmsContext_struct* ctx,
+ const struct _cmsContext_struct* src);
+
+
+// The global Context0 storage for memory management
+extern _cmsMemPluginChunkType _cmsMemPluginChunk;
+
+// Allocate and init memory management container.
+void _cmsAllocMemPluginChunk(struct _cmsContext_struct* ctx,
+ const struct _cmsContext_struct* src);
+
+// Container for interpolation plug-in
+typedef struct {
+
+ cmsInterpFnFactory Interpolators;
+
+} _cmsInterpPluginChunkType;
+
+// The global Context0 storage for interpolation plug-in
+extern _cmsInterpPluginChunkType _cmsInterpPluginChunk;
+
+// Allocate and init interpolation container.
+void _cmsAllocInterpPluginChunk(struct _cmsContext_struct* ctx,
+ const struct _cmsContext_struct* src);
+
+// Container for parametric curves plug-in
+typedef struct {
+
+ struct _cmsParametricCurvesCollection_st* ParametricCurves;
+
+} _cmsCurvesPluginChunkType;
+
+// The global Context0 storage for tone curves plug-in
+extern _cmsCurvesPluginChunkType _cmsCurvesPluginChunk;
+
+// Allocate and init parametric curves container.
+void _cmsAllocCurvesPluginChunk(struct _cmsContext_struct* ctx,
+ const struct _cmsContext_struct* src);
+
+// Container for formatters plug-in
+typedef struct {
+
+ struct _cms_formatters_factory_list* FactoryList;
+
+} _cmsFormattersPluginChunkType;
+
+// The global Context0 storage for formatters plug-in
+extern _cmsFormattersPluginChunkType _cmsFormattersPluginChunk;
+
+// Allocate and init formatters container.
+void _cmsAllocFormattersPluginChunk(struct _cmsContext_struct* ctx,
+ const struct _cmsContext_struct* src);
+
+// This chunk type is shared by TagType plug-in and MPE Plug-in
+typedef struct {
+
+ struct _cmsTagTypeLinkedList_st* TagTypes;
+
+} _cmsTagTypePluginChunkType;
+
+
+// The global Context0 storage for tag types plug-in
+extern _cmsTagTypePluginChunkType _cmsTagTypePluginChunk;
+
+
+// The global Context0 storage for mult process elements plug-in
+extern _cmsTagTypePluginChunkType _cmsMPETypePluginChunk;
+
+// Allocate and init Tag types container.
+void _cmsAllocTagTypePluginChunk(struct _cmsContext_struct* ctx,
+ const struct _cmsContext_struct* src);
+// Allocate and init MPE container.
+void _cmsAllocMPETypePluginChunk(struct _cmsContext_struct* ctx,
+ const struct _cmsContext_struct* src);
+// Container for tag plug-in
+typedef struct {
+
+ struct _cmsTagLinkedList_st* Tag;
+
+} _cmsTagPluginChunkType;
+
+
+// The global Context0 storage for tag plug-in
+extern _cmsTagPluginChunkType _cmsTagPluginChunk;
+
+// Allocate and init Tag container.
+void _cmsAllocTagPluginChunk(struct _cmsContext_struct* ctx,
+ const struct _cmsContext_struct* src);
+
+// Container for intents plug-in
+typedef struct {
+
+ struct _cms_intents_list* Intents;
+
+} _cmsIntentsPluginChunkType;
+
+
+// The global Context0 storage for intents plug-in
+extern _cmsIntentsPluginChunkType _cmsIntentsPluginChunk;
+
+// Allocate and init intents container.
+void _cmsAllocIntentsPluginChunk(struct _cmsContext_struct* ctx,
+ const struct _cmsContext_struct* src);
+
+// Container for optimization plug-in
+typedef struct {
+
+ struct _cmsOptimizationCollection_st* OptimizationCollection;
+
+} _cmsOptimizationPluginChunkType;
+
+
+// The global Context0 storage for optimizers plug-in
+extern _cmsOptimizationPluginChunkType _cmsOptimizationPluginChunk;
+
+// Allocate and init optimizers container.
+void _cmsAllocOptimizationPluginChunk(struct _cmsContext_struct* ctx,
+ const struct _cmsContext_struct* src);
+
+// Container for transform plug-in
+typedef struct {
+
+ struct _cmsTransformCollection_st* TransformCollection;
+
+} _cmsTransformPluginChunkType;
+
+// The global Context0 storage for full-transform replacement plug-in
+extern _cmsTransformPluginChunkType _cmsTransformPluginChunk;
+
+// Allocate and init transform container.
+void _cmsAllocTransformPluginChunk(struct _cmsContext_struct* ctx,
+ const struct _cmsContext_struct* src);
+
+// Container for mutex plug-in
+typedef struct {
+
+ _cmsCreateMutexFnPtrType CreateMutexPtr;
+ _cmsDestroyMutexFnPtrType DestroyMutexPtr;
+ _cmsLockMutexFnPtrType LockMutexPtr;
+ _cmsUnlockMutexFnPtrType UnlockMutexPtr;
+
+} _cmsMutexPluginChunkType;
+
+// The global Context0 storage for mutex plug-in
+extern _cmsMutexPluginChunkType _cmsMutexPluginChunk;
+
+// Allocate and init mutex container.
+void _cmsAllocMutexPluginChunk(struct _cmsContext_struct* ctx,
+ const struct _cmsContext_struct* src);
+
+// ----------------------------------------------------------------------------------
// MLU internal representation
typedef struct {
@@ -347,10 +760,14 @@
cmsBool TagSaveAsRaw[MAX_TABLE_TAG]; // True to write uncooked
void * TagPtrs[MAX_TABLE_TAG];
cmsTagTypeHandler* TagTypeHandlers[MAX_TABLE_TAG]; // Same structure may be serialized on different types
- // depending on profile version, so we keep track of the // type handler for each tag in the list.
+ // depending on profile version, so we keep track of the
+ // type handler for each tag in the list.
// Special
cmsBool IsWrite;
+ // Keep a mutex for cmsReadTag -- Note that this only works if the user includes a mutex plugin
+ void * UsrMutex;
+
} _cmsICCPROFILE;
// IO helpers for profiles
@@ -359,9 +776,9 @@
int _cmsSearchTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, cmsBool lFollowLinks);
// Tag types
-cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsTagTypeSignature sig);
+cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsContext ContextID, cmsTagTypeSignature sig);
cmsTagTypeSignature _cmsGetTagTrueType(cmsHPROFILE hProfile, cmsTagSignature sig);
-cmsTagDescriptor* _cmsGetTagDescriptor(cmsTagSignature sig);
+cmsTagDescriptor* _cmsGetTagDescriptor(cmsContext ContextID, cmsTagSignature sig);
// Error logging ---------------------------------------------------------------------------------------------------------
@@ -372,7 +789,7 @@
cmsInterpParams* _cmsComputeInterpParams(cmsContext ContextID, int nSamples, int InputChan, int OutputChan, const void* Table, cmsUInt32Number dwFlags);
cmsInterpParams* _cmsComputeInterpParamsEx(cmsContext ContextID, const cmsUInt32Number nSamples[], int InputChan, int OutputChan, const void* Table, cmsUInt32Number dwFlags);
void _cmsFreeInterpParams(cmsInterpParams* p);
-cmsBool _cmsSetInterpolationRoutine(cmsInterpParams* p);
+cmsBool _cmsSetInterpolationRoutine(cmsContext ContextID, cmsInterpParams* p);
// Curves ----------------------------------------------------------------------------------------------------------------
@@ -503,7 +920,8 @@
cmsUInt16Number **Black,
cmsUInt32Number *nOutputs);
-cmsBool _cmsOptimizePipeline(cmsPipeline** Lut,
+cmsBool _cmsOptimizePipeline(cmsContext ContextID,
+ cmsPipeline** Lut,
int Intent,
cmsUInt32Number* InputFormat,
cmsUInt32Number* OutputFormat,
@@ -528,7 +946,8 @@
cmsBool _cmsFormatterIsFloat(cmsUInt32Number Type);
cmsBool _cmsFormatterIs8bit(cmsUInt32Number Type);
-cmsFormatter _cmsGetFormatter(cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8
+cmsFormatter _cmsGetFormatter(cmsContext ContextID,
+ cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8
cmsFormatterDirection Dir,
cmsUInt32Number dwFlags);
diff --git a/src/share/native/sun/java2d/cmm/lcms/lcms2_plugin.h b/src/share/native/sun/java2d/cmm/lcms/lcms2_plugin.h
index 1df7cf7..77ff228 100644
--- a/src/share/native/sun/java2d/cmm/lcms/lcms2_plugin.h
+++ b/src/share/native/sun/java2d/cmm/lcms/lcms2_plugin.h
@@ -231,6 +231,7 @@
#define cmsPluginMultiProcessElementSig 0x6D706548 // 'mpeH'
#define cmsPluginOptimizationSig 0x6F707448 // 'optH'
#define cmsPluginTransformSig 0x7A666D48 // 'xfmH'
+#define cmsPluginMutexSig 0x6D747A48 // 'mtxH'
typedef struct _cmsPluginBaseStruct {
@@ -247,19 +248,28 @@
//----------------------------------------------------------------------------------------------------------
// Memory handler. Each new plug-in type replaces current behaviour
+
+typedef void* (* _cmsMallocFnPtrType)(cmsContext ContextID, cmsUInt32Number size);
+typedef void (* _cmsFreeFnPtrType)(cmsContext ContextID, void *Ptr);
+typedef void* (* _cmsReallocFnPtrType)(cmsContext ContextID, void* Ptr, cmsUInt32Number NewSize);
+
+typedef void* (* _cmsMalloZerocFnPtrType)(cmsContext ContextID, cmsUInt32Number size);
+typedef void* (* _cmsCallocFnPtrType)(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size);
+typedef void* (* _cmsDupFnPtrType)(cmsContext ContextID, const void* Org, cmsUInt32Number size);
+
typedef struct {
cmsPluginBase base;
// Required
- void * (* MallocPtr)(cmsContext ContextID, cmsUInt32Number size);
- void (* FreePtr)(cmsContext ContextID, void *Ptr);
- void * (* ReallocPtr)(cmsContext ContextID, void* Ptr, cmsUInt32Number NewSize);
+ _cmsMallocFnPtrType MallocPtr;
+ _cmsFreeFnPtrType FreePtr;
+ _cmsReallocFnPtrType ReallocPtr;
// Optional
- void * (* MallocZeroPtr)(cmsContext ContextID, cmsUInt32Number size);
- void * (* CallocPtr)(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Number size);
- void * (* DupPtr)(cmsContext ContextID, const void* Org, cmsUInt32Number size);
+ _cmsMalloZerocFnPtrType MallocZeroPtr;
+ _cmsCallocFnPtrType CallocPtr;
+ _cmsDupFnPtrType DupPtr;
} cmsPluginMemHandler;
@@ -622,6 +632,29 @@
} cmsPluginTransform;
+//----------------------------------------------------------------------------------------------------------
+// Mutex
+
+typedef void* (* _cmsCreateMutexFnPtrType)(cmsContext ContextID);
+typedef void (* _cmsDestroyMutexFnPtrType)(cmsContext ContextID, void* mtx);
+typedef cmsBool (* _cmsLockMutexFnPtrType)(cmsContext ContextID, void* mtx);
+typedef void (* _cmsUnlockMutexFnPtrType)(cmsContext ContextID, void* mtx);
+
+typedef struct {
+ cmsPluginBase base;
+
+ _cmsCreateMutexFnPtrType CreateMutexPtr;
+ _cmsDestroyMutexFnPtrType DestroyMutexPtr;
+ _cmsLockMutexFnPtrType LockMutexPtr;
+ _cmsUnlockMutexFnPtrType UnlockMutexPtr;
+
+} cmsPluginMutex;
+
+CMSAPI void* CMSEXPORT _cmsCreateMutex(cmsContext ContextID);
+CMSAPI void CMSEXPORT _cmsDestroyMutex(cmsContext ContextID, void* mtx);
+CMSAPI cmsBool CMSEXPORT _cmsLockMutex(cmsContext ContextID, void* mtx);
+CMSAPI void CMSEXPORT _cmsUnlockMutex(cmsContext ContextID, void* mtx);
+
#ifndef CMS_USE_CPP_API
# ifdef __cplusplus
diff --git a/src/solaris/classes/sun/awt/X11/XTextAreaPeer.java b/src/solaris/classes/sun/awt/X11/XTextAreaPeer.java
index 7c7b2d1..4092e85 100644
--- a/src/solaris/classes/sun/awt/X11/XTextAreaPeer.java
+++ b/src/solaris/classes/sun/awt/X11/XTextAreaPeer.java
@@ -1024,7 +1024,8 @@
}
}
- protected void uninstallListeners(JScrollPane scrollPane) {
+ @Override
+ protected void uninstallListeners(JComponent scrollPane) {
super.uninstallListeners(scrollPane);
scrollPane.removePropertyChangeListener(propertyChangeHandler);
}
diff --git a/src/solaris/classes/sun/awt/X11/XWindow.java b/src/solaris/classes/sun/awt/X11/XWindow.java
index e55b8b8..19cf229 100644
--- a/src/solaris/classes/sun/awt/X11/XWindow.java
+++ b/src/solaris/classes/sun/awt/X11/XWindow.java
@@ -55,7 +55,6 @@
*/
private final static int AWT_MULTICLICK_SMUDGE = 4;
// ButtonXXX events stuff
- static int rbutton = 0;
static int lastX = 0, lastY = 0;
static long lastTime = 0;
static long lastButton = 0;
@@ -632,23 +631,6 @@
return res;
}
- /**
- * Returns true if this event is disabled and shouldn't be passed to Java.
- * Default implementation returns false for all events.
- */
- static int getRightButtonNumber() {
- if (rbutton == 0) { // not initialized yet
- XToolkit.awtLock();
- try {
- rbutton = XlibWrapper.XGetPointerMapping(XToolkit.getDisplay(), XlibWrapper.ibuffer, 3);
- }
- finally {
- XToolkit.awtUnlock();
- }
- }
- return rbutton;
- }
-
static int getMouseMovementSmudge() {
//TODO: It's possible to read corresponding settings
return AWT_MULTICLICK_SMUDGE;
@@ -716,11 +698,7 @@
/*
Check for popup trigger !!
*/
- if (lbutton == getRightButtonNumber() || lbutton > 2) {
- popupTrigger = true;
- } else {
- popupTrigger = false;
- }
+ popupTrigger = (lbutton == 3);
}
button = XConstants.buttons[lbutton - 1];
diff --git a/test/java/util/Currency/tablea1.txt b/test/java/util/Currency/tablea1.txt
index 94c848a..2988567 100644
--- a/test/java/util/Currency/tablea1.txt
+++ b/test/java/util/Currency/tablea1.txt
@@ -1,12 +1,12 @@
#
#
-# Amendments up until ISO 4217 AMENDMENT NUMBER 156
-# (As of 23 July 2013)
+# Amendments up until ISO 4217 AMENDMENT NUMBER 159
+# (As of 15 August 2014)
#
# Version
FILEVERSION=1
-DATAVERSION=156
+DATAVERSION=159
# ISO 4217 currency data
AF AFN 971 2
@@ -142,7 +142,7 @@
LR LRD 430 2
LY LYD 434 3
LI CHF 756 2
-LT LTL 440 2
+LT LTL 440 2 2014-12-31-22-00-00 EUR 978 2
LU EUR 978 2
MO MOP 446 2
MK MKD 807 2
diff --git a/test/java/util/logging/CheckZombieLockTest.java b/test/java/util/logging/CheckZombieLockTest.java
new file mode 100644
index 0000000..ab65a81
--- /dev/null
+++ b/test/java/util/logging/CheckZombieLockTest.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright (c) 2014, 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 8048020
+ * @author Daniel Fuchs
+ * @summary Regression on java.util.logging.FileHandler.
+ * The fix is to avoid filling up the file system with zombie lock files.
+ *
+ * @run main/othervm CheckZombieLockTest WRITABLE CLOSE CLEANUP
+ * @run main/othervm CheckZombieLockTest CLEANUP
+ * @run main/othervm CheckZombieLockTest WRITABLE
+ * @run main/othervm CheckZombieLockTest CREATE_FIRST
+ * @run main/othervm CheckZombieLockTest CREATE_NEXT
+ * @run main/othervm CheckZombieLockTest CREATE_NEXT
+ * @run main/othervm CheckZombieLockTest CLEANUP
+ * @run main/othervm CheckZombieLockTest REUSE
+ * @run main/othervm CheckZombieLockTest CLEANUP
+ */
+import java.io.File;
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+import java.util.logging.FileHandler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+public class CheckZombieLockTest {
+
+ private static final String WRITABLE_DIR = "writable-lockfile-dir";
+ private static volatile boolean supportsLocking = true;
+
+ static enum TestCase {
+ WRITABLE, // just verifies that we can create a file in our 'writable-lockfile-dir'
+ CLOSE, // checks that closing a FileHandler removes its lock file
+ CREATE_FIRST, // verifies that 'writable-lockfile-dir' contains no lock, then creates a first FileHandler.
+ CREATE_NEXT, // verifies that 'writable-lockfile-dir' contains a single lock, then creates the next FileHandler
+ REUSE, // verifies that zombie lock files can be reused
+ CLEANUP // removes "writable-lockfile-dir"
+ };
+
+ public static void main(String... args) throws IOException {
+ // we'll base all file creation attempts on the system temp directory,
+ // %t
+ File writableDir = setup();
+ System.out.println("Writable dir is: " + writableDir.getAbsolutePath());
+ // we now have one writable directory to work with:
+ // writableDir
+ if (args == null || args.length == 0) {
+ args = new String[] { "WRITABLE", "CLOSE", "CLEANUP" };
+ }
+ try {
+ runTests(writableDir, args);
+ } catch (RuntimeException | IOException | Error x) {
+ // some error occured: cleanup
+ delete(writableDir);
+ throw x;
+ }
+ }
+
+ /**
+ * @param writableDir in which log and lock file are created
+ * @throws SecurityException
+ * @throws RuntimeException
+ * @throws IOException
+ */
+ private static void runTests(File writableDir, String... args) throws SecurityException,
+ RuntimeException, IOException {
+ for (String arg : args) {
+ switch(TestCase.valueOf(arg)) {
+ // Test 1: makes sure we can create FileHandler in writable directory
+ case WRITABLE: checkWritable(writableDir); break;
+ // Test 2: verifies that FileHandler.close() cleans up its lock file
+ case CLOSE: testFileHandlerClose(writableDir); break;
+ // Test 3: creates the first file handler
+ case CREATE_FIRST: testFileHandlerCreate(writableDir, true); break;
+ // Test 4, 5, ... creates the next file handler
+ case CREATE_NEXT: testFileHandlerCreate(writableDir, false); break;
+ // Checks that zombie lock files are reused appropriatly
+ case REUSE: testFileHandlerReuse(writableDir); break;
+ // Removes the writableDir
+ case CLEANUP: delete(writableDir); break;
+ default: throw new RuntimeException("No such test case: " + arg);
+ }
+ }
+ }
+
+ /**
+ * @param writableDir in which log and lock file are created
+ * @throws SecurityException
+ * @throws RuntimeException
+ * @throws IOException
+ */
+ private static void checkWritable(File writableDir) throws SecurityException,
+ RuntimeException, IOException {
+ // Test 1: make sure we can create/delete files in the writable dir.
+ final File file = new File(writableDir, "test.txt");
+ if (!createFile(file, false)) {
+ throw new IOException("Can't create " + file + "\n\tUnable to run test");
+ } else {
+ delete(file);
+ }
+ }
+
+
+ private static FileHandler createFileHandler(File writableDir) throws SecurityException,
+ RuntimeException, IOException {
+ // Test 1: make sure we can create FileHandler in writable directory
+ try {
+ FileHandler handler = new FileHandler("%t/" + WRITABLE_DIR + "/log.log");
+ handler.publish(new LogRecord(Level.INFO, handler.toString()));
+ handler.flush();
+ return handler;
+ } catch (IOException ex) {
+ throw new RuntimeException("Test failed: should have been able"
+ + " to create FileHandler for " + "%t/" + WRITABLE_DIR
+ + "/log.log in writable directory.", ex);
+ }
+ }
+
+ private static List<File> listLocks(File writableDir, boolean print)
+ throws IOException {
+ List<File> locks = new ArrayList<>();
+ for (File f : writableDir.listFiles()) {
+ if (print) {
+ System.out.println("Found file: " + f.getName());
+ }
+ if (f.getName().endsWith(".lck")) {
+ locks.add(f);
+ }
+ }
+ return locks;
+ }
+
+ private static void testFileHandlerClose(File writableDir) throws IOException {
+ File fakeLock = new File(writableDir, "log.log.lck");
+ if (!createFile(fakeLock, false)) {
+ throw new IOException("Can't create fake lock file: " + fakeLock);
+ }
+ try {
+ List<File> before = listLocks(writableDir, true);
+ System.out.println("before: " + before.size() + " locks found");
+ FileHandler handler = createFileHandler(writableDir);
+ System.out.println("handler created: " + handler);
+ List<File> after = listLocks(writableDir, true);
+ System.out.println("after creating handler: " + after.size() + " locks found");
+ handler.close();
+ System.out.println("handler closed: " + handler);
+ List<File> afterClose = listLocks(writableDir, true);
+ System.out.println("after closing handler: " + afterClose.size() + " locks found");
+ afterClose.removeAll(before);
+ if (!afterClose.isEmpty()) {
+ throw new RuntimeException("Zombie lock file detected: " + afterClose);
+ }
+ } finally {
+ if (fakeLock.canRead()) delete(fakeLock);
+ }
+ List<File> finalLocks = listLocks(writableDir, false);
+ System.out.println("After cleanup: " + finalLocks.size() + " locks found");
+ }
+
+
+ private static void testFileHandlerReuse(File writableDir) throws IOException {
+ List<File> before = listLocks(writableDir, true);
+ System.out.println("before: " + before.size() + " locks found");
+ try {
+ if (!before.isEmpty()) {
+ throw new RuntimeException("Expected no lock file! Found: " + before);
+ }
+ } finally {
+ before.stream().forEach(CheckZombieLockTest::delete);
+ }
+
+ FileHandler handler1 = createFileHandler(writableDir);
+ System.out.println("handler created: " + handler1);
+ List<File> after = listLocks(writableDir, true);
+ System.out.println("after creating handler: " + after.size() + " locks found");
+ if (after.size() != 1) {
+ throw new RuntimeException("Unexpected number of lock files found for "
+ + handler1 + ": " + after);
+ }
+ final File lock = after.get(0);
+ after.clear();
+ handler1.close();
+ after = listLocks(writableDir, true);
+ System.out.println("after closing handler: " + after.size() + " locks found");
+ if (!after.isEmpty()) {
+ throw new RuntimeException("Unexpected number of lock files found for "
+ + handler1 + ": " + after);
+ }
+ if (!createFile(lock, false)) {
+ throw new IOException("Can't create fake lock file: " + lock);
+ }
+ try {
+ before = listLocks(writableDir, true);
+ System.out.println("before: " + before.size() + " locks found");
+ if (before.size() != 1) {
+ throw new RuntimeException("Unexpected number of lock files found: "
+ + before + " expected [" + lock + "].");
+ }
+ FileHandler handler2 = createFileHandler(writableDir);
+ System.out.println("handler created: " + handler2);
+ after = listLocks(writableDir, true);
+ System.out.println("after creating handler: " + after.size() + " locks found");
+ after.removeAll(before);
+ if (!after.isEmpty()) {
+ throw new RuntimeException("Unexpected lock file found: " + after
+ + "\n\t" + lock + " should have been reused");
+ }
+ handler2.close();
+ System.out.println("handler closed: " + handler2);
+ List<File> afterClose = listLocks(writableDir, true);
+ System.out.println("after closing handler: " + afterClose.size() + " locks found");
+ if (!afterClose.isEmpty()) {
+ throw new RuntimeException("Zombie lock file detected: " + afterClose);
+ }
+
+ if (supportsLocking) {
+ FileChannel fc = FileChannel.open(Paths.get(lock.getAbsolutePath()),
+ StandardOpenOption.CREATE_NEW, StandardOpenOption.APPEND,
+ StandardOpenOption.WRITE);
+ try {
+ if (fc.tryLock() != null) {
+ System.out.println("locked: " + lock);
+ handler2 = createFileHandler(writableDir);
+ System.out.println("handler created: " + handler2);
+ after = listLocks(writableDir, true);
+ System.out.println("after creating handler: " + after.size()
+ + " locks found");
+ after.removeAll(before);
+ if (after.size() != 1) {
+ throw new RuntimeException("Unexpected lock files found: " + after
+ + "\n\t" + lock + " should not have been reused");
+ }
+ } else {
+ throw new RuntimeException("Failed to lock: " + lock);
+ }
+ } finally {
+ delete(lock);
+ }
+ }
+ } finally {
+ List<File> finalLocks = listLocks(writableDir, false);
+ System.out.println("end: " + finalLocks.size() + " locks found");
+ delete(writableDir);
+ }
+ }
+
+
+ private static void testFileHandlerCreate(File writableDir, boolean first)
+ throws IOException {
+ List<File> before = listLocks(writableDir, true);
+ System.out.println("before: " + before.size() + " locks found");
+ try {
+ if (first && !before.isEmpty()) {
+ throw new RuntimeException("Expected no lock file! Found: " + before);
+ } else if (!first && before.size() != 1) {
+ throw new RuntimeException("Expected a single lock file! Found: " + before);
+ }
+ } finally {
+ before.stream().forEach(CheckZombieLockTest::delete);
+ }
+ FileHandler handler = createFileHandler(writableDir);
+ System.out.println("handler created: " + handler);
+ List<File> after = listLocks(writableDir, true);
+ System.out.println("after creating handler: " + after.size() + " locks found");
+ if (after.size() != 1) {
+ throw new RuntimeException("Unexpected number of lock files found for "
+ + handler + ": " + after);
+ }
+ }
+
+
+ /**
+ * Setup all the files and directories needed for the tests
+ *
+ * @return writable directory created that needs to be deleted when done
+ * @throws RuntimeException
+ */
+ private static File setup() throws RuntimeException {
+ // First do some setup in the temporary directory (using same logic as
+ // FileHandler for %t pattern)
+ String tmpDir = System.getProperty("java.io.tmpdir"); // i.e. %t
+ if (tmpDir == null) {
+ tmpDir = System.getProperty("user.home");
+ }
+ File tmpOrHomeDir = new File(tmpDir);
+ // Create a writable directory here (%t/writable-lockfile-dir)
+ File writableDir = new File(tmpOrHomeDir, WRITABLE_DIR);
+ if (!createFile(writableDir, true)) {
+ throw new RuntimeException("Test setup failed: unable to create"
+ + " writable working directory "
+ + writableDir.getAbsolutePath() );
+ }
+
+ // try to determine whether file locking is supported
+ final String uniqueFileName = UUID.randomUUID().toString()+".lck";
+ try {
+ FileChannel fc = FileChannel.open(Paths.get(writableDir.getAbsolutePath(),
+ uniqueFileName),
+ StandardOpenOption.CREATE_NEW, StandardOpenOption.APPEND,
+ StandardOpenOption.DELETE_ON_CLOSE);
+ try {
+ fc.tryLock();
+ } catch(IOException x) {
+ supportsLocking = false;
+ } finally {
+ fc.close();
+ }
+ } catch (IOException t) {
+ // should not happen
+ System.err.println("Failed to create new file " + uniqueFileName +
+ " in " + writableDir.getAbsolutePath());
+ throw new RuntimeException("Test setup failed: unable to run test", t);
+ }
+ return writableDir;
+ }
+
+ /**
+ * @param newFile
+ * @return true if file already exists or creation succeeded
+ */
+ private static boolean createFile(File newFile, boolean makeDirectory) {
+ if (newFile.exists()) {
+ return true;
+ }
+ if (makeDirectory) {
+ return newFile.mkdir();
+ } else {
+ try {
+ return newFile.createNewFile();
+ } catch (IOException ioex) {
+ ioex.printStackTrace();
+ return false;
+ }
+ }
+ }
+
+ /*
+ * Recursively delete all files starting at specified file
+ */
+ private static void delete(File f) {
+ if (f != null && f.isDirectory()) {
+ for (File c : f.listFiles())
+ delete(c);
+ }
+ if (!f.delete())
+ System.err.println(
+ "WARNING: unable to delete/cleanup writable test directory: "
+ + f );
+ }
+}
diff --git a/test/javax/xml/bind/marshal/8036981/Good.java b/test/javax/xml/bind/marshal/8036981/Good.java
new file mode 100644
index 0000000..75987f3
--- /dev/null
+++ b/test/javax/xml/bind/marshal/8036981/Good.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2014, 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.
+ */
+
+package testjaxbcontext;
+
+import org.w3c.dom.Element;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAnyElement;
+import javax.xml.bind.annotation.XmlType;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * <p>
+ * Java class for Good complex type.
+ *
+ * <p>
+ * The following schema fragment specifies the expected content contained within
+ * this class.
+ *
+ * <pre>
+ * <complexType name="Good">
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <any processContents='skip' maxOccurs="70"/>
+ * </sequence>
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </pre>
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "Good", propOrder = {
+ "any"
+})
+public class Good {
+
+ @XmlAnyElement
+ protected List<Element> any;
+
+ /**
+ * Gets the value of the any property.
+ *
+ * <p>
+ * This accessor method returns a reference to the live list, not a
+ * snapshot. Therefore any modification you make to the returned list will
+ * be present inside the JAXB object. This is why there is not a
+ * <CODE>set</CODE> method for the any property.
+ *
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getAny().add(newItem);
+ * </pre>
+ *
+ *
+ * <p>
+ * Objects of the following type(s) are allowed in the list
+ * {@link org.w3c.dom.Element }
+ *
+ *
+ */
+ public List<Element> getAny() {
+ if (any == null) {
+ any = new ArrayList<Element>();
+ }
+ return this.any;
+ }
+
+}
diff --git a/test/javax/xml/bind/marshal/8036981/Main.java b/test/javax/xml/bind/marshal/8036981/Main.java
new file mode 100644
index 0000000..aa92593
--- /dev/null
+++ b/test/javax/xml/bind/marshal/8036981/Main.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2014, 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.
+ */
+
+package testjaxbcontext;
+
+import javax.xml.bind.annotation.*;
+
+/**
+ * <p>
+ * Java class for main complex type.
+ *
+ * <p>
+ * The following schema fragment specifies the expected content contained within
+ * this class.
+ *
+ * <pre>
+ * <complexType name="main">
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="Root" type="{}Root"/>
+ * <element name="Good" type="{}Good"/>
+ * </sequence>
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </pre>
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "main", propOrder = {
+ "root",
+ "good"
+})
+@XmlRootElement
+public class Main {
+
+ @XmlElement(name = "Root", required = true)
+ protected Root root;
+ @XmlElement(name = "Good", required = true)
+ protected Good good;
+
+ /**
+ * Gets the value of the root property.
+ *
+ * @return possible object is {@link Root }
+ *
+ */
+ public Root getRoot() {
+ return root;
+ }
+
+ /**
+ * Sets the value of the root property.
+ *
+ * @param value allowed object is {@link Root }
+ *
+ */
+ public void setRoot(Root value) {
+ this.root = value;
+ }
+
+ /**
+ * Gets the value of the good property.
+ *
+ * @return possible object is {@link Good }
+ *
+ */
+ public Good getGood() {
+ return good;
+ }
+
+ /**
+ * Sets the value of the good property.
+ *
+ * @param value allowed object is {@link Good }
+ *
+ */
+ public void setGood(Good value) {
+ this.good = value;
+ }
+
+}
diff --git a/test/javax/xml/bind/marshal/8036981/ObjectFactory.java b/test/javax/xml/bind/marshal/8036981/ObjectFactory.java
new file mode 100644
index 0000000..adb2ddf
--- /dev/null
+++ b/test/javax/xml/bind/marshal/8036981/ObjectFactory.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2014, 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.
+ */
+
+package testjaxbcontext;
+
+import javax.xml.bind.annotation.XmlRegistry;
+
+/**
+ * This object contains factory methods for each Java content interface and Java
+ * element interface generated in the generated package.
+ * <p>
+ * An ObjectFactory allows you to programatically construct new instances of the
+ * Java representation for XML content. The Java representation of XML content
+ * can consist of schema derived interfaces and classes representing the binding
+ * of schema type definitions, element declarations and model groups. Factory
+ * methods for each of these are provided in this class.
+ *
+ */
+@XmlRegistry
+public class ObjectFactory {
+
+ /**
+ * Create a new ObjectFactory that can be used to create new instances of
+ * schema derived classes for package: generated
+ *
+ */
+ public ObjectFactory() {
+ }
+
+ /**
+ * Create an instance of {@link Root }
+ *
+ */
+ public Root createRoot() {
+ return new Root();
+ }
+
+ /**
+ * Create an instance of {@link Good }
+ *
+ */
+ public Good createGood() {
+ return new Good();
+ }
+
+ /**
+ * Create an instance of {@link Main }
+ *
+ */
+ public Main createMain() {
+ return new Main();
+ }
+
+}
diff --git a/test/javax/xml/bind/marshal/8036981/Root.java b/test/javax/xml/bind/marshal/8036981/Root.java
new file mode 100644
index 0000000..85fff71
--- /dev/null
+++ b/test/javax/xml/bind/marshal/8036981/Root.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2014, 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.
+ */
+
+package testjaxbcontext;
+
+import javax.xml.bind.annotation.*;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * <p>
+ * Java class for Root complex type.
+ *
+ * <p>
+ * The following schema fragment specifies the expected content contained within
+ * this class.
+ *
+ * <pre>
+ * <complexType name="Root">
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <any processContents='skip' maxOccurs="70"/>
+ * </sequence>
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </pre>
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "Root", propOrder = {
+ "content"
+})
+public class Root {
+
+ @XmlMixed
+ @XmlAnyElement
+ protected List<Object> content;
+
+ /**
+ * Gets the value of the content property.
+ *
+ * <p>
+ * This accessor method returns a reference to the live list, not a
+ * snapshot. Therefore any modification you make to the returned list will
+ * be present inside the JAXB object. This is why there is not a
+ * <CODE>set</CODE> method for the content property.
+ *
+ * <p>
+ * For example, to add a new item, do as follows:
+ * <pre>
+ * getContent().add(newItem);
+ * </pre>
+ *
+ *
+ * <p>
+ * Objects of the following type(s) are allowed in the list {@link org.w3c.dom.Element }
+ * {@link String }
+ *
+ *
+ */
+ public List<Object> getContent() {
+ if (content == null) {
+ content = new ArrayList<Object>();
+ }
+ return this.content;
+ }
+
+}
diff --git a/test/javax/xml/bind/marshal/8036981/Test.java b/test/javax/xml/bind/marshal/8036981/Test.java
new file mode 100644
index 0000000..beedce1
--- /dev/null
+++ b/test/javax/xml/bind/marshal/8036981/Test.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2014, 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 Test.java
+ * @bug 8036981
+ * @summary JAXB not preserving formatting during unmarshalling/marshalling
+ * @compile Good.java Main.java ObjectFactory.java Root.java
+ * @run main/othervm Test
+ */
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import java.io.File;
+import java.io.StringWriter;
+
+/**
+ * Test for marshalling and unmarshalling mixed and unmixed content
+ */
+public class Test {
+
+ private static final String EXPECTED = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><main><Root>\n" +
+ " <SomeTag>\n" +
+ " <AChildTag>\n" +
+ " <AnotherChildTag/>\n" +
+ " <AnotherChildTag/>\n" +
+ " </AChildTag>\n" +
+ " </SomeTag>\n" +
+ " </Root><Good><VeryGood><TheBest><MegaSuper/><MegaSuper/>\n" +
+ " </TheBest>\n" +
+ " </VeryGood></Good></main>";
+
+ public static void main(String[] args) throws Exception {
+ JAXBContext jc = JAXBContext.newInstance("testjaxbcontext");
+ Unmarshaller u = jc.createUnmarshaller();
+ Object result = u.unmarshal(new File(System.getProperty("test.src", ".") + "/test.xml"));
+ StringWriter sw = new StringWriter();
+ Marshaller m = jc.createMarshaller();
+ m.marshal(result, sw);
+ System.out.println("Expected:" + EXPECTED);
+ System.out.println("Observed:" + sw.toString());
+ if (!EXPECTED.equals(sw.toString())) {
+ throw new Exception("Unmarshal/Marshal generates different content");
+ }
+ }
+}
diff --git a/test/javax/xml/bind/marshal/8036981/test.xml b/test/javax/xml/bind/marshal/8036981/test.xml
new file mode 100644
index 0000000..0d001a8
--- /dev/null
+++ b/test/javax/xml/bind/marshal/8036981/test.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<main>
+ <Root>
+ <SomeTag>
+ <AChildTag>
+ <AnotherChildTag/>
+ <AnotherChildTag/>
+ </AChildTag>
+ </SomeTag>
+ </Root>
+ <Good>
+ <VeryGood>
+ <TheBest>
+ <MegaSuper/>
+ <MegaSuper/>
+ </TheBest>
+ </VeryGood>
+ </Good>
+</main>
diff --git a/test/sun/text/resources/LocaleData b/test/sun/text/resources/LocaleData
index 9365989..9dca93b 100644
--- a/test/sun/text/resources/LocaleData
+++ b/test/sun/text/resources/LocaleData
@@ -7699,3 +7699,6 @@
# bug 8037343
FormatData/es_DO/DatePatterns/2=dd/MM/yyyy
FormatData/es_DO/DatePatterns/3=dd/MM/yy
+
+# bug 8055222
+CurrencyNames/lt_LT/EUR=\u20AC
diff --git a/test/sun/text/resources/LocaleDataTest.java b/test/sun/text/resources/LocaleDataTest.java
index e7245e6..e2cea1a 100644
--- a/test/sun/text/resources/LocaleDataTest.java
+++ b/test/sun/text/resources/LocaleDataTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2014, 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
@@ -36,7 +36,7 @@
* 6919624 6998391 7019267 7020960 7025837 7020583 7036905 7066203 7101495
* 7003124 7085757 7028073 7171028 7189611 8000983 7195759 8004489 8006509
* 7114053 7074882 7040556 8013836 8021121 6192407 6931564 8027695 7090826
- * 8017142 8037343
+ * 8017142 8037343 8055222
* @summary Verify locale data
*
*/