Merge tag jb8u152-b1248.8
diff --git a/.gitignore b/.gitignore
index 814f170..3a01364 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,3 @@
 JTwork
 JTreport
 *.class
-.idea/workspace.xml
-idea/java/.idea/workspace.xml
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 35eb1dd..0000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="VcsDirectoryMappings">
-    <mapping directory="" vcs="Git" />
-  </component>
-</project>
\ No newline at end of file
diff --git a/idea/native/.idea/codeStyles/codeStyleConfig.xml b/idea/native/.idea/codeStyles/codeStyleConfig.xml
deleted file mode 100644
index 79ee123..0000000
--- a/idea/native/.idea/codeStyles/codeStyleConfig.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<component name="ProjectCodeStyleConfiguration">
-  <state>
-    <option name="USE_PER_PROJECT_SETTINGS" value="true" />
-  </state>
-</component>
\ No newline at end of file
diff --git a/idea/native/.idea/vcs.xml b/idea/native/.idea/vcs.xml
deleted file mode 100644
index 2717432..0000000
--- a/idea/native/.idea/vcs.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="VcsDirectoryMappings">
-    <mapping directory="$PROJECT_DIR$/../../.." vcs="Git" />
-    <mapping directory="$PROJECT_DIR$/../../../corba" vcs="Git" />
-    <mapping directory="$PROJECT_DIR$/../../../hotspot" vcs="Git" />
-    <mapping directory="$PROJECT_DIR$/../../../jaxp" vcs="Git" />
-    <mapping directory="$PROJECT_DIR$/../../../jaxws" vcs="Git" />
-    <mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
-    <mapping directory="$PROJECT_DIR$/../../../langtools" vcs="Git" />
-    <mapping directory="$PROJECT_DIR$/../../../nashorn" vcs="Git" />
-  </component>
-</project>
\ No newline at end of file
diff --git a/idea/native/CMakeLists.txt b/idea/native/CMakeLists.txt
deleted file mode 100644
index e79edb7..0000000
--- a/idea/native/CMakeLists.txt
+++ /dev/null
@@ -1,1887 +0,0 @@
-cmake_minimum_required(VERSION 3.4)
-project(jdk)
-
-include_directories(
-        ../../src/share/javavm/export
-        ../../src/share/native/common
-        ../../src/share/native/sun/font
-        ../../src/share/native/sun/java2d
-        ../../src/share/native/sun/java2d/loops)
-
-if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin" OR ${CMAKE_SYSTEM_NAME} MATCHES "Linux")
-    include_directories(
-            ../../src/solaris/native/common
-            ../../src/solaris/javavm/export)
-endif()
-
-if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
-    set(CMAKE_FRAMEWORK_PATH ${CMAKE_FRAMEWORK_PATH} ${CMAKE_OSX_SYSROOT}/System/Library/Frameworks/JavaVM.framework/Versions/A/Frameworks/)
-    find_library(JAVA_NATIVE_FOUNDATION JavaNativeFoundation)
-    include_directories(
-            ../../src/macosx/native/sun/osxapp
-            ../../../build/macosx-x86_64-normal-server-release/jdk/gensrc_headers)
-
-elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
-    include_directories(
-            ../../../build/linux-x86_64-normal-server-release/jdk/gensrc_headers)
-elseif(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
-    include_directories(
-            ../../src/windows/native/common
-            ../../src/windows/javavm/export
-            ../../../build/windows-x86_64-normal-server-release/jdk/gensrc_headers)
-endif()
-
-find_package(Freetype REQUIRED)
-include_directories(${FREETYPE_INCLUDE_DIRS})
-
-set(SOURCE_FILES
-    ../../src/share/javavm/export/classfile_constants.h
-    ../../src/share/javavm/export/jawt.h
-    ../../src/share/javavm/export/jdwpTransport.h
-    ../../src/share/javavm/export/jmm.h
-    ../../src/share/javavm/export/jni.h
-    ../../src/share/javavm/export/jvm.h
-    ../../src/share/javavm/export/jvmti.h
-    ../../src/share/javavm/export/jvmticmlr.h
-    ../../src/share/native/com/sun/java/util/jar/pack/bands.cpp
-    ../../src/share/native/com/sun/java/util/jar/pack/bands.h
-    ../../src/share/native/com/sun/java/util/jar/pack/bytes.cpp
-    ../../src/share/native/com/sun/java/util/jar/pack/bytes.h
-    ../../src/share/native/com/sun/java/util/jar/pack/coding.cpp
-    ../../src/share/native/com/sun/java/util/jar/pack/coding.h
-    ../../src/share/native/com/sun/java/util/jar/pack/constants.h
-    ../../src/share/native/com/sun/java/util/jar/pack/defines.h
-    ../../src/share/native/com/sun/java/util/jar/pack/jni.cpp
-    ../../src/share/native/com/sun/java/util/jar/pack/main.cpp
-    ../../src/share/native/com/sun/java/util/jar/pack/unpack.cpp
-    ../../src/share/native/com/sun/java/util/jar/pack/unpack.h
-    ../../src/share/native/com/sun/java/util/jar/pack/utils.cpp
-    ../../src/share/native/com/sun/java/util/jar/pack/utils.h
-    ../../src/share/native/com/sun/java/util/jar/pack/zip.cpp
-    ../../src/share/native/com/sun/java/util/jar/pack/zip.h
-    ../../src/share/native/com/sun/media/sound/Configure.h
-    ../../src/share/native/com/sun/media/sound/DirectAudio.h
-    ../../src/share/native/com/sun/media/sound/DirectAudioDevice.c
-    ../../src/share/native/com/sun/media/sound/DirectAudioDeviceProvider.c
-    ../../src/share/native/com/sun/media/sound/MidiInDevice.c
-    ../../src/share/native/com/sun/media/sound/MidiInDeviceProvider.c
-    ../../src/share/native/com/sun/media/sound/MidiOutDevice.c
-    ../../src/share/native/com/sun/media/sound/MidiOutDeviceProvider.c
-    ../../src/share/native/com/sun/media/sound/Platform.c
-    ../../src/share/native/com/sun/media/sound/PlatformMidi.c
-    ../../src/share/native/com/sun/media/sound/PlatformMidi.h
-    ../../src/share/native/com/sun/media/sound/PortMixer.c
-    ../../src/share/native/com/sun/media/sound/PortMixerProvider.c
-    ../../src/share/native/com/sun/media/sound/Ports.h
-    ../../src/share/native/com/sun/media/sound/SoundDefs.h
-    ../../src/share/native/com/sun/media/sound/Utilities.c
-    ../../src/share/native/com/sun/media/sound/Utilities.h
-    ../../src/share/native/com/sun/tools/jdi/SharedMemory.h
-    ../../src/share/native/com/sun/tools/jdi/SharedMemoryConnection.c
-    ../../src/share/native/com/sun/tools/jdi/SharedMemoryTransport.c
-    ../../src/share/native/common/check_code.c
-    ../../src/share/native/common/check_format.c
-    ../../src/share/native/common/check_version.c
-    ../../src/share/native/common/gdefs.h
-    ../../src/share/native/common/jdk_util.c
-    ../../src/share/native/common/jdk_util.h
-    ../../src/share/native/common/jio.c
-    ../../src/share/native/common/jlong.h
-    ../../src/share/native/common/jni_util.c
-    ../../src/share/native/common/jni_util.h
-    ../../src/share/native/common/sizecalc.h
-    ../../src/share/native/common/verify_stub.c
-    ../../src/share/native/java/io/FileInputStream.c
-    ../../src/share/native/java/io/io_util.c
-    ../../src/share/native/java/io/io_util.h
-    ../../src/share/native/java/io/ObjectInputStream.c
-    ../../src/share/native/java/io/ObjectOutputStream.c
-    ../../src/share/native/java/io/ObjectStreamClass.c
-    ../../src/share/native/java/io/RandomAccessFile.c
-    ../../src/share/native/java/lang/fdlibm/include/fdlibm.h
-    ../../src/share/native/java/lang/fdlibm/include/jfdlibm.h
-    ../../src/share/native/java/lang/fdlibm/src/e_acos.c
-    ../../src/share/native/java/lang/fdlibm/src/e_asin.c
-    ../../src/share/native/java/lang/fdlibm/src/e_atan2.c
-    ../../src/share/native/java/lang/fdlibm/src/e_atanh.c
-    ../../src/share/native/java/lang/fdlibm/src/e_cosh.c
-    ../../src/share/native/java/lang/fdlibm/src/e_exp.c
-    ../../src/share/native/java/lang/fdlibm/src/e_fmod.c
-    ../../src/share/native/java/lang/fdlibm/src/e_hypot.c
-    ../../src/share/native/java/lang/fdlibm/src/e_log.c
-    ../../src/share/native/java/lang/fdlibm/src/e_log10.c
-    ../../src/share/native/java/lang/fdlibm/src/e_pow.c
-    ../../src/share/native/java/lang/fdlibm/src/e_rem_pio2.c
-    ../../src/share/native/java/lang/fdlibm/src/e_remainder.c
-    ../../src/share/native/java/lang/fdlibm/src/e_scalb.c
-    ../../src/share/native/java/lang/fdlibm/src/e_sinh.c
-    ../../src/share/native/java/lang/fdlibm/src/e_sqrt.c
-    ../../src/share/native/java/lang/fdlibm/src/k_cos.c
-    ../../src/share/native/java/lang/fdlibm/src/k_rem_pio2.c
-    ../../src/share/native/java/lang/fdlibm/src/k_sin.c
-    ../../src/share/native/java/lang/fdlibm/src/k_standard.c
-    ../../src/share/native/java/lang/fdlibm/src/k_tan.c
-    ../../src/share/native/java/lang/fdlibm/src/s_atan.c
-    ../../src/share/native/java/lang/fdlibm/src/s_cbrt.c
-    ../../src/share/native/java/lang/fdlibm/src/s_ceil.c
-    ../../src/share/native/java/lang/fdlibm/src/s_copysign.c
-    ../../src/share/native/java/lang/fdlibm/src/s_cos.c
-    ../../src/share/native/java/lang/fdlibm/src/s_expm1.c
-    ../../src/share/native/java/lang/fdlibm/src/s_fabs.c
-    ../../src/share/native/java/lang/fdlibm/src/s_finite.c
-    ../../src/share/native/java/lang/fdlibm/src/s_floor.c
-    ../../src/share/native/java/lang/fdlibm/src/s_frexp.c
-    ../../src/share/native/java/lang/fdlibm/src/s_ilogb.c
-    ../../src/share/native/java/lang/fdlibm/src/s_isnan.c
-    ../../src/share/native/java/lang/fdlibm/src/s_ldexp.c
-    ../../src/share/native/java/lang/fdlibm/src/s_lib_version.c
-    ../../src/share/native/java/lang/fdlibm/src/s_log1p.c
-    ../../src/share/native/java/lang/fdlibm/src/s_logb.c
-    ../../src/share/native/java/lang/fdlibm/src/s_matherr.c
-    ../../src/share/native/java/lang/fdlibm/src/s_modf.c
-    ../../src/share/native/java/lang/fdlibm/src/s_nextafter.c
-    ../../src/share/native/java/lang/fdlibm/src/s_rint.c
-    ../../src/share/native/java/lang/fdlibm/src/s_scalbn.c
-    ../../src/share/native/java/lang/fdlibm/src/s_signgam.c
-    ../../src/share/native/java/lang/fdlibm/src/s_significand.c
-    ../../src/share/native/java/lang/fdlibm/src/s_sin.c
-    ../../src/share/native/java/lang/fdlibm/src/s_tan.c
-    ../../src/share/native/java/lang/fdlibm/src/s_tanh.c
-    ../../src/share/native/java/lang/fdlibm/src/w_acos.c
-    ../../src/share/native/java/lang/fdlibm/src/w_asin.c
-    ../../src/share/native/java/lang/fdlibm/src/w_atan2.c
-    ../../src/share/native/java/lang/fdlibm/src/w_atanh.c
-    ../../src/share/native/java/lang/fdlibm/src/w_cosh.c
-    ../../src/share/native/java/lang/fdlibm/src/w_exp.c
-    ../../src/share/native/java/lang/fdlibm/src/w_fmod.c
-    ../../src/share/native/java/lang/fdlibm/src/w_hypot.c
-    ../../src/share/native/java/lang/fdlibm/src/w_log.c
-    ../../src/share/native/java/lang/fdlibm/src/w_log10.c
-    ../../src/share/native/java/lang/fdlibm/src/w_pow.c
-    ../../src/share/native/java/lang/fdlibm/src/w_remainder.c
-    ../../src/share/native/java/lang/fdlibm/src/w_scalb.c
-    ../../src/share/native/java/lang/fdlibm/src/w_sinh.c
-    ../../src/share/native/java/lang/fdlibm/src/w_sqrt.c
-    ../../src/share/native/java/lang/reflect/Array.c
-    ../../src/share/native/java/lang/reflect/Executable.c
-    ../../src/share/native/java/lang/reflect/Field.c
-    ../../src/share/native/java/lang/reflect/Proxy.c
-    ../../src/share/native/java/lang/Class.c
-    ../../src/share/native/java/lang/ClassLoader.c
-    ../../src/share/native/java/lang/Compiler.c
-    ../../src/share/native/java/lang/Double.c
-    ../../src/share/native/java/lang/Float.c
-    ../../src/share/native/java/lang/java_props.h
-    ../../src/share/native/java/lang/Object.c
-    ../../src/share/native/java/lang/Package.c
-    ../../src/share/native/java/lang/Runtime.c
-    ../../src/share/native/java/lang/SecurityManager.c
-    ../../src/share/native/java/lang/Shutdown.c
-    ../../src/share/native/java/lang/StrictMath.c
-    ../../src/share/native/java/lang/String.c
-    ../../src/share/native/java/lang/System.c
-    ../../src/share/native/java/lang/Thread.c
-    ../../src/share/native/java/lang/Throwable.c
-    ../../src/share/native/java/net/DatagramPacket.c
-    ../../src/share/native/java/net/Inet4Address.c
-    ../../src/share/native/java/net/Inet6Address.c
-    ../../src/share/native/java/net/InetAddress.c
-    ../../src/share/native/java/net/net_util.c
-    ../../src/share/native/java/net/net_util.h
-    ../../src/share/native/java/nio/Bits.c
-    ../../src/share/native/java/security/AccessController.c
-    ../../src/share/native/java/util/concurrent/atomic/AtomicLong.c
-    ../../src/share/native/java/util/zip/zlib-1.2.8/compress.c
-    ../../src/share/native/java/util/zip/zlib-1.2.8/crc32.h
-    ../../src/share/native/java/util/zip/zlib-1.2.8/deflate.c
-    ../../src/share/native/java/util/zip/zlib-1.2.8/deflate.h
-    ../../src/share/native/java/util/zip/zlib-1.2.8/gzclose.c
-    ../../src/share/native/java/util/zip/zlib-1.2.8/gzguts.h
-    ../../src/share/native/java/util/zip/zlib-1.2.8/gzlib.c
-    ../../src/share/native/java/util/zip/zlib-1.2.8/gzread.c
-    ../../src/share/native/java/util/zip/zlib-1.2.8/gzwrite.c
-    ../../src/share/native/java/util/zip/zlib-1.2.8/infback.c
-    ../../src/share/native/java/util/zip/zlib-1.2.8/inffast.c
-    ../../src/share/native/java/util/zip/zlib-1.2.8/inffast.h
-    ../../src/share/native/java/util/zip/zlib-1.2.8/inffixed.h
-    ../../src/share/native/java/util/zip/zlib-1.2.8/inflate.c
-    ../../src/share/native/java/util/zip/zlib-1.2.8/inflate.h
-    ../../src/share/native/java/util/zip/zlib-1.2.8/inftrees.c
-    ../../src/share/native/java/util/zip/zlib-1.2.8/inftrees.h
-    ../../src/share/native/java/util/zip/zlib-1.2.8/trees.c
-    ../../src/share/native/java/util/zip/zlib-1.2.8/trees.h
-    ../../src/share/native/java/util/zip/zlib-1.2.8/uncompr.c
-    ../../src/share/native/java/util/zip/zlib-1.2.8/zadler32.c
-    ../../src/share/native/java/util/zip/zlib-1.2.8/zconf.h
-    ../../src/share/native/java/util/zip/zlib-1.2.8/zcrc32.c
-    ../../src/share/native/java/util/zip/zlib-1.2.8/zlib.h
-    ../../src/share/native/java/util/zip/zlib-1.2.8/zutil.c
-    ../../src/share/native/java/util/zip/zlib-1.2.8/zutil.h
-    ../../src/share/native/java/util/zip/Adler32.c
-    ../../src/share/native/java/util/zip/CRC32.c
-    ../../src/share/native/java/util/zip/Deflater.c
-    ../../src/share/native/java/util/zip/Inflater.c
-    ../../src/share/native/java/util/zip/zip_util.c
-    ../../src/share/native/java/util/zip/zip_util.h
-    ../../src/share/native/java/util/zip/ZipFile.c
-    ../../src/share/native/java/util/TimeZone.c
-    ../../src/share/native/sun/awt/debug/debug_assert.c
-    ../../src/share/native/sun/awt/debug/debug_assert.h
-    ../../src/share/native/sun/awt/debug/debug_mem.c
-    ../../src/share/native/sun/awt/debug/debug_mem.h
-    ../../src/share/native/sun/awt/debug/debug_trace.c
-    ../../src/share/native/sun/awt/debug/debug_trace.h
-    ../../src/share/native/sun/awt/debug/debug_util.c
-    ../../src/share/native/sun/awt/debug/debug_util.h
-    ../../src/share/native/sun/awt/giflib/dgif_lib.c
-    ../../src/share/native/sun/awt/giflib/gif_err.c
-    ../../src/share/native/sun/awt/giflib/gif_hash.h
-    ../../src/share/native/sun/awt/giflib/gif_lib.h
-    ../../src/share/native/sun/awt/giflib/gif_lib_private.h
-    ../../src/share/native/sun/awt/giflib/gifalloc.c
-    ../../src/share/native/sun/awt/image/cvutils/img_alpha.h
-    ../../src/share/native/sun/awt/image/cvutils/img_anycm.h
-    ../../src/share/native/sun/awt/image/cvutils/img_colors.c
-    ../../src/share/native/sun/awt/image/cvutils/img_colors.h
-    ../../src/share/native/sun/awt/image/cvutils/img_dcm.h
-    ../../src/share/native/sun/awt/image/cvutils/img_dcm8.h
-    ../../src/share/native/sun/awt/image/cvutils/img_dir8dither.h
-    ../../src/share/native/sun/awt/image/cvutils/img_dirdither.h
-    ../../src/share/native/sun/awt/image/cvutils/img_fscolor.h
-    ../../src/share/native/sun/awt/image/cvutils/img_fsdither.h
-    ../../src/share/native/sun/awt/image/cvutils/img_fsgray.h
-    ../../src/share/native/sun/awt/image/cvutils/img_fsutil.h
-    ../../src/share/native/sun/awt/image/cvutils/img_globals.c
-    ../../src/share/native/sun/awt/image/cvutils/img_globals.h
-    ../../src/share/native/sun/awt/image/cvutils/img_icm.h
-    ../../src/share/native/sun/awt/image/cvutils/img_input32.h
-    ../../src/share/native/sun/awt/image/cvutils/img_input8.h
-    ../../src/share/native/sun/awt/image/cvutils/img_input8_32.h
-    ../../src/share/native/sun/awt/image/cvutils/img_nodither.h
-    ../../src/share/native/sun/awt/image/cvutils/img_noscale.h
-    ../../src/share/native/sun/awt/image/cvutils/img_opaque.h
-    ../../src/share/native/sun/awt/image/cvutils/img_ordclrsgn.h
-    ../../src/share/native/sun/awt/image/cvutils/img_ordclruns.h
-    ../../src/share/native/sun/awt/image/cvutils/img_orddither.h
-    ../../src/share/native/sun/awt/image/cvutils/img_ordgray.h
-    ../../src/share/native/sun/awt/image/cvutils/img_output16.h
-    ../../src/share/native/sun/awt/image/cvutils/img_output16_32.h
-    ../../src/share/native/sun/awt/image/cvutils/img_output24.h
-    ../../src/share/native/sun/awt/image/cvutils/img_output32.h
-    ../../src/share/native/sun/awt/image/cvutils/img_output8.h
-    ../../src/share/native/sun/awt/image/cvutils/img_output8_16_24.h
-    ../../src/share/native/sun/awt/image/cvutils/img_output8_16_32.h
-    ../../src/share/native/sun/awt/image/cvutils/img_output8_32.h
-    ../../src/share/native/sun/awt/image/cvutils/img_replscale.h
-    ../../src/share/native/sun/awt/image/cvutils/img_scaleloop.h
-    ../../src/share/native/sun/awt/image/cvutils/img_util.h
-    ../../src/share/native/sun/awt/image/gif/gifdecoder.c
-    ../../src/share/native/sun/awt/image/jpeg/imageioJPEG.c
-    ../../src/share/native/sun/awt/image/jpeg/jcapimin.c
-    ../../src/share/native/sun/awt/image/jpeg/jcapistd.c
-    ../../src/share/native/sun/awt/image/jpeg/jccoefct.c
-    ../../src/share/native/sun/awt/image/jpeg/jccolor.c
-    ../../src/share/native/sun/awt/image/jpeg/jcdctmgr.c
-    ../../src/share/native/sun/awt/image/jpeg/jchuff.c
-    ../../src/share/native/sun/awt/image/jpeg/jchuff.h
-    ../../src/share/native/sun/awt/image/jpeg/jcinit.c
-    ../../src/share/native/sun/awt/image/jpeg/jcmainct.c
-    ../../src/share/native/sun/awt/image/jpeg/jcmarker.c
-    ../../src/share/native/sun/awt/image/jpeg/jcmaster.c
-    ../../src/share/native/sun/awt/image/jpeg/jcomapi.c
-    ../../src/share/native/sun/awt/image/jpeg/jconfig.h
-    ../../src/share/native/sun/awt/image/jpeg/jcparam.c
-    ../../src/share/native/sun/awt/image/jpeg/jcphuff.c
-    ../../src/share/native/sun/awt/image/jpeg/jcprepct.c
-    ../../src/share/native/sun/awt/image/jpeg/jcsample.c
-    ../../src/share/native/sun/awt/image/jpeg/jctrans.c
-    ../../src/share/native/sun/awt/image/jpeg/jdapimin.c
-    ../../src/share/native/sun/awt/image/jpeg/jdapistd.c
-    ../../src/share/native/sun/awt/image/jpeg/jdcoefct.c
-    ../../src/share/native/sun/awt/image/jpeg/jdcolor.c
-    ../../src/share/native/sun/awt/image/jpeg/jdct.h
-    ../../src/share/native/sun/awt/image/jpeg/jddctmgr.c
-    ../../src/share/native/sun/awt/image/jpeg/jdhuff.c
-    ../../src/share/native/sun/awt/image/jpeg/jdhuff.h
-    ../../src/share/native/sun/awt/image/jpeg/jdinput.c
-    ../../src/share/native/sun/awt/image/jpeg/jdmainct.c
-    ../../src/share/native/sun/awt/image/jpeg/jdmarker.c
-    ../../src/share/native/sun/awt/image/jpeg/jdmaster.c
-    ../../src/share/native/sun/awt/image/jpeg/jdmerge.c
-    ../../src/share/native/sun/awt/image/jpeg/jdphuff.c
-    ../../src/share/native/sun/awt/image/jpeg/jdpostct.c
-    ../../src/share/native/sun/awt/image/jpeg/jdsample.c
-    ../../src/share/native/sun/awt/image/jpeg/jdtrans.c
-    ../../src/share/native/sun/awt/image/jpeg/jerror.c
-    ../../src/share/native/sun/awt/image/jpeg/jerror.h
-    ../../src/share/native/sun/awt/image/jpeg/jfdctflt.c
-    ../../src/share/native/sun/awt/image/jpeg/jfdctfst.c
-    ../../src/share/native/sun/awt/image/jpeg/jfdctint.c
-    ../../src/share/native/sun/awt/image/jpeg/jidctflt.c
-    ../../src/share/native/sun/awt/image/jpeg/jidctfst.c
-    ../../src/share/native/sun/awt/image/jpeg/jidctint.c
-    ../../src/share/native/sun/awt/image/jpeg/jidctred.c
-    ../../src/share/native/sun/awt/image/jpeg/jinclude.h
-    ../../src/share/native/sun/awt/image/jpeg/jmemmgr.c
-    ../../src/share/native/sun/awt/image/jpeg/jmemnobs.c
-    ../../src/share/native/sun/awt/image/jpeg/jmemsys.h
-    ../../src/share/native/sun/awt/image/jpeg/jmorecfg.h
-    ../../src/share/native/sun/awt/image/jpeg/jpegdecoder.c
-    ../../src/share/native/sun/awt/image/jpeg/jpegint.h
-    ../../src/share/native/sun/awt/image/jpeg/jpeglib.h
-    ../../src/share/native/sun/awt/image/jpeg/jquant1.c
-    ../../src/share/native/sun/awt/image/jpeg/jquant2.c
-    ../../src/share/native/sun/awt/image/jpeg/jutils.c
-    ../../src/share/native/sun/awt/image/jpeg/jversion.h
-    ../../src/share/native/sun/awt/image/awt_ImageRep.c
-    ../../src/share/native/sun/awt/image/awt_parseImage.c
-    ../../src/share/native/sun/awt/image/awt_parseImage.h
-    ../../src/share/native/sun/awt/image/BufImgSurfaceData.c
-    ../../src/share/native/sun/awt/image/BufImgSurfaceData.h
-    ../../src/share/native/sun/awt/image/DataBufferNative.c
-    ../../src/share/native/sun/awt/image/dither.c
-    ../../src/share/native/sun/awt/image/dither.h
-    ../../src/share/native/sun/awt/image/imageInitIDs.c
-    ../../src/share/native/sun/awt/image/imageInitIDs.h
-    ../../src/share/native/sun/awt/libpng/png.c
-    ../../src/share/native/sun/awt/libpng/png.h
-    ../../src/share/native/sun/awt/libpng/pngconf.h
-    ../../src/share/native/sun/awt/libpng/pngdebug.h
-    ../../src/share/native/sun/awt/libpng/pngerror.c
-    ../../src/share/native/sun/awt/libpng/pngget.c
-    ../../src/share/native/sun/awt/libpng/pnginfo.h
-    ../../src/share/native/sun/awt/libpng/pnglibconf.h
-    ../../src/share/native/sun/awt/libpng/pngmem.c
-    ../../src/share/native/sun/awt/libpng/pngpread.c
-    ../../src/share/native/sun/awt/libpng/pngpriv.h
-    ../../src/share/native/sun/awt/libpng/pngread.c
-    ../../src/share/native/sun/awt/libpng/pngrio.c
-    ../../src/share/native/sun/awt/libpng/pngrtran.c
-    ../../src/share/native/sun/awt/libpng/pngrutil.c
-    ../../src/share/native/sun/awt/libpng/pngset.c
-    ../../src/share/native/sun/awt/libpng/pngstruct.h
-    ../../src/share/native/sun/awt/libpng/pngtest.c
-    ../../src/share/native/sun/awt/libpng/pngtrans.c
-    ../../src/share/native/sun/awt/libpng/pngwio.c
-    ../../src/share/native/sun/awt/libpng/pngwrite.c
-    ../../src/share/native/sun/awt/libpng/pngwtran.c
-    ../../src/share/native/sun/awt/libpng/pngwutil.c
-    ../../src/share/native/sun/awt/medialib/awt_ImagingLib.c
-    ../../src/share/native/sun/awt/medialib/awt_ImagingLib.h
-    ../../src/share/native/sun/awt/medialib/j2d_names.h
-    ../../src/share/native/sun/awt/medialib/mlib.h
-    ../../src/share/native/sun/awt/medialib/mlib_c_ImageAffine_BC.c
-    ../../src/share/native/sun/awt/medialib/mlib_c_ImageAffine_BC_S16.c
-    ../../src/share/native/sun/awt/medialib/mlib_c_ImageAffine_BC_U16.c
-    ../../src/share/native/sun/awt/medialib/mlib_c_ImageAffine_BL.c
-    ../../src/share/native/sun/awt/medialib/mlib_c_ImageAffine_BL_S16.c
-    ../../src/share/native/sun/awt/medialib/mlib_c_ImageAffine_BL_U16.c
-    ../../src/share/native/sun/awt/medialib/mlib_c_ImageAffine_NN.c
-    ../../src/share/native/sun/awt/medialib/mlib_c_ImageAffineIndex_BC.c
-    ../../src/share/native/sun/awt/medialib/mlib_c_ImageAffineIndex_BL.c
-    ../../src/share/native/sun/awt/medialib/mlib_c_ImageBlendTable.c
-    ../../src/share/native/sun/awt/medialib/mlib_c_ImageBlendTable.h
-    ../../src/share/native/sun/awt/medialib/mlib_c_ImageConv.h
-    ../../src/share/native/sun/awt/medialib/mlib_c_ImageConv_f.c
-    ../../src/share/native/sun/awt/medialib/mlib_c_ImageConvClearEdge.c
-    ../../src/share/native/sun/awt/medialib/mlib_c_ImageConvCopyEdge.c
-    ../../src/share/native/sun/awt/medialib/mlib_c_ImageConvVersion.c
-    ../../src/share/native/sun/awt/medialib/mlib_c_ImageCopy.c
-    ../../src/share/native/sun/awt/medialib/mlib_c_ImageLookUp.c
-    ../../src/share/native/sun/awt/medialib/mlib_c_ImageLookUp.h
-    ../../src/share/native/sun/awt/medialib/mlib_c_ImageLookUp_f.c
-    ../../src/share/native/sun/awt/medialib/mlib_c_ImageThresh1.h
-    ../../src/share/native/sun/awt/medialib/mlib_c_ImageThresh1_U8.c
-    ../../src/share/native/sun/awt/medialib/mlib_image.h
-    ../../src/share/native/sun/awt/medialib/mlib_image_blend_proto.h
-    ../../src/share/native/sun/awt/medialib/mlib_image_get.h
-    ../../src/share/native/sun/awt/medialib/mlib_image_proto.h
-    ../../src/share/native/sun/awt/medialib/mlib_image_types.h
-    ../../src/share/native/sun/awt/medialib/mlib_ImageAffine.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageAffine.h
-    ../../src/share/native/sun/awt/medialib/mlib_ImageAffine_BC_D64.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageAffine_BC_F32.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageAffine_BC_S32.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageAffine_BL_D64.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageAffine_BL_F32.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageAffine_BL_S32.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageAffine_NN.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageAffine_NN_Bit.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageAffineEdge.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageCheck.h
-    ../../src/share/native/sun/awt/medialib/mlib_ImageClipping.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageClipping.h
-    ../../src/share/native/sun/awt/medialib/mlib_ImageColormap.h
-    ../../src/share/native/sun/awt/medialib/mlib_ImageColorTrue2Index.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageConv.h
-    ../../src/share/native/sun/awt/medialib/mlib_ImageConv2x2_f.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageConv_16ext.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageConv_16nw.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageConv_32nw.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageConv_8ext.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageConv_8nw.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageConv_D64nw.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageConv_F32nw.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageConv_u16ext.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageConv_u16nw.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageConvClearEdge_Bit.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageConvClearEdge_Fp.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageConvCopyEdge_Bit.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageConvEdge.h
-    ../../src/share/native/sun/awt/medialib/mlib_ImageConvKernelConvert.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageConvMxN.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageConvMxN_ext.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageConvMxN_Fp.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageCopy.h
-    ../../src/share/native/sun/awt/medialib/mlib_ImageCopy_Bit.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageCreate.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageCreate.h
-    ../../src/share/native/sun/awt/medialib/mlib_ImageDivTables.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageDivTables.h
-    ../../src/share/native/sun/awt/medialib/mlib_ImageFilters.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageFilters.h
-    ../../src/share/native/sun/awt/medialib/mlib_ImageLookUp.h
-    ../../src/share/native/sun/awt/medialib/mlib_ImageLookUp_64.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageLookUp_Bit.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageRowTable.h
-    ../../src/share/native/sun/awt/medialib/mlib_ImageScanPoly.c
-    ../../src/share/native/sun/awt/medialib/mlib_ImageUtils.c
-    ../../src/share/native/sun/awt/medialib/mlib_status.h
-    ../../src/share/native/sun/awt/medialib/mlib_sys.c
-    ../../src/share/native/sun/awt/medialib/mlib_sys.h
-    ../../src/share/native/sun/awt/medialib/mlib_sys_proto.h
-    ../../src/share/native/sun/awt/medialib/mlib_SysMath.h
-    ../../src/share/native/sun/awt/medialib/mlib_types.h
-    ../../src/share/native/sun/awt/medialib/safe_alloc.h
-    ../../src/share/native/sun/awt/medialib/safe_math.h
-    ../../src/share/native/sun/awt/splashscreen/java_awt_SplashScreen.c
-    ../../src/share/native/sun/awt/splashscreen/splashscreen_gfx.h
-    ../../src/share/native/sun/awt/splashscreen/splashscreen_gfx_impl.c
-    ../../src/share/native/sun/awt/splashscreen/splashscreen_gfx_impl.h
-    ../../src/share/native/sun/awt/splashscreen/splashscreen_gif.c
-    ../../src/share/native/sun/awt/splashscreen/splashscreen_impl.c
-    ../../src/share/native/sun/awt/splashscreen/splashscreen_impl.h
-    ../../src/share/native/sun/awt/splashscreen/splashscreen_jpeg.c
-    ../../src/share/native/sun/awt/splashscreen/splashscreen_png.c
-    ../../src/share/native/sun/awt/utility/rect.c
-    ../../src/share/native/sun/font/harfbuzz/hb-ucdn/ucdn.c
-    ../../src/share/native/sun/font/harfbuzz/hb-ucdn/ucdn.h
-    ../../src/share/native/sun/font/harfbuzz/hb-ucdn/unicodedata_db.h
-    ../../src/share/native/sun/font/harfbuzz/hb-atomic-private.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-blob.cpp
-    ../../src/share/native/sun/font/harfbuzz/hb-blob.h
-    ../../src/share/native/sun/font/harfbuzz/hb-buffer-deserialize-json.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-buffer-deserialize-text.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-buffer-private.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-buffer-serialize.cpp
-    ../../src/share/native/sun/font/harfbuzz/hb-buffer.cpp
-    ../../src/share/native/sun/font/harfbuzz/hb-buffer.h
-    ../../src/share/native/sun/font/harfbuzz/hb-cache-private.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-common.cpp
-    ../../src/share/native/sun/font/harfbuzz/hb-common.h
-    ../../src/share/native/sun/font/harfbuzz/hb-coretext.cpp
-    ../../src/share/native/sun/font/harfbuzz/hb-coretext.h
-    ../../src/share/native/sun/font/harfbuzz/hb-deprecated.h
-    ../../src/share/native/sun/font/harfbuzz/hb-face-private.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-face.cpp
-    ../../src/share/native/sun/font/harfbuzz/hb-face.h
-    ../../src/share/native/sun/font/harfbuzz/hb-fallback-shape.cpp
-    ../../src/share/native/sun/font/harfbuzz/hb-font-private.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-font.cpp
-    ../../src/share/native/sun/font/harfbuzz/hb-font.h
-    ../../src/share/native/sun/font/harfbuzz/hb-ft.cpp
-    ../../src/share/native/sun/font/harfbuzz/hb-ft.h
-    ../../src/share/native/sun/font/harfbuzz/hb-mutex-private.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-object-private.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-open-file-private.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-open-type-private.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-cmap-table.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-font.cpp
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-font.h
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-glyf-table.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-head-table.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-hhea-table.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-hmtx-table.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-layout-common-private.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-layout-gdef-table.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-layout-gpos-table.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-layout-gsub-table.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-layout-gsubgpos-private.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-layout-jstf-table.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-layout-private.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-layout.cpp
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-layout.h
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-map-private.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-map.cpp
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-maxp-table.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-name-table.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-arabic-fallback.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-arabic-private.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-arabic-table.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-arabic-win1256.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-arabic.cpp
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-default.cpp
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-hangul.cpp
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-hebrew.cpp
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-indic-machine.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-indic-private.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-indic-table.cpp
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-indic.cpp
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-myanmar-machine.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-myanmar.cpp
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-private.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-thai.cpp
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-tibetan.cpp
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-use-machine.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-use-private.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-use-table.cpp
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-complex-use.cpp
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-fallback-private.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-fallback.cpp
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-normalize-private.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-normalize.cpp
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape-private.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape.cpp
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-shape.h
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-tag.cpp
-    ../../src/share/native/sun/font/harfbuzz/hb-ot-tag.h
-    ../../src/share/native/sun/font/harfbuzz/hb-ot.h
-    ../../src/share/native/sun/font/harfbuzz/hb-private.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-set-private.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-set.cpp
-    ../../src/share/native/sun/font/harfbuzz/hb-set.h
-    ../../src/share/native/sun/font/harfbuzz/hb-shape-plan-private.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-shape-plan.cpp
-    ../../src/share/native/sun/font/harfbuzz/hb-shape-plan.h
-    ../../src/share/native/sun/font/harfbuzz/hb-shape.cpp
-    ../../src/share/native/sun/font/harfbuzz/hb-shape.h
-    ../../src/share/native/sun/font/harfbuzz/hb-shaper-impl-private.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-shaper-list.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-shaper-private.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-shaper.cpp
-    ../../src/share/native/sun/font/harfbuzz/hb-ucdn.cpp
-    ../../src/share/native/sun/font/harfbuzz/hb-unicode-private.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-unicode.cpp
-    ../../src/share/native/sun/font/harfbuzz/hb-unicode.h
-    ../../src/share/native/sun/font/harfbuzz/hb-utf-private.hh
-    ../../src/share/native/sun/font/harfbuzz/hb-version.h
-    ../../src/share/native/sun/font/harfbuzz/hb-warning.cpp
-    ../../src/share/native/sun/font/harfbuzz/hb.h
-    ../../src/share/native/sun/font/layout/AlternateSubstSubtables.cpp
-    ../../src/share/native/sun/font/layout/AlternateSubstSubtables.h
-    ../../src/share/native/sun/font/layout/AnchorTables.cpp
-    ../../src/share/native/sun/font/layout/AnchorTables.h
-    ../../src/share/native/sun/font/layout/ArabicLayoutEngine.cpp
-    ../../src/share/native/sun/font/layout/ArabicLayoutEngine.h
-    ../../src/share/native/sun/font/layout/ArabicShaping.cpp
-    ../../src/share/native/sun/font/layout/ArabicShaping.h
-    ../../src/share/native/sun/font/layout/AttachmentPosnSubtables.h
-    ../../src/share/native/sun/font/layout/CanonData.cpp
-    ../../src/share/native/sun/font/layout/CanonShaping.cpp
-    ../../src/share/native/sun/font/layout/CanonShaping.h
-    ../../src/share/native/sun/font/layout/CharSubstitutionFilter.h
-    ../../src/share/native/sun/font/layout/ClassDefinitionTables.cpp
-    ../../src/share/native/sun/font/layout/ClassDefinitionTables.h
-    ../../src/share/native/sun/font/layout/ContextualGlyphInsertion.h
-    ../../src/share/native/sun/font/layout/ContextualGlyphInsertionProc2.cpp
-    ../../src/share/native/sun/font/layout/ContextualGlyphInsertionProc2.h
-    ../../src/share/native/sun/font/layout/ContextualGlyphSubstitution.h
-    ../../src/share/native/sun/font/layout/ContextualGlyphSubstProc.cpp
-    ../../src/share/native/sun/font/layout/ContextualGlyphSubstProc.h
-    ../../src/share/native/sun/font/layout/ContextualGlyphSubstProc2.cpp
-    ../../src/share/native/sun/font/layout/ContextualGlyphSubstProc2.h
-    ../../src/share/native/sun/font/layout/ContextualSubstSubtables.cpp
-    ../../src/share/native/sun/font/layout/ContextualSubstSubtables.h
-    ../../src/share/native/sun/font/layout/CoverageTables.cpp
-    ../../src/share/native/sun/font/layout/CoverageTables.h
-    ../../src/share/native/sun/font/layout/CursiveAttachmentSubtables.cpp
-    ../../src/share/native/sun/font/layout/CursiveAttachmentSubtables.h
-    ../../src/share/native/sun/font/layout/DefaultCharMapper.h
-    ../../src/share/native/sun/font/layout/DeviceTables.cpp
-    ../../src/share/native/sun/font/layout/DeviceTables.h
-    ../../src/share/native/sun/font/layout/ExtensionSubtables.cpp
-    ../../src/share/native/sun/font/layout/ExtensionSubtables.h
-    ../../src/share/native/sun/font/layout/Features.cpp
-    ../../src/share/native/sun/font/layout/GDEFMarkFilter.cpp
-    ../../src/share/native/sun/font/layout/GDEFMarkFilter.h
-    ../../src/share/native/sun/font/layout/GlyphDefinitionTables.cpp
-    ../../src/share/native/sun/font/layout/GlyphDefinitionTables.h
-    ../../src/share/native/sun/font/layout/GlyphIterator.cpp
-    ../../src/share/native/sun/font/layout/GlyphIterator.h
-    ../../src/share/native/sun/font/layout/GlyphLookupTables.cpp
-    ../../src/share/native/sun/font/layout/GlyphLookupTables.h
-    ../../src/share/native/sun/font/layout/GlyphPositionAdjustments.cpp
-    ../../src/share/native/sun/font/layout/GlyphPositionAdjustments.h
-    ../../src/share/native/sun/font/layout/GlyphPositioningTables.cpp
-    ../../src/share/native/sun/font/layout/GlyphPositioningTables.h
-    ../../src/share/native/sun/font/layout/GlyphPosnLookupProc.cpp
-    ../../src/share/native/sun/font/layout/GlyphPosnLookupProc.h
-    ../../src/share/native/sun/font/layout/GlyphSubstitutionTables.cpp
-    ../../src/share/native/sun/font/layout/GlyphSubstitutionTables.h
-    ../../src/share/native/sun/font/layout/GlyphSubstLookupProc.cpp
-    ../../src/share/native/sun/font/layout/GlyphSubstLookupProc.h
-    ../../src/share/native/sun/font/layout/GXLayoutEngine.cpp
-    ../../src/share/native/sun/font/layout/GXLayoutEngine.h
-    ../../src/share/native/sun/font/layout/GXLayoutEngine2.cpp
-    ../../src/share/native/sun/font/layout/GXLayoutEngine2.h
-    ../../src/share/native/sun/font/layout/HangulLayoutEngine.cpp
-    ../../src/share/native/sun/font/layout/HangulLayoutEngine.h
-    ../../src/share/native/sun/font/layout/HanLayoutEngine.cpp
-    ../../src/share/native/sun/font/layout/HanLayoutEngine.h
-    ../../src/share/native/sun/font/layout/ICUFeatures.h
-    ../../src/share/native/sun/font/layout/IndicClassTables.cpp
-    ../../src/share/native/sun/font/layout/IndicLayoutEngine.cpp
-    ../../src/share/native/sun/font/layout/IndicLayoutEngine.h
-    ../../src/share/native/sun/font/layout/IndicRearrangement.h
-    ../../src/share/native/sun/font/layout/IndicRearrangementProcessor.cpp
-    ../../src/share/native/sun/font/layout/IndicRearrangementProcessor.h
-    ../../src/share/native/sun/font/layout/IndicRearrangementProcessor2.cpp
-    ../../src/share/native/sun/font/layout/IndicRearrangementProcessor2.h
-    ../../src/share/native/sun/font/layout/IndicReordering.cpp
-    ../../src/share/native/sun/font/layout/IndicReordering.h
-    ../../src/share/native/sun/font/layout/KernTable.cpp
-    ../../src/share/native/sun/font/layout/KernTable.h
-    ../../src/share/native/sun/font/layout/KhmerLayoutEngine.cpp
-    ../../src/share/native/sun/font/layout/KhmerLayoutEngine.h
-    ../../src/share/native/sun/font/layout/KhmerReordering.cpp
-    ../../src/share/native/sun/font/layout/KhmerReordering.h
-    ../../src/share/native/sun/font/layout/LayoutEngine.cpp
-    ../../src/share/native/sun/font/layout/LayoutEngine.h
-    ../../src/share/native/sun/font/layout/LayoutTables.h
-    ../../src/share/native/sun/font/layout/LEFontInstance.cpp
-    ../../src/share/native/sun/font/layout/LEFontInstance.h
-    ../../src/share/native/sun/font/layout/LEGlyphFilter.h
-    ../../src/share/native/sun/font/layout/LEGlyphStorage.cpp
-    ../../src/share/native/sun/font/layout/LEGlyphStorage.h
-    ../../src/share/native/sun/font/layout/LEInsertionList.cpp
-    ../../src/share/native/sun/font/layout/LEInsertionList.h
-    ../../src/share/native/sun/font/layout/LELanguages.h
-    ../../src/share/native/sun/font/layout/LEScripts.h
-    ../../src/share/native/sun/font/layout/LEStandalone.h
-    ../../src/share/native/sun/font/layout/LESwaps.h
-    ../../src/share/native/sun/font/layout/LETableReference.h
-    ../../src/share/native/sun/font/layout/LETypes.h
-    ../../src/share/native/sun/font/layout/LigatureSubstitution.h
-    ../../src/share/native/sun/font/layout/LigatureSubstProc.cpp
-    ../../src/share/native/sun/font/layout/LigatureSubstProc.h
-    ../../src/share/native/sun/font/layout/LigatureSubstProc2.cpp
-    ../../src/share/native/sun/font/layout/LigatureSubstProc2.h
-    ../../src/share/native/sun/font/layout/LigatureSubstSubtables.cpp
-    ../../src/share/native/sun/font/layout/LigatureSubstSubtables.h
-    ../../src/share/native/sun/font/layout/LookupProcessor.cpp
-    ../../src/share/native/sun/font/layout/LookupProcessor.h
-    ../../src/share/native/sun/font/layout/Lookups.cpp
-    ../../src/share/native/sun/font/layout/Lookups.h
-    ../../src/share/native/sun/font/layout/LookupTables.cpp
-    ../../src/share/native/sun/font/layout/LookupTables.h
-    ../../src/share/native/sun/font/layout/MarkArrays.cpp
-    ../../src/share/native/sun/font/layout/MarkArrays.h
-    ../../src/share/native/sun/font/layout/MarkToBasePosnSubtables.cpp
-    ../../src/share/native/sun/font/layout/MarkToBasePosnSubtables.h
-    ../../src/share/native/sun/font/layout/MarkToLigaturePosnSubtables.cpp
-    ../../src/share/native/sun/font/layout/MarkToLigaturePosnSubtables.h
-    ../../src/share/native/sun/font/layout/MarkToMarkPosnSubtables.cpp
-    ../../src/share/native/sun/font/layout/MarkToMarkPosnSubtables.h
-    ../../src/share/native/sun/font/layout/MirroredCharData.cpp
-    ../../src/share/native/sun/font/layout/MorphStateTables.h
-    ../../src/share/native/sun/font/layout/MorphTables.cpp
-    ../../src/share/native/sun/font/layout/MorphTables.h
-    ../../src/share/native/sun/font/layout/MorphTables2.cpp
-    ../../src/share/native/sun/font/layout/MPreFixups.cpp
-    ../../src/share/native/sun/font/layout/MPreFixups.h
-    ../../src/share/native/sun/font/layout/MultipleSubstSubtables.cpp
-    ../../src/share/native/sun/font/layout/MultipleSubstSubtables.h
-    ../../src/share/native/sun/font/layout/NonContextualGlyphSubst.h
-    ../../src/share/native/sun/font/layout/NonContextualGlyphSubstProc.cpp
-    ../../src/share/native/sun/font/layout/NonContextualGlyphSubstProc.h
-    ../../src/share/native/sun/font/layout/NonContextualGlyphSubstProc2.cpp
-    ../../src/share/native/sun/font/layout/NonContextualGlyphSubstProc2.h
-    ../../src/share/native/sun/font/layout/OpenTypeLayoutEngine.cpp
-    ../../src/share/native/sun/font/layout/OpenTypeLayoutEngine.h
-    ../../src/share/native/sun/font/layout/OpenTypeTables.h
-    ../../src/share/native/sun/font/layout/OpenTypeUtilities.cpp
-    ../../src/share/native/sun/font/layout/OpenTypeUtilities.h
-    ../../src/share/native/sun/font/layout/PairPositioningSubtables.cpp
-    ../../src/share/native/sun/font/layout/PairPositioningSubtables.h
-    ../../src/share/native/sun/font/layout/ScriptAndLanguage.cpp
-    ../../src/share/native/sun/font/layout/ScriptAndLanguage.h
-    ../../src/share/native/sun/font/layout/ScriptAndLanguageTags.cpp
-    ../../src/share/native/sun/font/layout/ScriptAndLanguageTags.h
-    ../../src/share/native/sun/font/layout/SegmentArrayProcessor.cpp
-    ../../src/share/native/sun/font/layout/SegmentArrayProcessor.h
-    ../../src/share/native/sun/font/layout/SegmentArrayProcessor2.cpp
-    ../../src/share/native/sun/font/layout/SegmentArrayProcessor2.h
-    ../../src/share/native/sun/font/layout/SegmentSingleProcessor.cpp
-    ../../src/share/native/sun/font/layout/SegmentSingleProcessor.h
-    ../../src/share/native/sun/font/layout/SegmentSingleProcessor2.cpp
-    ../../src/share/native/sun/font/layout/SegmentSingleProcessor2.h
-    ../../src/share/native/sun/font/layout/ShapingTypeData.cpp
-    ../../src/share/native/sun/font/layout/SimpleArrayProcessor.cpp
-    ../../src/share/native/sun/font/layout/SimpleArrayProcessor.h
-    ../../src/share/native/sun/font/layout/SimpleArrayProcessor2.cpp
-    ../../src/share/native/sun/font/layout/SimpleArrayProcessor2.h
-    ../../src/share/native/sun/font/layout/SinglePositioningSubtables.cpp
-    ../../src/share/native/sun/font/layout/SinglePositioningSubtables.h
-    ../../src/share/native/sun/font/layout/SingleSubstitutionSubtables.cpp
-    ../../src/share/native/sun/font/layout/SingleSubstitutionSubtables.h
-    ../../src/share/native/sun/font/layout/SingleTableProcessor.cpp
-    ../../src/share/native/sun/font/layout/SingleTableProcessor.h
-    ../../src/share/native/sun/font/layout/SingleTableProcessor2.cpp
-    ../../src/share/native/sun/font/layout/SingleTableProcessor2.h
-    ../../src/share/native/sun/font/layout/StateTableProcessor.cpp
-    ../../src/share/native/sun/font/layout/StateTableProcessor.h
-    ../../src/share/native/sun/font/layout/StateTableProcessor2.cpp
-    ../../src/share/native/sun/font/layout/StateTableProcessor2.h
-    ../../src/share/native/sun/font/layout/StateTables.h
-    ../../src/share/native/sun/font/layout/SubstitutionLookups.cpp
-    ../../src/share/native/sun/font/layout/SubstitutionLookups.h
-    ../../src/share/native/sun/font/layout/SubtableProcessor.cpp
-    ../../src/share/native/sun/font/layout/SubtableProcessor.h
-    ../../src/share/native/sun/font/layout/SubtableProcessor2.cpp
-    ../../src/share/native/sun/font/layout/SubtableProcessor2.h
-    ../../src/share/native/sun/font/layout/SunLayoutEngine.cpp
-    ../../src/share/native/sun/font/layout/ThaiLayoutEngine.cpp
-    ../../src/share/native/sun/font/layout/ThaiLayoutEngine.h
-    ../../src/share/native/sun/font/layout/ThaiShaping.cpp
-    ../../src/share/native/sun/font/layout/ThaiShaping.h
-    ../../src/share/native/sun/font/layout/ThaiStateTables.cpp
-    ../../src/share/native/sun/font/layout/TibetanLayoutEngine.cpp
-    ../../src/share/native/sun/font/layout/TibetanLayoutEngine.h
-    ../../src/share/native/sun/font/layout/TibetanReordering.cpp
-    ../../src/share/native/sun/font/layout/TibetanReordering.h
-    ../../src/share/native/sun/font/layout/TrimmedArrayProcessor.cpp
-    ../../src/share/native/sun/font/layout/TrimmedArrayProcessor.h
-    ../../src/share/native/sun/font/layout/TrimmedArrayProcessor2.cpp
-    ../../src/share/native/sun/font/layout/TrimmedArrayProcessor2.h
-    ../../src/share/native/sun/font/layout/ValueRecords.cpp
-    ../../src/share/native/sun/font/layout/ValueRecords.h
-    ../../src/share/native/sun/font/AccelGlyphCache.c
-    ../../src/share/native/sun/font/AccelGlyphCache.h
-    ../../src/share/native/sun/font/DrawGlyphList.c
-    ../../src/share/native/sun/font/fontconfig.h
-    ../../src/share/native/sun/font/FontInstanceAdapter.cpp
-    ../../src/share/native/sun/font/FontInstanceAdapter.h
-    ../../src/share/native/sun/font/fontscaler.h
-    ../../src/share/native/sun/font/fontscalerdefs.h
-    ../../src/share/native/sun/font/freetypeScaler.c
-    ../../src/share/native/sun/font/glyphblitting.h
-    ../../src/share/native/sun/font/hb-jdk-font.cpp
-    ../../src/share/native/sun/font/hb-jdk.h
-    ../../src/share/native/sun/font/HBShaper.c
-    ../../src/share/native/sun/font/scriptMapping.c
-    ../../src/share/native/sun/font/scriptMapping.h
-    ../../src/share/native/sun/font/sunFont.c
-    ../../src/share/native/sun/font/sunfontids.h
-    ../../src/share/native/sun/java2d/cmm/lcms/cmscam02.c
-    ../../src/share/native/sun/java2d/cmm/lcms/cmscgats.c
-    ../../src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c
-    ../../src/share/native/sun/java2d/cmm/lcms/cmserr.c
-    ../../src/share/native/sun/java2d/cmm/lcms/cmsgamma.c
-    ../../src/share/native/sun/java2d/cmm/lcms/cmsgmt.c
-    ../../src/share/native/sun/java2d/cmm/lcms/cmshalf.c
-    ../../src/share/native/sun/java2d/cmm/lcms/cmsintrp.c
-    ../../src/share/native/sun/java2d/cmm/lcms/cmsio0.c
-    ../../src/share/native/sun/java2d/cmm/lcms/cmsio1.c
-    ../../src/share/native/sun/java2d/cmm/lcms/cmslut.c
-    ../../src/share/native/sun/java2d/cmm/lcms/cmsmd5.c
-    ../../src/share/native/sun/java2d/cmm/lcms/cmsmtrx.c
-    ../../src/share/native/sun/java2d/cmm/lcms/cmsnamed.c
-    ../../src/share/native/sun/java2d/cmm/lcms/cmsopt.c
-    ../../src/share/native/sun/java2d/cmm/lcms/cmspack.c
-    ../../src/share/native/sun/java2d/cmm/lcms/cmspcs.c
-    ../../src/share/native/sun/java2d/cmm/lcms/cmsplugin.c
-    ../../src/share/native/sun/java2d/cmm/lcms/cmsps2.c
-    ../../src/share/native/sun/java2d/cmm/lcms/cmssamp.c
-    ../../src/share/native/sun/java2d/cmm/lcms/cmssm.c
-    ../../src/share/native/sun/java2d/cmm/lcms/cmstypes.c
-    ../../src/share/native/sun/java2d/cmm/lcms/cmsvirt.c
-    ../../src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c
-    ../../src/share/native/sun/java2d/cmm/lcms/cmsxform.c
-    ../../src/share/native/sun/java2d/cmm/lcms/LCMS.c
-    ../../src/share/native/sun/java2d/cmm/lcms/lcms2.h
-    ../../src/share/native/sun/java2d/cmm/lcms/lcms2_internal.h
-    ../../src/share/native/sun/java2d/cmm/lcms/lcms2_plugin.h
-    ../../src/share/native/sun/java2d/loops/AlphaMacros.c
-    ../../src/share/native/sun/java2d/loops/AlphaMacros.h
-    ../../src/share/native/sun/java2d/loops/AlphaMath.c
-    ../../src/share/native/sun/java2d/loops/AlphaMath.h
-    ../../src/share/native/sun/java2d/loops/Any3Byte.c
-    ../../src/share/native/sun/java2d/loops/Any3Byte.h
-    ../../src/share/native/sun/java2d/loops/Any4Byte.c
-    ../../src/share/native/sun/java2d/loops/Any4Byte.h
-    ../../src/share/native/sun/java2d/loops/AnyByte.c
-    ../../src/share/native/sun/java2d/loops/AnyByte.h
-    ../../src/share/native/sun/java2d/loops/AnyByteBinary.h
-    ../../src/share/native/sun/java2d/loops/AnyInt.c
-    ../../src/share/native/sun/java2d/loops/AnyInt.h
-    ../../src/share/native/sun/java2d/loops/AnyShort.c
-    ../../src/share/native/sun/java2d/loops/AnyShort.h
-    ../../src/share/native/sun/java2d/loops/Blit.c
-    ../../src/share/native/sun/java2d/loops/BlitBg.c
-    ../../src/share/native/sun/java2d/loops/ByteBinary1Bit.c
-    ../../src/share/native/sun/java2d/loops/ByteBinary1Bit.h
-    ../../src/share/native/sun/java2d/loops/ByteBinary2Bit.c
-    ../../src/share/native/sun/java2d/loops/ByteBinary2Bit.h
-    ../../src/share/native/sun/java2d/loops/ByteBinary4Bit.c
-    ../../src/share/native/sun/java2d/loops/ByteBinary4Bit.h
-    ../../src/share/native/sun/java2d/loops/ByteGray.c
-    ../../src/share/native/sun/java2d/loops/ByteGray.h
-    ../../src/share/native/sun/java2d/loops/ByteIndexed.c
-    ../../src/share/native/sun/java2d/loops/ByteIndexed.h
-    ../../src/share/native/sun/java2d/loops/DrawLine.c
-    ../../src/share/native/sun/java2d/loops/DrawParallelogram.c
-    ../../src/share/native/sun/java2d/loops/DrawPath.c
-    ../../src/share/native/sun/java2d/loops/DrawPath.h
-    ../../src/share/native/sun/java2d/loops/DrawPolygons.c
-    ../../src/share/native/sun/java2d/loops/DrawRect.c
-    ../../src/share/native/sun/java2d/loops/FillParallelogram.c
-    ../../src/share/native/sun/java2d/loops/FillPath.c
-    ../../src/share/native/sun/java2d/loops/FillRect.c
-    ../../src/share/native/sun/java2d/loops/FillSpans.c
-    ../../src/share/native/sun/java2d/loops/FourByteAbgr.c
-    ../../src/share/native/sun/java2d/loops/FourByteAbgr.h
-    ../../src/share/native/sun/java2d/loops/FourByteAbgrPre.c
-    ../../src/share/native/sun/java2d/loops/FourByteAbgrPre.h
-    ../../src/share/native/sun/java2d/loops/GlyphImageRef.h
-    ../../src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.c
-    ../../src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.h
-    ../../src/share/native/sun/java2d/loops/ImageData.h
-    ../../src/share/native/sun/java2d/loops/Index12Gray.c
-    ../../src/share/native/sun/java2d/loops/Index12Gray.h
-    ../../src/share/native/sun/java2d/loops/Index8Gray.c
-    ../../src/share/native/sun/java2d/loops/Index8Gray.h
-    ../../src/share/native/sun/java2d/loops/IntArgb.c
-    ../../src/share/native/sun/java2d/loops/IntArgb.h
-    ../../src/share/native/sun/java2d/loops/IntArgbBm.c
-    ../../src/share/native/sun/java2d/loops/IntArgbBm.h
-    ../../src/share/native/sun/java2d/loops/IntArgbPre.c
-    ../../src/share/native/sun/java2d/loops/IntArgbPre.h
-    ../../src/share/native/sun/java2d/loops/IntBgr.c
-    ../../src/share/native/sun/java2d/loops/IntBgr.h
-    ../../src/share/native/sun/java2d/loops/IntDcm.h
-    ../../src/share/native/sun/java2d/loops/IntRgb.c
-    ../../src/share/native/sun/java2d/loops/IntRgb.h
-    ../../src/share/native/sun/java2d/loops/IntRgbx.c
-    ../../src/share/native/sun/java2d/loops/IntRgbx.h
-    ../../src/share/native/sun/java2d/loops/LineUtils.h
-    ../../src/share/native/sun/java2d/loops/LoopMacros.h
-    ../../src/share/native/sun/java2d/loops/MapAccelFunc.c
-    ../../src/share/native/sun/java2d/loops/MaskBlit.c
-    ../../src/share/native/sun/java2d/loops/MaskFill.c
-    ../../src/share/native/sun/java2d/loops/ParallelogramUtils.h
-    ../../src/share/native/sun/java2d/loops/ProcessPath.c
-    ../../src/share/native/sun/java2d/loops/ProcessPath.h
-    ../../src/share/native/sun/java2d/loops/ScaledBlit.c
-    ../../src/share/native/sun/java2d/loops/ThreeByteBgr.c
-    ../../src/share/native/sun/java2d/loops/ThreeByteBgr.h
-    ../../src/share/native/sun/java2d/loops/TransformHelper.c
-    ../../src/share/native/sun/java2d/loops/Ushort4444Argb.c
-    ../../src/share/native/sun/java2d/loops/Ushort4444Argb.h
-    ../../src/share/native/sun/java2d/loops/Ushort555Rgb.c
-    ../../src/share/native/sun/java2d/loops/Ushort555Rgb.h
-    ../../src/share/native/sun/java2d/loops/Ushort555Rgbx.c
-    ../../src/share/native/sun/java2d/loops/Ushort555Rgbx.h
-    ../../src/share/native/sun/java2d/loops/Ushort565Rgb.c
-    ../../src/share/native/sun/java2d/loops/Ushort565Rgb.h
-    ../../src/share/native/sun/java2d/loops/UshortGray.c
-    ../../src/share/native/sun/java2d/loops/UshortGray.h
-    ../../src/share/native/sun/java2d/loops/UshortIndexed.c
-    ../../src/share/native/sun/java2d/loops/UshortIndexed.h
-    ../../src/share/native/sun/java2d/opengl/J2D_GL/gl.h
-    ../../src/share/native/sun/java2d/opengl/J2D_GL/glext.h
-    ../../src/share/native/sun/java2d/opengl/OGLBlitLoops.c
-    ../../src/share/native/sun/java2d/opengl/OGLBlitLoops.h
-    ../../src/share/native/sun/java2d/opengl/OGLBufImgOps.c
-    ../../src/share/native/sun/java2d/opengl/OGLBufImgOps.h
-    ../../src/share/native/sun/java2d/opengl/OGLContext.c
-    ../../src/share/native/sun/java2d/opengl/OGLContext.h
-    ../../src/share/native/sun/java2d/opengl/OGLFuncMacros.h
-    ../../src/share/native/sun/java2d/opengl/OGLFuncs.c
-    ../../src/share/native/sun/java2d/opengl/OGLFuncs.h
-    ../../src/share/native/sun/java2d/opengl/OGLMaskBlit.c
-    ../../src/share/native/sun/java2d/opengl/OGLMaskBlit.h
-    ../../src/share/native/sun/java2d/opengl/OGLMaskFill.c
-    ../../src/share/native/sun/java2d/opengl/OGLMaskFill.h
-    ../../src/share/native/sun/java2d/opengl/OGLPaints.c
-    ../../src/share/native/sun/java2d/opengl/OGLPaints.h
-    ../../src/share/native/sun/java2d/opengl/OGLRenderer.c
-    ../../src/share/native/sun/java2d/opengl/OGLRenderer.h
-    ../../src/share/native/sun/java2d/opengl/OGLRenderQueue.c
-    ../../src/share/native/sun/java2d/opengl/OGLRenderQueue.h
-    ../../src/share/native/sun/java2d/opengl/OGLSurfaceData.c
-    ../../src/share/native/sun/java2d/opengl/OGLSurfaceData.h
-    ../../src/share/native/sun/java2d/opengl/OGLTextRenderer.c
-    ../../src/share/native/sun/java2d/opengl/OGLTextRenderer.h
-    ../../src/share/native/sun/java2d/opengl/OGLVertexCache.c
-    ../../src/share/native/sun/java2d/opengl/OGLVertexCache.h
-    ../../src/share/native/sun/java2d/pipe/BufferedMaskBlit.c
-    ../../src/share/native/sun/java2d/pipe/BufferedRenderPipe.c
-    ../../src/share/native/sun/java2d/pipe/PathConsumer2D.h
-    ../../src/share/native/sun/java2d/pipe/Region.c
-    ../../src/share/native/sun/java2d/pipe/Region.h
-    ../../src/share/native/sun/java2d/pipe/ShapeSpanIterator.c
-    ../../src/share/native/sun/java2d/pipe/SpanClipRenderer.c
-    ../../src/share/native/sun/java2d/pipe/SpanIterator.h
-    ../../src/share/native/sun/java2d/Disposer.c
-    ../../src/share/native/sun/java2d/Disposer.h
-    ../../src/share/native/sun/java2d/ShaderList.c
-    ../../src/share/native/sun/java2d/ShaderList.h
-    ../../src/share/native/sun/java2d/SurfaceData.c
-    ../../src/share/native/sun/java2d/SurfaceData.h
-    ../../src/share/native/sun/java2d/Trace.c
-    ../../src/share/native/sun/java2d/Trace.h
-    ../../src/share/native/sun/management/ClassLoadingImpl.c
-    ../../src/share/native/sun/management/DiagnosticCommandImpl.c
-    ../../src/share/native/sun/management/Flag.c
-    ../../src/share/native/sun/management/GarbageCollectorImpl.c
-    ../../src/share/native/sun/management/GcInfoBuilder.c
-    ../../src/share/native/sun/management/HotSpotDiagnostic.c
-    ../../src/share/native/sun/management/HotspotThread.c
-    ../../src/share/native/sun/management/management.c
-    ../../src/share/native/sun/management/management.h
-    ../../src/share/native/sun/management/MemoryImpl.c
-    ../../src/share/native/sun/management/MemoryManagerImpl.c
-    ../../src/share/native/sun/management/MemoryPoolImpl.c
-    ../../src/share/native/sun/management/ThreadImpl.c
-    ../../src/share/native/sun/management/VMManagementImpl.c
-    ../../src/share/native/sun/misc/GC.c
-    ../../src/share/native/sun/misc/MessageUtils.c
-    ../../src/share/native/sun/misc/NativeSignalHandler.c
-    ../../src/share/native/sun/misc/Signal.c
-    ../../src/share/native/sun/misc/URLClassPath.c
-    ../../src/share/native/sun/misc/Version.c
-    ../../src/share/native/sun/misc/VM.c
-    ../../src/share/native/sun/misc/VMSupport.c
-    ../../src/share/native/sun/nio/ch/nio.h
-    ../../src/share/native/sun/reflect/ConstantPool.c
-    ../../src/share/native/sun/reflect/NativeAccessors.c
-    ../../src/share/native/sun/reflect/Reflection.c
-    ../../src/share/native/sun/security/ec/impl/ec.c
-    ../../src/share/native/sun/security/ec/impl/ec.h
-    ../../src/share/native/sun/security/ec/impl/ec2.h
-    ../../src/share/native/sun/security/ec/impl/ec2_163.c
-    ../../src/share/native/sun/security/ec/impl/ec2_193.c
-    ../../src/share/native/sun/security/ec/impl/ec2_233.c
-    ../../src/share/native/sun/security/ec/impl/ec2_aff.c
-    ../../src/share/native/sun/security/ec/impl/ec2_mont.c
-    ../../src/share/native/sun/security/ec/impl/ec_naf.c
-    ../../src/share/native/sun/security/ec/impl/ecc_impl.h
-    ../../src/share/native/sun/security/ec/impl/ecdecode.c
-    ../../src/share/native/sun/security/ec/impl/ecl-curve.h
-    ../../src/share/native/sun/security/ec/impl/ecl-exp.h
-    ../../src/share/native/sun/security/ec/impl/ecl-priv.h
-    ../../src/share/native/sun/security/ec/impl/ecl.c
-    ../../src/share/native/sun/security/ec/impl/ecl.h
-    ../../src/share/native/sun/security/ec/impl/ecl_curve.c
-    ../../src/share/native/sun/security/ec/impl/ecl_gf.c
-    ../../src/share/native/sun/security/ec/impl/ecl_mult.c
-    ../../src/share/native/sun/security/ec/impl/ecp.h
-    ../../src/share/native/sun/security/ec/impl/ecp_192.c
-    ../../src/share/native/sun/security/ec/impl/ecp_224.c
-    ../../src/share/native/sun/security/ec/impl/ecp_256.c
-    ../../src/share/native/sun/security/ec/impl/ecp_384.c
-    ../../src/share/native/sun/security/ec/impl/ecp_521.c
-    ../../src/share/native/sun/security/ec/impl/ecp_aff.c
-    ../../src/share/native/sun/security/ec/impl/ecp_jac.c
-    ../../src/share/native/sun/security/ec/impl/ecp_jm.c
-    ../../src/share/native/sun/security/ec/impl/ecp_mont.c
-    ../../src/share/native/sun/security/ec/impl/logtab.h
-    ../../src/share/native/sun/security/ec/impl/mp_gf2m-priv.h
-    ../../src/share/native/sun/security/ec/impl/mp_gf2m.c
-    ../../src/share/native/sun/security/ec/impl/mp_gf2m.h
-    ../../src/share/native/sun/security/ec/impl/mpi-config.h
-    ../../src/share/native/sun/security/ec/impl/mpi-priv.h
-    ../../src/share/native/sun/security/ec/impl/mpi.c
-    ../../src/share/native/sun/security/ec/impl/mpi.h
-    ../../src/share/native/sun/security/ec/impl/mplogic.c
-    ../../src/share/native/sun/security/ec/impl/mplogic.h
-    ../../src/share/native/sun/security/ec/impl/mpmontg.c
-    ../../src/share/native/sun/security/ec/impl/mpprime.h
-    ../../src/share/native/sun/security/ec/impl/oid.c
-    ../../src/share/native/sun/security/ec/impl/secitem.c
-    ../../src/share/native/sun/security/ec/impl/secoidt.h
-    ../../src/share/native/sun/security/ec/ECC_JNI.cpp
-    ../../src/share/native/sun/security/jgss/wrapper/gssapi.h
-    ../../src/share/native/sun/security/jgss/wrapper/GSSLibStub.c
-    ../../src/share/native/sun/security/jgss/wrapper/NativeUtil.c
-    ../../src/share/native/sun/security/jgss/wrapper/NativeUtil.h
-    ../../src/share/native/sun/security/krb5/nativeccache.c
-    ../../src/share/native/sun/security/pkcs11/wrapper/p11_convert.c
-    ../../src/share/native/sun/security/pkcs11/wrapper/p11_crypt.c
-    ../../src/share/native/sun/security/pkcs11/wrapper/p11_digest.c
-    ../../src/share/native/sun/security/pkcs11/wrapper/p11_dual.c
-    ../../src/share/native/sun/security/pkcs11/wrapper/p11_general.c
-    ../../src/share/native/sun/security/pkcs11/wrapper/p11_keymgmt.c
-    ../../src/share/native/sun/security/pkcs11/wrapper/p11_mutex.c
-    ../../src/share/native/sun/security/pkcs11/wrapper/p11_objmgmt.c
-    ../../src/share/native/sun/security/pkcs11/wrapper/p11_sessmgmt.c
-    ../../src/share/native/sun/security/pkcs11/wrapper/p11_sign.c
-    ../../src/share/native/sun/security/pkcs11/wrapper/p11_util.c
-    ../../src/share/native/sun/security/pkcs11/wrapper/pkcs-11v2-20a3.h
-    ../../src/share/native/sun/security/pkcs11/wrapper/pkcs11.h
-    ../../src/share/native/sun/security/pkcs11/wrapper/pkcs11f.h
-    ../../src/share/native/sun/security/pkcs11/wrapper/pkcs11t.h
-    ../../src/share/native/sun/security/pkcs11/wrapper/pkcs11wrapper.h
-    ../../src/share/native/sun/security/pkcs11/j2secmod.c
-    ../../src/share/native/sun/security/pkcs11/j2secmod.h
-    ../../src/share/native/sun/security/smartcardio/pcsc.c
-    ../../src/share/native/sun/tracing/dtrace/JVM.c
-    ../../src/share/native/sun/tracing/dtrace/jvm_symbols.h)
-
-if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
-    set(SOURCE_FILES
-            ${SOURCE_FILES}
-            ../../src/solaris/native/sun/xawt/awt_Desktop.c
-            ../../src/solaris/native/sun/xawt/gnome_interface.c
-            ../../src/solaris/native/sun/xawt/gnome_interface.h
-            ../../src/solaris/native/sun/xawt/XlibWrapper.c
-            ../../src/solaris/native/sun/xawt/XToolkit.c
-            ../../src/solaris/native/sun/xawt/XWindow.c)
-endif()
-
-if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
-    set(SOURCE_FILES
-            ${SOURCE_FILES}
-            ../../src/macosx/native/apple/applescript/AppleScriptEngine.m
-            ../../src/macosx/native/apple/applescript/AppleScriptExecutionContext.h
-            ../../src/macosx/native/apple/applescript/AppleScriptExecutionContext.m
-            ../../src/macosx/native/apple/applescript/AS_NS_ConversionUtils.h
-            ../../src/macosx/native/apple/applescript/AS_NS_ConversionUtils.m
-            ../../src/macosx/native/apple/applescript/NS_Java_ConversionUtils.h
-            ../../src/macosx/native/apple/applescript/NS_Java_ConversionUtils.m
-            ../../src/macosx/native/apple/launcher/JavaAppLauncher.m
-            ../../src/macosx/native/apple/security/KeystoreImpl.m
-            ../../src/macosx/native/com/apple/concurrent/Dispatch.m
-            ../../src/macosx/native/com/apple/eio/CFileManager.m
-            ../../src/macosx/native/com/apple/laf/AquaFileView.m
-            ../../src/macosx/native/com/apple/laf/AquaLookAndFeel.m
-            ../../src/macosx/native/com/apple/laf/AquaNativeResources.m
-            ../../src/macosx/native/com/apple/laf/JRSUIConstantSync.h
-            ../../src/macosx/native/com/apple/laf/JRSUIConstantSync.m
-            ../../src/macosx/native/com/apple/laf/JRSUIController.m
-            ../../src/macosx/native/com/apple/laf/JRSUIFocus.m
-            ../../src/macosx/native/com/apple/laf/ScreenMenu.h
-            ../../src/macosx/native/com/apple/laf/ScreenMenu.m
-            ../../src/macosx/native/com/apple/laf/ScreenPopupFactory.m
-            ../../src/macosx/native/com/sun/media/sound/PLATFORM_API_MacOSX_MidiIn.c
-            ../../src/macosx/native/com/sun/media/sound/PLATFORM_API_MacOSX_MidiOut.c
-            ../../src/macosx/native/com/sun/media/sound/PLATFORM_API_MacOSX_MidiUtils.c
-            ../../src/macosx/native/com/sun/media/sound/PLATFORM_API_MacOSX_MidiUtils.h
-            ../../src/macosx/native/com/sun/media/sound/PLATFORM_API_MacOSX_PCM.cpp
-            ../../src/macosx/native/com/sun/media/sound/PLATFORM_API_MacOSX_Ports.cpp
-            ../../src/macosx/native/com/sun/media/sound/PLATFORM_API_MacOSX_Utils.cpp
-            ../../src/macosx/native/com/sun/media/sound/PLATFORM_API_MacOSX_Utils.h
-            ../../src/macosx/native/java/util/MacOSXPreferencesFile.m
-            ../../src/macosx/native/java/util/SCDynamicStoreConfig.m
-            ../../src/macosx/native/jobjc/src/core/native/CIF.m
-            ../../src/macosx/native/jobjc/src/core/native/Coder.m
-            ../../src/macosx/native/jobjc/src/core/native/FFIType.m
-            ../../src/macosx/native/jobjc/src/core/native/Function.m
-            ../../src/macosx/native/jobjc/src/core/native/ID.m
-            ../../src/macosx/native/jobjc/src/core/native/Invoke.m
-            ../../src/macosx/native/jobjc/src/core/native/JObjCRuntime.m
-            ../../src/macosx/native/jobjc/src/core/native/MacOSXFramework.m
-            ../../src/macosx/native/jobjc/src/core/native/NativeBuffer.h
-            ../../src/macosx/native/jobjc/src/core/native/NativeBuffer.m
-            ../../src/macosx/native/jobjc/src/core/native/NativeObjectLifecycleManager.m
-            ../../src/macosx/native/jobjc/src/core/native/NSClass.m
-            ../../src/macosx/native/jobjc/src/core/native/SEL.m
-            ../../src/macosx/native/jobjc/src/core/native/Subclassing.m
-            ../../src/macosx/native/jobjc/src/core/PrimitiveCoder.hs
-            ../../src/macosx/native/jobjc/src/runtime-additions/native/NativeNumber.m
-            ../../src/macosx/native/jobjc/src/runtime-additions/native/NativeString.m
-            ../../src/macosx/native/jobjc/src/runtime-additions/native/NativeThread.m
-            ../../src/macosx/native/jobjc/src/tests/native/FunCallBench.m
-            ../../src/macosx/native/sun/awt/ApplicationDelegate.h
-            ../../src/macosx/native/sun/awt/ApplicationDelegate.m
-            ../../src/macosx/native/sun/awt/awt.m
-            ../../src/macosx/native/sun/awt/awt_DrawingSurface.m
-            ../../src/macosx/native/sun/awt/AWTEvent.h
-            ../../src/macosx/native/sun/awt/AWTEvent.m
-            ../../src/macosx/native/sun/awt/AWTSurfaceLayers.h
-            ../../src/macosx/native/sun/awt/AWTSurfaceLayers.m
-            ../../src/macosx/native/sun/awt/AWTView.h
-            ../../src/macosx/native/sun/awt/AWTView.m
-            ../../src/macosx/native/sun/awt/AWTWindow.h
-            ../../src/macosx/native/sun/awt/AWTWindow.m
-            ../../src/macosx/native/sun/awt/CClipboard.h
-            ../../src/macosx/native/sun/awt/CClipboard.m
-            ../../src/macosx/native/sun/awt/CCursorManager.m
-            ../../src/macosx/native/sun/awt/CDataTransferer.h
-            ../../src/macosx/native/sun/awt/CDataTransferer.m
-            ../../src/macosx/native/sun/awt/CDesktopPeer.m
-            ../../src/macosx/native/sun/awt/CDragSource.h
-            ../../src/macosx/native/sun/awt/CDragSource.m
-            ../../src/macosx/native/sun/awt/CDragSourceContextPeer.m
-            ../../src/macosx/native/sun/awt/CDropTarget.h
-            ../../src/macosx/native/sun/awt/CDropTarget.m
-            ../../src/macosx/native/sun/awt/CDropTargetContextPeer.m
-            ../../src/macosx/native/sun/awt/CFileDialog.h
-            ../../src/macosx/native/sun/awt/CFileDialog.m
-            ../../src/macosx/native/sun/awt/CFRetainedResource.m
-            ../../src/macosx/native/sun/awt/CGraphicsConfig.m
-            ../../src/macosx/native/sun/awt/CGraphicsDevice.m
-            ../../src/macosx/native/sun/awt/CGraphicsEnv.m
-            ../../src/macosx/native/sun/awt/CImage.m
-            ../../src/macosx/native/sun/awt/CInputMethod.m
-            ../../src/macosx/native/sun/awt/CMenu.h
-            ../../src/macosx/native/sun/awt/CMenu.m
-            ../../src/macosx/native/sun/awt/CMenuBar.h
-            ../../src/macosx/native/sun/awt/CMenuBar.m
-            ../../src/macosx/native/sun/awt/CMenuComponent.h
-            ../../src/macosx/native/sun/awt/CMenuComponent.m
-            ../../src/macosx/native/sun/awt/CMenuItem.h
-            ../../src/macosx/native/sun/awt/CMenuItem.m
-            ../../src/macosx/native/sun/awt/CPopupMenu.h
-            ../../src/macosx/native/sun/awt/CPopupMenu.m
-            ../../src/macosx/native/sun/awt/CPrinterJob.m
-            ../../src/macosx/native/sun/awt/CRobot.m
-            ../../src/macosx/native/sun/awt/CSystemColors.h
-            ../../src/macosx/native/sun/awt/CSystemColors.m
-            ../../src/macosx/native/sun/awt/CTextPipe.m
-            ../../src/macosx/native/sun/awt/CTrayIcon.h
-            ../../src/macosx/native/sun/awt/CTrayIcon.m
-            ../../src/macosx/native/sun/awt/CWrapper.m
-            ../../src/macosx/native/sun/awt/DnDUtilities.h
-            ../../src/macosx/native/sun/awt/DnDUtilities.m
-            ../../src/macosx/native/sun/awt/GeomUtilities.h
-            ../../src/macosx/native/sun/awt/GeomUtilities.m
-            ../../src/macosx/native/sun/awt/ImageSurfaceData.h
-            ../../src/macosx/native/sun/awt/ImageSurfaceData.m
-            ../../src/macosx/native/sun/awt/InitIDs.h
-            ../../src/macosx/native/sun/awt/InitIDs.m
-            ../../src/macosx/native/sun/awt/JavaAccessibilityAction.h
-            ../../src/macosx/native/sun/awt/JavaAccessibilityAction.m
-            ../../src/macosx/native/sun/awt/JavaAccessibilityUtilities.h
-            ../../src/macosx/native/sun/awt/JavaAccessibilityUtilities.m
-            ../../src/macosx/native/sun/awt/JavaComponentAccessibility.h
-            ../../src/macosx/native/sun/awt/JavaComponentAccessibility.m
-            ../../src/macosx/native/sun/awt/JavaTextAccessibility.h
-            ../../src/macosx/native/sun/awt/JavaTextAccessibility.m
-            ../../src/macosx/native/sun/awt/jawt.m
-            ../../src/macosx/native/sun/awt/LWCToolkit.h
-            ../../src/macosx/native/sun/awt/LWCToolkit.m
-            ../../src/macosx/native/sun/awt/OSVersion.h
-            ../../src/macosx/native/sun/awt/OSVersion.m
-            ../../src/macosx/native/sun/awt/PrinterSurfaceData.h
-            ../../src/macosx/native/sun/awt/PrinterSurfaceData.m
-            ../../src/macosx/native/sun/awt/PrinterView.h
-            ../../src/macosx/native/sun/awt/PrinterView.m
-            ../../src/macosx/native/sun/awt/PrintModel.h
-            ../../src/macosx/native/sun/awt/PrintModel.m
-            ../../src/macosx/native/sun/awt/QuartzRenderer.m
-            ../../src/macosx/native/sun/awt/QuartzSurfaceData.h
-            ../../src/macosx/native/sun/awt/QuartzSurfaceData.m
-            ../../src/macosx/native/sun/awt/splashscreen/splashscreen_config.h
-            ../../src/macosx/native/sun/awt/splashscreen/splashscreen_sys.m
-            ../../src/macosx/native/sun/font/AWTFont.h
-            ../../src/macosx/native/sun/font/AWTFont.m
-            ../../src/macosx/native/sun/font/AWTStrike.h
-            ../../src/macosx/native/sun/font/AWTStrike.m
-            ../../src/macosx/native/sun/font/CCharToGlyphMapper.m
-            ../../src/macosx/native/sun/font/CGGlyphImages.h
-            ../../src/macosx/native/sun/font/CGGlyphImages.m
-            ../../src/macosx/native/sun/font/CGGlyphOutlines.h
-            ../../src/macosx/native/sun/font/CGGlyphOutlines.m
-            ../../src/macosx/native/sun/font/CoreTextSupport.h
-            ../../src/macosx/native/sun/font/CoreTextSupport.m
-            ../../src/macosx/native/sun/java2d/opengl/CGLGraphicsConfig.h
-            ../../src/macosx/native/sun/java2d/opengl/CGLGraphicsConfig.m
-            ../../src/macosx/native/sun/java2d/opengl/CGLLayer.h
-            ../../src/macosx/native/sun/java2d/opengl/CGLLayer.m
-            ../../src/macosx/native/sun/java2d/opengl/CGLSurfaceData.h
-            ../../src/macosx/native/sun/java2d/opengl/CGLSurfaceData.m
-            ../../src/macosx/native/sun/java2d/opengl/J2D_GL/cglext.h
-            ../../src/macosx/native/sun/java2d/opengl/OGLFuncs_md.h
-            ../../src/macosx/native/sun/nio/ch/KQueueArrayWrapper.c
-            ../../src/macosx/native/sun/osxapp/AWT_debug.h
-            ../../src/macosx/native/sun/osxapp/NSApplicationAWT.h
-            ../../src/macosx/native/sun/osxapp/NSApplicationAWT.m
-            ../../src/macosx/native/sun/osxapp/PropertiesUtilities.h
-            ../../src/macosx/native/sun/osxapp/PropertiesUtilities.m
-            ../../src/macosx/native/sun/osxapp/QueuingApplicationDelegate.h
-            ../../src/macosx/native/sun/osxapp/QueuingApplicationDelegate.m
-            ../../src/macosx/native/sun/osxapp/ThreadUtilities.h
-            ../../src/macosx/native/sun/osxapp/ThreadUtilities.m
-            ../../src/macosx/native/sun/util/locale/provider/HostLocaleProviderAdapter_md.c)
-endif()
-
-if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin" OR ${CMAKE_SYSTEM_NAME} MATCHES "Linux")
-    set(SOURCE_FILES
-            ${SOURCE_FILES}
-            ../../src/solaris/javavm/export/jawt_md.h
-            ../../src/solaris/javavm/export/jni_md.h
-            ../../src/solaris/javavm/export/jvm_md.h
-            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_BsdOS_ALSA_CommonUtils.c
-            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_BsdOS_ALSA_CommonUtils.h
-            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_BsdOS_ALSA_MidiIn.c
-            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_BsdOS_ALSA_MidiOut.c
-            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_BsdOS_ALSA_MidiUtils.c
-            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_BsdOS_ALSA_MidiUtils.h
-            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_BsdOS_ALSA_PCM.c
-            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_BsdOS_ALSA_PCMUtils.c
-            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_BsdOS_ALSA_PCMUtils.h
-            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_BsdOS_ALSA_Ports.c
-            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_CommonUtils.c
-            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_CommonUtils.h
-            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_MidiIn.c
-            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_MidiOut.c
-            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_MidiUtils.c
-            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_MidiUtils.h
-            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_PCM.c
-            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_PCMUtils.c
-            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_PCMUtils.h
-            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_Ports.c
-            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_SolarisOS_PCM.c
-            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_SolarisOS_Ports.c
-            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_SolarisOS_Utils.c
-            ../../src/solaris/native/com/sun/media/sound/PLATFORM_API_SolarisOS_Utils.h
-            ../../src/solaris/native/com/sun/security/auth/module/Solaris.c
-            ../../src/solaris/native/com/sun/security/auth/module/Unix.c
-            ../../src/solaris/native/common/gdefs_md.h
-            ../../src/solaris/native/common/jdk_util_md.c
-            ../../src/solaris/native/common/jdk_util_md.h
-            ../../src/solaris/native/common/jlong_md.h
-            ../../src/solaris/native/common/jni_util_md.c
-            ../../src/solaris/native/java/io/canonicalize_md.c
-            ../../src/solaris/native/java/io/Console_md.c
-            ../../src/solaris/native/java/io/FileDescriptor_md.c
-            ../../src/solaris/native/java/io/FileInputStream_md.c
-            ../../src/solaris/native/java/io/FileOutputStream_md.c
-            ../../src/solaris/native/java/io/io_util_md.c
-            ../../src/solaris/native/java/io/io_util_md.h
-            ../../src/solaris/native/java/io/RandomAccessFile_md.c
-            ../../src/solaris/native/java/io/UnixFileSystem_md.c
-            ../../src/solaris/native/java/lang/childproc.c
-            ../../src/solaris/native/java/lang/childproc.h
-            ../../src/solaris/native/java/lang/java_props_macosx.c
-            ../../src/solaris/native/java/lang/java_props_macosx.h
-            ../../src/solaris/native/java/lang/java_props_md.c
-            ../../src/solaris/native/java/lang/jspawnhelper.c
-            ../../src/solaris/native/java/lang/locale_str.h
-            ../../src/solaris/native/java/lang/ProcessEnvironment_md.c
-            ../../src/solaris/native/java/lang/UNIXProcess_md.c
-            ../../src/solaris/native/java/net/bsd_close.c
-            ../../src/solaris/native/java/net/ExtendedOptionsImpl.c
-            ../../src/solaris/native/java/net/Inet4AddressImpl.c
-            ../../src/solaris/native/java/net/Inet6AddressImpl.c
-            ../../src/solaris/native/java/net/InetAddressImplFactory.c
-            ../../src/solaris/native/java/net/linux_close.c
-            ../../src/solaris/native/java/net/net_util_md.c
-            ../../src/solaris/native/java/net/net_util_md.h
-            ../../src/solaris/native/java/net/NetworkInterface.c
-            ../../src/solaris/native/java/net/PlainDatagramSocketImpl.c
-            ../../src/solaris/native/java/net/PlainSocketImpl.c
-            ../../src/solaris/native/java/net/SocketInputStream.c
-            ../../src/solaris/native/java/net/SocketOutputStream.c
-            ../../src/solaris/native/java/nio/MappedByteBuffer.c
-            ../../src/solaris/native/java/util/FileSystemPreferences.c
-            ../../src/solaris/native/java/util/logging.c
-            ../../src/solaris/native/java/util/TimeZone_md.c
-            ../../src/solaris/native/java/util/TimeZone_md.h
-            ../../src/solaris/native/sun/awt/medialib/mlib_ImageConvCopyEdge_Fp.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageAffine_BC.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageAffine_BC_S16.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageAffine_BC_U16.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageAffine_BL.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageAffine_BL_S16.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageAffine_BL_S16.h
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageAffine_BL_U16.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageAffine_NN.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageAffineIndex_BC.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageChannelExtract.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageChannelExtract.h
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageChannelExtract_1.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageChannelExtract_43.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageChannelExtract_f.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageChannelInsert.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageChannelInsert.h
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageChannelInsert_1.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageChannelInsert_34.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageConv.h
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageConv_8nw.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageConvClearEdge.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageConvCopyEdge.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageConvIndex3_8_16nw.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageConvIndex3_8_8nw.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageConvMxN_8.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageConvMxN_8ext.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageConvVersion.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageCopy.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageCopy_f.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageCopy_f.h
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageFilters.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageFilters.h
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUp.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpFunc.h
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpS16S16Func.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpS16S32Func.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpS16U16Func.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpS16U8Func.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpS32S16Func.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpS32S32Func.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpS32U16Func.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpS32U8Func.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpSIS16S16Func.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpSIS16S32Func.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpSIS16U16Func.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpSIS16U8Func.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpSIS32S16Func.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpSIS32S32Func.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpSIS32U16Func.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpSIS32U8Func.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpSIU16S16Func.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpSIU16S32Func.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpSIU16U16Func.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpSIU16U8Func.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpSIU8S16Func.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpSIU8S32Func.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpSIU8U16Func.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpSIU8U8Func.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpU16S16Func.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpU16S32Func.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpU16U16Func.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpU16U8Func.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpU8S16Func.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpU8S32Func.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpU8U16Func.c
-            ../../src/solaris/native/sun/awt/medialib/mlib_v_ImageLookUpU8U8Func.c
-            ../../src/solaris/native/sun/awt/medialib/vis_asi.h
-            ../../src/solaris/native/sun/awt/medialib/vis_proto.h
-            ../../src/solaris/native/sun/awt/splashscreen/splashscreen_config.h
-            ../../src/solaris/native/sun/awt/splashscreen/splashscreen_sys.c
-            ../../src/solaris/native/sun/awt/utility/rect.h
-            ../../src/solaris/native/sun/awt/awt.h
-            ../../src/solaris/native/sun/awt/awt_AWTEvent.c
-            ../../src/solaris/native/sun/awt/awt_AWTEvent.h
-            ../../src/solaris/native/sun/awt/awt_Component.h
-            ../../src/solaris/native/sun/awt/awt_DrawingSurface.c
-            ../../src/solaris/native/sun/awt/awt_DrawingSurface.h
-            ../../src/solaris/native/sun/awt/awt_Event.c
-            ../../src/solaris/native/sun/awt/awt_Event.h
-            ../../src/solaris/native/sun/awt/awt_Font.c
-            ../../src/solaris/native/sun/awt/awt_Font.h
-            ../../src/solaris/native/sun/awt/awt_GraphicsEnv.c
-            ../../src/solaris/native/sun/awt/awt_GraphicsEnv.h
-            ../../src/solaris/native/sun/awt/awt_InputMethod.c
-            ../../src/solaris/native/sun/awt/awt_Insets.c
-            ../../src/solaris/native/sun/awt/awt_Insets.h
-            ../../src/solaris/native/sun/awt/awt_LoadLibrary.c
-            ../../src/solaris/native/sun/awt/awt_MenuComponent.h
-            ../../src/solaris/native/sun/awt/awt_Mlib.c
-            ../../src/solaris/native/sun/awt/awt_Mlib.h
-            ../../src/solaris/native/sun/awt/awt_p.h
-            ../../src/solaris/native/sun/awt/awt_Robot.c
-            ../../src/solaris/native/sun/awt/awt_UNIXToolkit.c
-            ../../src/solaris/native/sun/awt/awt_util.c
-            ../../src/solaris/native/sun/awt/awt_util.h
-            ../../src/solaris/native/sun/awt/canvas.h
-            ../../src/solaris/native/sun/awt/color.h
-            ../../src/solaris/native/sun/awt/colordata.h
-            ../../src/solaris/native/sun/awt/CUPSfuncs.c
-            ../../src/solaris/native/sun/awt/extutil.h
-            ../../src/solaris/native/sun/awt/fontconfig.h
-            ../../src/solaris/native/sun/awt/fontpath.c
-            ../../src/solaris/native/sun/awt/gtk2_interface.c
-            ../../src/solaris/native/sun/awt/gtk2_interface.h
-            ../../src/solaris/native/sun/awt/HeadlessToolkit.c
-            ../../src/solaris/native/sun/awt/HPkeysym.h
-            ../../src/solaris/native/sun/awt/img_util_md.h
-            ../../src/solaris/native/sun/awt/initIDs.c
-            ../../src/solaris/native/sun/awt/jawt.c
-            ../../src/solaris/native/sun/awt/list.c
-            ../../src/solaris/native/sun/awt/list.h
-            ../../src/solaris/native/sun/awt/multi_font.c
-            ../../src/solaris/native/sun/awt/multi_font.h
-            ../../src/solaris/native/sun/awt/multiVis.c
-            ../../src/solaris/native/sun/awt/multiVis.h
-            ../../src/solaris/native/sun/awt/randr.h
-            ../../src/solaris/native/sun/awt/robot_common.c
-            ../../src/solaris/native/sun/awt/robot_common.h
-            ../../src/solaris/native/sun/awt/sun_awt_X11_GtkFileDialogPeer.c
-            ../../src/solaris/native/sun/awt/swing_GTKEngine.c
-            ../../src/solaris/native/sun/awt/swing_GTKStyle.c
-            ../../src/solaris/native/sun/awt/VDrawingArea.c
-            ../../src/solaris/native/sun/awt/VDrawingArea.h
-            ../../src/solaris/native/sun/awt/VDrawingAreaP.h
-            ../../src/solaris/native/sun/awt/wsutils.h
-            ../../src/solaris/native/sun/awt/X11Color.c
-            ../../src/solaris/native/sun/awt/Xrandr.h
-            ../../src/solaris/native/sun/font/X11FontScaler.c
-            ../../src/solaris/native/sun/font/X11FontScaler.h
-            ../../src/solaris/native/sun/font/X11TextRenderer.c
-            ../../src/solaris/native/sun/java2d/loops/java2d_Mlib.c
-            ../../src/solaris/native/sun/java2d/loops/java2d_Mlib.h
-            ../../src/solaris/native/sun/java2d/loops/mlib_ImageCopy.h
-            ../../src/solaris/native/sun/java2d/loops/mlib_ImageLogic_proto.h
-            ../../src/solaris/native/sun/java2d/loops/mlib_ImageZoom.h
-            ../../src/solaris/native/sun/java2d/loops/mlib_ImageZoom_NN.c
-            ../../src/solaris/native/sun/java2d/loops/mlib_v_ImageClear.c
-            ../../src/solaris/native/sun/java2d/loops/mlib_v_ImageClear_f.c
-            ../../src/solaris/native/sun/java2d/loops/mlib_v_ImageClear_f.h
-            ../../src/solaris/native/sun/java2d/loops/mlib_v_ImageConstLogic.h
-            ../../src/solaris/native/sun/java2d/loops/mlib_v_ImageConstXor.c
-            ../../src/solaris/native/sun/java2d/loops/mlib_v_ImageLogic.h
-            ../../src/solaris/native/sun/java2d/loops/mlib_v_ImageLogic_proto.h
-            ../../src/solaris/native/sun/java2d/loops/mlib_v_ImageXor.c
-            ../../src/solaris/native/sun/java2d/loops/mlib_v_ImageZoom_NN_f.c
-            ../../src/solaris/native/sun/java2d/loops/vis_AlphaMacros.c
-            ../../src/solaris/native/sun/java2d/loops/vis_AlphaMacros.h
-            ../../src/solaris/native/sun/java2d/loops/vis_AlphaMaskBlit.c
-            ../../src/solaris/native/sun/java2d/loops/vis_AlphaMaskFill.c
-            ../../src/solaris/native/sun/java2d/loops/vis_ByteGray.c
-            ../../src/solaris/native/sun/java2d/loops/vis_ByteGray_FromRgb.c
-            ../../src/solaris/native/sun/java2d/loops/vis_ByteGray_Mask.c
-            ../../src/solaris/native/sun/java2d/loops/vis_ByteIndexed.c
-            ../../src/solaris/native/sun/java2d/loops/vis_DrawLine.c
-            ../../src/solaris/native/sun/java2d/loops/vis_FourByteAbgr.c
-            ../../src/solaris/native/sun/java2d/loops/vis_FourByteAbgrPre.c
-            ../../src/solaris/native/sun/java2d/loops/vis_FuncArray.c
-            ../../src/solaris/native/sun/java2d/loops/vis_GlyphList.c
-            ../../src/solaris/native/sun/java2d/loops/vis_GlyphListXor.c
-            ../../src/solaris/native/sun/java2d/loops/vis_IntArgb.c
-            ../../src/solaris/native/sun/java2d/loops/vis_IntArgbBm.c
-            ../../src/solaris/native/sun/java2d/loops/vis_IntArgbPre.c
-            ../../src/solaris/native/sun/java2d/loops/vis_IntArgbPre_Mask.c
-            ../../src/solaris/native/sun/java2d/loops/vis_IntBgr.c
-            ../../src/solaris/native/sun/java2d/loops/vis_Interp.c
-            ../../src/solaris/native/sun/java2d/loops/vis_IntRgb.c
-            ../../src/solaris/native/sun/java2d/loops/vis_IntRgbx.c
-            ../../src/solaris/native/sun/java2d/loops/vis_SrcMaskFill.c
-            ../../src/solaris/native/sun/java2d/loops/vis_SrcOverMaskBlit.c
-            ../../src/solaris/native/sun/java2d/loops/vis_SrcOverMaskFill.c
-            ../../src/solaris/native/sun/java2d/loops/vis_ThreeByteBgr.c
-            ../../src/solaris/native/sun/java2d/loops/vis_UshortGray.c
-            ../../src/solaris/native/sun/java2d/loops/vis_UshortGray_FromRgb.c
-            ../../src/solaris/native/sun/java2d/loops/vis_XorBlit.c
-            ../../src/solaris/native/sun/java2d/opengl/J2D_GL/glx.h
-            ../../src/solaris/native/sun/java2d/opengl/J2D_GL/glxext.h
-            ../../src/solaris/native/sun/java2d/opengl/GLXGraphicsConfig.c
-            ../../src/solaris/native/sun/java2d/opengl/GLXGraphicsConfig.h
-            ../../src/solaris/native/sun/java2d/opengl/GLXSurfaceData.c
-            ../../src/solaris/native/sun/java2d/opengl/GLXSurfaceData.h
-            ../../src/solaris/native/sun/java2d/opengl/OGLFuncs_md.h
-            ../../src/solaris/native/sun/java2d/x11/X11FontScaler_md.c
-            ../../src/solaris/native/sun/java2d/x11/X11PMBlitLoops.c
-            ../../src/solaris/native/sun/java2d/x11/X11Renderer.c
-            ../../src/solaris/native/sun/java2d/x11/X11SurfaceData.c
-            ../../src/solaris/native/sun/java2d/x11/X11SurfaceData.h
-            ../../src/solaris/native/sun/java2d/x11/X11TextRenderer_md.c
-            ../../src/solaris/native/sun/java2d/x11/XRBackendNative.c
-            ../../src/solaris/native/sun/java2d/x11/XRSurfaceData.c
-            ../../src/solaris/native/sun/java2d/j2d_md.h
-            ../../src/solaris/native/sun/jdga/dgalock.c
-            ../../src/solaris/native/sun/jdga/jdga.h
-            ../../src/solaris/native/sun/jdga/jdgadevice.h
-            ../../src/solaris/native/sun/management/FileSystemImpl.c
-            ../../src/solaris/native/sun/management/LinuxOperatingSystem.c
-            ../../src/solaris/native/sun/management/MacosxOperatingSystem.c
-            ../../src/solaris/native/sun/management/OperatingSystemImpl.c
-            ../../src/solaris/native/sun/management/SolarisOperatingSystem.c
-            ../../src/solaris/native/sun/net/dns/ResolverConfigurationImpl.c
-            ../../src/solaris/native/sun/net/sdp/SdpSupport.c
-            ../../src/solaris/native/sun/net/spi/DefaultProxySelector.c
-            ../../src/solaris/native/sun/net/portconfig.c
-            ../../src/solaris/native/sun/nio/ch/sctp/Sctp.h
-            ../../src/solaris/native/sun/nio/ch/sctp/SctpChannelImpl.c
-            ../../src/solaris/native/sun/nio/ch/sctp/SctpNet.c
-            ../../src/solaris/native/sun/nio/ch/sctp/SctpServerChannelImpl.c
-            ../../src/solaris/native/sun/nio/ch/DatagramChannelImpl.c
-            ../../src/solaris/native/sun/nio/ch/DatagramDispatcher.c
-            ../../src/solaris/native/sun/nio/ch/DevPollArrayWrapper.c
-            ../../src/solaris/native/sun/nio/ch/EPoll.c
-            ../../src/solaris/native/sun/nio/ch/EPollArrayWrapper.c
-            ../../src/solaris/native/sun/nio/ch/EPollPort.c
-            ../../src/solaris/native/sun/nio/ch/FileChannelImpl.c
-            ../../src/solaris/native/sun/nio/ch/FileDispatcherImpl.c
-            ../../src/solaris/native/sun/nio/ch/FileKey.c
-            ../../src/solaris/native/sun/nio/ch/InheritedChannel.c
-            ../../src/solaris/native/sun/nio/ch/IOUtil.c
-            ../../src/solaris/native/sun/nio/ch/KQueue.c
-            ../../src/solaris/native/sun/nio/ch/KQueuePort.c
-            ../../src/solaris/native/sun/nio/ch/NativeThread.c
-            ../../src/solaris/native/sun/nio/ch/Net.c
-            ../../src/solaris/native/sun/nio/ch/nio_util.h
-            ../../src/solaris/native/sun/nio/ch/PollArrayWrapper.c
-            ../../src/solaris/native/sun/nio/ch/ServerSocketChannelImpl.c
-            ../../src/solaris/native/sun/nio/ch/SocketChannelImpl.c
-            ../../src/solaris/native/sun/nio/ch/SocketDispatcher.c
-            ../../src/solaris/native/sun/nio/ch/SolarisEventPort.c
-            ../../src/solaris/native/sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.c
-            ../../src/solaris/native/sun/nio/ch/UnixAsynchronousSocketChannelImpl.c
-            ../../src/solaris/native/sun/nio/fs/BsdNativeDispatcher.c
-            ../../src/solaris/native/sun/nio/fs/GnomeFileTypeDetector.c
-            ../../src/solaris/native/sun/nio/fs/LinuxNativeDispatcher.c
-            ../../src/solaris/native/sun/nio/fs/LinuxWatchService.c
-            ../../src/solaris/native/sun/nio/fs/MacOSXNativeDispatcher.c
-            ../../src/solaris/native/sun/nio/fs/MagicFileTypeDetector.c
-            ../../src/solaris/native/sun/nio/fs/SolarisNativeDispatcher.c
-            ../../src/solaris/native/sun/nio/fs/SolarisWatchService.c
-            ../../src/solaris/native/sun/nio/fs/UnixCopyFile.c
-            ../../src/solaris/native/sun/nio/fs/UnixNativeDispatcher.c
-            ../../src/solaris/native/sun/security/jgss/wrapper/NativeFunc.c
-            ../../src/solaris/native/sun/security/jgss/wrapper/NativeFunc.h
-            ../../src/solaris/native/sun/security/pkcs11/wrapper/p11_md.c
-            ../../src/solaris/native/sun/security/pkcs11/wrapper/p11_md.h
-            ../../src/solaris/native/sun/security/pkcs11/j2secmod_md.c
-            ../../src/solaris/native/sun/security/pkcs11/j2secmod_md.h
-            ../../src/solaris/native/sun/security/smartcardio/MUSCLE/pcsclite.h
-            ../../src/solaris/native/sun/security/smartcardio/MUSCLE/winscard.h
-            ../../src/solaris/native/sun/security/smartcardio/pcsc_md.c
-            ../../src/solaris/native/sun/security/smartcardio/pcsc_md.h
-            ../../src/solaris/native/sun/tools/attach/BsdVirtualMachine.c
-            ../../src/solaris/native/sun/tools/attach/LinuxVirtualMachine.c
-            ../../src/solaris/native/sun/tools/attach/SolarisVirtualMachine.c
-            ../../src/solaris/native/sun/tracing/dtrace/jvm_symbols_md.c)
-
-elseif(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
-    set(SOURCE_FILES
-            ${SOURCE_FILES}
-            ../../src/windows/native/com/sun/media/sound/PLATFORM_API_WinOS_DirectSound.cpp
-            ../../src/windows/native/com/sun/media/sound/PLATFORM_API_WinOS_MidiIn.cpp
-            ../../src/windows/native/com/sun/media/sound/PLATFORM_API_WinOS_MidiOut.c
-            ../../src/windows/native/com/sun/media/sound/PLATFORM_API_WinOS_Ports.c
-            ../../src/windows/native/com/sun/media/sound/PLATFORM_API_WinOS_Util.c
-            ../../src/windows/native/com/sun/media/sound/PLATFORM_API_WinOS_Util.h
-            ../../src/windows/native/com/sun/security/auth/module/nt.c
-            ../../src/windows/native/common/gdefs_md.h
-            ../../src/windows/native/common/java_main_md.h
-            ../../src/windows/native/common/jdk_util_md.c
-            ../../src/windows/native/common/jdk_util_md.h
-            ../../src/windows/native/common/jlong_md.h
-            ../../src/windows/native/common/jni_util_md.c
-            ../../src/windows/native/common/locale_str.h
-            ../../src/windows/native/java/io/canonicalize_md.c
-            ../../src/windows/native/java/io/Console_md.c
-            ../../src/windows/native/java/io/dirent_md.c
-            ../../src/windows/native/java/io/dirent_md.h
-            ../../src/windows/native/java/io/FileDescriptor_md.c
-            ../../src/windows/native/java/io/FileInputStream_md.c
-            ../../src/windows/native/java/io/FileOutputStream_md.c
-            ../../src/windows/native/java/io/io_util_md.c
-            ../../src/windows/native/java/io/io_util_md.h
-            ../../src/windows/native/java/io/RandomAccessFile_md.c
-            ../../src/windows/native/java/io/WinNTFileSystem_md.c
-            ../../src/windows/native/java/lang/java_props_md.c
-            ../../src/windows/native/java/lang/ProcessEnvironment_md.c
-            ../../src/windows/native/java/lang/ProcessImpl_md.c
-            ../../src/windows/native/java/net/DualStackPlainDatagramSocketImpl.c
-            ../../src/windows/native/java/net/DualStackPlainSocketImpl.c
-            ../../src/windows/native/java/net/ExtendedOptionsImpl.c
-            ../../src/windows/native/java/net/icmp.h
-            ../../src/windows/native/java/net/Inet4AddressImpl.c
-            ../../src/windows/native/java/net/Inet6AddressImpl.c
-            ../../src/windows/native/java/net/InetAddressImplFactory.c
-            ../../src/windows/native/java/net/NetworkInterface.c
-            ../../src/windows/native/java/net/NetworkInterface.h
-            ../../src/windows/native/java/net/NetworkInterface_winXP.c
-            ../../src/windows/native/java/net/net_util_md.c
-            ../../src/windows/native/java/net/net_util_md.h
-            ../../src/windows/native/java/net/SocketInputStream.c
-            ../../src/windows/native/java/net/SocketOutputStream.c
-            ../../src/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c
-            ../../src/windows/native/java/net/TwoStacksPlainSocketImpl.c
-            ../../src/windows/native/java/nio/MappedByteBuffer.c
-            ../../src/windows/native/java/util/logging.c
-            ../../src/windows/native/java/util/TimeZone_md.c
-            ../../src/windows/native/java/util/TimeZone_md.h
-            ../../src/windows/native/java/util/WindowsPreferences.c
-            ../../src/windows/native/sun/awt/splashscreen/splashscreen_config.h
-            ../../src/windows/native/sun/awt/splashscreen/splashscreen_sys.c
-            ../../src/windows/native/sun/awt/utility/rect.h
-            ../../src/windows/native/sun/awt_common/awt_makecube.cpp
-            ../../src/windows/native/sun/bridge/AccessBridgeATInstance.cpp
-            ../../src/windows/native/sun/bridge/AccessBridgeATInstance.h
-            ../../src/windows/native/sun/bridge/AccessBridgeCallbacks.h
-            ../../src/windows/native/sun/bridge/AccessBridgeCalls.c
-            ../../src/windows/native/sun/bridge/AccessBridgeCalls.h
-            ../../src/windows/native/sun/bridge/AccessBridgeDebug.cpp
-            ../../src/windows/native/sun/bridge/AccessBridgeDebug.h
-            ../../src/windows/native/sun/bridge/AccessBridgeEventHandler.cpp
-            ../../src/windows/native/sun/bridge/AccessBridgeEventHandler.h
-            ../../src/windows/native/sun/bridge/AccessBridgeJavaEntryPoints.cpp
-            ../../src/windows/native/sun/bridge/AccessBridgeJavaEntryPoints.h
-            ../../src/windows/native/sun/bridge/AccessBridgeJavaVMInstance.cpp
-            ../../src/windows/native/sun/bridge/AccessBridgeJavaVMInstance.h
-            ../../src/windows/native/sun/bridge/AccessBridgeMessageQueue.cpp
-            ../../src/windows/native/sun/bridge/AccessBridgeMessageQueue.h
-            ../../src/windows/native/sun/bridge/AccessBridgeMessages.cpp
-            ../../src/windows/native/sun/bridge/AccessBridgeMessages.h
-            ../../src/windows/native/sun/bridge/AccessBridgePackages.h
-            ../../src/windows/native/sun/bridge/accessBridgeResource.h
-            ../../src/windows/native/sun/bridge/AccessBridgeStatusWindow.RC
-            ../../src/windows/native/sun/bridge/AccessBridgeWindowsEntryPoints.cpp
-            ../../src/windows/native/sun/bridge/AccessBridgeWindowsEntryPoints.h
-            ../../src/windows/native/sun/bridge/accessibility.properties
-            ../../src/windows/native/sun/bridge/jabswitch.cpp
-            ../../src/windows/native/sun/bridge/jabswitch.manifest
-            ../../src/windows/native/sun/bridge/jabswitch_manifest.rc
-            ../../src/windows/native/sun/bridge/JavaAccessBridge.cpp
-            ../../src/windows/native/sun/bridge/JavaAccessBridge.h
-            ../../src/windows/native/sun/bridge/JAWTAccessBridge.cpp
-            ../../src/windows/native/sun/bridge/JAWTAccessBridge.h
-            ../../src/windows/native/sun/bridge/resource.h
-            ../../src/windows/native/sun/bridge/WinAccessBridge.cpp
-            ../../src/windows/native/sun/bridge/WinAccessBridge.DEF
-            ../../src/windows/native/sun/bridge/WinAccessBridge.h
-            ../../src/windows/native/sun/font/fontpath.c
-            ../../src/windows/native/sun/font/lcdglyph.c
-            ../../src/windows/native/sun/font/lcdglyphDW.cpp
-            ../../src/windows/native/sun/io/Win32ErrorMode.c
-            ../../src/windows/native/sun/java2d/d3d/D3DBadHardware.h
-            ../../src/windows/native/sun/java2d/d3d/D3DBlitLoops.cpp
-            ../../src/windows/native/sun/java2d/d3d/D3DBlitLoops.h
-            ../../src/windows/native/sun/java2d/d3d/D3DBufImgOps.cpp
-            ../../src/windows/native/sun/java2d/d3d/D3DBufImgOps.h
-            ../../src/windows/native/sun/java2d/d3d/D3DContext.cpp
-            ../../src/windows/native/sun/java2d/d3d/D3DContext.h
-            ../../src/windows/native/sun/java2d/d3d/D3DGlyphCache.cpp
-            ../../src/windows/native/sun/java2d/d3d/D3DGlyphCache.h
-            ../../src/windows/native/sun/java2d/d3d/D3DGraphicsDevice.cpp
-            ../../src/windows/native/sun/java2d/d3d/D3DGraphicsDevice.h
-            ../../src/windows/native/sun/java2d/d3d/D3DMaskBlit.cpp
-            ../../src/windows/native/sun/java2d/d3d/D3DMaskBlit.h
-            ../../src/windows/native/sun/java2d/d3d/D3DMaskCache.cpp
-            ../../src/windows/native/sun/java2d/d3d/D3DMaskCache.h
-            ../../src/windows/native/sun/java2d/d3d/D3DMaskFill.cpp
-            ../../src/windows/native/sun/java2d/d3d/D3DMaskFill.h
-            ../../src/windows/native/sun/java2d/d3d/D3DPaints.cpp
-            ../../src/windows/native/sun/java2d/d3d/D3DPaints.h
-            ../../src/windows/native/sun/java2d/d3d/D3DPipeline.cpp
-            ../../src/windows/native/sun/java2d/d3d/D3DPipeline.h
-            ../../src/windows/native/sun/java2d/d3d/D3DPipelineManager.cpp
-            ../../src/windows/native/sun/java2d/d3d/D3DPipelineManager.h
-            ../../src/windows/native/sun/java2d/d3d/D3DRenderer.cpp
-            ../../src/windows/native/sun/java2d/d3d/D3DRenderer.h
-            ../../src/windows/native/sun/java2d/d3d/D3DRenderQueue.cpp
-            ../../src/windows/native/sun/java2d/d3d/D3DRenderQueue.h
-            ../../src/windows/native/sun/java2d/d3d/D3DResourceManager.cpp
-            ../../src/windows/native/sun/java2d/d3d/D3DResourceManager.h
-            ../../src/windows/native/sun/java2d/d3d/D3DShaderGen.c
-            ../../src/windows/native/sun/java2d/d3d/D3DShaders.h
-            ../../src/windows/native/sun/java2d/d3d/D3DSurfaceData.cpp
-            ../../src/windows/native/sun/java2d/d3d/D3DSurfaceData.h
-            ../../src/windows/native/sun/java2d/d3d/D3DTextRenderer.cpp
-            ../../src/windows/native/sun/java2d/d3d/D3DTextRenderer.h
-            ../../src/windows/native/sun/java2d/d3d/D3DVertexCacher.cpp
-            ../../src/windows/native/sun/java2d/d3d/D3DVertexCacher.h
-            ../../src/windows/native/sun/java2d/j2d_md.h
-            ../../src/windows/native/sun/java2d/opengl/J2D_GL/wglext.h
-            ../../src/windows/native/sun/java2d/opengl/OGLFuncs_md.h
-            ../../src/windows/native/sun/java2d/opengl/WGLGraphicsConfig.c
-            ../../src/windows/native/sun/java2d/opengl/WGLGraphicsConfig.h
-            ../../src/windows/native/sun/java2d/opengl/WGLSurfaceData.c
-            ../../src/windows/native/sun/java2d/opengl/WGLSurfaceData.h
-            ../../src/windows/native/sun/java2d/windows/GDIBlitLoops.cpp
-            ../../src/windows/native/sun/java2d/windows/GDIRenderer.cpp
-            ../../src/windows/native/sun/java2d/windows/GDIWindowSurfaceData.cpp
-            ../../src/windows/native/sun/java2d/windows/GDIWindowSurfaceData.h
-            ../../src/windows/native/sun/java2d/windows/WindowsFlags.cpp
-            ../../src/windows/native/sun/java2d/windows/WindowsFlags.h
-            ../../src/windows/native/sun/management/FileSystemImpl.c
-            ../../src/windows/native/sun/management/OperatingSystemImpl.c
-            ../../src/windows/native/sun/net/dns/ResolverConfigurationImpl.c
-            ../../src/windows/native/sun/net/portconfig.c
-            ../../src/windows/native/sun/net/spi/DefaultProxySelector.c
-            ../../src/windows/native/sun/net/www/protocol/http/ntlm/NTLMAuthSequence.c
-            ../../src/windows/native/sun/nio/ch/DatagramChannelImpl.c
-            ../../src/windows/native/sun/nio/ch/DatagramDispatcher.c
-            ../../src/windows/native/sun/nio/ch/FileChannelImpl.c
-            ../../src/windows/native/sun/nio/ch/FileDispatcherImpl.c
-            ../../src/windows/native/sun/nio/ch/FileKey.c
-            ../../src/windows/native/sun/nio/ch/Iocp.c
-            ../../src/windows/native/sun/nio/ch/IOUtil.c
-            ../../src/windows/native/sun/nio/ch/Net.c
-            ../../src/windows/native/sun/nio/ch/nio_util.h
-            ../../src/windows/native/sun/nio/ch/ServerSocketChannelImpl.c
-            ../../src/windows/native/sun/nio/ch/SocketChannelImpl.c
-            ../../src/windows/native/sun/nio/ch/SocketDispatcher.c
-            ../../src/windows/native/sun/nio/ch/WindowsAsynchronousFileChannelImpl.c
-            ../../src/windows/native/sun/nio/ch/WindowsAsynchronousServerSocketChannelImpl.c
-            ../../src/windows/native/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.c
-            ../../src/windows/native/sun/nio/ch/WindowsSelectorImpl.c
-            ../../src/windows/native/sun/nio/fs/RegistryFileTypeDetector.c
-            ../../src/windows/native/sun/nio/fs/WindowsNativeDispatcher.c
-            ../../src/windows/native/sun/security/krb5/NativeCreds.c
-            ../../src/windows/native/sun/security/krb5/WindowsDirectory.c
-            ../../src/windows/native/sun/security/mscapi/security.cpp
-            ../../src/windows/native/sun/security/pkcs11/j2secmod_md.c
-            ../../src/windows/native/sun/security/pkcs11/j2secmod_md.h
-            ../../src/windows/native/sun/security/pkcs11/wrapper/p11_md.c
-            ../../src/windows/native/sun/security/pkcs11/wrapper/p11_md.h
-            ../../src/windows/native/sun/security/provider/WinCAPISeedGenerator.c
-            ../../src/windows/native/sun/security/smartcardio/pcsc_md.c
-            ../../src/windows/native/sun/security/smartcardio/pcsc_md.h
-            ../../src/windows/native/sun/tools/attach/WindowsAttachProvider.c
-            ../../src/windows/native/sun/tools/attach/WindowsVirtualMachine.c
-            ../../src/windows/native/sun/tracing/dtrace/jvm_symbols_md.c
-            ../../src/windows/native/sun/util/locale/provider/HostLocaleProviderAdapter_md.c
-            ../../src/windows/native/sun/windows/alloc.h
-            ../../src/windows/native/sun/windows/awt.h
-            ../../src/windows/native/sun/windows/awt.rc
-            ../../src/windows/native/sun/windows/awtmsg.h
-            ../../src/windows/native/sun/windows/awt_AWTEvent.cpp
-            ../../src/windows/native/sun/windows/awt_AWTEvent.h
-            ../../src/windows/native/sun/windows/awt_BitmapUtil.cpp
-            ../../src/windows/native/sun/windows/awt_BitmapUtil.h
-            ../../src/windows/native/sun/windows/awt_Brush.cpp
-            ../../src/windows/native/sun/windows/awt_Brush.h
-            ../../src/windows/native/sun/windows/awt_Button.cpp
-            ../../src/windows/native/sun/windows/awt_Button.h
-            ../../src/windows/native/sun/windows/awt_Canvas.cpp
-            ../../src/windows/native/sun/windows/awt_Canvas.h
-            ../../src/windows/native/sun/windows/awt_Checkbox.cpp
-            ../../src/windows/native/sun/windows/awt_Checkbox.h
-            ../../src/windows/native/sun/windows/awt_Choice.cpp
-            ../../src/windows/native/sun/windows/awt_Choice.h
-            ../../src/windows/native/sun/windows/awt_Clipboard.cpp
-            ../../src/windows/native/sun/windows/awt_Clipboard.h
-            ../../src/windows/native/sun/windows/awt_Color.cpp
-            ../../src/windows/native/sun/windows/awt_Color.h
-            ../../src/windows/native/sun/windows/awt_Component.cpp
-            ../../src/windows/native/sun/windows/awt_Component.h
-            ../../src/windows/native/sun/windows/awt_Container.cpp
-            ../../src/windows/native/sun/windows/awt_Container.h
-            ../../src/windows/native/sun/windows/awt_Cursor.cpp
-            ../../src/windows/native/sun/windows/awt_Cursor.h
-            ../../src/windows/native/sun/windows/awt_CustomPaletteDef.h
-            ../../src/windows/native/sun/windows/awt_DataTransferer.cpp
-            ../../src/windows/native/sun/windows/awt_DataTransferer.h
-            ../../src/windows/native/sun/windows/awt_DCHolder.cpp
-            ../../src/windows/native/sun/windows/awt_DCHolder.h
-            ../../src/windows/native/sun/windows/awt_Debug.cpp
-            ../../src/windows/native/sun/windows/awt_Debug.h
-            ../../src/windows/native/sun/windows/awt_Desktop.cpp
-            ../../src/windows/native/sun/windows/awt_DesktopProperties.cpp
-            ../../src/windows/native/sun/windows/awt_DesktopProperties.h
-            ../../src/windows/native/sun/windows/awt_Dialog.cpp
-            ../../src/windows/native/sun/windows/awt_Dialog.h
-            ../../src/windows/native/sun/windows/awt_Dimension.cpp
-            ../../src/windows/native/sun/windows/awt_Dimension.h
-            ../../src/windows/native/sun/windows/awt_DnDDS.cpp
-            ../../src/windows/native/sun/windows/awt_DnDDS.h
-            ../../src/windows/native/sun/windows/awt_DnDDT.cpp
-            ../../src/windows/native/sun/windows/awt_DnDDT.h
-            ../../src/windows/native/sun/windows/awt_DrawingSurface.cpp
-            ../../src/windows/native/sun/windows/awt_DrawingSurface.h
-            ../../src/windows/native/sun/windows/awt_Event.cpp
-            ../../src/windows/native/sun/windows/awt_Event.h
-            ../../src/windows/native/sun/windows/awt_FileDialog.cpp
-            ../../src/windows/native/sun/windows/awt_FileDialog.h
-            ../../src/windows/native/sun/windows/awt_Font.cpp
-            ../../src/windows/native/sun/windows/awt_Font.h
-            ../../src/windows/native/sun/windows/awt_Frame.cpp
-            ../../src/windows/native/sun/windows/awt_Frame.h
-            ../../src/windows/native/sun/windows/awt_GDIObject.cpp
-            ../../src/windows/native/sun/windows/awt_GDIObject.h
-            ../../src/windows/native/sun/windows/awt_IconCursor.cpp
-            ../../src/windows/native/sun/windows/awt_IconCursor.h
-            ../../src/windows/native/sun/windows/awt_InputEvent.cpp
-            ../../src/windows/native/sun/windows/awt_InputEvent.h
-            ../../src/windows/native/sun/windows/awt_InputMethod.cpp
-            ../../src/windows/native/sun/windows/awt_InputTextInfor.cpp
-            ../../src/windows/native/sun/windows/awt_InputTextInfor.h
-            ../../src/windows/native/sun/windows/awt_Insets.cpp
-            ../../src/windows/native/sun/windows/awt_Insets.h
-            ../../src/windows/native/sun/windows/awt_KeyboardFocusManager.cpp
-            ../../src/windows/native/sun/windows/awt_KeyEvent.cpp
-            ../../src/windows/native/sun/windows/awt_KeyEvent.h
-            ../../src/windows/native/sun/windows/awt_Label.cpp
-            ../../src/windows/native/sun/windows/awt_Label.h
-            ../../src/windows/native/sun/windows/awt_List.cpp
-            ../../src/windows/native/sun/windows/awt_List.h
-            ../../src/windows/native/sun/windows/awt_Menu.cpp
-            ../../src/windows/native/sun/windows/awt_Menu.h
-            ../../src/windows/native/sun/windows/awt_MenuBar.cpp
-            ../../src/windows/native/sun/windows/awt_MenuBar.h
-            ../../src/windows/native/sun/windows/awt_MenuItem.cpp
-            ../../src/windows/native/sun/windows/awt_MenuItem.h
-            ../../src/windows/native/sun/windows/awt_Mlib.cpp
-            ../../src/windows/native/sun/windows/awt_Mlib.h
-            ../../src/windows/native/sun/windows/awt_MouseEvent.cpp
-            ../../src/windows/native/sun/windows/awt_MouseEvent.h
-            ../../src/windows/native/sun/windows/awt_new.cpp
-            ../../src/windows/native/sun/windows/awt_new.h
-            ../../src/windows/native/sun/windows/awt_Object.cpp
-            ../../src/windows/native/sun/windows/awt_Object.h
-            ../../src/windows/native/sun/windows/awt_ole.cpp
-            ../../src/windows/native/sun/windows/awt_ole.h
-            ../../src/windows/native/sun/windows/awt_Palette.cpp
-            ../../src/windows/native/sun/windows/awt_Palette.h
-            ../../src/windows/native/sun/windows/awt_Panel.cpp
-            ../../src/windows/native/sun/windows/awt_Panel.h
-            ../../src/windows/native/sun/windows/awt_Pen.cpp
-            ../../src/windows/native/sun/windows/awt_Pen.h
-            ../../src/windows/native/sun/windows/awt_PopupMenu.cpp
-            ../../src/windows/native/sun/windows/awt_PopupMenu.h
-            ../../src/windows/native/sun/windows/awt_PrintControl.cpp
-            ../../src/windows/native/sun/windows/awt_PrintControl.h
-            ../../src/windows/native/sun/windows/awt_PrintDialog.cpp
-            ../../src/windows/native/sun/windows/awt_PrintDialog.h
-            ../../src/windows/native/sun/windows/awt_PrintJob.cpp
-            ../../src/windows/native/sun/windows/awt_Rectangle.cpp
-            ../../src/windows/native/sun/windows/awt_Rectangle.h
-            ../../src/windows/native/sun/windows/awt_Robot.cpp
-            ../../src/windows/native/sun/windows/awt_Robot.h
-            ../../src/windows/native/sun/windows/awt_Scrollbar.cpp
-            ../../src/windows/native/sun/windows/awt_Scrollbar.h
-            ../../src/windows/native/sun/windows/awt_ScrollPane.cpp
-            ../../src/windows/native/sun/windows/awt_ScrollPane.h
-            ../../src/windows/native/sun/windows/awt_TextArea.cpp
-            ../../src/windows/native/sun/windows/awt_TextArea.h
-            ../../src/windows/native/sun/windows/awt_TextComponent.cpp
-            ../../src/windows/native/sun/windows/awt_TextComponent.h
-            ../../src/windows/native/sun/windows/awt_TextField.cpp
-            ../../src/windows/native/sun/windows/awt_TextField.h
-            ../../src/windows/native/sun/windows/awt_Toolkit.cpp
-            ../../src/windows/native/sun/windows/awt_Toolkit.h
-            ../../src/windows/native/sun/windows/awt_TrayIcon.cpp
-            ../../src/windows/native/sun/windows/awt_TrayIcon.h
-            ../../src/windows/native/sun/windows/awt_Win32GraphicsConfig.cpp
-            ../../src/windows/native/sun/windows/awt_Win32GraphicsConfig.h
-            ../../src/windows/native/sun/windows/awt_Win32GraphicsDevice.cpp
-            ../../src/windows/native/sun/windows/awt_Win32GraphicsDevice.h
-            ../../src/windows/native/sun/windows/awt_Win32GraphicsEnv.cpp
-            ../../src/windows/native/sun/windows/awt_Window.cpp
-            ../../src/windows/native/sun/windows/awt_Window.h
-            ../../src/windows/native/sun/windows/check.bmp
-            ../../src/windows/native/sun/windows/CmdIDList.cpp
-            ../../src/windows/native/sun/windows/CmdIDList.h
-            ../../src/windows/native/sun/windows/colordata.h
-            ../../src/windows/native/sun/windows/ComCtl32Util.cpp
-            ../../src/windows/native/sun/windows/ComCtl32Util.h
-            ../../src/windows/native/sun/windows/Devices.cpp
-            ../../src/windows/native/sun/windows/Devices.h
-            ../../src/windows/native/sun/windows/DllUtil.cpp
-            ../../src/windows/native/sun/windows/DllUtil.h
-            ../../src/windows/native/sun/windows/GDIHashtable.cpp
-            ../../src/windows/native/sun/windows/GDIHashtable.h
-            ../../src/windows/native/sun/windows/hand.cur
-            ../../src/windows/native/sun/windows/Hashtable.cpp
-            ../../src/windows/native/sun/windows/Hashtable.h
-            ../../src/windows/native/sun/windows/img_util_md.h
-            ../../src/windows/native/sun/windows/initIDs.cpp
-            ../../src/windows/native/sun/windows/jawt.cpp
-            ../../src/windows/native/sun/windows/mlib_types_md.h
-            ../../src/windows/native/sun/windows/MouseInfo.cpp
-            ../../src/windows/native/sun/windows/ObjectList.cpp
-            ../../src/windows/native/sun/windows/ObjectList.h
-            ../../src/windows/native/sun/windows/README.JNI
-            ../../src/windows/native/sun/windows/security_warning.ico
-            ../../src/windows/native/sun/windows/security_warning_bw.ico
-            ../../src/windows/native/sun/windows/security_warning_int.ico
-            ../../src/windows/native/sun/windows/ShellFolder2.cpp
-            ../../src/windows/native/sun/windows/stdhdrs.h
-            ../../src/windows/native/sun/windows/ThemeReader.cpp
-            ../../src/windows/native/sun/windows/WBufferStrategy.cpp
-            ../../src/windows/native/sun/windows/WPrinterJob.cpp)
-endif()
-
-add_custom_target(make_java /usr/bin/make COMPILER_WARNINGS_FATAL=false -C ${CMAKE_SOURCE_DIR}/../../../ images
-        DEPENDS ${SOURCE_FILES})
-
-add_executable(java ${SOURCE_FILES})
-
-if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
-    target_link_libraries(java ${JAVA_NATIVE_FOUNDATION})
-endif()
\ No newline at end of file
diff --git a/make/CreateJars.gmk b/make/CreateJars.gmk
index c1a0769..e8b042b 100644
--- a/make/CreateJars.gmk
+++ b/make/CreateJars.gmk
@@ -265,7 +265,7 @@
 $(IMAGES_OUTPUTDIR)/lib$(PROFILE)/_the.rt.jar.contents: $(IMAGES_OUTPUTDIR)/lib$(PROFILE)/_the.jars.contents
 	$(MKDIR) -p $(@D)
 	$(RM) $@ $@.tmp
-	$(GREP) -e '\.class$$' $(IMAGES_OUTPUTDIR)/lib$(PROFILE)/_the.jars.contents > $@.tmp
+	$(CAT) $(IMAGES_OUTPUTDIR)/lib$(PROFILE)/_the.jars.contents | $(TR) -d '\r' |  $(GREP) -e '\.class$$' > $@.tmp
         ifneq ($(PROFILE), )
           ifneq ($(strip $(RT_JAR_INCLUDE_TYPES)), )
            # Add back classes from excluded packages (fixing the $ substitution in the process)
diff --git a/src/macosx/bundle/JavaAppLauncher/JavaAppLauncher.xcodeproj/project.pbxproj b/src/macosx/bundle/JavaAppLauncher/JavaAppLauncher.xcodeproj/project.pbxproj
index b51cbefb..2637055 100644
--- a/src/macosx/bundle/JavaAppLauncher/JavaAppLauncher.xcodeproj/project.pbxproj
+++ b/src/macosx/bundle/JavaAppLauncher/JavaAppLauncher.xcodeproj/project.pbxproj
@@ -1,318 +1,297 @@
 // !$*UTF8*$!
 {
-        archiveVersion = 1;
-        classes = {
-        };
-        objectVersion = 45;
-        objects = {
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 45;
+	objects = {
 
 /* Begin PBXBuildFile section */
-                2C483E05143512EB00F2AEFD /* 1.7.0.jre in Copy PlugIns */ = {isa = PBXBuildFile; fileRef = 2C483E04143512EB00F2AEFD /* 1.7.0.jre */; };
-                89D3CD32142EEB2200A08AED /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 89D3CD29142EEB2200A08AED /* InfoPlist.strings */; };
-                89D3CD33142EEB2200A08AED /* GenericApp.icns in Resources */ = {isa = PBXBuildFile; fileRef = 89D3CD2B142EEB2200A08AED /* GenericApp.icns */; };
-                89D3CD35142EEB2200A08AED /* JVMArgs.m in Sources */ = {isa = PBXBuildFile; fileRef = 89D3CD30142EEB2200A08AED /* JVMArgs.m */; };
-                89D3CD36142EEB2200A08AED /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 89D3CD31142EEB2200A08AED /* main.m */; };
-                89D3D365143041F000A08AED /* JavaAppLauncher.m in Sources */ = {isa = PBXBuildFile; fileRef = 89D3D364143041F000A08AED /* JavaAppLauncher.m */; };
-                8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
+		89D3CD32142EEB2200A08AED /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 89D3CD29142EEB2200A08AED /* InfoPlist.strings */; };
+		89D3CD33142EEB2200A08AED /* GenericApp.icns in Resources */ = {isa = PBXBuildFile; fileRef = 89D3CD2B142EEB2200A08AED /* GenericApp.icns */; };
+		89D3CD35142EEB2200A08AED /* JVMArgs.m in Sources */ = {isa = PBXBuildFile; fileRef = 89D3CD30142EEB2200A08AED /* JVMArgs.m */; };
+		89D3CD36142EEB2200A08AED /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 89D3CD31142EEB2200A08AED /* main.m */; };
+		89D3D365143041F000A08AED /* JavaAppLauncher.m in Sources */ = {isa = PBXBuildFile; fileRef = 89D3D364143041F000A08AED /* JavaAppLauncher.m */; };
+		8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
+		F2153B911FF56444006B8026 /* jre1.8.0.jre in Copy PlugIns */ = {isa = PBXBuildFile; fileRef = F2153B901FF56444006B8026 /* jre1.8.0.jre */; };
+		F2153BA31FF56605006B8026 /* jdk1.8.0.jdk in Copy PlugIns */ = {isa = PBXBuildFile; fileRef = F2153BA21FF56605006B8026 /* jdk1.8.0.jdk */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXCopyFilesBuildPhase section */
-                2C48F06614350F0F00F2AEFD /* Copy PlugIns */ = {
-                        isa = PBXCopyFilesBuildPhase;
-                        buildActionMask = 2147483647;
-                        dstPath = "";
-                        dstSubfolderSpec = 13;
-                        files = (
-                                2C483E05143512EB00F2AEFD /* 1.7.0.jre in Copy PlugIns */,
-                        );
-                        name = "Copy PlugIns";
-                        runOnlyForDeploymentPostprocessing = 0;
-                };
+		2C48F06614350F0F00F2AEFD /* Copy PlugIns */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 12;
+			dstPath = "";
+			dstSubfolderSpec = 13;
+			files = (
+				F2153BA31FF56605006B8026 /* jdk1.8.0.jdk in Copy PlugIns */,
+				F2153B911FF56444006B8026 /* jre1.8.0.jre in Copy PlugIns */,
+			);
+			name = "Copy PlugIns";
+			runOnlyForDeploymentPostprocessing = 0;
+		};
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
-                1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
-                2C483E04143512EB00F2AEFD /* 1.7.0.jre */ = {isa = PBXFileReference; lastKnownFileType = folder; name = 1.7.0.jre; path = "../../../../../build/macosx-universal/j2sdk-bundle/1.7.0.jdk/Contents/Home/1.7.0.jre"; sourceTree = SOURCE_ROOT; };
-                2C48F06714350F8300F2AEFD /* 1.7.0.jdk */ = {isa = PBXFileReference; lastKnownFileType = folder; name = 1.7.0.jdk; path = "../../../../../build/macosx-universal/j2sdk-bundle/1.7.0.jdk"; sourceTree = SOURCE_ROOT; };
-                2CB5DA5E14355FCA00D3A656 /* classfile_constants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = classfile_constants.h; sourceTree = "<group>"; };
-                2CB5DA6014355FCA00D3A656 /* jawt_md.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jawt_md.h; sourceTree = "<group>"; };
-                2CB5DA6114355FCA00D3A656 /* jni_md.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jni_md.h; sourceTree = "<group>"; };
-                2CB5DA6214355FCA00D3A656 /* jawt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jawt.h; sourceTree = "<group>"; };
-                2CB5DA6314355FCA00D3A656 /* jdwpTransport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jdwpTransport.h; sourceTree = "<group>"; };
-                2CB5DA6414355FCA00D3A656 /* jni.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jni.h; sourceTree = "<group>"; };
-                2CB5DA6514355FCA00D3A656 /* jvmti.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jvmti.h; sourceTree = "<group>"; };
-                2CB5DA6614355FCA00D3A656 /* jvmticmlr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jvmticmlr.h; sourceTree = "<group>"; };
-                89D3CD2A142EEB2200A08AED /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
-                89D3CD2B142EEB2200A08AED /* GenericApp.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = GenericApp.icns; path = /System/Library/Frameworks/JavaVM.framework/Versions/A/Resources/GenericApp.icns; sourceTree = "<absolute>"; };
-                89D3CD2C142EEB2200A08AED /* JavaAppLauncher-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "JavaAppLauncher-Info.plist"; sourceTree = "<group>"; };
-                89D3CD2E142EEB2200A08AED /* JavaAppLauncher_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JavaAppLauncher_Prefix.pch; sourceTree = "<group>"; };
-                89D3CD2F142EEB2200A08AED /* JVMArgs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JVMArgs.h; sourceTree = "<group>"; };
-                89D3CD30142EEB2200A08AED /* JVMArgs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JVMArgs.m; sourceTree = "<group>"; };
-                89D3CD31142EEB2200A08AED /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
-                89D3D363143041F000A08AED /* JavaAppLauncher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JavaAppLauncher.h; sourceTree = "<group>"; };
-                89D3D364143041F000A08AED /* JavaAppLauncher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JavaAppLauncher.m; sourceTree = "<group>"; };
-                8D1107320486CEB800E47090 /* JavaAppLauncher.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JavaAppLauncher.app; sourceTree = BUILT_PRODUCTS_DIR; };
+		1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
+		89D3CD2A142EEB2200A08AED /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
+		89D3CD2B142EEB2200A08AED /* GenericApp.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = GenericApp.icns; path = /System/Library/Frameworks/JavaVM.framework/Versions/A/Resources/GenericApp.icns; sourceTree = "<absolute>"; };
+		89D3CD2C142EEB2200A08AED /* JavaAppLauncher-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "JavaAppLauncher-Info.plist"; sourceTree = "<group>"; };
+		89D3CD2E142EEB2200A08AED /* JavaAppLauncher_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JavaAppLauncher_Prefix.pch; sourceTree = "<group>"; };
+		89D3CD2F142EEB2200A08AED /* JVMArgs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JVMArgs.h; sourceTree = "<group>"; };
+		89D3CD30142EEB2200A08AED /* JVMArgs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JVMArgs.m; sourceTree = "<group>"; };
+		89D3CD31142EEB2200A08AED /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+		89D3D363143041F000A08AED /* JavaAppLauncher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JavaAppLauncher.h; sourceTree = "<group>"; };
+		89D3D364143041F000A08AED /* JavaAppLauncher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JavaAppLauncher.m; sourceTree = "<group>"; };
+		8D1107320486CEB800E47090 /* JavaAppLauncher.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JavaAppLauncher.app; sourceTree = BUILT_PRODUCTS_DIR; };
+		F2153B901FF56444006B8026 /* jre1.8.0.jre */ = {isa = PBXFileReference; lastKnownFileType = folder; name = jre1.8.0.jre; path = "../../../../../build/macosx-x86_64-normal-server-release/images/j2re-bundle/jre1.8.0.jre"; sourceTree = "<group>"; };
+		F2153BA21FF56605006B8026 /* jdk1.8.0.jdk */ = {isa = PBXFileReference; lastKnownFileType = folder; name = jdk1.8.0.jdk; path = "../../../../../build/macosx-x86_64-normal-server-release/images/j2sdk-bundle/jdk1.8.0.jdk"; sourceTree = "<group>"; };
+		F2153BA71FF5672A006B8026 /* jni.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = jni.h; path = "../../../../../../build/macosx-x86_64-normal-server-release/images/j2sdk-image/include/jni.h"; sourceTree = "<group>"; };
+		F2153BA81FF56745006B8026 /* jawt_md.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = jawt_md.h; path = "../../../../../../build/macosx-x86_64-normal-server-release/images/j2sdk-image/include/darwin/jawt_md.h"; sourceTree = "<group>"; };
+		F2153BA91FF56746006B8026 /* jni_md.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = jni_md.h; path = "../../../../../../build/macosx-x86_64-normal-server-release/images/j2sdk-image/include/darwin/jni_md.h"; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
-                8D11072E0486CEB800E47090 /* Frameworks */ = {
-                        isa = PBXFrameworksBuildPhase;
-                        buildActionMask = 2147483647;
-                        files = (
-                                8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */,
-                        );
-                        runOnlyForDeploymentPostprocessing = 0;
-                };
+		8D11072E0486CEB800E47090 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
-                1058C7A0FEA54F0111CA2CBB /* frameworks */ = {
-                        isa = PBXGroup;
-                        children = (
-                                1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */,
-                        );
-                        name = frameworks;
-                        sourceTree = "<group>";
-                };
-                19C28FACFE9D520D11CA2CBB /* Products */ = {
-                        isa = PBXGroup;
-                        children = (
-                                8D1107320486CEB800E47090 /* JavaAppLauncher.app */,
-                        );
-                        name = Products;
-                        sourceTree = "<group>";
-                };
-                29B97314FDCFA39411CA2CEA /* JavaAppLauncher */ = {
-                        isa = PBXGroup;
-                        children = (
-                                89D3CD2D142EEB2200A08AED /* src */,
-                                89D3CD28142EEB2200A08AED /* resources */,
-                                29B97323FDCFA39411CA2CEA /* linking */,
-                                19C28FACFE9D520D11CA2CBB /* Products */,
-                        );
-                        name = JavaAppLauncher;
-                        sourceTree = "<group>";
-                };
-                29B97323FDCFA39411CA2CEA /* linking */ = {
-                        isa = PBXGroup;
-                        children = (
-                                2C48F06714350F8300F2AEFD /* 1.7.0.jdk */,
-                                2C483E04143512EB00F2AEFD /* 1.7.0.jre */,
-                                2CB5DA5D14355FCA00D3A656 /* include */,
-                                1058C7A0FEA54F0111CA2CBB /* frameworks */,
-                        );
-                        name = linking;
-                        sourceTree = "<group>";
-                };
-                2CB5DA5D14355FCA00D3A656 /* include */ = {
-                        isa = PBXGroup;
-                        children = (
-                                2CB5DA5E14355FCA00D3A656 /* classfile_constants.h */,
-                                2CB5DA5F14355FCA00D3A656 /* darwin */,
-                                2CB5DA6214355FCA00D3A656 /* jawt.h */,
-                                2CB5DA6314355FCA00D3A656 /* jdwpTransport.h */,
-                                2CB5DA6414355FCA00D3A656 /* jni.h */,
-                                2CB5DA6514355FCA00D3A656 /* jvmti.h */,
-                                2CB5DA6614355FCA00D3A656 /* jvmticmlr.h */,
-                        );
-                        name = include;
-                        path = "../../../../../build/macosx-universal/j2sdk-bundle/1.7.0.jdk/Contents/Home/include";
-                        sourceTree = "<group>";
-                };
-                2CB5DA5F14355FCA00D3A656 /* darwin */ = {
-                        isa = PBXGroup;
-                        children = (
-                                2CB5DA6014355FCA00D3A656 /* jawt_md.h */,
-                                2CB5DA6114355FCA00D3A656 /* jni_md.h */,
-                        );
-                        path = darwin;
-                        sourceTree = "<group>";
-                };
-                89D3CD28142EEB2200A08AED /* resources */ = {
-                        isa = PBXGroup;
-                        children = (
-                                89D3CD29142EEB2200A08AED /* InfoPlist.strings */,
-                                89D3CD2B142EEB2200A08AED /* GenericApp.icns */,
-                                89D3CD2C142EEB2200A08AED /* JavaAppLauncher-Info.plist */,
-                        );
-                        path = resources;
-                        sourceTree = "<group>";
-                };
-                89D3CD2D142EEB2200A08AED /* src */ = {
-                        isa = PBXGroup;
-                        children = (
-                                89D3CD31142EEB2200A08AED /* main.m */,
-                                89D3D363143041F000A08AED /* JavaAppLauncher.h */,
-                                89D3D364143041F000A08AED /* JavaAppLauncher.m */,
-                                89D3CD2F142EEB2200A08AED /* JVMArgs.h */,
-                                89D3CD30142EEB2200A08AED /* JVMArgs.m */,
-                                89D3CD2E142EEB2200A08AED /* JavaAppLauncher_Prefix.pch */,
-                        );
-                        path = src;
-                        sourceTree = "<group>";
-                };
+		1058C7A0FEA54F0111CA2CBB /* frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */,
+			);
+			name = frameworks;
+			sourceTree = "<group>";
+		};
+		19C28FACFE9D520D11CA2CBB /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				8D1107320486CEB800E47090 /* JavaAppLauncher.app */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		29B97314FDCFA39411CA2CEA /* JavaAppLauncher */ = {
+			isa = PBXGroup;
+			children = (
+				89D3CD2D142EEB2200A08AED /* src */,
+				89D3CD28142EEB2200A08AED /* resources */,
+				29B97323FDCFA39411CA2CEA /* linking */,
+				19C28FACFE9D520D11CA2CBB /* Products */,
+			);
+			name = JavaAppLauncher;
+			sourceTree = "<group>";
+		};
+		29B97323FDCFA39411CA2CEA /* linking */ = {
+			isa = PBXGroup;
+			children = (
+				F2153BA21FF56605006B8026 /* jdk1.8.0.jdk */,
+				F2153B901FF56444006B8026 /* jre1.8.0.jre */,
+				1058C7A0FEA54F0111CA2CBB /* frameworks */,
+			);
+			name = linking;
+			sourceTree = "<group>";
+		};
+		89D3CD28142EEB2200A08AED /* resources */ = {
+			isa = PBXGroup;
+			children = (
+				89D3CD29142EEB2200A08AED /* InfoPlist.strings */,
+				89D3CD2B142EEB2200A08AED /* GenericApp.icns */,
+				89D3CD2C142EEB2200A08AED /* JavaAppLauncher-Info.plist */,
+			);
+			path = resources;
+			sourceTree = "<group>";
+		};
+		89D3CD2D142EEB2200A08AED /* src */ = {
+			isa = PBXGroup;
+			children = (
+				F2153BA81FF56745006B8026 /* jawt_md.h */,
+				F2153BA91FF56746006B8026 /* jni_md.h */,
+				F2153BA71FF5672A006B8026 /* jni.h */,
+				89D3CD31142EEB2200A08AED /* main.m */,
+				89D3D363143041F000A08AED /* JavaAppLauncher.h */,
+				89D3D364143041F000A08AED /* JavaAppLauncher.m */,
+				89D3CD2F142EEB2200A08AED /* JVMArgs.h */,
+				89D3CD30142EEB2200A08AED /* JVMArgs.m */,
+				89D3CD2E142EEB2200A08AED /* JavaAppLauncher_Prefix.pch */,
+			);
+			path = src;
+			sourceTree = "<group>";
+		};
 /* End PBXGroup section */
 
 /* Begin PBXNativeTarget section */
-                8D1107260486CEB800E47090 /* JavaAppLauncher */ = {
-                        isa = PBXNativeTarget;
-                        buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "JavaAppLauncher" */;
-                        buildPhases = (
-                                8D1107290486CEB800E47090 /* Resources */,
-                                2C48F06614350F0F00F2AEFD /* Copy PlugIns */,
-                                8D11072C0486CEB800E47090 /* Sources */,
-                                8D11072E0486CEB800E47090 /* Frameworks */,
-                        );
-                        buildRules = (
-                        );
-                        dependencies = (
-                        );
-                        name = JavaAppLauncher;
-                        productInstallPath = "$(HOME)/Applications";
-                        productName = JavaAppLauncher;
-                        productReference = 8D1107320486CEB800E47090 /* JavaAppLauncher.app */;
-                        productType = "com.apple.product-type.application";
-                };
+		8D1107260486CEB800E47090 /* JavaAppLauncher */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "JavaAppLauncher" */;
+			buildPhases = (
+				8D1107290486CEB800E47090 /* Resources */,
+				2C48F06614350F0F00F2AEFD /* Copy PlugIns */,
+				8D11072C0486CEB800E47090 /* Sources */,
+				8D11072E0486CEB800E47090 /* Frameworks */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = JavaAppLauncher;
+			productInstallPath = "$(HOME)/Applications";
+			productName = JavaAppLauncher;
+			productReference = 8D1107320486CEB800E47090 /* JavaAppLauncher.app */;
+			productType = "com.apple.product-type.application";
+		};
 /* End PBXNativeTarget section */
 
 /* Begin PBXProject section */
-                29B97313FDCFA39411CA2CEA /* Project object */ = {
-                        isa = PBXProject;
-                        buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "JavaAppLauncher" */;
-                        compatibilityVersion = "Xcode 3.1";
-                        developmentRegion = English;
-                        hasScannedForEncodings = 1;
-                        knownRegions = (
-                                en,
-                                English,
-                        );
-                        mainGroup = 29B97314FDCFA39411CA2CEA /* JavaAppLauncher */;
-                        projectDirPath = "";
-                        projectRoot = "";
-                        targets = (
-                                8D1107260486CEB800E47090 /* JavaAppLauncher */,
-                        );
-                };
+		29B97313FDCFA39411CA2CEA /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+			};
+			buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "JavaAppLauncher" */;
+			compatibilityVersion = "Xcode 3.1";
+			developmentRegion = English;
+			hasScannedForEncodings = 1;
+			knownRegions = (
+				en,
+				English,
+			);
+			mainGroup = 29B97314FDCFA39411CA2CEA /* JavaAppLauncher */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				8D1107260486CEB800E47090 /* JavaAppLauncher */,
+			);
+		};
 /* End PBXProject section */
 
 /* Begin PBXResourcesBuildPhase section */
-                8D1107290486CEB800E47090 /* Resources */ = {
-                        isa = PBXResourcesBuildPhase;
-                        buildActionMask = 2147483647;
-                        files = (
-                                89D3CD32142EEB2200A08AED /* InfoPlist.strings in Resources */,
-                                89D3CD33142EEB2200A08AED /* GenericApp.icns in Resources */,
-                        );
-                        runOnlyForDeploymentPostprocessing = 0;
-                };
+		8D1107290486CEB800E47090 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				89D3CD32142EEB2200A08AED /* InfoPlist.strings in Resources */,
+				89D3CD33142EEB2200A08AED /* GenericApp.icns in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
 /* End PBXResourcesBuildPhase section */
 
 /* Begin PBXSourcesBuildPhase section */
-                8D11072C0486CEB800E47090 /* Sources */ = {
-                        isa = PBXSourcesBuildPhase;
-                        buildActionMask = 2147483647;
-                        files = (
-                                89D3CD35142EEB2200A08AED /* JVMArgs.m in Sources */,
-                                89D3CD36142EEB2200A08AED /* main.m in Sources */,
-                                89D3D365143041F000A08AED /* JavaAppLauncher.m in Sources */,
-                        );
-                        runOnlyForDeploymentPostprocessing = 0;
-                };
+		8D11072C0486CEB800E47090 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				89D3CD35142EEB2200A08AED /* JVMArgs.m in Sources */,
+				89D3CD36142EEB2200A08AED /* main.m in Sources */,
+				89D3D365143041F000A08AED /* JavaAppLauncher.m in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
 /* End PBXSourcesBuildPhase section */
 
 /* Begin PBXVariantGroup section */
-                89D3CD29142EEB2200A08AED /* InfoPlist.strings */ = {
-                        isa = PBXVariantGroup;
-                        children = (
-                                89D3CD2A142EEB2200A08AED /* English */,
-                        );
-                        name = InfoPlist.strings;
-                        sourceTree = "<group>";
-                };
+		89D3CD29142EEB2200A08AED /* InfoPlist.strings */ = {
+			isa = PBXVariantGroup;
+			children = (
+				89D3CD2A142EEB2200A08AED /* English */,
+			);
+			name = InfoPlist.strings;
+			sourceTree = "<group>";
+		};
 /* End PBXVariantGroup section */
 
 /* Begin XCBuildConfiguration section */
-                C01FCF4B08A954540054247B /* Debug */ = {
-                        isa = XCBuildConfiguration;
-                        buildSettings = {
-                                ALWAYS_SEARCH_USER_PATHS = NO;
-                                COPY_PHASE_STRIP = NO;
-                                GCC_DYNAMIC_NO_PIC = NO;
-                                GCC_ENABLE_FIX_AND_CONTINUE = YES;
-                                GCC_MODEL_TUNING = G5;
-                                GCC_OPTIMIZATION_LEVEL = 0;
-                                GCC_PRECOMPILE_PREFIX_HEADER = YES;
-                                GCC_PREFIX_HEADER = src/JavaAppLauncher_Prefix.pch;
-                                INFOPLIST_FILE = "resources/JavaAppLauncher-Info.plist";
-                                INSTALL_PATH = "$(HOME)/Applications";
-                                LIBRARY_SEARCH_PATHS = "$(inherited)";
-                                PRODUCT_NAME = JavaAppLauncher;
-                        };
-                        name = Debug;
-                };
-                C01FCF4C08A954540054247B /* Release */ = {
-                        isa = XCBuildConfiguration;
-                        buildSettings = {
-                                ALWAYS_SEARCH_USER_PATHS = NO;
-                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-                                GCC_MODEL_TUNING = G5;
-                                GCC_PRECOMPILE_PREFIX_HEADER = YES;
-                                GCC_PREFIX_HEADER = src/JavaAppLauncher_Prefix.pch;
-                                INFOPLIST_FILE = "resources/JavaAppLauncher-Info.plist";
-                                INSTALL_PATH = "$(HOME)/Applications";
-                                LIBRARY_SEARCH_PATHS = "$(inherited)";
-                                PRODUCT_NAME = JavaAppLauncher;
-                        };
-                        name = Release;
-                };
-                C01FCF4F08A954540054247B /* Debug */ = {
-                        isa = XCBuildConfiguration;
-                        buildSettings = {
-                                ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
-                                GCC_C_LANGUAGE_STANDARD = gnu99;
-                                GCC_OPTIMIZATION_LEVEL = 0;
-                                GCC_WARN_ABOUT_RETURN_TYPE = YES;
-                                GCC_WARN_UNUSED_VARIABLE = YES;
-                                ONLY_ACTIVE_ARCH = YES;
-                                PREBINDING = NO;
-                                SDKROOT = "";
-                        };
-                        name = Debug;
-                };
-                C01FCF5008A954540054247B /* Release */ = {
-                        isa = XCBuildConfiguration;
-                        buildSettings = {
-                                ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
-                                GCC_C_LANGUAGE_STANDARD = gnu99;
-                                GCC_WARN_ABOUT_RETURN_TYPE = YES;
-                                GCC_WARN_UNUSED_VARIABLE = YES;
-                                PREBINDING = NO;
-                                SDKROOT = "";
-                        };
-                        name = Release;
-                };
+		C01FCF4B08A954540054247B /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				COPY_PHASE_STRIP = NO;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_ENABLE_FIX_AND_CONTINUE = YES;
+				GCC_MODEL_TUNING = G5;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PRECOMPILE_PREFIX_HEADER = YES;
+				GCC_PREFIX_HEADER = src/JavaAppLauncher_Prefix.pch;
+				INFOPLIST_FILE = "resources/JavaAppLauncher-Info.plist";
+				INSTALL_PATH = "$(HOME)/Applications";
+				LIBRARY_SEARCH_PATHS = "$(inherited)";
+				PRODUCT_NAME = JavaAppLauncher;
+			};
+			name = Debug;
+		};
+		C01FCF4C08A954540054247B /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				GCC_MODEL_TUNING = G5;
+				GCC_PRECOMPILE_PREFIX_HEADER = YES;
+				GCC_PREFIX_HEADER = src/JavaAppLauncher_Prefix.pch;
+				INFOPLIST_FILE = "resources/JavaAppLauncher-Info.plist";
+				INSTALL_PATH = "$(HOME)/Applications";
+				LIBRARY_SEARCH_PATHS = "$(inherited)";
+				PRODUCT_NAME = JavaAppLauncher;
+			};
+			name = Release;
+		};
+		C01FCF4F08A954540054247B /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ARCHS = "$(ARCHS_STANDARD)";
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				PREBINDING = NO;
+				SDKROOT = "";
+				VALID_ARCHS = x86_64;
+			};
+			name = Debug;
+		};
+		C01FCF5008A954540054247B /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ARCHS = "$(ARCHS_STANDARD)";
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				PREBINDING = NO;
+				SDKROOT = "";
+				VALID_ARCHS = x86_64;
+			};
+			name = Release;
+		};
 /* End XCBuildConfiguration section */
 
 /* Begin XCConfigurationList section */
-                C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "JavaAppLauncher" */ = {
-                        isa = XCConfigurationList;
-                        buildConfigurations = (
-                                C01FCF4B08A954540054247B /* Debug */,
-                                C01FCF4C08A954540054247B /* Release */,
-                        );
-                        defaultConfigurationIsVisible = 0;
-                        defaultConfigurationName = Release;
-                };
-                C01FCF4E08A954540054247B /* Build configuration list for PBXProject "JavaAppLauncher" */ = {
-                        isa = XCConfigurationList;
-                        buildConfigurations = (
-                                C01FCF4F08A954540054247B /* Debug */,
-                                C01FCF5008A954540054247B /* Release */,
-                        );
-                        defaultConfigurationIsVisible = 0;
-                        defaultConfigurationName = Release;
-                };
+		C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "JavaAppLauncher" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				C01FCF4B08A954540054247B /* Debug */,
+				C01FCF4C08A954540054247B /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		C01FCF4E08A954540054247B /* Build configuration list for PBXProject "JavaAppLauncher" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				C01FCF4F08A954540054247B /* Debug */,
+				C01FCF5008A954540054247B /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
 /* End XCConfigurationList section */
-        };
-        rootObject = 29B97313FDCFA39411CA2CEA /* Project object */;
+	};
+	rootObject = 29B97313FDCFA39411CA2CEA /* Project object */;
 }
diff --git a/src/macosx/bundle/JavaAppLauncher/resources/JavaAppLauncher-Info.plist b/src/macosx/bundle/JavaAppLauncher/resources/JavaAppLauncher-Info.plist
index a3268bb..dcf6177 100644
--- a/src/macosx/bundle/JavaAppLauncher/resources/JavaAppLauncher-Info.plist
+++ b/src/macosx/bundle/JavaAppLauncher/resources/JavaAppLauncher-Info.plist
@@ -2,47 +2,47 @@
 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
 <dict>
-        <key>CFBundleDevelopmentRegion</key>
-        <string>English</string>
-        <key>CFBundleExecutable</key>
-        <string>${EXECUTABLE_NAME}</string>
-        <key>CFBundleIconFile</key>
-        <string>GenericApp.icns</string>
-        <key>CFBundleIdentifier</key>
-        <string>com.yourcompany.${PRODUCT_NAME:rfc1034identifier}</string>
-        <key>CFBundleDisplayName</key>
-        <string>Your Cool App</string>
-        <key>CFBundleInfoDictionaryVersion</key>
-        <string>6.0</string>
-        <key>CFBundleName</key>
-        <string>${PRODUCT_NAME}</string>
-        <key>CFBundlePackageType</key>
-        <string>APPL</string>
-        <key>CFBundleShortVersionString</key>
-        <string>1.0</string>
-        <key>CFBundleSignature</key>
-        <string>????</string>
-        <key>CFBundleVersion</key>
-        <string>1</string>
-        <key>LSMinimumSystemVersion</key>
-        <string>${MACOSX_DEPLOYMENT_TARGET}</string>
-        <key>NSHumanReadableCopyright</key>
-        <string>Copyright © 2011 Your Company Inc. All Rights Reserved.</string>
-        <key>JVMInfo</key>
-        <dict>
-                <key>JRE</key>
-                <string>1.7.0.jre</string>
-                <key>ClassPath</key>
-                <array/>
-                <key>Properties</key>
-                <dict>
-                        <key>apple.laf.useScreenMenuBar</key>
-                        <string>true</string>
-                </dict>
-                <key>MainClass</key>
-                <string>com.yourcompany.yourapp.mainclass</string>
-                <key>Arguments</key>
-                <array/>
-        </dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>English</string>
+	<key>CFBundleExecutable</key>
+	<string>${EXECUTABLE_NAME}</string>
+	<key>CFBundleIconFile</key>
+	<string>GenericApp.icns</string>
+	<key>CFBundleIdentifier</key>
+	<string>com.yourcompany.${PRODUCT_NAME:rfc1034identifier}</string>
+	<key>CFBundleDisplayName</key>
+	<string>Your Cool App</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>${PRODUCT_NAME}</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>1.0</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>1</string>
+	<key>LSMinimumSystemVersion</key>
+	<string>${MACOSX_DEPLOYMENT_TARGET}</string>
+	<key>NSHumanReadableCopyright</key>
+	<string>Copyright © 2011 Your Company Inc. All Rights Reserved.</string>
+	<key>JVMInfo</key>
+	<dict>
+		<key>JRE</key>
+		<string>jre1.8.0.jre</string>
+		<key>ClassPath</key>
+		<array/>
+		<key>Properties</key>
+		<dict>
+			<key>apple.laf.useScreenMenuBar</key>
+			<string>true</string>
+		</dict>
+		<key>MainClass</key>
+		<string>com.yourcompany.yourapp.mainclass</string>
+		<key>Arguments</key>
+		<array/>
+	</dict>
 </dict>
 </plist>
diff --git a/src/macosx/bundle/JavaAppLauncher/src/JVMArgs.m b/src/macosx/bundle/JavaAppLauncher/src/JVMArgs.m
index 1f4af01..eefaf53 100644
--- a/src/macosx/bundle/JavaAppLauncher/src/JVMArgs.m
+++ b/src/macosx/bundle/JavaAppLauncher/src/JVMArgs.m
@@ -97,9 +97,9 @@
     if (obj == nil) return nil;
     if ([obj isKindOfClass:[NSArray class]]) return obj;
     if (![obj isKindOfClass:[NSString class]]) {
-        [NSException raise:@kArgsFailure format:@"%@", [NSString stringWithFormat:@"Failed to find '%@' array in JVMInfo Info.plist"]];
+        [NSException raise:@kArgsFailure format:@"%@", [NSString stringWithFormat:@"Failed to find '%@' array in JVMInfo Info.plist", key]];
     }
-
+	
     // split
     return [(NSString *)obj componentsSeparatedByString:delimiter];
 }
@@ -194,7 +194,7 @@
     // Sum up all the classpath entries into one big JVM arg
     NSMutableString *classpathOption = [NSMutableString stringWithString:@"-Djava.class.path="];
     [classpath enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
-        if (idx > 1) [classpathOption appendString:@":"];
+        if (idx > 0) [classpathOption appendString:@":"];
         [classpathOption appendString:obj];
     }];
 
diff --git a/src/macosx/classes/sun/lwawt/macosx/CCursorManager.java b/src/macosx/classes/sun/lwawt/macosx/CCursorManager.java
index e4abc5f..2289899 100644
--- a/src/macosx/classes/sun/lwawt/macosx/CCursorManager.java
+++ b/src/macosx/classes/sun/lwawt/macosx/CCursorManager.java
@@ -29,11 +29,10 @@
 
 import java.awt.Cursor;
 import java.awt.Point;
-import java.awt.geom.Point2D;
 
 final class CCursorManager extends LWCursorManager {
 
-    private static native Point2D nativeGetCursorPosition();
+    private static native void nativeGetCursorPosition(int[] pos);
     private static native void nativeSetBuiltInCursor(final int type, final String name);
     private static native void nativeSetCustomCursor(final long imgPtr, final double x, final double y);
     public static native void nativeSetAllowsCursorSetInBackground(final boolean allows);
@@ -51,8 +50,9 @@
 
     @Override
     protected Point getCursorPosition() {
-        final Point2D nativePosition = nativeGetCursorPosition();
-        return new Point((int)nativePosition.getX(), (int)nativePosition.getY());
+        final int [] pos = new int[2];
+        nativeGetCursorPosition(pos);
+        return new Point(pos[0], pos[1]);
     }
 
     @Override
diff --git a/src/macosx/native/sun/awt/CClipboard.m b/src/macosx/native/sun/awt/CClipboard.m
index 543ed20..eaeb8f6 100644
--- a/src/macosx/native/sun/awt/CClipboard.m
+++ b/src/macosx/native/sun/awt/CClipboard.m
@@ -25,6 +25,7 @@
 
 #import "CClipboard.h"
 #import "CDataTransferer.h"
+#include "sun_lwawt_macosx_CDataTransferer.h"
 #import "ThreadUtilities.h"
 #import "jni_util.h" 
 #import <Cocoa/Cocoa.h>
@@ -343,13 +344,22 @@
     }
 
     NSUInteger dataSize = [clipData length];
+    const void *dataBuffer = [clipData bytes];
+    if (format == sun_lwawt_macosx_CDataTransferer_CF_STRING && dataSize >= 3) {
+        const unsigned char *bytesPtr = (const unsigned char *)dataBuffer;
+        if (bytesPtr[0] == 0xEF && bytesPtr[1] == 0xBB && bytesPtr[2] == 0xBF) {
+            // strip BOM from string content, like native applications do
+            dataSize -= 3;
+            dataBuffer = (const void *)(bytesPtr + 3);
+        }
+    }
+
     returnValue = (*env)->NewByteArray(env, dataSize);
     if (returnValue == NULL) {
         return NULL;
     }
 
     if (dataSize != 0) {
-        const void *dataBuffer = [clipData bytes];
         (*env)->SetByteArrayRegion(env, returnValue, 0, dataSize, (jbyte *)dataBuffer);
     }
 
diff --git a/src/macosx/native/sun/awt/CCursorManager.m b/src/macosx/native/sun/awt/CCursorManager.m
index 9581b93..732f7ed 100644
--- a/src/macosx/native/sun/awt/CCursorManager.m
+++ b/src/macosx/native/sun/awt/CCursorManager.m
@@ -110,23 +110,23 @@
 JNF_COCOA_EXIT(env);
 }
 
-JNIEXPORT jobject JNICALL
+JNIEXPORT void JNICALL
 Java_sun_lwawt_macosx_CCursorManager_nativeGetCursorPosition
-(JNIEnv *env, jclass class)
+(JNIEnv *env, jclass class, jintArray jPos)
 {
-    jobject jpt = NULL;
+    jint *pos = (*env)->GetPrimitiveArrayCritical(env, jPos, 0);
+    if (pos == NULL)  return;
 
 JNF_COCOA_ENTER(env);
 
     CGEventRef event = CGEventCreate(NULL);
     CGPoint globalPos = CGEventGetLocation(event);
     CFRelease(event);
-
-    jpt = NSToJavaPoint(env, globalPos);
+    pos[0] = (jint)globalPos.x;
+    pos[1] = (jint)globalPos.y;
 
 JNF_COCOA_EXIT(env);
-
-    return jpt;
+    (*env)->ReleasePrimitiveArrayCritical(env, jPos, pos, 0);
 }
 
 
diff --git a/src/macosx/native/sun/font/AWTStrike.h b/src/macosx/native/sun/font/AWTStrike.h
index 05ef198..905c730 100644
--- a/src/macosx/native/sun/font/AWTStrike.h
+++ b/src/macosx/native/sun/font/AWTStrike.h
@@ -34,6 +34,7 @@
     CGFloat                  fSize;
     JRSFontRenderingStyle    fStyle;
     jint                     fAAStyle;
+    jint                     fFmHint;
 
     CGAffineTransform        fTx;
     CGAffineTransform        fDevTx;
@@ -41,6 +42,6 @@
     CGAffineTransform        fFontTx;
 }
 
-+ (AWTStrike *) awtStrikeForFont:(AWTFont *)awtFont tx:(CGAffineTransform)tx invDevTx:(CGAffineTransform)invDevTx style:(JRSFontRenderingStyle)style aaStyle:(jint)aaStyle;
++ (AWTStrike *) awtStrikeForFont:(AWTFont *)awtFont tx:(CGAffineTransform)tx invDevTx:(CGAffineTransform)invDevTx style:(JRSFontRenderingStyle)style aaStyle:(jint)aaStyle fmHint:(jint)fmHint;
 
 @end
diff --git a/src/macosx/native/sun/font/AWTStrike.m b/src/macosx/native/sun/font/AWTStrike.m
index b854d5b..86d2c0b 100644
--- a/src/macosx/native/sun/font/AWTStrike.m
+++ b/src/macosx/native/sun/font/AWTStrike.m
@@ -45,13 +45,15 @@
                  tx:(CGAffineTransform)tx
            invDevTx:(CGAffineTransform)invDevTx
               style:(JRSFontRenderingStyle)style
-            aaStyle:(jint)aaStyle {
+            aaStyle:(jint)aaStyle
+             fmHint:(jint)fmHint {
 
     self = [super init];
     if (self) {
         fAWTFont = [awtFont retain];
         fStyle = style;
         fAAStyle = aaStyle;
+        fFmHint = fmHint;
 
         fTx = tx; // composited glyph and device transform
 
@@ -81,12 +83,14 @@
                               tx:(CGAffineTransform)tx
                         invDevTx:(CGAffineTransform)invDevTx
                            style:(JRSFontRenderingStyle)style
-                         aaStyle:(jint)aaStyle {
+                         aaStyle:(jint)aaStyle
+                          fmHint:(jint)fmHint {
 
     return [[[AWTStrike alloc] initWithFont:awtFont
                                          tx:tx invDevTx:invDevTx
                                       style:style
-                                    aaStyle:aaStyle] autorelease];
+                                    aaStyle:aaStyle
+                                     fmHint:fmHint] autorelease];
 }
 
 @end
@@ -420,7 +424,7 @@
     CGAffineTransform glyphTx = GetTxFromDoubles(env, glyphTxArray);
     CGAffineTransform invDevTx = GetTxFromDoubles(env, invDevTxArray);
 
-    awtStrike = [AWTStrike awtStrikeForFont:awtFont tx:glyphTx invDevTx:invDevTx style:style aaStyle:aaStyle]; // autoreleased
+    awtStrike = [AWTStrike awtStrikeForFont:awtFont tx:glyphTx invDevTx:invDevTx style:style aaStyle:aaStyle fmHint:fmHint]; // autoreleased
 
     if (awtStrike)
     {
diff --git a/src/macosx/native/sun/font/CGGlyphImages.m b/src/macosx/native/sun/font/CGGlyphImages.m
index 48027c4..2268bc5 100644
--- a/src/macosx/native/sun/font/CGGlyphImages.m
+++ b/src/macosx/native/sun/font/CGGlyphImages.m
@@ -583,14 +583,17 @@
     }
     advance = CGGI_ScaleAdvance(advance, strike);
 
+    int imageBytes = height * width * pixelSize;
+    int extraPixelStorage = (strike->fAAStyle == sun_awt_SunHints_INTVAL_TEXT_ANTIALIAS_LCD_HRGB &&
+                             strike->fFmHint == sun_awt_SunHints_INTVAL_FRACTIONALMETRICS_ON) ? 3 : 0;
+
 #ifdef USE_IMAGE_ALIGNED_MEMORY
     // create separate memory
     GlyphInfo *glyphInfo = (GlyphInfo *)malloc(sizeof(GlyphInfo));
-    void *image = (void *)malloc(height * width * pixelSize);
+    void *image = (void *)malloc(imageBytes + extraPixelStorage);
 #else
     // create a GlyphInfo struct fused to the image it points to
-    GlyphInfo *glyphInfo = (GlyphInfo *)malloc(sizeof(GlyphInfo) +
-                                               height * width * pixelSize);
+    GlyphInfo *glyphInfo = (GlyphInfo *)malloc(sizeof(GlyphInfo) + imageBytes + extraPixelStorage);
 #endif
 
     glyphInfo->advanceX = advance.width;
@@ -608,6 +611,9 @@
     glyphInfo->image = ((void *)glyphInfo) + sizeof(GlyphInfo);
 #endif
 
+    int i;
+    for (i = 0; i < extraPixelStorage; i++) (glyphInfo->image)[imageBytes + i] = 0;
+
     return glyphInfo;
 }
 
diff --git a/src/share/classes/javax/swing/RepaintManager.java b/src/share/classes/javax/swing/RepaintManager.java
index 4fd122f..d656880 100644
--- a/src/share/classes/javax/swing/RepaintManager.java
+++ b/src/share/classes/javax/swing/RepaintManager.java
@@ -112,6 +112,8 @@
 
     private Dimension doubleBufferMaxSize;
 
+    private boolean isCustomMaxBufferSizeSet = false;
+
     // Support for both the standard and volatile offscreen buffers exists to
     // provide backwards compatibility for the [rare] programs which may be
     // calling getOffScreenBuffer() and not expecting to get a VolatileImage.
@@ -337,11 +339,13 @@
     }
 
     private void displayChanged() {
-        clearImages();
-
-        // Reset buffer maximum size to get valid size from updated graphics
-        // environment in getDoubleBufferMaximumSize()
-        setDoubleBufferMaximumSize(null);
+        if (isCustomMaxBufferSizeSet) {
+            clearImages();
+        } else {
+            // Reset buffer maximum size to get valid size from updated graphics
+            // environment in getDoubleBufferMaximumSize()
+            setDoubleBufferMaximumSize(null);
+        }
     }
 
     /**
@@ -838,24 +842,27 @@
                                                            localBoundsW,
                                                            localBoundsH,
                                                            rect);
-                        if (dirtyComponent instanceof JComponent) {
-                            ((JComponent)dirtyComponent).paintImmediately(
-                                rect.x,rect.y,rect.width, rect.height);
-                        }
-                        else if (dirtyComponent.isShowing()) {
-                            Graphics g = JComponent.safelyGetGraphics(
-                                    dirtyComponent, dirtyComponent);
-                            // If the Graphics goes away, it means someone disposed of
-                            // the window, don't do anything.
-                            if (g != null) {
-                                g.setClip(rect.x, rect.y, rect.width, rect.height);
-                                try {
-                                    dirtyComponent.paint(g);
-                                } finally {
-                                    g.dispose();
+
+                        if (!rect.isEmpty()) {
+                            if (dirtyComponent instanceof JComponent) {
+                                ((JComponent) dirtyComponent).paintImmediately(
+                                        rect.x, rect.y, rect.width, rect.height);
+                            } else if (dirtyComponent.isShowing()) {
+                                Graphics g = JComponent.safelyGetGraphics(
+                                        dirtyComponent, dirtyComponent);
+                                // If the Graphics goes away, it means someone disposed of
+                                // the window, don't do anything.
+                                if (g != null) {
+                                    g.setClip(rect.x, rect.y, rect.width, rect.height);
+                                    try {
+                                        dirtyComponent.paint(g);
+                                    } finally {
+                                        g.dispose();
+                                    }
                                 }
                             }
                         }
+
                         // If the repaintRoot has been set, service it now and
                         // remove any components that are children of repaintRoot.
                         if (repaintRoot != null) {
@@ -1126,8 +1133,10 @@
     public void setDoubleBufferMaximumSize(Dimension d) {
         doubleBufferMaxSize = d;
         if (doubleBufferMaxSize == null) {
+            isCustomMaxBufferSizeSet = false;
             clearImages();
         } else {
+            isCustomMaxBufferSizeSet = true;
             clearImages(d.width, d.height);
         }
     }
diff --git a/src/share/classes/sun/java2d/loops/GraphicsPrimitive.java b/src/share/classes/sun/java2d/loops/GraphicsPrimitive.java
index 93d8e05..24f1bedb 100644
--- a/src/share/classes/sun/java2d/loops/GraphicsPrimitive.java
+++ b/src/share/classes/sun/java2d/loops/GraphicsPrimitive.java
@@ -320,6 +320,7 @@
 
     public static int traceflags;
     public static String tracefile;
+    public static String pname;
     public static PrintStream traceout;
     public static long treshold = 0;
     public static boolean verbose = false;
@@ -328,10 +329,11 @@
     public static final int TRACETIMESTAMP = 2;
     public static final int TRACECOUNTS = 4;
     public static final int TRACEPTIME = 8;
+    public static final int TRACEPNAME = 16;
 
     static void showTraceUsage() {
         System.err.println("usage: -Dsun.java2d.trace="+
-                "[log[,timestamp]],[count],[ptime],"+
+                "[log[,timestamp]],[count],[ptime],[name:<substr pattern>],"+
                 "[out:<filename>],[td=<treshold>],[help],[verbose]");
     }
 
@@ -351,6 +353,9 @@
                     traceflags |= GraphicsPrimitive.TRACETIMESTAMP;
                 } else if (tok.equalsIgnoreCase("ptime")) {
                     traceflags |=GraphicsPrimitive.TRACEPTIME;
+                } else if (tok.regionMatches(true, 0, "name:", 0, 5)) {
+                    traceflags |=GraphicsPrimitive.TRACEPNAME;
+                    pname = tok.substring(6);
                 } else if (tok.equalsIgnoreCase("verbose")) {
                     verbose = true;
                 } else if (tok.regionMatches(true, 0, "out:", 0, 4)) {
@@ -368,6 +373,9 @@
                     showTraceUsage();
                 }
             }
+
+            GraphicsPrimitiveMgr.setTraceFlags(traceflags);
+
             if (verbose) {
                 System.err.print("GraphicsPrimitive logging ");
                 if ((traceflags & GraphicsPrimitive.TRACELOG) != 0) {
@@ -467,6 +475,10 @@
     }
 
     public synchronized static void tracePrimitive(Object prim) {
+        if ((traceflags & TRACEPNAME) != 0) {
+            if (!prim.toString().contains(pname)) return;
+        }
+
         if ((traceflags & TRACECOUNTS) != 0) {
             if (traceMap == null) {
                 traceMap = new HashMap();
@@ -489,6 +501,9 @@
     }
 
     public synchronized static void tracePrimitiveTime(Object prim, long time) {
+        if ((traceflags & TRACEPNAME) != 0) {
+            if (!prim.toString().contains(pname)) return;
+        }
         if (time > treshold && (traceflags & TRACEPTIME) != 0  && (traceflags & TRACELOG) != 0) {
             PrintStream ps = getTraceOutputFile();
             ps.println(prim + " time: " + time);
diff --git a/src/share/classes/sun/java2d/loops/GraphicsPrimitiveMgr.java b/src/share/classes/sun/java2d/loops/GraphicsPrimitiveMgr.java
index 6f76f54..faa9383 100644
--- a/src/share/classes/sun/java2d/loops/GraphicsPrimitiveMgr.java
+++ b/src/share/classes/sun/java2d/loops/GraphicsPrimitiveMgr.java
@@ -51,6 +51,7 @@
                                        Class Path2D, Class Path2DFloat,
                                        Class SHints);
     private static native void registerNativeLoops();
+    static native void setTraceFlags(int traceflags);
 
     static {
         initIDs(GraphicsPrimitive.class,
diff --git a/src/share/classes/sun/java2d/marlin/ArrayCache.java b/src/share/classes/sun/java2d/marlin/ArrayCache.java
deleted file mode 100644
index 5f36e0d..0000000
--- a/src/share/classes/sun/java2d/marlin/ArrayCache.java
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.java2d.marlin;
-
-import java.util.Arrays;
-import static sun.java2d.marlin.MarlinUtils.logInfo;
-
-public final class ArrayCache implements MarlinConst {
-
-    static final int BUCKETS = 4;
-    static final int MIN_ARRAY_SIZE = 4096;
-    static final int MAX_ARRAY_SIZE;
-    static final int MASK_CLR_1 = ~1;
-    // threshold to grow arrays only by (3/2) instead of 2
-    static final int THRESHOLD_ARRAY_SIZE;
-    static final int[] ARRAY_SIZES = new int[BUCKETS];
-    // dirty byte array sizes
-    static final int MIN_DIRTY_BYTE_ARRAY_SIZE = 32 * 2048; // 32px x 2048px
-    static final int MAX_DIRTY_BYTE_ARRAY_SIZE;
-    static final int[] DIRTY_BYTE_ARRAY_SIZES = new int[BUCKETS];
-    // large array thresholds:
-    static final long THRESHOLD_LARGE_ARRAY_SIZE;
-    static final long THRESHOLD_HUGE_ARRAY_SIZE;
-    // stats
-    private static int resizeInt = 0;
-    private static int resizeDirtyInt = 0;
-    private static int resizeDirtyFloat = 0;
-    private static int resizeDirtyByte = 0;
-    private static int oversize = 0;
-
-    static {
-        // initialize buckets for int/float arrays
-        int arraySize = MIN_ARRAY_SIZE;
-
-        for (int i = 0; i < BUCKETS; i++, arraySize <<= 2) {
-            ARRAY_SIZES[i] = arraySize;
-
-            if (DO_TRACE) {
-                logInfo("arraySize[" + i + "]: " + arraySize);
-            }
-        }
-        MAX_ARRAY_SIZE = arraySize >> 2;
-
-        /* initialize buckets for dirty byte arrays
-         (large AA chunk = 32 x 2048 pixels) */
-        arraySize = MIN_DIRTY_BYTE_ARRAY_SIZE;
-
-        for (int i = 0; i < BUCKETS; i++, arraySize <<= 1) {
-            DIRTY_BYTE_ARRAY_SIZES[i] = arraySize;
-
-            if (DO_TRACE) {
-                logInfo("dirty arraySize[" + i + "]: " + arraySize);
-            }
-        }
-        MAX_DIRTY_BYTE_ARRAY_SIZE = arraySize >> 1;
-
-        // threshold to grow arrays only by (3/2) instead of 2
-        THRESHOLD_ARRAY_SIZE = Math.max(2 * 1024 * 1024, MAX_ARRAY_SIZE); // 2M
-
-        THRESHOLD_LARGE_ARRAY_SIZE = 8L * THRESHOLD_ARRAY_SIZE; // 16M
-        THRESHOLD_HUGE_ARRAY_SIZE  = 8L * THRESHOLD_LARGE_ARRAY_SIZE; // 128M
-
-        if (DO_STATS || DO_MONITORS) {
-            logInfo("ArrayCache.BUCKETS        = " + BUCKETS);
-            logInfo("ArrayCache.MIN_ARRAY_SIZE = " + MIN_ARRAY_SIZE);
-            logInfo("ArrayCache.MAX_ARRAY_SIZE = " + MAX_ARRAY_SIZE);
-            logInfo("ArrayCache.ARRAY_SIZES = "
-                    + Arrays.toString(ARRAY_SIZES));
-            logInfo("ArrayCache.MIN_DIRTY_BYTE_ARRAY_SIZE = "
-                    + MIN_DIRTY_BYTE_ARRAY_SIZE);
-            logInfo("ArrayCache.MAX_DIRTY_BYTE_ARRAY_SIZE = "
-                    + MAX_DIRTY_BYTE_ARRAY_SIZE);
-            logInfo("ArrayCache.ARRAY_SIZES = "
-                    + Arrays.toString(DIRTY_BYTE_ARRAY_SIZES));
-            logInfo("ArrayCache.THRESHOLD_ARRAY_SIZE = "
-                    + THRESHOLD_ARRAY_SIZE);
-            logInfo("ArrayCache.THRESHOLD_LARGE_ARRAY_SIZE = "
-                    + THRESHOLD_LARGE_ARRAY_SIZE);
-            logInfo("ArrayCache.THRESHOLD_HUGE_ARRAY_SIZE = "
-                    + THRESHOLD_HUGE_ARRAY_SIZE);
-        }
-    }
-
-    private ArrayCache() {
-        // Utility class
-    }
-
-    static synchronized void incResizeInt() {
-        resizeInt++;
-    }
-
-    static synchronized void incResizeDirtyInt() {
-        resizeDirtyInt++;
-    }
-
-    static synchronized void incResizeDirtyFloat() {
-        resizeDirtyFloat++;
-    }
-
-    static synchronized void incResizeDirtyByte() {
-        resizeDirtyByte++;
-    }
-
-    static synchronized void incOversize() {
-        oversize++;
-    }
-
-    static void dumpStats() {
-        if (resizeInt != 0 || resizeDirtyInt != 0 || resizeDirtyFloat != 0
-                || resizeDirtyByte != 0 || oversize != 0) {
-            logInfo("ArrayCache: int resize: " + resizeInt
-                    + " - dirty int resize: " + resizeDirtyInt
-                    + " - dirty float resize: " + resizeDirtyFloat
-                    + " - dirty byte resize: " + resizeDirtyByte
-                    + " - oversize: " + oversize);
-        }
-    }
-
-    // small methods used a lot (to be inlined / optimized by hotspot)
-
-    static int getBucket(final int length) {
-        for (int i = 0; i < ARRAY_SIZES.length; i++) {
-            if (length <= ARRAY_SIZES[i]) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
-    static int getBucketDirtyBytes(final int length) {
-        for (int i = 0; i < DIRTY_BYTE_ARRAY_SIZES.length; i++) {
-            if (length <= DIRTY_BYTE_ARRAY_SIZES[i]) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
-    /**
-     * Return the new array size (~ x2)
-     * @param curSize current used size
-     * @param needSize needed size
-     * @return new array size
-     */
-    public static int getNewSize(final int curSize, final int needSize) {
-        // check if needSize is negative or integer overflow:
-        if (needSize < 0) {
-            // hard overflow failure - we can't even accommodate
-            // new items without overflowing
-            throw new ArrayIndexOutOfBoundsException(
-                          "array exceeds maximum capacity !");
-        }
-        assert curSize >= 0;
-        final int initial = (curSize & MASK_CLR_1);
-        int size;
-        if (initial > THRESHOLD_ARRAY_SIZE) {
-            size = initial + (initial >> 1); // x(3/2)
-        } else {
-            size = (initial << 1); // x2
-        }
-        // ensure the new size is >= needed size:
-        if (size < needSize) {
-            // align to 4096 (may overflow):
-            size = ((needSize >> 12) + 1) << 12;
-        }
-        // check integer overflow:
-        if (size < 0) {
-            // resize to maximum capacity:
-            size = Integer.MAX_VALUE;
-        }
-        return size;
-    }
-
-    /**
-     * Return the new array size (~ x2)
-     * @param curSize current used size
-     * @param needSize needed size
-     * @return new array size
-     */
-    public static long getNewLargeSize(final long curSize, final long needSize) {
-        // check if needSize is negative or integer overflow:
-        if ((needSize >> 31L) != 0L) {
-            // hard overflow failure - we can't even accommodate
-            // new items without overflowing
-            throw new ArrayIndexOutOfBoundsException(
-                          "array exceeds maximum capacity !");
-        }
-        assert curSize >= 0L;
-        long size;
-        if (curSize > THRESHOLD_HUGE_ARRAY_SIZE) {
-            size = curSize + (curSize >> 2L); // x(5/4)
-        } else  if (curSize > THRESHOLD_LARGE_ARRAY_SIZE) {
-            size = curSize + (curSize >> 1L); // x(3/2)
-        } else {
-            size = (curSize << 1L); // x2
-        }
-        // ensure the new size is >= needed size:
-        if (size < needSize) {
-            // align to 4096:
-            size = ((needSize >> 12L) + 1L) << 12L;
-        }
-        // check integer overflow:
-        if (size > Integer.MAX_VALUE) {
-            // resize to maximum capacity:
-            size = Integer.MAX_VALUE;
-        }
-        return size;
-    }
-}
diff --git a/src/share/classes/sun/java2d/marlin/ArrayCacheConst.java b/src/share/classes/sun/java2d/marlin/ArrayCacheConst.java
new file mode 100644
index 0000000..2c0cfe2
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/ArrayCacheConst.java
@@ -0,0 +1,275 @@
+/*
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d.marlin;
+
+import java.util.Arrays;
+import static sun.java2d.marlin.MarlinUtils.logInfo;
+
+public final class ArrayCacheConst implements MarlinConst {
+
+    static final int BUCKETS = 8;
+    static final int MIN_ARRAY_SIZE = 4096;
+    // maximum array size
+    static final int MAX_ARRAY_SIZE;
+    // threshold below to grow arrays by 4
+    static final int THRESHOLD_SMALL_ARRAY_SIZE = 4 * 1024 * 1024;
+    // threshold to grow arrays only by (3/2) instead of 2
+    static final int THRESHOLD_ARRAY_SIZE;
+    // threshold to grow arrays only by (5/4) instead of (3/2)
+    static final long THRESHOLD_HUGE_ARRAY_SIZE;
+    static final int[] ARRAY_SIZES = new int[BUCKETS];
+
+    static {
+        // initialize buckets for int/float arrays
+        int arraySize = MIN_ARRAY_SIZE;
+
+        int inc_lg = 2; // x4
+
+        for (int i = 0; i < BUCKETS; i++, arraySize <<= inc_lg) {
+            ARRAY_SIZES[i] = arraySize;
+
+            if (DO_TRACE) {
+                logInfo("arraySize[" + i + "]: " + arraySize);
+            }
+
+            if (arraySize >= THRESHOLD_SMALL_ARRAY_SIZE) {
+                inc_lg = 1; // x2
+            }
+        }
+        MAX_ARRAY_SIZE = arraySize >> inc_lg;
+
+        if (MAX_ARRAY_SIZE <= 0) {
+            throw new IllegalStateException("Invalid max array size !");
+        }
+
+        THRESHOLD_ARRAY_SIZE       =  16  * 1024 * 1024; // >16M
+        THRESHOLD_HUGE_ARRAY_SIZE  =  48L * 1024 * 1024; // >48M
+
+        if (DO_STATS || DO_MONITORS) {
+            logInfo("ArrayCache.BUCKETS        = " + BUCKETS);
+            logInfo("ArrayCache.MIN_ARRAY_SIZE = " + MIN_ARRAY_SIZE);
+            logInfo("ArrayCache.MAX_ARRAY_SIZE = " + MAX_ARRAY_SIZE);
+            logInfo("ArrayCache.ARRAY_SIZES = "
+                    + Arrays.toString(ARRAY_SIZES));
+            logInfo("ArrayCache.THRESHOLD_ARRAY_SIZE = "
+                    + THRESHOLD_ARRAY_SIZE);
+            logInfo("ArrayCache.THRESHOLD_HUGE_ARRAY_SIZE = "
+                    + THRESHOLD_HUGE_ARRAY_SIZE);
+        }
+    }
+
+    private ArrayCacheConst() {
+        // Utility class
+    }
+
+    // small methods used a lot (to be inlined / optimized by hotspot)
+
+    static int getBucket(final int length) {
+        for (int i = 0; i < ARRAY_SIZES.length; i++) {
+            if (length <= ARRAY_SIZES[i]) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Return the new array size (~ x2)
+     * @param curSize current used size
+     * @param needSize needed size
+     * @return new array size
+     */
+    public static int getNewSize(final int curSize, final int needSize) {
+        // check if needSize is negative or integer overflow:
+        if (needSize < 0) {
+            // hard overflow failure - we can't even accommodate
+            // new items without overflowing
+            throw new ArrayIndexOutOfBoundsException(
+                          "array exceeds maximum capacity !");
+        }
+        assert curSize >= 0;
+        final int initial = curSize;
+        int size;
+        if (initial > THRESHOLD_ARRAY_SIZE) {
+            size = initial + (initial >> 1); // x(3/2)
+        } else {
+            size = (initial << 1); // x2
+        }
+        // ensure the new size is >= needed size:
+        if (size < needSize) {
+            // align to 4096 (may overflow):
+            size = ((needSize >> 12) + 1) << 12;
+        }
+        // check integer overflow:
+        if (size < 0) {
+            // resize to maximum capacity:
+            size = Integer.MAX_VALUE;
+        }
+        return size;
+    }
+
+    /**
+     * Return the new array size (~ x2)
+     * @param curSize current used size
+     * @param needSize needed size
+     * @return new array size
+     */
+    public static long getNewLargeSize(final long curSize, final long needSize) {
+        // check if needSize is negative or integer overflow:
+        if ((needSize >> 31L) != 0L) {
+            // hard overflow failure - we can't even accommodate
+            // new items without overflowing
+            throw new ArrayIndexOutOfBoundsException(
+                          "array exceeds maximum capacity !");
+        }
+        assert curSize >= 0L;
+        long size;
+        if (curSize > THRESHOLD_HUGE_ARRAY_SIZE) {
+            size = curSize + (curSize >> 2L); // x(5/4)
+        } else if (curSize > THRESHOLD_ARRAY_SIZE) {
+            size = curSize + (curSize >> 1L); // x(3/2)
+        } else if (curSize > THRESHOLD_SMALL_ARRAY_SIZE) {
+            size = (curSize << 1L); // x2
+        } else {
+            size = (curSize << 2L); // x4
+        }
+        // ensure the new size is >= needed size:
+        if (size < needSize) {
+            // align to 4096:
+            size = ((needSize >> 12L) + 1L) << 12L;
+        }
+        // check integer overflow:
+        if (size > Integer.MAX_VALUE) {
+            // resize to maximum capacity:
+            size = Integer.MAX_VALUE;
+        }
+        return size;
+    }
+
+    static final class CacheStats {
+        final String name;
+        final BucketStats[] bucketStats;
+        int resize = 0;
+        int oversize = 0;
+        long totalInitial = 0L;
+
+        CacheStats(final String name) {
+            this.name = name;
+
+            bucketStats = new BucketStats[BUCKETS];
+            for (int i = 0; i < BUCKETS; i++) {
+                bucketStats[i] = new BucketStats();
+            }
+        }
+
+        void reset() {
+            resize = 0;
+            oversize = 0;
+
+            for (int i = 0; i < BUCKETS; i++) {
+                bucketStats[i].reset();
+            }
+        }
+
+        long dumpStats() {
+            long totalCacheBytes = 0L;
+
+            if (DO_STATS) {
+                for (int i = 0; i < BUCKETS; i++) {
+                    final BucketStats s = bucketStats[i];
+
+                    if (s.maxSize != 0) {
+                        totalCacheBytes += getByteFactor()
+                                           * (s.maxSize * ARRAY_SIZES[i]);
+                    }
+                }
+
+                if (totalInitial != 0L || totalCacheBytes != 0L
+                    || resize != 0 || oversize != 0)
+                {
+                    logInfo(name + ": resize: " + resize
+                            + " - oversize: " + oversize
+                            + " - initial: " + getTotalInitialBytes()
+                            + " bytes (" + totalInitial + " elements)"
+                            + " - cache: " + totalCacheBytes + " bytes"
+                    );
+                }
+
+                if (totalCacheBytes != 0L) {
+                    logInfo(name + ": usage stats:");
+
+                    for (int i = 0; i < BUCKETS; i++) {
+                        final BucketStats s = bucketStats[i];
+
+                        if (s.getOp != 0) {
+                            logInfo("  Bucket[" + ARRAY_SIZES[i] + "]: "
+                                    + "get: " + s.getOp
+                                    + " - put: " + s.returnOp
+                                    + " - create: " + s.createOp
+                                    + " :: max size: " + s.maxSize
+                            );
+                        }
+                    }
+                }
+            }
+            return totalCacheBytes;
+        }
+
+        private int getByteFactor() {
+            int factor = 1;
+            if (name.contains("Int") || name.contains("Float")) {
+                factor = 4;
+            } else if (name.contains("Double")) {
+                factor = 8;
+            }
+            return factor;
+        }
+
+        long getTotalInitialBytes() {
+            return getByteFactor() * totalInitial;
+        }
+    }
+
+    static final class BucketStats {
+        int getOp = 0;
+        int createOp = 0;
+        int returnOp = 0;
+        int maxSize = 0;
+
+        void reset() {
+            getOp = 0;
+            createOp = 0;
+            returnOp = 0;
+            maxSize = 0;
+        }
+
+        void updateMaxSize(final int size) {
+            if (size > maxSize) {
+                maxSize = size;
+            }
+        }
+    }
+}
diff --git a/src/share/classes/sun/java2d/marlin/ByteArrayCache.java b/src/share/classes/sun/java2d/marlin/ByteArrayCache.java
index 7854795..0b7e370 100644
--- a/src/share/classes/sun/java2d/marlin/ByteArrayCache.java
+++ b/src/share/classes/sun/java2d/marlin/ByteArrayCache.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, 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
@@ -25,106 +25,219 @@
 
 package sun.java2d.marlin;
 
-import java.util.ArrayDeque;
-import java.util.Arrays;
-import static sun.java2d.marlin.MarlinUtils.logException;
+import static sun.java2d.marlin.ArrayCacheConst.ARRAY_SIZES;
+import static sun.java2d.marlin.ArrayCacheConst.BUCKETS;
+import static sun.java2d.marlin.ArrayCacheConst.MAX_ARRAY_SIZE;
 import static sun.java2d.marlin.MarlinUtils.logInfo;
+import static sun.java2d.marlin.MarlinUtils.logException;
+
+import java.lang.ref.WeakReference;
+import java.util.Arrays;
+
+import sun.java2d.marlin.ArrayCacheConst.BucketStats;
+import sun.java2d.marlin.ArrayCacheConst.CacheStats;
+
+/*
+ * Note that the [BYTE/INT/FLOAT/DOUBLE]ArrayCache files are nearly identical except
+ * for a few type and name differences. Typically, the [BYTE]ArrayCache.java file
+ * is edited manually and then [INT/FLOAT/DOUBLE]ArrayCache.java
+ * files are generated with the following command lines:
+ */
+// % sed -e 's/(b\yte)[ ]*//g' -e 's/b\yte/int/g' -e 's/B\yte/Int/g' < B\yteArrayCache.java > IntArrayCache.java
+// % sed -e 's/(b\yte)[ ]*0/0.0f/g' -e 's/(b\yte)[ ]*/(float) /g' -e 's/b\yte/float/g' -e 's/B\yte/Float/g' < B\yteArrayCache.java > FloatArrayCache.java
+// % sed -e 's/(b\yte)[ ]*0/0.0d/g' -e 's/(b\yte)[ ]*/(double) /g' -e 's/b\yte/double/g' -e 's/B\yte/Double/g' < B\yteArrayCache.java > DoubleArrayCache.java
 
 final class ByteArrayCache implements MarlinConst {
 
-    private final int arraySize;
-    private final ArrayDeque<byte[]> byteArrays;
-    // stats
-    private int getOp = 0;
-    private int createOp = 0;
-    private int returnOp = 0;
+    final boolean clean;
+    private final int bucketCapacity;
+    private WeakReference<Bucket[]> refBuckets = null;
+    final CacheStats stats;
 
-    void dumpStats() {
-        if (getOp > 0) {
-            logInfo("ByteArrayCache[" + arraySize + "]: get: " + getOp
-                    + " created: " + createOp + " - returned: " + returnOp
-                    + " :: cache size: " + byteArrays.size());
-        }
+    ByteArrayCache(final boolean clean, final int bucketCapacity) {
+        this.clean = clean;
+        this.bucketCapacity = bucketCapacity;
+        this.stats = (DO_STATS) ?
+            new CacheStats(getLogPrefix(clean) + "ByteArrayCache") : null;
     }
 
-    ByteArrayCache(final int arraySize) {
-        this.arraySize = arraySize;
-        // small but enough: almost 1 cache line
-        this.byteArrays = new ArrayDeque<byte[]>(6);
+    Bucket getCacheBucket(final int length) {
+        final int bucket = ArrayCacheConst.getBucket(length);
+        return getBuckets()[bucket];
     }
 
-    byte[] getArray() {
-        if (DO_STATS) {
-            getOp++;
-        }
+    private Bucket[] getBuckets() {
+        // resolve reference:
+        Bucket[] buckets = (refBuckets != null) ? refBuckets.get() : null;
 
-        // use cache:
-        final byte[] array = byteArrays.pollLast();
-        if (array != null) {
-            return array;
-        }
+        // create a new buckets ?
+        if (buckets == null) {
+            buckets = new Bucket[BUCKETS];
 
-        if (DO_STATS) {
-            createOp++;
-        }
-
-        return new byte[arraySize];
-    }
-
-    void putDirtyArray(final byte[] array, final int length) {
-        if (length != arraySize) {
-            if (DO_CHECKS) {
-                MarlinUtils.logInfo("ArrayCache: bad length = " + length);
+            for (int i = 0; i < BUCKETS; i++) {
+                buckets[i] = new Bucket(clean, ARRAY_SIZES[i], bucketCapacity,
+                        (DO_STATS) ? stats.bucketStats[i] : null);
             }
-            return;
-        }
-        if (DO_STATS) {
-            returnOp++;
-        }
 
-        // NO clean-up of array data = DIRTY ARRAY
-
-        if (DO_CLEAN_DIRTY) {
-            // Force zero-fill dirty arrays:
-            Arrays.fill(array, 0, array.length, BYTE_0);
+            // update weak reference:
+            refBuckets = new WeakReference<Bucket[]>(buckets);
         }
-
-        // fill cache:
-        byteArrays.addLast(array);
+        return buckets;
     }
 
-    void putArray(final byte[] array, final int length,
-                  final int fromIndex, final int toIndex)
-    {
-        if (length != arraySize) {
-            if (DO_CHECKS) {
-                MarlinUtils.logInfo("ArrayCache: bad length = " + length);
+    Reference createRef(final int initialSize) {
+        return new Reference(this, initialSize);
+    }
+
+    static final class Reference {
+
+        // initial array reference (direct access)
+        final byte[] initial;
+        private final boolean clean;
+        private final ByteArrayCache cache;
+
+        Reference(final ByteArrayCache cache, final int initialSize) {
+            this.cache = cache;
+            this.clean = cache.clean;
+            this.initial = createArray(initialSize);
+            if (DO_STATS) {
+                cache.stats.totalInitial += initialSize;
             }
-            return;
-        }
-        if (DO_STATS) {
-            returnOp++;
         }
 
-        // clean-up array of dirty part[fromIndex; toIndex[
-        fill(array, fromIndex, toIndex, BYTE_0);
+        byte[] getArray(final int length) {
+            if (length <= MAX_ARRAY_SIZE) {
+                return cache.getCacheBucket(length).getArray();
+            }
+            if (DO_STATS) {
+                cache.stats.oversize++;
+            }
+            if (DO_LOG_OVERSIZE) {
+                logInfo(getLogPrefix(clean) + "ByteArrayCache: "
+                        + "getArray[oversize]: length=\t" + length);
+            }
+            return createArray(length);
+        }
 
-        // fill cache:
-        byteArrays.addLast(array);
+        byte[] widenArray(final byte[] array, final int usedSize,
+                          final int needSize)
+        {
+            final int length = array.length;
+            if (DO_CHECKS && length >= needSize) {
+                return array;
+            }
+            if (DO_STATS) {
+                cache.stats.resize++;
+            }
+
+            // maybe change bucket:
+            // ensure getNewSize() > newSize:
+            final byte[] res = getArray(ArrayCacheConst.getNewSize(usedSize, needSize));
+
+            // use wrapper to ensure proper copy:
+            System.arraycopy(array, 0, res, 0, usedSize); // copy only used elements
+
+            // maybe return current array:
+            putArray(array, 0, usedSize); // ensure array is cleared
+
+            if (DO_LOG_WIDEN_ARRAY) {
+                logInfo(getLogPrefix(clean) + "ByteArrayCache: "
+                        + "widenArray[" + res.length
+                        + "]: usedSize=\t" + usedSize + "\tlength=\t" + length
+                        + "\tneeded length=\t" + needSize);
+            }
+            return res;
+        }
+
+        byte[] putArray(final byte[] array)
+        {
+            // dirty array helper:
+            return putArray(array, 0, array.length);
+        }
+
+        byte[] putArray(final byte[] array, final int fromIndex,
+                        final int toIndex)
+        {
+            if (array.length <= MAX_ARRAY_SIZE) {
+                if ((clean || DO_CLEAN_DIRTY) && (toIndex != 0)) {
+                    // clean-up array of dirty part[fromIndex; toIndex[
+                    fill(array, fromIndex, toIndex, (byte)0);
+                }
+                // ensure to never store initial arrays in cache:
+                if (array != initial) {
+                    cache.getCacheBucket(array.length).putArray(array);
+                }
+            }
+            return initial;
+        }
+    }
+
+    static final class Bucket {
+
+        private int tail = 0;
+        private final int arraySize;
+        private final boolean clean;
+        private final byte[][] arrays;
+        private final BucketStats stats;
+
+        Bucket(final boolean clean, final int arraySize,
+               final int capacity, final BucketStats stats)
+        {
+            this.arraySize = arraySize;
+            this.clean = clean;
+            this.stats = stats;
+            this.arrays = new byte[capacity][];
+        }
+
+        byte[] getArray() {
+            if (DO_STATS) {
+                stats.getOp++;
+            }
+            // use cache:
+            if (tail != 0) {
+                final byte[] array = arrays[--tail];
+                arrays[tail] = null;
+                return array;
+            }
+            if (DO_STATS) {
+                stats.createOp++;
+            }
+            return createArray(arraySize);
+        }
+
+        void putArray(final byte[] array)
+        {
+            if (DO_CHECKS && (array.length != arraySize)) {
+                logInfo(getLogPrefix(clean) + "ByteArrayCache: "
+                        + "bad length = " + array.length);
+                return;
+            }
+            if (DO_STATS) {
+                stats.returnOp++;
+            }
+            // fill cache:
+            if (arrays.length > tail) {
+                arrays[tail++] = array;
+
+                if (DO_STATS) {
+                    stats.updateMaxSize(tail);
+                }
+            } else if (DO_CHECKS) {
+                logInfo(getLogPrefix(clean) + "ByteArrayCache: "
+                        + "array capacity exceeded !");
+            }
+        }
+    }
+
+    static byte[] createArray(final int length) {
+        return new byte[length];
     }
 
     static void fill(final byte[] array, final int fromIndex,
                      final int toIndex, final byte value)
     {
         // clear array data:
-        /*
-         * Arrays.fill is faster than System.arraycopy(empty array)
-         * or Unsafe.setMemory(byte 0)
-         */
-        if (toIndex != 0) {
-            Arrays.fill(array, fromIndex, toIndex, value);
-        }
-
+        Arrays.fill(array, fromIndex, toIndex, value);
         if (DO_CHECKS) {
             check(array, fromIndex, toIndex, value);
         }
@@ -149,4 +262,8 @@
             }
         }
     }
+
+    static String getLogPrefix(final boolean clean) {
+        return (clean) ? "Clean" : "Dirty";
+    }
 }
diff --git a/src/share/classes/sun/java2d/marlin/CollinearSimplifier.java b/src/share/classes/sun/java2d/marlin/CollinearSimplifier.java
index dbe9c2c..4da33af 100644
--- a/src/share/classes/sun/java2d/marlin/CollinearSimplifier.java
+++ b/src/share/classes/sun/java2d/marlin/CollinearSimplifier.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, 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
@@ -29,24 +29,26 @@
 
 final class CollinearSimplifier implements PathConsumer2D {
 
-    enum SimplifierState {
+    private static final int STATE_PREV_LINE = 0;
+    private static final int STATE_PREV_POINT = 1;
+    private static final int STATE_EMPTY = 2;
 
-        Empty, PreviousPoint, PreviousLine
-    };
     // slope precision threshold
-    static final float EPS = 1e-4f; // aaime proposed 1e-3f
+    private static final float EPS = 1e-3f; // aaime proposed 1e-3f
 
-    PathConsumer2D delegate;
-    SimplifierState state;
-    float px1, py1, px2, py2;
-    float pslope;
+    // members:
+    private PathConsumer2D delegate;
+    private int state;
+    private float px1, py1;
+    private float pdx, pdy;
+    private float px2, py2;
 
     CollinearSimplifier() {
     }
 
-    public CollinearSimplifier init(PathConsumer2D delegate) {
+    public CollinearSimplifier init(final PathConsumer2D delegate) {
         this.delegate = delegate;
-        this.state = SimplifierState.Empty;
+        this.state = STATE_EMPTY;
 
         return this; // fluent API
     }
@@ -54,15 +56,15 @@
     @Override
     public void pathDone() {
         emitStashedLine();
-        state = SimplifierState.Empty;
         delegate.pathDone();
+        state = STATE_EMPTY;
     }
 
     @Override
     public void closePath() {
         emitStashedLine();
-        state = SimplifierState.Empty;
         delegate.closePath();
+        state = STATE_EMPTY;
     }
 
     @Override
@@ -71,85 +73,85 @@
     }
 
     @Override
-    public void quadTo(float x1, float y1, float x2, float y2) {
+    public void quadTo(final float x1, final float y1,
+                       final float xe, final float ye)
+    {
         emitStashedLine();
-        delegate.quadTo(x1, y1, x2, y2);
+        delegate.quadTo(x1, y1, xe, ye);
         // final end point:
-        state = SimplifierState.PreviousPoint;
-        px1 = x2;
-        py1 = y2;
+        state = STATE_PREV_POINT;
+        px1 = xe;
+        py1 = ye;
     }
 
     @Override
-    public void curveTo(float x1, float y1, float x2, float y2,
-                        float x3, float y3) {
+    public void curveTo(final float x1, final float y1,
+                        final float x2, final float y2,
+                        final float xe, final float ye)
+    {
         emitStashedLine();
-        delegate.curveTo(x1, y1, x2, y2, x3, y3);
+        delegate.curveTo(x1, y1, x2, y2, xe, ye);
         // final end point:
-        state = SimplifierState.PreviousPoint;
-        px1 = x3;
-        py1 = y3;
+        state = STATE_PREV_POINT;
+        px1 = xe;
+        py1 = ye;
     }
 
     @Override
-    public void moveTo(float x, float y) {
+    public void moveTo(final float xe, final float ye) {
         emitStashedLine();
-        delegate.moveTo(x, y);
-        state = SimplifierState.PreviousPoint;
-        px1 = x;
-        py1 = y;
+        delegate.moveTo(xe, ye);
+        state = STATE_PREV_POINT;
+        px1 = xe;
+        py1 = ye;
     }
 
     @Override
-    public void lineTo(final float x, final float y) {
-        switch (state) {
-            case Empty:
-                delegate.lineTo(x, y);
-                state = SimplifierState.PreviousPoint;
-                px1 = x;
-                py1 = y;
-                return;
+    public void lineTo(final float xe, final float ye) {
+        // most probable case first:
+        if (state == STATE_PREV_LINE) {
+            // test for collinearity
+            final float dx = (xe - px2);
+            final float dy = (ye - py2);
 
-            case PreviousPoint:
-                state = SimplifierState.PreviousLine;
-                px2 = x;
-                py2 = y;
-                pslope = getSlope(px1, py1, x, y);
-                return;
-
-            case PreviousLine:
-                final float slope = getSlope(px2, py2, x, y);
-                // test for collinearity
-                if ((slope == pslope) || (Math.abs(pslope - slope) < EPS)) {
-                    // merge segments
-                    px2 = x;
-                    py2 = y;
-                    return;
-                }
+            // perf: avoid slope computation (fdiv) replaced by 3 fmul
+            if ((dy == 0.0f && pdy == 0.0f && (pdx * dx) >= 0.0f)
+// uncertainty on slope:
+//                || (Math.abs(pdx * dy - pdy * dx) < EPS * Math.abs(pdy * dy))) {
+// try 0
+                || ((pdy * dy) != 0.0f && (pdx * dy - pdy * dx) == 0.0f)) {
+                // same horizontal orientation or same slope:
+                // TODO: store cumulated error on slope ?
+                // merge segments
+                px2 = xe;
+                py2 = ye;
+            } else {
                 // emit previous segment
                 delegate.lineTo(px2, py2);
                 px1 = px2;
                 py1 = py2;
-                px2 = x;
-                py2 = y;
-                pslope = slope;
-                return;
-            default:
+                pdx = dx;
+                pdy = dy;
+                px2 = xe;
+                py2 = ye;
+            }
+        } else if (state == STATE_PREV_POINT) {
+            state = STATE_PREV_LINE;
+            pdx = (xe - px1);
+            pdy = (ye - py1);
+            px2 = xe;
+            py2 = ye;
+        } else if (state == STATE_EMPTY) {
+            delegate.lineTo(xe, ye);
+            state = STATE_PREV_POINT;
+            px1 = xe;
+            py1 = ye;
         }
     }
 
     private void emitStashedLine() {
-        if (state == SimplifierState.PreviousLine) {
+        if (state == STATE_PREV_LINE) {
             delegate.lineTo(px2, py2);
         }
     }
-
-    private static float getSlope(float x1, float y1, float x2, float y2) {
-        float dy = y2 - y1;
-        if (dy == 0f) {
-            return (x2 > x1) ? Float.POSITIVE_INFINITY
-                   : Float.NEGATIVE_INFINITY;
-        }
-        return (x2 - x1) / dy;
-    }
 }
diff --git a/src/share/classes/sun/java2d/marlin/Curve.java b/src/share/classes/sun/java2d/marlin/Curve.java
index 092a38e..ad73572 100644
--- a/src/share/classes/sun/java2d/marlin/Curve.java
+++ b/src/share/classes/sun/java2d/marlin/Curve.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, 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
@@ -29,110 +29,136 @@
 
     float ax, ay, bx, by, cx, cy, dx, dy;
     float dax, day, dbx, dby;
-    // shared iterator instance
-    private final BreakPtrIterator iterator = new BreakPtrIterator();
 
     Curve() {
     }
 
-    void set(float[] points, int type) {
-        switch(type) {
-        case 8:
+    void set(final float[] points, final int type) {
+        // if instead of switch (perf + most probable cases first)
+        if (type == 8) {
             set(points[0], points[1],
                 points[2], points[3],
                 points[4], points[5],
                 points[6], points[7]);
-            return;
-        case 6:
+        } else if (type == 4) {
+            set(points[0], points[1],
+                points[2], points[3]);
+        } else {
             set(points[0], points[1],
                 points[2], points[3],
                 points[4], points[5]);
-            return;
-        default:
-            throw new InternalError("Curves can only be cubic or quadratic");
         }
     }
 
-    void set(float x1, float y1,
-             float x2, float y2,
-             float x3, float y3,
-             float x4, float y4)
+    void set(final float x1, final float y1,
+             final float x2, final float y2,
+             final float x3, final float y3,
+             final float x4, final float y4)
     {
-        ax = 3f * (x2 - x3) + x4 - x1;
-        ay = 3f * (y2 - y3) + y4 - y1;
-        bx = 3f * (x1 - 2f * x2 + x3);
-        by = 3f * (y1 - 2f * y2 + y3);
-        cx = 3f * (x2 - x1);
-        cy = 3f * (y2 - y1);
-        dx = x1;
+        final float dx32 = 3.0f * (x3 - x2);
+        final float dy32 = 3.0f * (y3 - y2);
+        final float dx21 = 3.0f * (x2 - x1);
+        final float dy21 = 3.0f * (y2 - y1);
+        ax = (x4 - x1) - dx32;  // A = P3 - P0 - 3 (P2 - P1) = (P3 - P0) + 3 (P1 - P2)
+        ay = (y4 - y1) - dy32;
+        bx = (dx32 - dx21);     // B = 3 (P2 - P1) - 3(P1 - P0) = 3 (P2 + P0) - 6 P1
+        by = (dy32 - dy21);
+        cx = dx21;              // C = 3 (P1 - P0)
+        cy = dy21;
+        dx = x1;                // D = P0
         dy = y1;
-        dax = 3f * ax; day = 3f * ay;
-        dbx = 2f * bx; dby = 2f * by;
+        dax = 3.0f * ax;
+        day = 3.0f * ay;
+        dbx = 2.0f * bx;
+        dby = 2.0f * by;
     }
 
-    void set(float x1, float y1,
-             float x2, float y2,
-             float x3, float y3)
+    void set(final float x1, final float y1,
+             final float x2, final float y2,
+             final float x3, final float y3)
     {
-        ax = 0f; ay = 0f;
-        bx = x1 - 2f * x2 + x3;
-        by = y1 - 2f * y2 + y3;
-        cx = 2f * (x2 - x1);
-        cy = 2f * (y2 - y1);
-        dx = x1;
+        final float dx21 = (x2 - x1);
+        final float dy21 = (y2 - y1);
+        ax = 0.0f;              // A = 0
+        ay = 0.0f;
+        bx = (x3 - x2) - dx21;  // B = P3 - P0 - 2 P2
+        by = (y3 - y2) - dy21;
+        cx = 2.0f * dx21;       // C = 2 (P2 - P1)
+        cy = 2.0f * dy21;
+        dx = x1;                // D = P1
         dy = y1;
-        dax = 0f; day = 0f;
-        dbx = 2f * bx; dby = 2f * by;
+        dax = 0.0f;
+        day = 0.0f;
+        dbx = 2.0f * bx;
+        dby = 2.0f * by;
     }
 
-    float xat(float t) {
-        return t * (t * (t * ax + bx) + cx) + dx;
-    }
-    float yat(float t) {
-        return t * (t * (t * ay + by) + cy) + dy;
+    void set(final float x1, final float y1,
+             final float x2, final float y2)
+    {
+        final float dx21 = (x2 - x1);
+        final float dy21 = (y2 - y1);
+        ax = 0.0f;              // A = 0
+        ay = 0.0f;
+        bx = 0.0f;              // B = 0
+        by = 0.0f;
+        cx = dx21;              // C = (P2 - P1)
+        cy = dy21;
+        dx = x1;                // D = P1
+        dy = y1;
+        // useless derivatives for lines
+        if (false) {
+            dax = 0.0f;
+            day = 0.0f;
+            dbx = 0.0f;
+            dby = 0.0f;
+        }
     }
 
-    float dxat(float t) {
-        return t * (t * dax + dbx) + cx;
-    }
-
-    float dyat(float t) {
-        return t * (t * day + dby) + cy;
-    }
-
-    int dxRoots(float[] roots, int off) {
+    int dxRoots(final float[] roots, final int off) {
         return Helpers.quadraticRoots(dax, dbx, cx, roots, off);
     }
 
-    int dyRoots(float[] roots, int off) {
+    int dyRoots(final float[] roots, final int off) {
         return Helpers.quadraticRoots(day, dby, cy, roots, off);
     }
 
-    int infPoints(float[] pts, int off) {
+    int infPoints(final float[] pts, final int off) {
         // inflection point at t if -f'(t)x*f''(t)y + f'(t)y*f''(t)x == 0
         // Fortunately, this turns out to be quadratic, so there are at
         // most 2 inflection points.
         final float a = dax * dby - dbx * day;
-        final float b = 2f * (cy * dax - day * cx);
+        final float b = 2.0f * (cy * dax - day * cx);
         final float c = cy * dbx - cx * dby;
 
         return Helpers.quadraticRoots(a, b, c, pts, off);
     }
 
+    int xPoints(final float[] ts, final int off, final float x)
+    {
+        return Helpers.cubicRootsInAB(ax, bx, cx, dx - x, ts, off, 0.0f, 1.0f);
+    }
+
+    int yPoints(final float[] ts, final int off, final float y)
+    {
+        return Helpers.cubicRootsInAB(ay, by, cy, dy - y, ts, off, 0.0f, 1.0f);
+    }
+
     // finds points where the first and second derivative are
     // perpendicular. This happens when g(t) = f'(t)*f''(t) == 0 (where
     // * is a dot product). Unfortunately, we have to solve a cubic.
-    private int perpendiculardfddf(float[] pts, int off) {
+    private int perpendiculardfddf(final float[] pts, final int off) {
         assert pts.length >= off + 4;
 
         // these are the coefficients of some multiple of g(t) (not g(t),
         // because the roots of a polynomial are not changed after multiplication
         // by a constant, and this way we save a few multiplications).
-        final float a = 2f * (dax*dax + day*day);
-        final float b = 3f * (dax*dbx + day*dby);
-        final float c = 2f * (dax*cx + day*cy) + dbx*dbx + dby*dby;
-        final float d = dbx*cx + dby*cy;
-        return Helpers.cubicRootsInAB(a, b, c, d, pts, off, 0f, 1f);
+        final float a = 2.0f * (dax * dax + day * day);
+        final float b = 3.0f * (dax * dbx + day * dby);
+        final float c = 2.0f * (dax * cx  + day * cy) + dbx * dbx + dby * dby;
+        final float d = dbx * cx + dby * cy;
+
+        return Helpers.cubicRootsInAB(a, b, c, d, pts, off, 0.0f, 1.0f);
     }
 
     // Tries to find the roots of the function ROC(t)-w in [0, 1). It uses
@@ -148,22 +174,24 @@
     // at most 4 sub-intervals of (0,1). ROC has asymptotes at inflection
     // points, so roc-w can have at least 6 roots. This shouldn't be a
     // problem for what we're trying to do (draw a nice looking curve).
-    int rootsOfROCMinusW(float[] roots, int off, final float w, final float err) {
+    int rootsOfROCMinusW(final float[] roots, final int off, final float w2, final float err) {
         // no OOB exception, because by now off<=6, and roots.length >= 10
         assert off <= 6 && roots.length >= 10;
+
         int ret = off;
-        int numPerpdfddf = perpendiculardfddf(roots, off);
-        float t0 = 0, ft0 = ROCsq(t0) - w*w;
-        roots[off + numPerpdfddf] = 1f; // always check interval end points
-        numPerpdfddf++;
-        for (int i = off; i < off + numPerpdfddf; i++) {
-            float t1 = roots[i], ft1 = ROCsq(t1) - w*w;
-            if (ft0 == 0f) {
+        final int end = off + perpendiculardfddf(roots, off);
+        roots[end] = 1.0f; // always check interval end points
+
+        float t0 = 0.0f, ft0 = ROCsq(t0) - w2;
+
+        for (int i = off; i <= end; i++) {
+            float t1 = roots[i], ft1 = ROCsq(t1) - w2;
+            if (ft0 == 0.0f) {
                 roots[ret++] = t0;
-            } else if (ft1 * ft0 < 0f) { // have opposite signs
+            } else if (ft1 * ft0 < 0.0f) { // have opposite signs
                 // (ROC(t)^2 == w^2) == (ROC(t) == w) is true because
                 // ROC(t) >= 0 for all t.
-                roots[ret++] = falsePositionROCsqMinusX(t0, t1, w*w, err);
+                roots[ret++] = falsePositionROCsqMinusX(t0, t1, w2, err);
             }
             t0 = t1;
             ft0 = ft1;
@@ -172,9 +200,9 @@
         return ret - off;
     }
 
-    private static float eliminateInf(float x) {
+    private static float eliminateInf(final float x) {
         return (x == Float.POSITIVE_INFINITY ? Float.MAX_VALUE :
-            (x == Float.NEGATIVE_INFINITY ? Float.MIN_VALUE : x));
+               (x == Float.NEGATIVE_INFINITY ? Float.MIN_VALUE : x));
     }
 
     // A slight modification of the false position algorithm on wikipedia.
@@ -184,17 +212,18 @@
     // expressions make it into the language), depending on how closures
     // and turn out. Same goes for the newton's method
     // algorithm in Helpers.java
-    private float falsePositionROCsqMinusX(float x0, float x1,
-                                           final float x, final float err)
+    private float falsePositionROCsqMinusX(final float t0, final float t1,
+                                           final float w2, final float err)
     {
         final int iterLimit = 100;
         int side = 0;
-        float t = x1, ft = eliminateInf(ROCsq(t) - x);
-        float s = x0, fs = eliminateInf(ROCsq(s) - x);
+        float t = t1, ft = eliminateInf(ROCsq(t) - w2);
+        float s = t0, fs = eliminateInf(ROCsq(s) - w2);
         float r = s, fr;
+
         for (int i = 0; i < iterLimit && Math.abs(t - s) > err * Math.abs(t + s); i++) {
             r = (fs * t - ft * s) / (fs - ft);
-            fr = ROCsq(r) - x;
+            fr = ROCsq(r) - w2;
             if (sameSign(fr, ft)) {
                 ft = fr; t = r;
                 if (side < 0) {
@@ -203,7 +232,7 @@
                 } else {
                     side = -1;
                 }
-            } else if (fr * fs > 0) {
+            } else if (fr * fs > 0.0f) {
                 fs = fr; s = r;
                 if (side > 0) {
                     ft /= (1 << side);
@@ -218,87 +247,21 @@
         return r;
     }
 
-    private static boolean sameSign(float x, float y) {
+    private static boolean sameSign(final float x, final float y) {
         // another way is to test if x*y > 0. This is bad for small x, y.
-        return (x < 0f && y < 0f) || (x > 0f && y > 0f);
+        return (x < 0.0f && y < 0.0f) || (x > 0.0f && y > 0.0f);
     }
 
     // returns the radius of curvature squared at t of this curve
     // see http://en.wikipedia.org/wiki/Radius_of_curvature_(applications)
     private float ROCsq(final float t) {
-        // dx=xat(t) and dy=yat(t). These calls have been inlined for efficiency
         final float dx = t * (t * dax + dbx) + cx;
         final float dy = t * (t * day + dby) + cy;
-        final float ddx = 2f * dax * t + dbx;
-        final float ddy = 2f * day * t + dby;
-        final float dx2dy2 = dx*dx + dy*dy;
-        final float ddx2ddy2 = ddx*ddx + ddy*ddy;
-        final float ddxdxddydy = ddx*dx + ddy*dy;
-        return dx2dy2*((dx2dy2*dx2dy2) / (dx2dy2 * ddx2ddy2 - ddxdxddydy*ddxdxddydy));
-    }
-
-    // curve to be broken should be in pts
-    // this will change the contents of pts but not Ts
-    // TODO: There's no reason for Ts to be an array. All we need is a sequence
-    // of t values at which to subdivide. An array statisfies this condition,
-    // but is unnecessarily restrictive. Ts should be an Iterator<Float> instead.
-    // Doing this will also make dashing easier, since we could easily make
-    // LengthIterator an Iterator<Float> and feed it to this function to simplify
-    // the loop in Dasher.somethingTo.
-    BreakPtrIterator breakPtsAtTs(final float[] pts, final int type,
-                                  final float[] Ts, final int numTs)
-    {
-        assert pts.length >= 2*type && numTs <= Ts.length;
-
-        // initialize shared iterator:
-        iterator.init(pts, type, Ts, numTs);
-
-        return iterator;
-    }
-
-    static final class BreakPtrIterator {
-        private int nextCurveIdx;
-        private int curCurveOff;
-        private float prevT;
-        private float[] pts;
-        private int type;
-        private float[] ts;
-        private int numTs;
-
-        void init(final float[] pts, final int type,
-                  final float[] ts, final int numTs) {
-            this.pts = pts;
-            this.type = type;
-            this.ts = ts;
-            this.numTs = numTs;
-
-            nextCurveIdx = 0;
-            curCurveOff = 0;
-            prevT = 0f;
-        }
-
-        public boolean hasNext() {
-            return nextCurveIdx <= numTs;
-        }
-
-        public int next() {
-            int ret;
-            if (nextCurveIdx < numTs) {
-                float curT = ts[nextCurveIdx];
-                float splitT = (curT - prevT) / (1f - prevT);
-                Helpers.subdivideAt(splitT,
-                                    pts, curCurveOff,
-                                    pts, 0,
-                                    pts, type, type);
-                prevT = curT;
-                ret = 0;
-                curCurveOff = type;
-            } else {
-                ret = curCurveOff;
-            }
-            nextCurveIdx++;
-            return ret;
-        }
+        final float ddx = 2.0f * dax * t + dbx;
+        final float ddy = 2.0f * day * t + dby;
+        final float dx2dy2 = dx * dx + dy * dy;
+        final float ddx2ddy2 = ddx * ddx + ddy * ddy;
+        final float ddxdxddydy = ddx * dx + ddy * dy;
+        return dx2dy2 * ((dx2dy2 * dx2dy2) / (dx2dy2 * ddx2ddy2 - ddxdxddydy * ddxdxddydy));
     }
 }
-
diff --git a/src/share/classes/sun/java2d/marlin/DCollinearSimplifier.java b/src/share/classes/sun/java2d/marlin/DCollinearSimplifier.java
new file mode 100644
index 0000000..ee85b3e
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/DCollinearSimplifier.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d.marlin;
+
+
+final class DCollinearSimplifier implements DPathConsumer2D {
+
+    private static final int STATE_PREV_LINE = 0;
+    private static final int STATE_PREV_POINT = 1;
+    private static final int STATE_EMPTY = 2;
+
+    // slope precision threshold
+    private static final double EPS = 1e-3d; // aaime proposed 1e-3d
+
+    // members:
+    private DPathConsumer2D delegate;
+    private int state;
+    private double px1, py1;
+    private double pdx, pdy;
+    private double px2, py2;
+
+    DCollinearSimplifier() {
+    }
+
+    public DCollinearSimplifier init(final DPathConsumer2D delegate) {
+        this.delegate = delegate;
+        this.state = STATE_EMPTY;
+
+        return this; // fluent API
+    }
+
+    @Override
+    public void pathDone() {
+        emitStashedLine();
+        delegate.pathDone();
+        state = STATE_EMPTY;
+    }
+
+    @Override
+    public void closePath() {
+        emitStashedLine();
+        delegate.closePath();
+        state = STATE_EMPTY;
+    }
+
+    @Override
+    public long getNativeConsumer() {
+        return 0;
+    }
+
+    @Override
+    public void quadTo(final double x1, final double y1,
+                       final double xe, final double ye)
+    {
+        emitStashedLine();
+        delegate.quadTo(x1, y1, xe, ye);
+        // final end point:
+        state = STATE_PREV_POINT;
+        px1 = xe;
+        py1 = ye;
+    }
+
+    @Override
+    public void curveTo(final double x1, final double y1,
+                        final double x2, final double y2,
+                        final double xe, final double ye)
+    {
+        emitStashedLine();
+        delegate.curveTo(x1, y1, x2, y2, xe, ye);
+        // final end point:
+        state = STATE_PREV_POINT;
+        px1 = xe;
+        py1 = ye;
+    }
+
+    @Override
+    public void moveTo(final double xe, final double ye) {
+        emitStashedLine();
+        delegate.moveTo(xe, ye);
+        state = STATE_PREV_POINT;
+        px1 = xe;
+        py1 = ye;
+    }
+
+    @Override
+    public void lineTo(final double xe, final double ye) {
+        // most probable case first:
+        if (state == STATE_PREV_LINE) {
+            // test for collinearity
+            final double dx = (xe - px2);
+            final double dy = (ye - py2);
+
+            // perf: avoid slope computation (fdiv) replaced by 3 fmul
+            if ((dy == 0.0d && pdy == 0.0d && (pdx * dx) >= 0.0d)
+// uncertainty on slope:
+//                || (Math.abs(pdx * dy - pdy * dx) < EPS * Math.abs(pdy * dy))) {
+// try 0
+                || ((pdy * dy) != 0.0d && (pdx * dy - pdy * dx) == 0.0d)) {
+                // same horizontal orientation or same slope:
+                // TODO: store cumulated error on slope ?
+                // merge segments
+                px2 = xe;
+                py2 = ye;
+            } else {
+                // emit previous segment
+                delegate.lineTo(px2, py2);
+                px1 = px2;
+                py1 = py2;
+                pdx = dx;
+                pdy = dy;
+                px2 = xe;
+                py2 = ye;
+            }
+        } else if (state == STATE_PREV_POINT) {
+            state = STATE_PREV_LINE;
+            pdx = (xe - px1);
+            pdy = (ye - py1);
+            px2 = xe;
+            py2 = ye;
+        } else if (state == STATE_EMPTY) {
+            delegate.lineTo(xe, ye);
+            state = STATE_PREV_POINT;
+            px1 = xe;
+            py1 = ye;
+        }
+    }
+
+    private void emitStashedLine() {
+        if (state == STATE_PREV_LINE) {
+            delegate.lineTo(px2, py2);
+        }
+    }
+}
diff --git a/src/share/classes/sun/java2d/marlin/DCurve.java b/src/share/classes/sun/java2d/marlin/DCurve.java
new file mode 100644
index 0000000..2aaa551
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/DCurve.java
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d.marlin;
+
+final class DCurve {
+
+    double ax, ay, bx, by, cx, cy, dx, dy;
+    double dax, day, dbx, dby;
+
+    DCurve() {
+    }
+
+    void set(final double[] points, final int type) {
+        // if instead of switch (perf + most probable cases first)
+        if (type == 8) {
+            set(points[0], points[1],
+                points[2], points[3],
+                points[4], points[5],
+                points[6], points[7]);
+        } else if (type == 4) {
+            set(points[0], points[1],
+                points[2], points[3]);
+        } else {
+            set(points[0], points[1],
+                points[2], points[3],
+                points[4], points[5]);
+        }
+    }
+
+    void set(final double x1, final double y1,
+             final double x2, final double y2,
+             final double x3, final double y3,
+             final double x4, final double y4)
+    {
+        final double dx32 = 3.0d * (x3 - x2);
+        final double dy32 = 3.0d * (y3 - y2);
+        final double dx21 = 3.0d * (x2 - x1);
+        final double dy21 = 3.0d * (y2 - y1);
+        ax = (x4 - x1) - dx32;  // A = P3 - P0 - 3 (P2 - P1) = (P3 - P0) + 3 (P1 - P2)
+        ay = (y4 - y1) - dy32;
+        bx = (dx32 - dx21);     // B = 3 (P2 - P1) - 3(P1 - P0) = 3 (P2 + P0) - 6 P1
+        by = (dy32 - dy21);
+        cx = dx21;              // C = 3 (P1 - P0)
+        cy = dy21;
+        dx = x1;                // D = P0
+        dy = y1;
+        dax = 3.0d * ax;
+        day = 3.0d * ay;
+        dbx = 2.0d * bx;
+        dby = 2.0d * by;
+    }
+
+    void set(final double x1, final double y1,
+             final double x2, final double y2,
+             final double x3, final double y3)
+    {
+        final double dx21 = (x2 - x1);
+        final double dy21 = (y2 - y1);
+        ax = 0.0d;              // A = 0
+        ay = 0.0d;
+        bx = (x3 - x2) - dx21;  // B = P3 - P0 - 2 P2
+        by = (y3 - y2) - dy21;
+        cx = 2.0d * dx21;       // C = 2 (P2 - P1)
+        cy = 2.0d * dy21;
+        dx = x1;                // D = P1
+        dy = y1;
+        dax = 0.0d;
+        day = 0.0d;
+        dbx = 2.0d * bx;
+        dby = 2.0d * by;
+    }
+
+    void set(final double x1, final double y1,
+             final double x2, final double y2)
+    {
+        final double dx21 = (x2 - x1);
+        final double dy21 = (y2 - y1);
+        ax = 0.0d;              // A = 0
+        ay = 0.0d;
+        bx = 0.0d;              // B = 0
+        by = 0.0d;
+        cx = dx21;              // C = (P2 - P1)
+        cy = dy21;
+        dx = x1;                // D = P1
+        dy = y1;
+        if (false) {
+            dax = 0.0d;
+            day = 0.0d;
+            dbx = 0.0d;
+            dby = 0.0d;
+        }
+    }
+
+    int dxRoots(final double[] roots, final int off) {
+        return DHelpers.quadraticRoots(dax, dbx, cx, roots, off);
+    }
+
+    int dyRoots(final double[] roots, final int off) {
+        return DHelpers.quadraticRoots(day, dby, cy, roots, off);
+    }
+
+    int infPoints(final double[] pts, final int off) {
+        // inflection point at t if -f'(t)x*f''(t)y + f'(t)y*f''(t)x == 0
+        // Fortunately, this turns out to be quadratic, so there are at
+        // most 2 inflection points.
+        final double a = dax * dby - dbx * day;
+        final double b = 2.0d * (cy * dax - day * cx);
+        final double c = cy * dbx - cx * dby;
+
+        return DHelpers.quadraticRoots(a, b, c, pts, off);
+    }
+
+    int xPoints(final double[] ts, final int off, final double x)
+    {
+        return DHelpers.cubicRootsInAB(ax, bx, cx, dx - x, ts, off, 0.0d, 1.0d);
+    }
+
+    int yPoints(final double[] ts, final int off, final double y)
+    {
+        return DHelpers.cubicRootsInAB(ay, by, cy, dy - y, ts, off, 0.0d, 1.0d);
+    }
+
+    // finds points where the first and second derivative are
+    // perpendicular. This happens when g(t) = f'(t)*f''(t) == 0 (where
+    // * is a dot product). Unfortunately, we have to solve a cubic.
+    private int perpendiculardfddf(final double[] pts, final int off) {
+        assert pts.length >= off + 4;
+
+        // these are the coefficients of some multiple of g(t) (not g(t),
+        // because the roots of a polynomial are not changed after multiplication
+        // by a constant, and this way we save a few multiplications).
+        final double a = 2.0d * (dax * dax + day * day);
+        final double b = 3.0d * (dax * dbx + day * dby);
+        final double c = 2.0d * (dax * cx + day * cy) + dbx * dbx + dby * dby;
+        final double d = dbx * cx + dby * cy;
+
+        return DHelpers.cubicRootsInAB(a, b, c, d, pts, off, 0.0d, 1.0d);
+    }
+
+    // Tries to find the roots of the function ROC(t)-w in [0, 1). It uses
+    // a variant of the false position algorithm to find the roots. False
+    // position requires that 2 initial values x0,x1 be given, and that the
+    // function must have opposite signs at those values. To find such
+    // values, we need the local extrema of the ROC function, for which we
+    // need the roots of its derivative; however, it's harder to find the
+    // roots of the derivative in this case than it is to find the roots
+    // of the original function. So, we find all points where this curve's
+    // first and second derivative are perpendicular, and we pretend these
+    // are our local extrema. There are at most 3 of these, so we will check
+    // at most 4 sub-intervals of (0,1). ROC has asymptotes at inflection
+    // points, so roc-w can have at least 6 roots. This shouldn't be a
+    // problem for what we're trying to do (draw a nice looking curve).
+    int rootsOfROCMinusW(final double[] roots, final int off, final double w2, final double err) {
+        // no OOB exception, because by now off<=6, and roots.length >= 10
+        assert off <= 6 && roots.length >= 10;
+
+        int ret = off;
+        final int end = off + perpendiculardfddf(roots, off);
+        roots[end] = 1.0d; // always check interval end points
+
+        double t0 = 0.0d, ft0 = ROCsq(t0) - w2;
+
+        for (int i = off; i <= end; i++) {
+            double t1 = roots[i], ft1 = ROCsq(t1) - w2;
+            if (ft0 == 0.0d) {
+                roots[ret++] = t0;
+            } else if (ft1 * ft0 < 0.0d) { // have opposite signs
+                // (ROC(t)^2 == w^2) == (ROC(t) == w) is true because
+                // ROC(t) >= 0 for all t.
+                roots[ret++] = falsePositionROCsqMinusX(t0, t1, w2, err);
+            }
+            t0 = t1;
+            ft0 = ft1;
+        }
+
+        return ret - off;
+    }
+
+    private static double eliminateInf(final double x) {
+        return (x == Double.POSITIVE_INFINITY ? Double.MAX_VALUE :
+               (x == Double.NEGATIVE_INFINITY ? Double.MIN_VALUE : x));
+    }
+
+    // A slight modification of the false position algorithm on wikipedia.
+    // This only works for the ROCsq-x functions. It might be nice to have
+    // the function as an argument, but that would be awkward in java6.
+    // TODO: It is something to consider for java8 (or whenever lambda
+    // expressions make it into the language), depending on how closures
+    // and turn out. Same goes for the newton's method
+    // algorithm in DHelpers.java
+    private double falsePositionROCsqMinusX(final double t0, final double t1,
+                                            final double w2, final double err)
+    {
+        final int iterLimit = 100;
+        int side = 0;
+        double t = t1, ft = eliminateInf(ROCsq(t) - w2);
+        double s = t0, fs = eliminateInf(ROCsq(s) - w2);
+        double r = s, fr;
+
+        for (int i = 0; i < iterLimit && Math.abs(t - s) > err * Math.abs(t + s); i++) {
+            r = (fs * t - ft * s) / (fs - ft);
+            fr = ROCsq(r) - w2;
+            if (sameSign(fr, ft)) {
+                ft = fr; t = r;
+                if (side < 0) {
+                    fs /= (1 << (-side));
+                    side--;
+                } else {
+                    side = -1;
+                }
+            } else if (fr * fs > 0.0d) {
+                fs = fr; s = r;
+                if (side > 0) {
+                    ft /= (1 << side);
+                    side++;
+                } else {
+                    side = 1;
+                }
+            } else {
+                break;
+            }
+        }
+        return r;
+    }
+
+    private static boolean sameSign(final double x, final double y) {
+        // another way is to test if x*y > 0. This is bad for small x, y.
+        return (x < 0.0d && y < 0.0d) || (x > 0.0d && y > 0.0d);
+    }
+
+    // returns the radius of curvature squared at t of this curve
+    // see http://en.wikipedia.org/wiki/Radius_of_curvature_(applications)
+    private double ROCsq(final double t) {
+        final double dx = t * (t * dax + dbx) + cx;
+        final double dy = t * (t * day + dby) + cy;
+        final double ddx = 2.0d * dax * t + dbx;
+        final double ddy = 2.0d * day * t + dby;
+        final double dx2dy2 = dx * dx + dy * dy;
+        final double ddx2ddy2 = ddx * ddx + ddy * ddy;
+        final double ddxdxddydy = ddx * dx + ddy * dy;
+        return dx2dy2 * ((dx2dy2 * dx2dy2) / (dx2dy2 * ddx2ddy2 - ddxdxddydy * ddxdxddydy));
+    }
+}
diff --git a/src/share/classes/sun/java2d/marlin/DDasher.java b/src/share/classes/sun/java2d/marlin/DDasher.java
new file mode 100644
index 0000000..6ccc31e
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/DDasher.java
@@ -0,0 +1,1137 @@
+/*
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d.marlin;
+
+import java.util.Arrays;
+import sun.java2d.marlin.DTransformingPathConsumer2D.CurveBasicMonotonizer;
+import sun.java2d.marlin.DTransformingPathConsumer2D.CurveClipSplitter;
+
+/**
+ * The <code>DDasher</code> class takes a series of linear commands
+ * (<code>moveTo</code>, <code>lineTo</code>, <code>close</code> and
+ * <code>end</code>) and breaks them into smaller segments according to a
+ * dash pattern array and a starting dash phase.
+ *
+ * <p> Issues: in J2Se, a zero length dash segment as drawn as a very
+ * short dash, whereas Pisces does not draw anything.  The PostScript
+ * semantics are unclear.
+ *
+ */
+final class DDasher implements DPathConsumer2D, MarlinConst {
+
+    /* huge circle with radius ~ 2E9 only needs 12 subdivision levels */
+    static final int REC_LIMIT = 16;
+    static final double CURVE_LEN_ERR = MarlinProperties.getCurveLengthError(); // 0.01 initial
+    static final double MIN_T_INC = 1.0d / (1 << REC_LIMIT);
+
+    // More than 24 bits of mantissa means we can no longer accurately
+    // measure the number of times cycled through the dash array so we
+    // punt and override the phase to just be 0 past that point.
+    static final double MAX_CYCLES = 16000000.0d;
+
+    private DPathConsumer2D out;
+    private double[] dash;
+    private int dashLen;
+    private double startPhase;
+    private boolean startDashOn;
+    private int startIdx;
+
+    private boolean starting;
+    private boolean needsMoveTo;
+
+    private int idx;
+    private boolean dashOn;
+    private double phase;
+
+    // The starting point of the path
+    private double sx0, sy0;
+    // the current point
+    private double cx0, cy0;
+
+    // temporary storage for the current curve
+    private final double[] curCurvepts;
+
+    // per-thread renderer context
+    final DRendererContext rdrCtx;
+
+    // flag to recycle dash array copy
+    boolean recycleDashes;
+
+    // We don't emit the first dash right away. If we did, caps would be
+    // drawn on it, but we need joins to be drawn if there's a closePath()
+    // So, we store the path elements that make up the first dash in the
+    // buffer below.
+    private double[] firstSegmentsBuffer; // dynamic array
+    private int firstSegidx;
+
+    // dashes ref (dirty)
+    final DoubleArrayCache.Reference dashes_ref;
+    // firstSegmentsBuffer ref (dirty)
+    final DoubleArrayCache.Reference firstSegmentsBuffer_ref;
+
+    // Bounds of the drawing region, at pixel precision.
+    private double[] clipRect;
+
+    // the outcode of the current point
+    private int cOutCode = 0;
+
+    private boolean subdivide = DO_CLIP_SUBDIVIDER;
+
+    private final LengthIterator li = new LengthIterator();
+
+    private final CurveClipSplitter curveSplitter;
+
+    private double cycleLen;
+    private boolean outside;
+    private double totalSkipLen;
+
+    /**
+     * Constructs a <code>DDasher</code>.
+     * @param rdrCtx per-thread renderer context
+     */
+    DDasher(final DRendererContext rdrCtx) {
+        this.rdrCtx = rdrCtx;
+
+        dashes_ref = rdrCtx.newDirtyDoubleArrayRef(INITIAL_ARRAY); // 1K
+
+        firstSegmentsBuffer_ref = rdrCtx.newDirtyDoubleArrayRef(INITIAL_ARRAY); // 1K
+        firstSegmentsBuffer     = firstSegmentsBuffer_ref.initial;
+
+        // we need curCurvepts to be able to contain 2 curves because when
+        // dashing curves, we need to subdivide it
+        curCurvepts = new double[8 * 2];
+
+        this.curveSplitter = rdrCtx.curveClipSplitter;
+    }
+
+    /**
+     * Initialize the <code>DDasher</code>.
+     *
+     * @param out an output <code>DPathConsumer2D</code>.
+     * @param dash an array of <code>double</code>s containing the dash pattern
+     * @param dashLen length of the given dash array
+     * @param phase a <code>double</code> containing the dash phase
+     * @param recycleDashes true to indicate to recycle the given dash array
+     * @return this instance
+     */
+    DDasher init(final DPathConsumer2D out, double[] dash, int dashLen,
+                double phase, boolean recycleDashes)
+    {
+        this.out = out;
+
+        // Normalize so 0 <= phase < dash[0]
+        int sidx = 0;
+        dashOn = true;
+
+        double sum = 0.0d;
+        for (double d : dash) {
+            sum += d;
+        }
+        this.cycleLen = sum;
+
+        double cycles = phase / sum;
+        if (phase < 0.0d) {
+            if (-cycles >= MAX_CYCLES) {
+                phase = 0.0d;
+            } else {
+                int fullcycles = FloatMath.floor_int(-cycles);
+                if ((fullcycles & dash.length & 1) != 0) {
+                    dashOn = !dashOn;
+                }
+                phase += fullcycles * sum;
+                while (phase < 0.0d) {
+                    if (--sidx < 0) {
+                        sidx = dash.length - 1;
+                    }
+                    phase += dash[sidx];
+                    dashOn = !dashOn;
+                }
+            }
+        } else if (phase > 0.0d) {
+            if (cycles >= MAX_CYCLES) {
+                phase = 0.0d;
+            } else {
+                int fullcycles = FloatMath.floor_int(cycles);
+                if ((fullcycles & dash.length & 1) != 0) {
+                    dashOn = !dashOn;
+                }
+                phase -= fullcycles * sum;
+                double d;
+                while (phase >= (d = dash[sidx])) {
+                    phase -= d;
+                    sidx = (sidx + 1) % dash.length;
+                    dashOn = !dashOn;
+                }
+            }
+        }
+
+        this.dash = dash;
+        this.dashLen = dashLen;
+        this.phase = phase;
+        this.startPhase = phase;
+        this.startDashOn = dashOn;
+        this.startIdx = sidx;
+        this.starting = true;
+        this.needsMoveTo = false;
+        this.firstSegidx = 0;
+
+        this.recycleDashes = recycleDashes;
+
+        if (rdrCtx.doClip) {
+            this.clipRect = rdrCtx.clipRect;
+        } else {
+            this.clipRect = null;
+            this.cOutCode = 0;
+        }
+        return this; // fluent API
+    }
+
+    /**
+     * Disposes this dasher:
+     * clean up before reusing this instance
+     */
+    void dispose() {
+        if (DO_CLEAN_DIRTY) {
+            // Force zero-fill dirty arrays:
+            Arrays.fill(curCurvepts, 0.0d);
+        }
+        // Return arrays:
+        if (recycleDashes) {
+            dash = dashes_ref.putArray(dash);
+        }
+        firstSegmentsBuffer = firstSegmentsBuffer_ref.putArray(firstSegmentsBuffer);
+    }
+
+    double[] copyDashArray(final float[] dashes) {
+        final int len = dashes.length;
+        final double[] newDashes;
+        if (len <= MarlinConst.INITIAL_ARRAY) {
+            newDashes = dashes_ref.initial;
+        } else {
+            if (DO_STATS) {
+                rdrCtx.stats.stat_array_dasher_dasher.add(len);
+            }
+            newDashes = dashes_ref.getArray(len);
+        }
+        for (int i = 0; i < len; i++) { newDashes[i] = dashes[i]; }
+        return newDashes;
+    }
+
+    @Override
+    public void moveTo(final double x0, final double y0) {
+        if (firstSegidx != 0) {
+            out.moveTo(sx0, sy0);
+            emitFirstSegments();
+        }
+        this.needsMoveTo = true;
+        this.idx = startIdx;
+        this.dashOn = this.startDashOn;
+        this.phase = this.startPhase;
+        this.cx0 = x0;
+        this.cy0 = y0;
+
+        // update starting point:
+        this.sx0 = x0;
+        this.sy0 = y0;
+        this.starting = true;
+
+        if (clipRect != null) {
+            final int outcode = DHelpers.outcode(x0, y0, clipRect);
+            this.cOutCode = outcode;
+            this.outside = false;
+            this.totalSkipLen = 0.0d;
+        }
+    }
+
+    private void emitSeg(double[] buf, int off, int type) {
+        switch (type) {
+        case 8:
+            out.curveTo(buf[off    ], buf[off + 1],
+                        buf[off + 2], buf[off + 3],
+                        buf[off + 4], buf[off + 5]);
+            return;
+        case 6:
+            out.quadTo(buf[off    ], buf[off + 1],
+                       buf[off + 2], buf[off + 3]);
+            return;
+        case 4:
+            out.lineTo(buf[off], buf[off + 1]);
+            return;
+        default:
+        }
+    }
+
+    private void emitFirstSegments() {
+        final double[] fSegBuf = firstSegmentsBuffer;
+
+        for (int i = 0, len = firstSegidx; i < len; ) {
+            int type = (int)fSegBuf[i];
+            emitSeg(fSegBuf, i + 1, type);
+            i += (type - 1);
+        }
+        firstSegidx = 0;
+    }
+
+    // precondition: pts must be in relative coordinates (relative to x0,y0)
+    private void goTo(final double[] pts, final int off, final int type,
+                      final boolean on)
+    {
+        final int index = off + type;
+        final double x = pts[index - 4];
+        final double y = pts[index - 3];
+/*
+        if (type == 8) {
+            System.out.println("seg["+on+"] len: "
+                    +DHelpers.curvelen(pts[off - 2], pts[off - 1],
+                            pts[off    ], pts[off + 1],
+                        pts[off + 2], pts[off + 3],
+                        pts[off + 4], pts[off + 5]));
+        }
+*/
+        if (on) {
+            if (starting) {
+                goTo_starting(pts, off, type);
+            } else {
+                if (needsMoveTo) {
+                    needsMoveTo = false;
+                    out.moveTo(cx0, cy0);
+                }
+                emitSeg(pts, off, type);
+            }
+        } else {
+            if (starting) {
+                // low probability test (hotspot)
+                starting = false;
+            }
+            needsMoveTo = true;
+        }
+        this.cx0 = x;
+        this.cy0 = y;
+    }
+
+    private void goTo_starting(final double[] pts, final int off, final int type) {
+        int len = type - 1; // - 2 + 1
+        int segIdx = firstSegidx;
+        double[] buf = firstSegmentsBuffer;
+
+        if (segIdx + len  > buf.length) {
+            if (DO_STATS) {
+                rdrCtx.stats.stat_array_dasher_firstSegmentsBuffer
+                    .add(segIdx + len);
+            }
+            firstSegmentsBuffer = buf
+                = firstSegmentsBuffer_ref.widenArray(buf, segIdx,
+                                                     segIdx + len);
+        }
+        buf[segIdx++] = type;
+        len--;
+        // small arraycopy (2, 4 or 6) but with offset:
+        System.arraycopy(pts, off, buf, segIdx, len);
+        firstSegidx = segIdx + len;
+    }
+
+    @Override
+    public void lineTo(final double x1, final double y1) {
+        final int outcode0 = this.cOutCode;
+
+        if (clipRect != null) {
+            final int outcode1 = DHelpers.outcode(x1, y1, clipRect);
+
+            // Should clip
+            final int orCode = (outcode0 | outcode1);
+
+            if (orCode != 0) {
+                final int sideCode = outcode0 & outcode1;
+
+                // basic rejection criteria:
+                if (sideCode == 0) {
+                    // ovelap clip:
+                    if (subdivide) {
+                        // avoid reentrance
+                        subdivide = false;
+                        // subdivide curve => callback with subdivided parts:
+                        boolean ret = curveSplitter.splitLine(cx0, cy0, x1, y1,
+                                                              orCode, this);
+                        // reentrance is done:
+                        subdivide = true;
+                        if (ret) {
+                            return;
+                        }
+                    }
+                    // already subdivided so render it
+                } else {
+                    this.cOutCode = outcode1;
+                    skipLineTo(x1, y1);
+                    return;
+                }
+            }
+
+            this.cOutCode = outcode1;
+
+            if (this.outside) {
+                this.outside = false;
+                // Adjust current index, phase & dash:
+                skipLen();
+            }
+        }
+        _lineTo(x1, y1);
+    }
+
+    private void _lineTo(final double x1, final double y1) {
+        final double dx = x1 - cx0;
+        final double dy = y1 - cy0;
+
+        double len = dx * dx + dy * dy;
+        if (len == 0.0d) {
+            return;
+        }
+        len = Math.sqrt(len);
+
+        // The scaling factors needed to get the dx and dy of the
+        // transformed dash segments.
+        final double cx = dx / len;
+        final double cy = dy / len;
+
+        final double[] _curCurvepts = curCurvepts;
+        final double[] _dash = dash;
+        final int _dashLen = this.dashLen;
+
+        int _idx = idx;
+        boolean _dashOn = dashOn;
+        double _phase = phase;
+
+        double leftInThisDashSegment, d;
+
+        while (true) {
+            d = _dash[_idx];
+            leftInThisDashSegment = d - _phase;
+
+            if (len <= leftInThisDashSegment) {
+                _curCurvepts[0] = x1;
+                _curCurvepts[1] = y1;
+
+                goTo(_curCurvepts, 0, 4, _dashOn);
+
+                // Advance phase within current dash segment
+                _phase += len;
+
+                // TODO: compare double values using epsilon:
+                if (len == leftInThisDashSegment) {
+                    _phase = 0.0d;
+                    _idx = (_idx + 1) % _dashLen;
+                    _dashOn = !_dashOn;
+                }
+                break;
+            }
+
+            if (_phase == 0.0d) {
+                _curCurvepts[0] = cx0 + d * cx;
+                _curCurvepts[1] = cy0 + d * cy;
+            } else {
+                _curCurvepts[0] = cx0 + leftInThisDashSegment * cx;
+                _curCurvepts[1] = cy0 + leftInThisDashSegment * cy;
+            }
+
+            goTo(_curCurvepts, 0, 4, _dashOn);
+
+            len -= leftInThisDashSegment;
+            // Advance to next dash segment
+            _idx = (_idx + 1) % _dashLen;
+            _dashOn = !_dashOn;
+            _phase = 0.0d;
+        }
+        // Save local state:
+        idx = _idx;
+        dashOn = _dashOn;
+        phase = _phase;
+    }
+
+    private void skipLineTo(final double x1, final double y1) {
+        final double dx = x1 - cx0;
+        final double dy = y1 - cy0;
+
+        double len = dx * dx + dy * dy;
+        if (len != 0.0d) {
+            len = Math.sqrt(len);
+        }
+
+        // Accumulate skipped length:
+        this.outside = true;
+        this.totalSkipLen += len;
+
+        // Fix initial move:
+        this.needsMoveTo = true;
+        this.starting = false;
+
+        this.cx0 = x1;
+        this.cy0 = y1;
+    }
+
+    public void skipLen() {
+        double len = this.totalSkipLen;
+        this.totalSkipLen = 0.0d;
+
+        final double[] _dash = dash;
+        final int _dashLen = this.dashLen;
+
+        int _idx = idx;
+        boolean _dashOn = dashOn;
+        double _phase = phase;
+
+        // -2 to ensure having 2 iterations of the post-loop
+        // to compensate the remaining phase
+        final long fullcycles = (long)Math.floor(len / cycleLen) - 2L;
+
+        if (fullcycles > 0L) {
+            len -= cycleLen * fullcycles;
+
+            final long iterations = fullcycles * _dashLen;
+            _idx = (int) (iterations + _idx) % _dashLen;
+            _dashOn = (iterations + (_dashOn ? 1L : 0L) & 1L) == 1L;
+        }
+
+        double leftInThisDashSegment, d;
+
+        while (true) {
+            d = _dash[_idx];
+            leftInThisDashSegment = d - _phase;
+
+            if (len <= leftInThisDashSegment) {
+                // Advance phase within current dash segment
+                _phase += len;
+
+                // TODO: compare double values using epsilon:
+                if (len == leftInThisDashSegment) {
+                    _phase = 0.0d;
+                    _idx = (_idx + 1) % _dashLen;
+                    _dashOn = !_dashOn;
+                }
+                break;
+            }
+
+            len -= leftInThisDashSegment;
+            // Advance to next dash segment
+            _idx = (_idx + 1) % _dashLen;
+            _dashOn = !_dashOn;
+            _phase = 0.0d;
+        }
+        // Save local state:
+        idx = _idx;
+        dashOn = _dashOn;
+        phase = _phase;
+    }
+
+    // preconditions: curCurvepts must be an array of length at least 2 * type,
+    // that contains the curve we want to dash in the first type elements
+    private void somethingTo(final int type) {
+        final double[] _curCurvepts = curCurvepts;
+        if (pointCurve(_curCurvepts, type)) {
+            return;
+        }
+        final LengthIterator _li = li;
+        final double[] _dash = dash;
+        final int _dashLen = this.dashLen;
+
+        _li.initializeIterationOnCurve(_curCurvepts, type);
+
+        int _idx = idx;
+        boolean _dashOn = dashOn;
+        double _phase = phase;
+
+        // initially the current curve is at curCurvepts[0...type]
+        int curCurveoff = 0;
+        double prevT = 0.0d;
+        double t;
+        double leftInThisDashSegment = _dash[_idx] - _phase;
+
+        while ((t = _li.next(leftInThisDashSegment)) < 1.0d) {
+            if (t != 0.0d) {
+                DHelpers.subdivideAt((t - prevT) / (1.0d - prevT),
+                                    _curCurvepts, curCurveoff,
+                                    _curCurvepts, 0, type);
+                prevT = t;
+                goTo(_curCurvepts, 2, type, _dashOn);
+                curCurveoff = type;
+            }
+            // Advance to next dash segment
+            _idx = (_idx + 1) % _dashLen;
+            _dashOn = !_dashOn;
+            _phase = 0.0d;
+            leftInThisDashSegment = _dash[_idx];
+        }
+
+        goTo(_curCurvepts, curCurveoff + 2, type, _dashOn);
+
+        _phase += _li.lastSegLen();
+        if (_phase >= _dash[_idx]) {
+            _phase = 0.0d;
+            _idx = (_idx + 1) % _dashLen;
+            _dashOn = !_dashOn;
+        }
+        // Save local state:
+        idx = _idx;
+        dashOn = _dashOn;
+        phase = _phase;
+
+        // reset LengthIterator:
+        _li.reset();
+    }
+
+    private void skipSomethingTo(final int type) {
+        final double[] _curCurvepts = curCurvepts;
+        if (pointCurve(_curCurvepts, type)) {
+            return;
+        }
+        final LengthIterator _li = li;
+
+        _li.initializeIterationOnCurve(_curCurvepts, type);
+
+        // In contrary to somethingTo(),
+        // just estimate properly the curve length:
+        final double len = _li.totalLength();
+
+        // Accumulate skipped length:
+        this.outside = true;
+        this.totalSkipLen += len;
+
+        // Fix initial move:
+        this.needsMoveTo = true;
+        this.starting = false;
+    }
+
+    private static boolean pointCurve(final double[] curve, final int type) {
+        for (int i = 2; i < type; i++) {
+            if (curve[i] != curve[i-2]) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    // Objects of this class are used to iterate through curves. They return
+    // t values where the left side of the curve has a specified length.
+    // It does this by subdividing the input curve until a certain error
+    // condition has been met. A recursive subdivision procedure would
+    // return as many as 1<<limit curves, but this is an iterator and we
+    // don't need all the curves all at once, so what we carry out a
+    // lazy inorder traversal of the recursion tree (meaning we only move
+    // through the tree when we need the next subdivided curve). This saves
+    // us a lot of memory because at any one time we only need to store
+    // limit+1 curves - one for each level of the tree + 1.
+    // NOTE: the way we do things here is not enough to traverse a general
+    // tree; however, the trees we are interested in have the property that
+    // every non leaf node has exactly 2 children
+    static final class LengthIterator {
+        // Holds the curves at various levels of the recursion. The root
+        // (i.e. the original curve) is at recCurveStack[0] (but then it
+        // gets subdivided, the left half is put at 1, so most of the time
+        // only the right half of the original curve is at 0)
+        private final double[][] recCurveStack; // dirty
+        // sidesRight[i] indicates whether the node at level i+1 in the path from
+        // the root to the current leaf is a left or right child of its parent.
+        private final boolean[] sidesRight; // dirty
+        private int curveType;
+        // lastT and nextT delimit the current leaf.
+        private double nextT;
+        private double lenAtNextT;
+        private double lastT;
+        private double lenAtLastT;
+        private double lenAtLastSplit;
+        private double lastSegLen;
+        // the current level in the recursion tree. 0 is the root. limit
+        // is the deepest possible leaf.
+        private int recLevel;
+        private boolean done;
+
+        // the lengths of the lines of the control polygon. Only its first
+        // curveType/2 - 1 elements are valid. This is an optimization. See
+        // next() for more detail.
+        private final double[] curLeafCtrlPolyLengths = new double[3];
+
+        LengthIterator() {
+            this.recCurveStack = new double[REC_LIMIT + 1][8];
+            this.sidesRight = new boolean[REC_LIMIT];
+            // if any methods are called without first initializing this object
+            // on a curve, we want it to fail ASAP.
+            this.nextT = Double.MAX_VALUE;
+            this.lenAtNextT = Double.MAX_VALUE;
+            this.lenAtLastSplit = Double.MIN_VALUE;
+            this.recLevel = Integer.MIN_VALUE;
+            this.lastSegLen = Double.MAX_VALUE;
+            this.done = true;
+        }
+
+        /**
+         * Reset this LengthIterator.
+         */
+        void reset() {
+            // keep data dirty
+            // as it appears not useful to reset data:
+            if (DO_CLEAN_DIRTY) {
+                final int recLimit = recCurveStack.length - 1;
+                for (int i = recLimit; i >= 0; i--) {
+                    Arrays.fill(recCurveStack[i], 0.0d);
+                }
+                Arrays.fill(sidesRight, false);
+                Arrays.fill(curLeafCtrlPolyLengths, 0.0d);
+                Arrays.fill(nextRoots, 0.0d);
+                Arrays.fill(flatLeafCoefCache, 0.0d);
+                flatLeafCoefCache[2] = -1.0d;
+            }
+        }
+
+        void initializeIterationOnCurve(final double[] pts, final int type) {
+            // optimize arraycopy (8 values faster than 6 = type):
+            System.arraycopy(pts, 0, recCurveStack[0], 0, 8);
+            this.curveType = type;
+            this.recLevel = 0;
+            this.lastT = 0.0d;
+            this.lenAtLastT = 0.0d;
+            this.nextT = 0.0d;
+            this.lenAtNextT = 0.0d;
+            goLeft(); // initializes nextT and lenAtNextT properly
+            this.lenAtLastSplit = 0.0d;
+            if (recLevel > 0) {
+                this.sidesRight[0] = false;
+                this.done = false;
+            } else {
+                // the root of the tree is a leaf so we're done.
+                this.sidesRight[0] = true;
+                this.done = true;
+            }
+            this.lastSegLen = 0.0d;
+        }
+
+        // 0 == false, 1 == true, -1 == invalid cached value.
+        private int cachedHaveLowAcceleration = -1;
+
+        private boolean haveLowAcceleration(final double err) {
+            if (cachedHaveLowAcceleration == -1) {
+                final double len1 = curLeafCtrlPolyLengths[0];
+                final double len2 = curLeafCtrlPolyLengths[1];
+                // the test below is equivalent to !within(len1/len2, 1, err).
+                // It is using a multiplication instead of a division, so it
+                // should be a bit faster.
+                if (!DHelpers.within(len1, len2, err * len2)) {
+                    cachedHaveLowAcceleration = 0;
+                    return false;
+                }
+                if (curveType == 8) {
+                    final double len3 = curLeafCtrlPolyLengths[2];
+                    // if len1 is close to 2 and 2 is close to 3, that probably
+                    // means 1 is close to 3 so the second part of this test might
+                    // not be needed, but it doesn't hurt to include it.
+                    final double errLen3 = err * len3;
+                    if (!(DHelpers.within(len2, len3, errLen3) &&
+                          DHelpers.within(len1, len3, errLen3))) {
+                        cachedHaveLowAcceleration = 0;
+                        return false;
+                    }
+                }
+                cachedHaveLowAcceleration = 1;
+                return true;
+            }
+
+            return (cachedHaveLowAcceleration == 1);
+        }
+
+        // we want to avoid allocations/gc so we keep this array so we
+        // can put roots in it,
+        private final double[] nextRoots = new double[4];
+
+        // caches the coefficients of the current leaf in its flattened
+        // form (see inside next() for what that means). The cache is
+        // invalid when it's third element is negative, since in any
+        // valid flattened curve, this would be >= 0.
+        private final double[] flatLeafCoefCache = new double[]{0.0d, 0.0d, -1.0d, 0.0d};
+
+        // returns the t value where the remaining curve should be split in
+        // order for the left subdivided curve to have length len. If len
+        // is >= than the length of the uniterated curve, it returns 1.
+        double next(final double len) {
+            final double targetLength = lenAtLastSplit + len;
+            while (lenAtNextT < targetLength) {
+                if (done) {
+                    lastSegLen = lenAtNextT - lenAtLastSplit;
+                    return 1.0d;
+                }
+                goToNextLeaf();
+            }
+            lenAtLastSplit = targetLength;
+            final double leaflen = lenAtNextT - lenAtLastT;
+            double t = (targetLength - lenAtLastT) / leaflen;
+
+            // cubicRootsInAB is a fairly expensive call, so we just don't do it
+            // if the acceleration in this section of the curve is small enough.
+            if (!haveLowAcceleration(0.05d)) {
+                // We flatten the current leaf along the x axis, so that we're
+                // left with a, b, c which define a 1D Bezier curve. We then
+                // solve this to get the parameter of the original leaf that
+                // gives us the desired length.
+                final double[] _flatLeafCoefCache = flatLeafCoefCache;
+
+                if (_flatLeafCoefCache[2] < 0.0d) {
+                    double x =     curLeafCtrlPolyLengths[0],
+                           y = x + curLeafCtrlPolyLengths[1];
+                    if (curveType == 8) {
+                        double z = y + curLeafCtrlPolyLengths[2];
+                        _flatLeafCoefCache[0] = 3.0d * (x - y) + z;
+                        _flatLeafCoefCache[1] = 3.0d * (y - 2.0d * x);
+                        _flatLeafCoefCache[2] = 3.0d * x;
+                        _flatLeafCoefCache[3] = -z;
+                    } else if (curveType == 6) {
+                        _flatLeafCoefCache[0] = 0.0d;
+                        _flatLeafCoefCache[1] = y - 2.0d * x;
+                        _flatLeafCoefCache[2] = 2.0d * x;
+                        _flatLeafCoefCache[3] = -y;
+                    }
+                }
+                double a = _flatLeafCoefCache[0];
+                double b = _flatLeafCoefCache[1];
+                double c = _flatLeafCoefCache[2];
+                double d = t * _flatLeafCoefCache[3];
+
+                // we use cubicRootsInAB here, because we want only roots in 0, 1,
+                // and our quadratic root finder doesn't filter, so it's just a
+                // matter of convenience.
+                final int n = DHelpers.cubicRootsInAB(a, b, c, d, nextRoots, 0, 0.0d, 1.0d);
+// TODO: check NaN is impossible
+                if (n == 1 && !Double.isNaN(nextRoots[0])) {
+                    t = nextRoots[0];
+                }
+            }
+            // t is relative to the current leaf, so we must make it a valid parameter
+            // of the original curve.
+            t = t * (nextT - lastT) + lastT;
+            if (t >= 1.0d) {
+                t = 1.0d;
+                done = true;
+            }
+            // even if done = true, if we're here, that means targetLength
+            // is equal to, or very, very close to the total length of the
+            // curve, so lastSegLen won't be too high. In cases where len
+            // overshoots the curve, this method will exit in the while
+            // loop, and lastSegLen will still be set to the right value.
+            lastSegLen = len;
+            return t;
+        }
+
+        double totalLength() {
+            while (!done) {
+                goToNextLeaf();
+            }
+            // reset LengthIterator:
+            reset();
+
+            return lenAtNextT;
+        }
+
+        double lastSegLen() {
+            return lastSegLen;
+        }
+
+        // go to the next leaf (in an inorder traversal) in the recursion tree
+        // preconditions: must be on a leaf, and that leaf must not be the root.
+        private void goToNextLeaf() {
+            // We must go to the first ancestor node that has an unvisited
+            // right child.
+            final boolean[] _sides = sidesRight;
+            int _recLevel = recLevel;
+            _recLevel--;
+
+            while(_sides[_recLevel]) {
+                if (_recLevel == 0) {
+                    recLevel = 0;
+                    done = true;
+                    return;
+                }
+                _recLevel--;
+            }
+
+            _sides[_recLevel] = true;
+            // optimize arraycopy (8 values faster than 6 = type):
+            System.arraycopy(recCurveStack[_recLevel++], 0,
+                             recCurveStack[_recLevel], 0, 8);
+            recLevel = _recLevel;
+            goLeft();
+        }
+
+        // go to the leftmost node from the current node. Return its length.
+        private void goLeft() {
+            final double len = onLeaf();
+            if (len >= 0.0d) {
+                lastT = nextT;
+                lenAtLastT = lenAtNextT;
+                nextT += (1 << (REC_LIMIT - recLevel)) * MIN_T_INC;
+                lenAtNextT += len;
+                // invalidate caches
+                flatLeafCoefCache[2] = -1.0d;
+                cachedHaveLowAcceleration = -1;
+            } else {
+                DHelpers.subdivide(recCurveStack[recLevel],
+                                   recCurveStack[recLevel + 1],
+                                   recCurveStack[recLevel], curveType);
+
+                sidesRight[recLevel] = false;
+                recLevel++;
+                goLeft();
+            }
+        }
+
+        // this is a bit of a hack. It returns -1 if we're not on a leaf, and
+        // the length of the leaf if we are on a leaf.
+        private double onLeaf() {
+            final double[] curve = recCurveStack[recLevel];
+            final int _curveType = curveType;
+            double polyLen = 0.0d;
+
+            double x0 = curve[0], y0 = curve[1];
+            for (int i = 2; i < _curveType; i += 2) {
+                final double x1 = curve[i], y1 = curve[i + 1];
+                final double len = DHelpers.linelen(x0, y0, x1, y1);
+                polyLen += len;
+                curLeafCtrlPolyLengths[(i >> 1) - 1] = len;
+                x0 = x1;
+                y0 = y1;
+            }
+
+            final double lineLen = DHelpers.linelen(curve[0], curve[1], x0, y0);
+
+            if ((polyLen - lineLen) < CURVE_LEN_ERR || recLevel == REC_LIMIT) {
+/*
+                if (recLevel == REC_LIMIT) {
+                    System.out.println("REC_LIMIT[" + recLevel + "] reached !");
+                }
+*/
+                return (polyLen + lineLen) / 2.0d;
+            }
+            return -1.0d;
+        }
+    }
+
+    @Override
+    public void curveTo(final double x1, final double y1,
+                        final double x2, final double y2,
+                        final double x3, final double y3)
+    {
+        final int outcode0 = this.cOutCode;
+
+        if (clipRect != null) {
+            final int outcode1 = DHelpers.outcode(x1, y1, clipRect);
+            final int outcode2 = DHelpers.outcode(x2, y2, clipRect);
+            final int outcode3 = DHelpers.outcode(x3, y3, clipRect);
+
+            // Should clip
+            final int orCode = (outcode0 | outcode1 | outcode2 | outcode3);
+            if (orCode != 0) {
+                final int sideCode = outcode0 & outcode1 & outcode2 & outcode3;
+
+                // basic rejection criteria:
+                if (sideCode == 0) {
+                    // ovelap clip:
+                    if (subdivide) {
+                        // avoid reentrance
+                        subdivide = false;
+                        // subdivide curve => callback with subdivided parts:
+                        boolean ret = curveSplitter.splitCurve(cx0, cy0, x1, y1, x2, y2, x3, y3,
+                                                               orCode, this);
+                        // reentrance is done:
+                        subdivide = true;
+                        if (ret) {
+                            return;
+                        }
+                    }
+                    // already subdivided so render it
+                } else {
+                    this.cOutCode = outcode3;
+                    skipCurveTo(x1, y1, x2, y2, x3, y3);
+                    return;
+                }
+            }
+
+            this.cOutCode = outcode3;
+
+            if (this.outside) {
+                this.outside = false;
+                // Adjust current index, phase & dash:
+                skipLen();
+            }
+        }
+        _curveTo(x1, y1, x2, y2, x3, y3);
+    }
+
+    private void _curveTo(final double x1, final double y1,
+                          final double x2, final double y2,
+                          final double x3, final double y3)
+    {
+        final double[] _curCurvepts = curCurvepts;
+
+        // monotonize curve:
+        final CurveBasicMonotonizer monotonizer
+            = rdrCtx.monotonizer.curve(cx0, cy0, x1, y1, x2, y2, x3, y3);
+
+        final int nSplits = monotonizer.nbSplits;
+        final double[] mid = monotonizer.middle;
+
+        for (int i = 0, off = 0; i <= nSplits; i++, off += 6) {
+            // optimize arraycopy (8 values faster than 6 = type):
+            System.arraycopy(mid, off, _curCurvepts, 0, 8);
+
+            somethingTo(8);
+        }
+    }
+
+    private void skipCurveTo(final double x1, final double y1,
+                             final double x2, final double y2,
+                             final double x3, final double y3)
+    {
+        final double[] _curCurvepts = curCurvepts;
+        _curCurvepts[0] = cx0; _curCurvepts[1] = cy0;
+        _curCurvepts[2] = x1;  _curCurvepts[3] = y1;
+        _curCurvepts[4] = x2;  _curCurvepts[5] = y2;
+        _curCurvepts[6] = x3;  _curCurvepts[7] = y3;
+
+        skipSomethingTo(8);
+
+        this.cx0 = x3;
+        this.cy0 = y3;
+    }
+
+    @Override
+    public void quadTo(final double x1, final double y1,
+                       final double x2, final double y2)
+    {
+        final int outcode0 = this.cOutCode;
+
+        if (clipRect != null) {
+            final int outcode1 = DHelpers.outcode(x1, y1, clipRect);
+            final int outcode2 = DHelpers.outcode(x2, y2, clipRect);
+
+            // Should clip
+            final int orCode = (outcode0 | outcode1 | outcode2);
+            if (orCode != 0) {
+                final int sideCode = outcode0 & outcode1 & outcode2;
+
+                // basic rejection criteria:
+                if (sideCode == 0) {
+                    // ovelap clip:
+                    if (subdivide) {
+                        // avoid reentrance
+                        subdivide = false;
+                        // subdivide curve => call lineTo() with subdivided curves:
+                        boolean ret = curveSplitter.splitQuad(cx0, cy0, x1, y1,
+                                                              x2, y2, orCode, this);
+                        // reentrance is done:
+                        subdivide = true;
+                        if (ret) {
+                            return;
+                        }
+                    }
+                    // already subdivided so render it
+                } else {
+                    this.cOutCode = outcode2;
+                    skipQuadTo(x1, y1, x2, y2);
+                    return;
+                }
+            }
+
+            this.cOutCode = outcode2;
+
+            if (this.outside) {
+                this.outside = false;
+                // Adjust current index, phase & dash:
+                skipLen();
+            }
+        }
+        _quadTo(x1, y1, x2, y2);
+    }
+
+    private void _quadTo(final double x1, final double y1,
+                         final double x2, final double y2)
+    {
+        final double[] _curCurvepts = curCurvepts;
+
+        // monotonize quad:
+        final CurveBasicMonotonizer monotonizer
+            = rdrCtx.monotonizer.quad(cx0, cy0, x1, y1, x2, y2);
+
+        final int nSplits = monotonizer.nbSplits;
+        final double[] mid = monotonizer.middle;
+
+        for (int i = 0, off = 0; i <= nSplits; i++, off += 4) {
+            // optimize arraycopy (8 values faster than 6 = type):
+            System.arraycopy(mid, off, _curCurvepts, 0, 8);
+
+            somethingTo(6);
+        }
+    }
+
+    private void skipQuadTo(final double x1, final double y1,
+                            final double x2, final double y2)
+    {
+        final double[] _curCurvepts = curCurvepts;
+        _curCurvepts[0] = cx0; _curCurvepts[1] = cy0;
+        _curCurvepts[2] = x1;  _curCurvepts[3] = y1;
+        _curCurvepts[4] = x2;  _curCurvepts[5] = y2;
+
+        skipSomethingTo(6);
+
+        this.cx0 = x2;
+        this.cy0 = y2;
+    }
+
+    @Override
+    public void closePath() {
+        if (cx0 != sx0 || cy0 != sy0) {
+            lineTo(sx0, sy0);
+        }
+        if (firstSegidx != 0) {
+            if (!dashOn || needsMoveTo) {
+                out.moveTo(sx0, sy0);
+            }
+            emitFirstSegments();
+        }
+        moveTo(sx0, sy0);
+    }
+
+    @Override
+    public void pathDone() {
+        if (firstSegidx != 0) {
+            out.moveTo(sx0, sy0);
+            emitFirstSegments();
+        }
+        out.pathDone();
+
+        // Dispose this instance:
+        dispose();
+    }
+
+    @Override
+    public long getNativeConsumer() {
+        throw new InternalError("DDasher does not use a native consumer");
+    }
+}
+
diff --git a/src/share/classes/sun/java2d/marlin/DHelpers.java b/src/share/classes/sun/java2d/marlin/DHelpers.java
new file mode 100644
index 0000000..7bcb006
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/DHelpers.java
@@ -0,0 +1,995 @@
+/*
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d.marlin;
+
+import java.util.Arrays;
+import sun.java2d.marlin.stats.Histogram;
+import sun.java2d.marlin.stats.StatLong;
+
+final class DHelpers implements MarlinConst {
+
+    private DHelpers() {
+        throw new Error("This is a non instantiable class");
+    }
+
+    static boolean within(final double x, final double y, final double err) {
+        final double d = y - x;
+        return (d <= err && d >= -err);
+    }
+
+    public static double evalCubic(final double a, final double b,
+                                   final double c, final double d,
+                                   final double t)
+    {
+        return t * (t * (t * a + b) + c) + d;
+    }
+
+    public static double evalQuad(final double a, final double b,
+                                  final double c, final double t)
+    {
+        return t * (t * a + b) + c;
+    }
+
+    static int quadraticRoots(final double a, final double b, final double c,
+                              final double[] zeroes, final int off)
+    {
+        int ret = off;
+        if (a != 0.0d) {
+            final double dis = b*b - 4.0d * a * c;
+            if (dis > 0.0d) {
+                final double sqrtDis = Math.sqrt(dis);
+                // depending on the sign of b we use a slightly different
+                // algorithm than the traditional one to find one of the roots
+                // so we can avoid adding numbers of different signs (which
+                // might result in loss of precision).
+                if (b >= 0.0d) {
+                    zeroes[ret++] = (2.0d * c) / (-b - sqrtDis);
+                    zeroes[ret++] = (-b - sqrtDis) / (2.0d * a);
+                } else {
+                    zeroes[ret++] = (-b + sqrtDis) / (2.0d * a);
+                    zeroes[ret++] = (2.0d * c) / (-b + sqrtDis);
+                }
+            } else if (dis == 0.0d) {
+                zeroes[ret++] = -b / (2.0d * a);
+            }
+        } else if (b != 0.0d) {
+            zeroes[ret++] = -c / b;
+        }
+        return ret - off;
+    }
+
+    // find the roots of g(t) = d*t^3 + a*t^2 + b*t + c in [A,B)
+    static int cubicRootsInAB(final double d, double a, double b, double c,
+                              final double[] pts, final int off,
+                              final double A, final double B)
+    {
+        if (d == 0.0d) {
+            final int num = quadraticRoots(a, b, c, pts, off);
+            return filterOutNotInAB(pts, off, num, A, B) - off;
+        }
+        // From Graphics Gems:
+        // https://github.com/erich666/GraphicsGems/blob/master/gems/Roots3And4.c
+        // (also from awt.geom.CubicCurve2D. But here we don't need as
+        // much accuracy and we don't want to create arrays so we use
+        // our own customized version).
+
+        // normal form: x^3 + ax^2 + bx + c = 0
+
+        /*
+         * TODO: cleanup all that code after reading Roots3And4.c
+         */
+        a /= d;
+        b /= d;
+        c /= d;
+
+        //  substitute x = y - A/3 to eliminate quadratic term:
+        //     x^3 +Px + Q = 0
+        //
+        // Since we actually need P/3 and Q/2 for all of the
+        // calculations that follow, we will calculate
+        // p = P/3
+        // q = Q/2
+        // instead and use those values for simplicity of the code.
+        final double sub = (1.0d / 3.0d) * a;
+        final double sq_A = a * a;
+        final double p = (1.0d / 3.0d) * ((-1.0d / 3.0d) * sq_A + b);
+        final double q = (1.0d / 2.0d) * ((2.0d / 27.0d) * a * sq_A - sub * b + c);
+
+        // use Cardano's formula
+
+        final double cb_p = p * p * p;
+        final double D = q * q + cb_p;
+
+        int num;
+        if (D < 0.0d) {
+            // see: http://en.wikipedia.org/wiki/Cubic_function#Trigonometric_.28and_hyperbolic.29_method
+            final double phi = (1.0d / 3.0d) * Math.acos(-q / Math.sqrt(-cb_p));
+            final double t = 2.0d * Math.sqrt(-p);
+
+            pts[off    ] = ( t * Math.cos(phi) - sub);
+            pts[off + 1] = (-t * Math.cos(phi + (Math.PI / 3.0d)) - sub);
+            pts[off + 2] = (-t * Math.cos(phi - (Math.PI / 3.0d)) - sub);
+            num = 3;
+        } else {
+            final double sqrt_D = Math.sqrt(D);
+            final double u =   Math.cbrt(sqrt_D - q);
+            final double v = - Math.cbrt(sqrt_D + q);
+
+            pts[off    ] = (u + v - sub);
+            num = 1;
+
+            if (within(D, 0.0d, 1e-8d)) {
+                pts[off + 1] = ((-1.0d / 2.0d) * (u + v) - sub);
+                num = 2;
+            }
+        }
+
+        return filterOutNotInAB(pts, off, num, A, B) - off;
+    }
+
+    // returns the index 1 past the last valid element remaining after filtering
+    static int filterOutNotInAB(final double[] nums, final int off, final int len,
+                                final double a, final double b)
+    {
+        int ret = off;
+        for (int i = off, end = off + len; i < end; i++) {
+            if (nums[i] >= a && nums[i] < b) {
+                nums[ret++] = nums[i];
+            }
+        }
+        return ret;
+    }
+
+    static double fastLineLen(final double x0, final double y0,
+                              final double x1, final double y1)
+    {
+        final double dx = x1 - x0;
+        final double dy = y1 - y0;
+
+        // use manhattan norm:
+        return Math.abs(dx) + Math.abs(dy);
+    }
+
+    static double linelen(final double x0, final double y0,
+                          final double x1, final double y1)
+    {
+        final double dx = x1 - x0;
+        final double dy = y1 - y0;
+        return Math.sqrt(dx * dx + dy * dy);
+    }
+
+    static double fastQuadLen(final double x0, final double y0,
+                              final double x1, final double y1,
+                              final double x2, final double y2)
+    {
+        final double dx1 = x1 - x0;
+        final double dx2 = x2 - x1;
+        final double dy1 = y1 - y0;
+        final double dy2 = y2 - y1;
+
+        // use manhattan norm:
+        return Math.abs(dx1) + Math.abs(dx2)
+             + Math.abs(dy1) + Math.abs(dy2);
+    }
+
+    static double quadlen(final double x0, final double y0,
+                          final double x1, final double y1,
+                          final double x2, final double y2)
+    {
+        return (linelen(x0, y0, x1, y1)
+                + linelen(x1, y1, x2, y2)
+                + linelen(x0, y0, x2, y2)) / 2.0d;
+    }
+
+    static double fastCurvelen(final double x0, final double y0,
+                               final double x1, final double y1,
+                               final double x2, final double y2,
+                               final double x3, final double y3)
+    {
+        final double dx1 = x1 - x0;
+        final double dx2 = x2 - x1;
+        final double dx3 = x3 - x2;
+        final double dy1 = y1 - y0;
+        final double dy2 = y2 - y1;
+        final double dy3 = y3 - y2;
+
+        // use manhattan norm:
+        return Math.abs(dx1) + Math.abs(dx2) + Math.abs(dx3)
+             + Math.abs(dy1) + Math.abs(dy2) + Math.abs(dy3);
+    }
+
+    static double curvelen(final double x0, final double y0,
+                           final double x1, final double y1,
+                           final double x2, final double y2,
+                           final double x3, final double y3)
+    {
+        return (linelen(x0, y0, x1, y1)
+              + linelen(x1, y1, x2, y2)
+              + linelen(x2, y2, x3, y3)
+              + linelen(x0, y0, x3, y3)) / 2.0d;
+    }
+
+    // finds values of t where the curve in pts should be subdivided in order
+    // to get good offset curves a distance of w away from the middle curve.
+    // Stores the points in ts, and returns how many of them there were.
+    static int findSubdivPoints(final DCurve c, final double[] pts,
+                                final double[] ts, final int type,
+                                final double w2)
+    {
+        final double x12 = pts[2] - pts[0];
+        final double y12 = pts[3] - pts[1];
+        // if the curve is already parallel to either axis we gain nothing
+        // from rotating it.
+        if ((y12 != 0.0d && x12 != 0.0d)) {
+            // we rotate it so that the first vector in the control polygon is
+            // parallel to the x-axis. This will ensure that rotated quarter
+            // circles won't be subdivided.
+            final double hypot = Math.sqrt(x12 * x12 + y12 * y12);
+            final double cos = x12 / hypot;
+            final double sin = y12 / hypot;
+            final double x1 = cos * pts[0] + sin * pts[1];
+            final double y1 = cos * pts[1] - sin * pts[0];
+            final double x2 = cos * pts[2] + sin * pts[3];
+            final double y2 = cos * pts[3] - sin * pts[2];
+            final double x3 = cos * pts[4] + sin * pts[5];
+            final double y3 = cos * pts[5] - sin * pts[4];
+
+            switch(type) {
+            case 8:
+                final double x4 = cos * pts[6] + sin * pts[7];
+                final double y4 = cos * pts[7] - sin * pts[6];
+                c.set(x1, y1, x2, y2, x3, y3, x4, y4);
+                break;
+            case 6:
+                c.set(x1, y1, x2, y2, x3, y3);
+                break;
+            default:
+            }
+        } else {
+            c.set(pts, type);
+        }
+
+        int ret = 0;
+        // we subdivide at values of t such that the remaining rotated
+        // curves are monotonic in x and y.
+        ret += c.dxRoots(ts, ret);
+        ret += c.dyRoots(ts, ret);
+
+        // subdivide at inflection points.
+        if (type == 8) {
+            // quadratic curves can't have inflection points
+            ret += c.infPoints(ts, ret);
+        }
+
+        // now we must subdivide at points where one of the offset curves will have
+        // a cusp. This happens at ts where the radius of curvature is equal to w.
+        ret += c.rootsOfROCMinusW(ts, ret, w2, 0.0001d);
+
+        ret = filterOutNotInAB(ts, 0, ret, 0.0001d, 0.9999d);
+        isort(ts, ret);
+        return ret;
+    }
+
+    // finds values of t where the curve in pts should be subdivided in order
+    // to get intersections with the given clip rectangle.
+    // Stores the points in ts, and returns how many of them there were.
+    static int findClipPoints(final DCurve curve, final double[] pts,
+                              final double[] ts, final int type,
+                              final int outCodeOR,
+                              final double[] clipRect)
+    {
+        curve.set(pts, type);
+
+        // clip rectangle (ymin, ymax, xmin, xmax)
+        int ret = 0;
+
+        if ((outCodeOR & OUTCODE_LEFT) != 0) {
+            ret += curve.xPoints(ts, ret, clipRect[2]);
+        }
+        if ((outCodeOR & OUTCODE_RIGHT) != 0) {
+            ret += curve.xPoints(ts, ret, clipRect[3]);
+        }
+        if ((outCodeOR & OUTCODE_TOP) != 0) {
+            ret += curve.yPoints(ts, ret, clipRect[0]);
+        }
+        if ((outCodeOR & OUTCODE_BOTTOM) != 0) {
+            ret += curve.yPoints(ts, ret, clipRect[1]);
+        }
+        isort(ts, ret);
+        return ret;
+    }
+
+    static void subdivide(final double[] src,
+                          final double[] left, final double[] right,
+                          final int type)
+    {
+        switch(type) {
+        case 4:
+            subdivideLine(src, left, right);
+            return;
+        case 6:
+            subdivideQuad(src, left, right);
+            return;
+        case 8:
+            subdivideCubic(src, left, right);
+            return;
+        default:
+            throw new InternalError("Unsupported curve type");
+        }
+    }
+
+    static void isort(final double[] a, final int len) {
+        for (int i = 1, j; i < len; i++) {
+            final double ai = a[i];
+            j = i - 1;
+            for (; j >= 0 && a[j] > ai; j--) {
+                a[j + 1] = a[j];
+            }
+            a[j + 1] = ai;
+        }
+    }
+
+    // Most of these are copied from classes in java.awt.geom because we need
+    // both single and double precision variants of these functions, and Line2D,
+    // CubicCurve2D, QuadCurve2D don't provide them.
+    /**
+     * Subdivides the cubic curve specified by the coordinates
+     * stored in the <code>src</code> array at indices <code>srcoff</code>
+     * through (<code>srcoff</code>&nbsp;+&nbsp;7) and stores the
+     * resulting two subdivided curves into the two result arrays at the
+     * corresponding indices.
+     * Either or both of the <code>left</code> and <code>right</code>
+     * arrays may be <code>null</code> or a reference to the same array
+     * as the <code>src</code> array.
+     * Note that the last point in the first subdivided curve is the
+     * same as the first point in the second subdivided curve. Thus,
+     * it is possible to pass the same array for <code>left</code>
+     * and <code>right</code> and to use offsets, such as <code>rightoff</code>
+     * equals (<code>leftoff</code> + 6), in order
+     * to avoid allocating extra storage for this common point.
+     * @param src the array holding the coordinates for the source curve
+     * @param left the array for storing the coordinates for the first
+     * half of the subdivided curve
+     * @param right the array for storing the coordinates for the second
+     * half of the subdivided curve
+     * @since 1.7
+     */
+    static void subdivideCubic(final double[] src,
+                               final double[] left,
+                               final double[] right)
+    {
+        double  x1 = src[0];
+        double  y1 = src[1];
+        double cx1 = src[2];
+        double cy1 = src[3];
+        double cx2 = src[4];
+        double cy2 = src[5];
+        double  x2 = src[6];
+        double  y2 = src[7];
+
+        left[0]  = x1;
+        left[1]  = y1;
+
+        right[6] = x2;
+        right[7] = y2;
+
+        x1 = (x1 + cx1) / 2.0d;
+        y1 = (y1 + cy1) / 2.0d;
+        x2 = (x2 + cx2) / 2.0d;
+        y2 = (y2 + cy2) / 2.0d;
+
+        double cx = (cx1 + cx2) / 2.0d;
+        double cy = (cy1 + cy2) / 2.0d;
+
+        cx1 = (x1 + cx) / 2.0d;
+        cy1 = (y1 + cy) / 2.0d;
+        cx2 = (x2 + cx) / 2.0d;
+        cy2 = (y2 + cy) / 2.0d;
+        cx  = (cx1 + cx2) / 2.0d;
+        cy  = (cy1 + cy2) / 2.0d;
+
+        left[2] = x1;
+        left[3] = y1;
+        left[4] = cx1;
+        left[5] = cy1;
+        left[6] = cx;
+        left[7] = cy;
+
+        right[0] = cx;
+        right[1] = cy;
+        right[2] = cx2;
+        right[3] = cy2;
+        right[4] = x2;
+        right[5] = y2;
+    }
+
+    static void subdivideCubicAt(final double t,
+                                 final double[] src, final int offS,
+                                 final double[] pts, final int offL, final int offR)
+    {
+        double  x1 = src[offS    ];
+        double  y1 = src[offS + 1];
+        double cx1 = src[offS + 2];
+        double cy1 = src[offS + 3];
+        double cx2 = src[offS + 4];
+        double cy2 = src[offS + 5];
+        double  x2 = src[offS + 6];
+        double  y2 = src[offS + 7];
+
+        pts[offL    ] = x1;
+        pts[offL + 1] = y1;
+
+        pts[offR + 6] = x2;
+        pts[offR + 7] = y2;
+
+        x1 =  x1 + t * (cx1 - x1);
+        y1 =  y1 + t * (cy1 - y1);
+        x2 = cx2 + t * (x2 - cx2);
+        y2 = cy2 + t * (y2 - cy2);
+
+        double cx = cx1 + t * (cx2 - cx1);
+        double cy = cy1 + t * (cy2 - cy1);
+
+        cx1 =  x1 + t * (cx - x1);
+        cy1 =  y1 + t * (cy - y1);
+        cx2 =  cx + t * (x2 - cx);
+        cy2 =  cy + t * (y2 - cy);
+        cx  = cx1 + t * (cx2 - cx1);
+        cy  = cy1 + t * (cy2 - cy1);
+
+        pts[offL + 2] = x1;
+        pts[offL + 3] = y1;
+        pts[offL + 4] = cx1;
+        pts[offL + 5] = cy1;
+        pts[offL + 6] = cx;
+        pts[offL + 7] = cy;
+
+        pts[offR    ] = cx;
+        pts[offR + 1] = cy;
+        pts[offR + 2] = cx2;
+        pts[offR + 3] = cy2;
+        pts[offR + 4] = x2;
+        pts[offR + 5] = y2;
+    }
+
+    static void subdivideLine(final double[] src,
+                              final double[] left,
+                              final double[] right)
+    {
+        double x1 = src[0];
+        double y1 = src[1];
+        double x2 = src[2];
+        double y2 = src[3];
+
+        left[0]  = x1;
+        left[1]  = y1;
+
+        right[2] = x2;
+        right[3] = y2;
+
+        double cx = (x1 + x2) / 2.0d;
+        double cy = (y1 + y2) / 2.0d;
+
+        left[2] = cx;
+        left[3] = cy;
+
+        right[0] = cx;
+        right[1] = cy;
+    }
+
+    static void subdivideQuad(final double[] src,
+                              final double[] left,
+                              final double[] right)
+    {
+        double x1 = src[0];
+        double y1 = src[1];
+        double cx = src[2];
+        double cy = src[3];
+        double x2 = src[4];
+        double y2 = src[5];
+
+        left[0]  = x1;
+        left[1]  = y1;
+
+        right[4] = x2;
+        right[5] = y2;
+
+        x1 = (x1 + cx) / 2.0d;
+        y1 = (y1 + cy) / 2.0d;
+        x2 = (x2 + cx) / 2.0d;
+        y2 = (y2 + cy) / 2.0d;
+        cx = (x1 + x2) / 2.0d;
+        cy = (y1 + y2) / 2.0d;
+
+        left[2] = x1;
+        left[3] = y1;
+        left[4] = cx;
+        left[5] = cy;
+
+        right[0] = cx;
+        right[1] = cy;
+        right[2] = x2;
+        right[3] = y2;
+    }
+
+    static void subdivideQuadAt(final double t,
+                                final double[] src, final int offS,
+                                final double[] pts, final int offL, final int offR)
+    {
+        double x1 = src[offS    ];
+        double y1 = src[offS + 1];
+        double cx = src[offS + 2];
+        double cy = src[offS + 3];
+        double x2 = src[offS + 4];
+        double y2 = src[offS + 5];
+
+        pts[offL    ] = x1;
+        pts[offL + 1] = y1;
+
+        pts[offR + 4] = x2;
+        pts[offR + 5] = y2;
+
+        x1 = x1 + t * (cx - x1);
+        y1 = y1 + t * (cy - y1);
+        x2 = cx + t * (x2 - cx);
+        y2 = cy + t * (y2 - cy);
+        cx = x1 + t * (x2 - x1);
+        cy = y1 + t * (y2 - y1);
+
+        pts[offL + 2] = x1;
+        pts[offL + 3] = y1;
+        pts[offL + 4] = cx;
+        pts[offL + 5] = cy;
+
+        pts[offR    ] = cx;
+        pts[offR + 1] = cy;
+        pts[offR + 2] = x2;
+        pts[offR + 3] = y2;
+    }
+
+    static void subdivideLineAt(final double t,
+                                final double[] src, final int offS,
+                                final double[] pts, final int offL, final int offR)
+    {
+        double x1 = src[offS    ];
+        double y1 = src[offS + 1];
+        double x2 = src[offS + 2];
+        double y2 = src[offS + 3];
+
+        pts[offL    ] = x1;
+        pts[offL + 1] = y1;
+
+        pts[offR + 2] = x2;
+        pts[offR + 3] = y2;
+
+        x1 = x1 + t * (x2 - x1);
+        y1 = y1 + t * (y2 - y1);
+
+        pts[offL + 2] = x1;
+        pts[offL + 3] = y1;
+
+        pts[offR    ] = x1;
+        pts[offR + 1] = y1;
+    }
+
+    static void subdivideAt(final double t,
+                            final double[] src, final int offS,
+                            final double[] pts, final int offL, final int type)
+    {
+        // if instead of switch (perf + most probable cases first)
+        if (type == 8) {
+            subdivideCubicAt(t, src, offS, pts, offL, offL + type);
+        } else if (type == 4) {
+            subdivideLineAt(t, src, offS, pts, offL, offL + type);
+        } else {
+            subdivideQuadAt(t, src, offS, pts, offL, offL + type);
+        }
+    }
+
+    // From sun.java2d.loops.GeneralRenderer:
+
+    static int outcode(final double x, final double y,
+                       final double[] clipRect)
+    {
+        int code;
+        if (y < clipRect[0]) {
+            code = OUTCODE_TOP;
+        } else if (y >= clipRect[1]) {
+            code = OUTCODE_BOTTOM;
+        } else {
+            code = 0;
+        }
+        if (x < clipRect[2]) {
+            code |= OUTCODE_LEFT;
+        } else if (x >= clipRect[3]) {
+            code |= OUTCODE_RIGHT;
+        }
+        return code;
+    }
+
+    // a stack of polynomial curves where each curve shares endpoints with
+    // adjacent ones.
+    static final class PolyStack {
+        private static final byte TYPE_LINETO  = (byte) 0;
+        private static final byte TYPE_QUADTO  = (byte) 1;
+        private static final byte TYPE_CUBICTO = (byte) 2;
+
+        // curves capacity = edges count (8192) = edges x 2 (coords)
+        private static final int INITIAL_CURVES_COUNT = INITIAL_EDGES_COUNT << 1;
+
+        // types capacity = edges count (4096)
+        private static final int INITIAL_TYPES_COUNT = INITIAL_EDGES_COUNT;
+
+        double[] curves;
+        int end;
+        byte[] curveTypes;
+        int numCurves;
+
+        // curves ref (dirty)
+        final DoubleArrayCache.Reference curves_ref;
+        // curveTypes ref (dirty)
+        final ByteArrayCache.Reference curveTypes_ref;
+
+        // used marks (stats only)
+        int curveTypesUseMark;
+        int curvesUseMark;
+
+        private final StatLong stat_polystack_types;
+        private final StatLong stat_polystack_curves;
+        private final Histogram hist_polystack_curves;
+        private final StatLong stat_array_polystack_curves;
+        private final StatLong stat_array_polystack_curveTypes;
+
+        PolyStack(final DRendererContext rdrCtx) {
+            this(rdrCtx, null, null, null, null, null);
+        }
+
+        PolyStack(final DRendererContext rdrCtx,
+                  final StatLong stat_polystack_types,
+                  final StatLong stat_polystack_curves,
+                  final Histogram hist_polystack_curves,
+                  final StatLong stat_array_polystack_curves,
+                  final StatLong stat_array_polystack_curveTypes)
+        {
+            curves_ref = rdrCtx.newDirtyDoubleArrayRef(INITIAL_CURVES_COUNT); // 32K
+            curves     = curves_ref.initial;
+
+            curveTypes_ref = rdrCtx.newDirtyByteArrayRef(INITIAL_TYPES_COUNT); // 4K
+            curveTypes     = curveTypes_ref.initial;
+            numCurves = 0;
+            end = 0;
+
+            if (DO_STATS) {
+                curveTypesUseMark = 0;
+                curvesUseMark = 0;
+            }
+            this.stat_polystack_types = stat_polystack_types;
+            this.stat_polystack_curves = stat_polystack_curves;
+            this.hist_polystack_curves = hist_polystack_curves;
+            this.stat_array_polystack_curves = stat_array_polystack_curves;
+            this.stat_array_polystack_curveTypes = stat_array_polystack_curveTypes;
+        }
+
+        /**
+         * Disposes this PolyStack:
+         * clean up before reusing this instance
+         */
+        void dispose() {
+            end = 0;
+            numCurves = 0;
+
+            if (DO_STATS) {
+                stat_polystack_types.add(curveTypesUseMark);
+                stat_polystack_curves.add(curvesUseMark);
+                hist_polystack_curves.add(curvesUseMark);
+
+                // reset marks
+                curveTypesUseMark = 0;
+                curvesUseMark = 0;
+            }
+
+            // Return arrays:
+            // curves and curveTypes are kept dirty
+            curves     = curves_ref.putArray(curves);
+            curveTypes = curveTypes_ref.putArray(curveTypes);
+        }
+
+        private void ensureSpace(final int n) {
+            // use substraction to avoid integer overflow:
+            if (curves.length - end < n) {
+                if (DO_STATS) {
+                    stat_array_polystack_curves.add(end + n);
+                }
+                curves = curves_ref.widenArray(curves, end, end + n);
+            }
+            if (curveTypes.length <= numCurves) {
+                if (DO_STATS) {
+                    stat_array_polystack_curveTypes.add(numCurves + 1);
+                }
+                curveTypes = curveTypes_ref.widenArray(curveTypes,
+                                                       numCurves,
+                                                       numCurves + 1);
+            }
+        }
+
+        void pushCubic(double x0, double y0,
+                       double x1, double y1,
+                       double x2, double y2)
+        {
+            ensureSpace(6);
+            curveTypes[numCurves++] = TYPE_CUBICTO;
+            // we reverse the coordinate order to make popping easier
+            final double[] _curves = curves;
+            int e = end;
+            _curves[e++] = x2;    _curves[e++] = y2;
+            _curves[e++] = x1;    _curves[e++] = y1;
+            _curves[e++] = x0;    _curves[e++] = y0;
+            end = e;
+        }
+
+        void pushQuad(double x0, double y0,
+                      double x1, double y1)
+        {
+            ensureSpace(4);
+            curveTypes[numCurves++] = TYPE_QUADTO;
+            final double[] _curves = curves;
+            int e = end;
+            _curves[e++] = x1;    _curves[e++] = y1;
+            _curves[e++] = x0;    _curves[e++] = y0;
+            end = e;
+        }
+
+        void pushLine(double x, double y) {
+            ensureSpace(2);
+            curveTypes[numCurves++] = TYPE_LINETO;
+            curves[end++] = x;    curves[end++] = y;
+        }
+
+        void pullAll(final DPathConsumer2D io) {
+            final int nc = numCurves;
+            if (nc == 0) {
+                return;
+            }
+            if (DO_STATS) {
+                // update used marks:
+                if (numCurves > curveTypesUseMark) {
+                    curveTypesUseMark = numCurves;
+                }
+                if (end > curvesUseMark) {
+                    curvesUseMark = end;
+                }
+            }
+            final byte[]  _curveTypes = curveTypes;
+            final double[] _curves = curves;
+            int e = 0;
+
+            for (int i = 0; i < nc; i++) {
+                switch(_curveTypes[i]) {
+                case TYPE_LINETO:
+                    io.lineTo(_curves[e], _curves[e+1]);
+                    e += 2;
+                    continue;
+                case TYPE_QUADTO:
+                    io.quadTo(_curves[e],   _curves[e+1],
+                              _curves[e+2], _curves[e+3]);
+                    e += 4;
+                    continue;
+                case TYPE_CUBICTO:
+                    io.curveTo(_curves[e],   _curves[e+1],
+                               _curves[e+2], _curves[e+3],
+                               _curves[e+4], _curves[e+5]);
+                    e += 6;
+                    continue;
+                default:
+                }
+            }
+            numCurves = 0;
+            end = 0;
+        }
+
+        void popAll(final DPathConsumer2D io) {
+            int nc = numCurves;
+            if (nc == 0) {
+                return;
+            }
+            if (DO_STATS) {
+                // update used marks:
+                if (numCurves > curveTypesUseMark) {
+                    curveTypesUseMark = numCurves;
+                }
+                if (end > curvesUseMark) {
+                    curvesUseMark = end;
+                }
+            }
+            final byte[]  _curveTypes = curveTypes;
+            final double[] _curves = curves;
+            int e  = end;
+
+            while (nc != 0) {
+                switch(_curveTypes[--nc]) {
+                case TYPE_LINETO:
+                    e -= 2;
+                    io.lineTo(_curves[e], _curves[e+1]);
+                    continue;
+                case TYPE_QUADTO:
+                    e -= 4;
+                    io.quadTo(_curves[e],   _curves[e+1],
+                              _curves[e+2], _curves[e+3]);
+                    continue;
+                case TYPE_CUBICTO:
+                    e -= 6;
+                    io.curveTo(_curves[e],   _curves[e+1],
+                               _curves[e+2], _curves[e+3],
+                               _curves[e+4], _curves[e+5]);
+                    continue;
+                default:
+                }
+            }
+            numCurves = 0;
+            end = 0;
+        }
+
+        @Override
+        public String toString() {
+            String ret = "";
+            int nc = numCurves;
+            int last = end;
+            int len;
+            while (nc != 0) {
+                switch(curveTypes[--nc]) {
+                case TYPE_LINETO:
+                    len = 2;
+                    ret += "line: ";
+                    break;
+                case TYPE_QUADTO:
+                    len = 4;
+                    ret += "quad: ";
+                    break;
+                case TYPE_CUBICTO:
+                    len = 6;
+                    ret += "cubic: ";
+                    break;
+                default:
+                    len = 0;
+                }
+                last -= len;
+                ret += Arrays.toString(Arrays.copyOfRange(curves, last, last+len))
+                                       + "\n";
+            }
+            return ret;
+        }
+    }
+
+    // a stack of integer indices
+    static final class IndexStack {
+
+        // integer capacity = edges count / 4 ~ 1024
+        private static final int INITIAL_COUNT = INITIAL_EDGES_COUNT >> 2;
+
+        private int end;
+        private int[] indices;
+
+        // indices ref (dirty)
+        private final IntArrayCache.Reference indices_ref;
+
+        // used marks (stats only)
+        private int indicesUseMark;
+
+        private final StatLong stat_idxstack_indices;
+        private final Histogram hist_idxstack_indices;
+        private final StatLong stat_array_idxstack_indices;
+
+        IndexStack(final DRendererContext rdrCtx) {
+            this(rdrCtx, null, null, null);
+        }
+
+        IndexStack(final DRendererContext rdrCtx,
+                   final StatLong stat_idxstack_indices,
+                   final Histogram hist_idxstack_indices,
+                   final StatLong stat_array_idxstack_indices)
+        {
+            indices_ref = rdrCtx.newDirtyIntArrayRef(INITIAL_COUNT); // 4K
+            indices     = indices_ref.initial;
+            end = 0;
+
+            if (DO_STATS) {
+                indicesUseMark = 0;
+            }
+            this.stat_idxstack_indices = stat_idxstack_indices;
+            this.hist_idxstack_indices = hist_idxstack_indices;
+            this.stat_array_idxstack_indices = stat_array_idxstack_indices;
+        }
+
+        /**
+         * Disposes this PolyStack:
+         * clean up before reusing this instance
+         */
+        void dispose() {
+            end = 0;
+
+            if (DO_STATS) {
+                stat_idxstack_indices.add(indicesUseMark);
+                hist_idxstack_indices.add(indicesUseMark);
+
+                // reset marks
+                indicesUseMark = 0;
+            }
+
+            // Return arrays:
+            // values is kept dirty
+            indices = indices_ref.putArray(indices);
+        }
+
+        boolean isEmpty() {
+            return (end == 0);
+        }
+
+        void reset() {
+            end = 0;
+        }
+
+        void push(final int v) {
+            // remove redundant values (reverse order):
+            int[] _values = indices;
+            final int nc = end;
+            if (nc != 0) {
+                if (_values[nc - 1] == v) {
+                    // remove both duplicated values:
+                    end--;
+                    return;
+                }
+            }
+            if (_values.length <= nc) {
+                if (DO_STATS) {
+                    stat_array_idxstack_indices.add(nc + 1);
+                }
+                indices = _values = indices_ref.widenArray(_values, nc, nc + 1);
+            }
+            _values[end++] = v;
+
+            if (DO_STATS) {
+                // update used marks:
+                if (end > indicesUseMark) {
+                    indicesUseMark = end;
+                }
+            }
+        }
+
+        void pullAll(final double[] points, final DPathConsumer2D io) {
+            final int nc = end;
+            if (nc == 0) {
+                return;
+            }
+            final int[] _values = indices;
+
+            for (int i = 0, j; i < nc; i++) {
+                j = _values[i] << 1;
+                io.lineTo(points[j], points[j + 1]);
+            }
+            end = 0;
+        }
+    }
+}
diff --git a/src/share/classes/sun/java2d/marlin/DMarlinRenderingEngine.java b/src/share/classes/sun/java2d/marlin/DMarlinRenderingEngine.java
new file mode 100644
index 0000000..063584e
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/DMarlinRenderingEngine.java
@@ -0,0 +1,1219 @@
+/*
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d.marlin;
+
+import java.awt.BasicStroke;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Path2D;
+import java.awt.geom.PathIterator;
+import java.security.AccessController;
+import static sun.java2d.marlin.MarlinUtils.logInfo;
+import sun.java2d.ReentrantContextProvider;
+import sun.java2d.ReentrantContextProviderCLQ;
+import sun.java2d.ReentrantContextProviderTL;
+import sun.java2d.pipe.AATileGenerator;
+import sun.java2d.pipe.Region;
+import sun.java2d.pipe.RenderingEngine;
+import sun.security.action.GetPropertyAction;
+
+/**
+ * Marlin RendererEngine implementation (derived from Pisces)
+ */
+public final class DMarlinRenderingEngine extends RenderingEngine
+                                          implements MarlinConst
+{
+    // slightly slower ~2% if enabled stroker clipping (lines) but skipping cap / join handling is few percents faster in specific cases
+    static final boolean DISABLE_2ND_STROKER_CLIPPING = true;
+
+    static final boolean DO_TRACE_PATH = false;
+
+    static final boolean TEST_CLIP = false;
+
+    static final boolean DO_CLIP = MarlinProperties.isDoClip();
+    static final boolean DO_CLIP_FILL = true;
+    static final boolean DO_CLIP_RUNTIME_ENABLE = MarlinProperties.isDoClipRuntimeFlag();
+
+    private static final float MIN_PEN_SIZE = 1.0f / MIN_SUBPIXELS;
+
+    static final double UPPER_BND = Float.MAX_VALUE / 2.0d;
+    static final double LOWER_BND = -UPPER_BND;
+
+    private enum NormMode {
+        ON_WITH_AA {
+            @Override
+            PathIterator getNormalizingPathIterator(final DRendererContext rdrCtx,
+                                                    final PathIterator src)
+            {
+                // NormalizingPathIterator NearestPixelCenter:
+                return rdrCtx.nPCPathIterator.init(src);
+            }
+        },
+        ON_NO_AA{
+            @Override
+            PathIterator getNormalizingPathIterator(final DRendererContext rdrCtx,
+                                                    final PathIterator src)
+            {
+                // NearestPixel NormalizingPathIterator:
+                return rdrCtx.nPQPathIterator.init(src);
+            }
+        },
+        OFF{
+            @Override
+            PathIterator getNormalizingPathIterator(final DRendererContext rdrCtx,
+                                                    final PathIterator src)
+            {
+                // return original path iterator if normalization is disabled:
+                return src;
+            }
+        };
+
+        abstract PathIterator getNormalizingPathIterator(DRendererContext rdrCtx,
+                                                         PathIterator src);
+    }
+
+    /**
+     * Public constructor
+     */
+    public DMarlinRenderingEngine() {
+        super();
+        logSettings(DMarlinRenderingEngine.class.getName());
+    }
+
+    /**
+     * Create a widened path as specified by the parameters.
+     * <p>
+     * The specified {@code src} {@link Shape} is widened according
+     * to the specified attribute parameters as per the
+     * {@link BasicStroke} specification.
+     *
+     * @param src the source path to be widened
+     * @param width the width of the widened path as per {@code BasicStroke}
+     * @param caps the end cap decorations as per {@code BasicStroke}
+     * @param join the segment join decorations as per {@code BasicStroke}
+     * @param miterlimit the miter limit as per {@code BasicStroke}
+     * @param dashes the dash length array as per {@code BasicStroke}
+     * @param dashphase the initial dash phase as per {@code BasicStroke}
+     * @return the widened path stored in a new {@code Shape} object
+     * @since 1.7
+     */
+    @Override
+    public Shape createStrokedShape(Shape src,
+                                    float width,
+                                    int caps,
+                                    int join,
+                                    float miterlimit,
+                                    float[] dashes,
+                                    float dashphase)
+    {
+        final DRendererContext rdrCtx = getRendererContext();
+        try {
+            // initialize a large copyable Path2D to avoid a lot of array growing:
+            final Path2D.Double p2d = rdrCtx.getPath2D();
+
+            strokeTo(rdrCtx,
+                     src,
+                     null,
+                     width,
+                     NormMode.OFF,
+                     caps,
+                     join,
+                     miterlimit,
+                     dashes,
+                     dashphase,
+                     rdrCtx.transformerPC2D.wrapPath2D(p2d)
+                    );
+
+            // Use Path2D copy constructor (trim)
+            return new Path2D.Double(p2d);
+
+        } finally {
+            // recycle the DRendererContext instance
+            returnRendererContext(rdrCtx);
+        }
+    }
+
+    /**
+     * Sends the geometry for a widened path as specified by the parameters
+     * to the specified consumer.
+     * <p>
+     * The specified {@code src} {@link Shape} is widened according
+     * to the parameters specified by the {@link BasicStroke} object.
+     * Adjustments are made to the path as appropriate for the
+     * {@link java.awt.RenderingHints#VALUE_STROKE_NORMALIZE} hint if the
+     * {@code normalize} boolean parameter is true.
+     * Adjustments are made to the path as appropriate for the
+     * {@link java.awt.RenderingHints#VALUE_ANTIALIAS_ON} hint if the
+     * {@code antialias} boolean parameter is true.
+     * <p>
+     * The geometry of the widened path is forwarded to the indicated
+     * {@link DPathConsumer2D} object as it is calculated.
+     *
+     * @param src the source path to be widened
+     * @param bs the {@code BasicSroke} object specifying the
+     *           decorations to be applied to the widened path
+     * @param normalize indicates whether stroke normalization should
+     *                  be applied
+     * @param antialias indicates whether or not adjustments appropriate
+     *                  to antialiased rendering should be applied
+     * @param consumer the {@code DPathConsumer2D} instance to forward
+     *                 the widened geometry to
+     * @since 1.7
+     */
+    @Override
+    public void strokeTo(Shape src,
+                         AffineTransform at,
+                         BasicStroke bs,
+                         boolean thin,
+                         boolean normalize,
+                         boolean antialias,
+                         final sun.awt.geom.PathConsumer2D consumer)
+    {
+        final NormMode norm = (normalize) ?
+                ((antialias) ? NormMode.ON_WITH_AA : NormMode.ON_NO_AA)
+                : NormMode.OFF;
+
+        final DRendererContext rdrCtx = getRendererContext();
+        try {
+            strokeTo(rdrCtx, src, at, bs, thin, norm, antialias,
+                     rdrCtx.p2dAdapter.init(consumer));
+        } finally {
+            // recycle the DRendererContext instance
+            returnRendererContext(rdrCtx);
+        }
+    }
+
+    void strokeTo(final DRendererContext rdrCtx,
+                  Shape src,
+                  AffineTransform at,
+                  BasicStroke bs,
+                  boolean thin,
+                  NormMode normalize,
+                  boolean antialias,
+                  DPathConsumer2D pc2d)
+    {
+        double lw;
+        if (thin) {
+            if (antialias) {
+                lw = userSpaceLineWidth(at, MIN_PEN_SIZE);
+            } else {
+                lw = userSpaceLineWidth(at, 1.0d);
+            }
+        } else {
+            lw = bs.getLineWidth();
+        }
+        strokeTo(rdrCtx,
+                 src,
+                 at,
+                 lw,
+                 normalize,
+                 bs.getEndCap(),
+                 bs.getLineJoin(),
+                 bs.getMiterLimit(),
+                 bs.getDashArray(),
+                 bs.getDashPhase(),
+                 pc2d);
+    }
+
+    private double userSpaceLineWidth(AffineTransform at, double lw) {
+
+        double widthScale;
+
+        if (at == null) {
+            widthScale = 1.0d;
+        } else if ((at.getType() & (AffineTransform.TYPE_GENERAL_TRANSFORM  |
+                                    AffineTransform.TYPE_GENERAL_SCALE)) != 0) {
+            widthScale = Math.sqrt(at.getDeterminant());
+        } else {
+            // First calculate the "maximum scale" of this transform.
+            double A = at.getScaleX();       // m00
+            double C = at.getShearX();       // m01
+            double B = at.getShearY();       // m10
+            double D = at.getScaleY();       // m11
+
+            /*
+             * Given a 2 x 2 affine matrix [ A B ] such that
+             *                             [ C D ]
+             * v' = [x' y'] = [Ax + Cy, Bx + Dy], we want to
+             * find the maximum magnitude (norm) of the vector v'
+             * with the constraint (x^2 + y^2 = 1).
+             * The equation to maximize is
+             *     |v'| = sqrt((Ax+Cy)^2+(Bx+Dy)^2)
+             * or  |v'| = sqrt((AA+BB)x^2 + 2(AC+BD)xy + (CC+DD)y^2).
+             * Since sqrt is monotonic we can maximize |v'|^2
+             * instead and plug in the substitution y = sqrt(1 - x^2).
+             * Trigonometric equalities can then be used to get
+             * rid of most of the sqrt terms.
+             */
+
+            double EA = A*A + B*B;          // x^2 coefficient
+            double EB = 2.0d * (A*C + B*D); // xy coefficient
+            double EC = C*C + D*D;          // y^2 coefficient
+
+            /*
+             * There is a lot of calculus omitted here.
+             *
+             * Conceptually, in the interests of understanding the
+             * terms that the calculus produced we can consider
+             * that EA and EC end up providing the lengths along
+             * the major axes and the hypot term ends up being an
+             * adjustment for the additional length along the off-axis
+             * angle of rotated or sheared ellipses as well as an
+             * adjustment for the fact that the equation below
+             * averages the two major axis lengths.  (Notice that
+             * the hypot term contains a part which resolves to the
+             * difference of these two axis lengths in the absence
+             * of rotation.)
+             *
+             * In the calculus, the ratio of the EB and (EA-EC) terms
+             * ends up being the tangent of 2*theta where theta is
+             * the angle that the long axis of the ellipse makes
+             * with the horizontal axis.  Thus, this equation is
+             * calculating the length of the hypotenuse of a triangle
+             * along that axis.
+             */
+
+            double hypot = Math.sqrt(EB*EB + (EA-EC)*(EA-EC));
+            // sqrt omitted, compare to squared limits below.
+            double widthsquared = ((EA + EC + hypot) / 2.0d);
+
+            widthScale = Math.sqrt(widthsquared);
+        }
+
+        return (lw / widthScale);
+    }
+
+    void strokeTo(final DRendererContext rdrCtx,
+                  Shape src,
+                  AffineTransform at,
+                  double width,
+                  NormMode norm,
+                  int caps,
+                  int join,
+                  float miterlimit,
+                  float[] dashes,
+                  float dashphase,
+                  DPathConsumer2D pc2d)
+    {
+        // We use strokerat so that in Stroker and Dasher we can work only
+        // with the pre-transformation coordinates. This will repeat a lot of
+        // computations done in the path iterator, but the alternative is to
+        // work with transformed paths and compute untransformed coordinates
+        // as needed. This would be faster but I do not think the complexity
+        // of working with both untransformed and transformed coordinates in
+        // the same code is worth it.
+        // However, if a path's width is constant after a transformation,
+        // we can skip all this untransforming.
+
+        // As pathTo() will check transformed coordinates for invalid values
+        // (NaN / Infinity) to ignore such points, it is necessary to apply the
+        // transformation before the path processing.
+        AffineTransform strokerat = null;
+
+        int dashLen = -1;
+        boolean recycleDashes = false;
+        double scale = 1.0d;
+        double[] dashesD = null;
+
+        // Ensure converting dashes to double precision:
+        if (dashes != null) {
+            recycleDashes = true;
+            dashLen = dashes.length;
+            dashesD = rdrCtx.dasher.copyDashArray(dashes);
+        }
+
+        if (at != null && !at.isIdentity()) {
+            final double a = at.getScaleX();
+            final double b = at.getShearX();
+            final double c = at.getShearY();
+            final double d = at.getScaleY();
+            final double det = a * d - c * b;
+
+            if (Math.abs(det) <= (2.0d * Double.MIN_VALUE)) {
+                // this rendering engine takes one dimensional curves and turns
+                // them into 2D shapes by giving them width.
+                // However, if everything is to be passed through a singular
+                // transformation, these 2D shapes will be squashed down to 1D
+                // again so, nothing can be drawn.
+
+                // Every path needs an initial moveTo and a pathDone. If these
+                // are not there this causes a SIGSEGV in libawt.so (at the time
+                // of writing of this comment (September 16, 2010)). Actually,
+                // I am not sure if the moveTo is necessary to avoid the SIGSEGV
+                // but the pathDone is definitely needed.
+                pc2d.moveTo(0.0d, 0.0d);
+                pc2d.pathDone();
+                return;
+            }
+
+            // If the transform is a constant multiple of an orthogonal transformation
+            // then every length is just multiplied by a constant, so we just
+            // need to transform input paths to stroker and tell stroker
+            // the scaled width. This condition is satisfied if
+            // a*b == -c*d && a*a+c*c == b*b+d*d. In the actual check below, we
+            // leave a bit of room for error.
+            if (nearZero(a*b + c*d) && nearZero(a*a + c*c - (b*b + d*d))) {
+                scale =  Math.sqrt(a*a + c*c);
+
+                if (dashesD != null) {
+                    for (int i = 0; i < dashLen; i++) {
+                        dashesD[i] *= scale;
+                    }
+                    dashphase *= scale;
+                }
+                width *= scale;
+
+                // by now strokerat == null. Input paths to
+                // stroker (and maybe dasher) will have the full transform at
+                // applied to them and nothing will happen to the output paths.
+            } else {
+                strokerat = at;
+
+                // by now strokerat == at. Input paths to
+                // stroker (and maybe dasher) will have the full transform at
+                // applied to them, then they will be normalized, and then
+                // the inverse of *only the non translation part of at* will
+                // be applied to the normalized paths. This won't cause problems
+                // in stroker, because, suppose at = T*A, where T is just the
+                // translation part of at, and A is the rest. T*A has already
+                // been applied to Stroker/Dasher's input. Then Ainv will be
+                // applied. Ainv*T*A is not equal to T, but it is a translation,
+                // which means that none of stroker's assumptions about its
+                // input will be violated. After all this, A will be applied
+                // to stroker's output.
+            }
+        } else {
+            // either at is null or it's the identity. In either case
+            // we don't transform the path.
+            at = null;
+        }
+
+        final DTransformingPathConsumer2D transformerPC2D = rdrCtx.transformerPC2D;
+
+        if (DO_TRACE_PATH) {
+            // trace Stroker:
+            pc2d = transformerPC2D.traceStroker(pc2d);
+        }
+
+        if (USE_SIMPLIFIER) {
+            // Use simplifier after stroker before Renderer
+            // to remove collinear segments (notably due to cap square)
+            pc2d = rdrCtx.simplifier.init(pc2d);
+        }
+
+        // deltaTransformConsumer may adjust the clip rectangle:
+        pc2d = transformerPC2D.deltaTransformConsumer(pc2d, strokerat);
+
+        // stroker will adjust the clip rectangle (width / miter limit):
+        pc2d = rdrCtx.stroker.init(pc2d, width, caps, join, miterlimit, scale,
+                (dashesD == null));
+
+        // Curve Monotizer:
+        rdrCtx.monotonizer.init(width);
+
+        if (dashesD != null) {
+            if (DO_TRACE_PATH) {
+                pc2d = transformerPC2D.traceDasher(pc2d);
+            }
+            pc2d = rdrCtx.dasher.init(pc2d, dashesD, dashLen, dashphase,
+                                      recycleDashes);
+
+            if (DISABLE_2ND_STROKER_CLIPPING) {
+                // disable stoker clipping:
+                rdrCtx.stroker.disableClipping();
+            }
+
+        } else if (rdrCtx.doClip && (caps != Stroker.CAP_BUTT)) {
+            if (DO_TRACE_PATH) {
+                pc2d = transformerPC2D.traceClosedPathDetector(pc2d);
+            }
+
+            // If no dash and clip is enabled:
+            // detect closedPaths (polygons) for caps
+            pc2d = transformerPC2D.detectClosedPath(pc2d);
+        }
+        pc2d = transformerPC2D.inverseDeltaTransformConsumer(pc2d, strokerat);
+
+        if (DO_TRACE_PATH) {
+            // trace Input:
+            pc2d = transformerPC2D.traceInput(pc2d);
+        }
+
+        final PathIterator pi = norm.getNormalizingPathIterator(rdrCtx,
+                                         src.getPathIterator(at));
+
+        pathTo(rdrCtx, pi, pc2d);
+
+        /*
+         * Pipeline seems to be:
+         * shape.getPathIterator(at)
+         * -> (NormalizingPathIterator)
+         * -> (inverseDeltaTransformConsumer)
+         * -> (Dasher)
+         * -> Stroker
+         * -> (deltaTransformConsumer)
+         *
+         * -> (CollinearSimplifier) to remove redundant segments
+         *
+         * -> pc2d = Renderer (bounding box)
+         */
+    }
+
+    private static boolean nearZero(final double num) {
+        return Math.abs(num) < 2.0d * Math.ulp(num);
+    }
+
+    abstract static class NormalizingPathIterator implements PathIterator {
+
+        private PathIterator src;
+
+        // the adjustment applied to the current position.
+        private double curx_adjust, cury_adjust;
+        // the adjustment applied to the last moveTo position.
+        private double movx_adjust, movy_adjust;
+
+        private final double[] tmp;
+
+        NormalizingPathIterator(final double[] tmp) {
+            this.tmp = tmp;
+        }
+
+        final NormalizingPathIterator init(final PathIterator src) {
+            this.src = src;
+            return this; // fluent API
+        }
+
+        /**
+         * Disposes this path iterator:
+         * clean up before reusing this instance
+         */
+        final void dispose() {
+            // free source PathIterator:
+            this.src = null;
+        }
+
+        @Override
+        public final int currentSegment(final double[] coords) {
+            int lastCoord;
+            final int type = src.currentSegment(coords);
+
+            switch(type) {
+                case PathIterator.SEG_MOVETO:
+                case PathIterator.SEG_LINETO:
+                    lastCoord = 0;
+                    break;
+                case PathIterator.SEG_QUADTO:
+                    lastCoord = 2;
+                    break;
+                case PathIterator.SEG_CUBICTO:
+                    lastCoord = 4;
+                    break;
+                case PathIterator.SEG_CLOSE:
+                    // we don't want to deal with this case later. We just exit now
+                    curx_adjust = movx_adjust;
+                    cury_adjust = movy_adjust;
+                    return type;
+                default:
+                    throw new InternalError("Unrecognized curve type");
+            }
+
+            // normalize endpoint
+            double coord, x_adjust, y_adjust;
+
+            coord = coords[lastCoord];
+            x_adjust = normCoord(coord); // new coord
+            coords[lastCoord] = x_adjust;
+            x_adjust -= coord;
+
+            coord = coords[lastCoord + 1];
+            y_adjust = normCoord(coord); // new coord
+            coords[lastCoord + 1] = y_adjust;
+            y_adjust -= coord;
+
+            // now that the end points are done, normalize the control points
+            switch(type) {
+                case PathIterator.SEG_MOVETO:
+                    movx_adjust = x_adjust;
+                    movy_adjust = y_adjust;
+                    break;
+                case PathIterator.SEG_LINETO:
+                    break;
+                case PathIterator.SEG_QUADTO:
+                    coords[0] += (curx_adjust + x_adjust) / 2.0d;
+                    coords[1] += (cury_adjust + y_adjust) / 2.0d;
+                    break;
+                case PathIterator.SEG_CUBICTO:
+                    coords[0] += curx_adjust;
+                    coords[1] += cury_adjust;
+                    coords[2] += x_adjust;
+                    coords[3] += y_adjust;
+                    break;
+                case PathIterator.SEG_CLOSE:
+                    // handled earlier
+                default:
+            }
+            curx_adjust = x_adjust;
+            cury_adjust = y_adjust;
+            return type;
+        }
+
+        abstract double normCoord(final double coord);
+
+        @Override
+        public final int currentSegment(final float[] coords) {
+            final double[] _tmp = tmp; // dirty
+            int type = this.currentSegment(_tmp);
+            for (int i = 0; i < 6; i++) {
+                coords[i] = (float)_tmp[i];
+            }
+            return type;
+        }
+
+        @Override
+        public final int getWindingRule() {
+            return src.getWindingRule();
+        }
+
+        @Override
+        public final boolean isDone() {
+            if (src.isDone()) {
+                // Dispose this instance:
+                dispose();
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public final void next() {
+            src.next();
+        }
+
+        static final class NearestPixelCenter
+                                extends NormalizingPathIterator
+        {
+            NearestPixelCenter(final double[] tmp) {
+                super(tmp);
+            }
+
+            @Override
+            double normCoord(final double coord) {
+                // round to nearest pixel center
+                return Math.floor(coord) + 0.5d;
+            }
+        }
+
+        static final class NearestPixelQuarter
+                                extends NormalizingPathIterator
+        {
+            NearestPixelQuarter(final double[] tmp) {
+                super(tmp);
+            }
+
+            @Override
+            double normCoord(final double coord) {
+                // round to nearest (0.25, 0.25) pixel quarter
+                return Math.floor(coord + 0.25d) + 0.25d;
+            }
+        }
+    }
+
+    private static void pathTo(final DRendererContext rdrCtx, final PathIterator pi,
+                               DPathConsumer2D pc2d)
+    {
+        if (USE_PATH_SIMPLIFIER) {
+            // Use path simplifier at the first step
+            // to remove useless points
+            pc2d = rdrCtx.pathSimplifier.init(pc2d);
+        }
+
+        // mark context as DIRTY:
+        rdrCtx.dirty = true;
+
+        pathToLoop(rdrCtx.double6, pi, pc2d);
+
+        // mark context as CLEAN:
+        rdrCtx.dirty = false;
+    }
+
+    private static void pathToLoop(final double[] coords, final PathIterator pi,
+                                   final DPathConsumer2D pc2d)
+    {
+        // ported from DuctusRenderingEngine.feedConsumer() but simplified:
+        // - removed skip flag = !subpathStarted
+        // - removed pathClosed (ie subpathStarted not set to false)
+        boolean subpathStarted = false;
+
+        for (; !pi.isDone(); pi.next()) {
+            switch (pi.currentSegment(coords)) {
+            case PathIterator.SEG_MOVETO:
+                /* Checking SEG_MOVETO coordinates if they are out of the
+                 * [LOWER_BND, UPPER_BND] range. This check also handles NaN
+                 * and Infinity values. Skipping next path segment in case of
+                 * invalid data.
+                 */
+                if (coords[0] < UPPER_BND && coords[0] > LOWER_BND &&
+                    coords[1] < UPPER_BND && coords[1] > LOWER_BND)
+                {
+                    pc2d.moveTo(coords[0], coords[1]);
+                    subpathStarted = true;
+                }
+                break;
+            case PathIterator.SEG_LINETO:
+                /* Checking SEG_LINETO coordinates if they are out of the
+                 * [LOWER_BND, UPPER_BND] range. This check also handles NaN
+                 * and Infinity values. Ignoring current path segment in case
+                 * of invalid data. If segment is skipped its endpoint
+                 * (if valid) is used to begin new subpath.
+                 */
+                if (coords[0] < UPPER_BND && coords[0] > LOWER_BND &&
+                    coords[1] < UPPER_BND && coords[1] > LOWER_BND)
+                {
+                    if (subpathStarted) {
+                        pc2d.lineTo(coords[0], coords[1]);
+                    } else {
+                        pc2d.moveTo(coords[0], coords[1]);
+                        subpathStarted = true;
+                    }
+                }
+                break;
+            case PathIterator.SEG_QUADTO:
+                // Quadratic curves take two points
+                /* Checking SEG_QUADTO coordinates if they are out of the
+                 * [LOWER_BND, UPPER_BND] range. This check also handles NaN
+                 * and Infinity values. Ignoring current path segment in case
+                 * of invalid endpoints's data. Equivalent to the SEG_LINETO
+                 * if endpoint coordinates are valid but there are invalid data
+                 * among other coordinates
+                 */
+                if (coords[2] < UPPER_BND && coords[2] > LOWER_BND &&
+                    coords[3] < UPPER_BND && coords[3] > LOWER_BND)
+                {
+                    if (subpathStarted) {
+                        if (coords[0] < UPPER_BND && coords[0] > LOWER_BND &&
+                            coords[1] < UPPER_BND && coords[1] > LOWER_BND)
+                        {
+                            pc2d.quadTo(coords[0], coords[1],
+                                        coords[2], coords[3]);
+                        } else {
+                            pc2d.lineTo(coords[2], coords[3]);
+                        }
+                    } else {
+                        pc2d.moveTo(coords[2], coords[3]);
+                        subpathStarted = true;
+                    }
+                }
+                break;
+            case PathIterator.SEG_CUBICTO:
+                // Cubic curves take three points
+                /* Checking SEG_CUBICTO coordinates if they are out of the
+                 * [LOWER_BND, UPPER_BND] range. This check also handles NaN
+                 * and Infinity values. Ignoring current path segment in case
+                 * of invalid endpoints's data. Equivalent to the SEG_LINETO
+                 * if endpoint coordinates are valid but there are invalid data
+                 * among other coordinates
+                 */
+                if (coords[4] < UPPER_BND && coords[4] > LOWER_BND &&
+                    coords[5] < UPPER_BND && coords[5] > LOWER_BND)
+                {
+                    if (subpathStarted) {
+                        if (coords[0] < UPPER_BND && coords[0] > LOWER_BND &&
+                            coords[1] < UPPER_BND && coords[1] > LOWER_BND &&
+                            coords[2] < UPPER_BND && coords[2] > LOWER_BND &&
+                            coords[3] < UPPER_BND && coords[3] > LOWER_BND)
+                        {
+                            pc2d.curveTo(coords[0], coords[1],
+                                         coords[2], coords[3],
+                                         coords[4], coords[5]);
+                        } else {
+                            pc2d.lineTo(coords[4], coords[5]);
+                        }
+                    } else {
+                        pc2d.moveTo(coords[4], coords[5]);
+                        subpathStarted = true;
+                    }
+                }
+                break;
+            case PathIterator.SEG_CLOSE:
+                if (subpathStarted) {
+                    pc2d.closePath();
+                    // do not set subpathStarted to false
+                    // in case of missing moveTo() after close()
+                }
+                break;
+            default:
+            }
+        }
+        pc2d.pathDone();
+    }
+
+    /**
+     * Construct an antialiased tile generator for the given shape with
+     * the given rendering attributes and store the bounds of the tile
+     * iteration in the bbox parameter.
+     * The {@code at} parameter specifies a transform that should affect
+     * both the shape and the {@code BasicStroke} attributes.
+     * The {@code clip} parameter specifies the current clip in effect
+     * in device coordinates and can be used to prune the data for the
+     * operation, but the renderer is not required to perform any
+     * clipping.
+     * If the {@code BasicStroke} parameter is null then the shape
+     * should be filled as is, otherwise the attributes of the
+     * {@code BasicStroke} should be used to specify a draw operation.
+     * The {@code thin} parameter indicates whether or not the
+     * transformed {@code BasicStroke} represents coordinates smaller
+     * than the minimum resolution of the antialiasing rasterizer as
+     * specified by the {@code getMinimumAAPenWidth()} method.
+     * <p>
+     * Upon returning, this method will fill the {@code bbox} parameter
+     * with 4 values indicating the bounds of the iteration of the
+     * tile generator.
+     * The iteration order of the tiles will be as specified by the
+     * pseudo-code:
+     * <pre>
+     *     for (y = bbox[1]; y < bbox[3]; y += tileheight) {
+     *         for (x = bbox[0]; x < bbox[2]; x += tilewidth) {
+     *         }
+     *     }
+     * </pre>
+     * If there is no output to be rendered, this method may return
+     * null.
+     *
+     * @param s the shape to be rendered (fill or draw)
+     * @param at the transform to be applied to the shape and the
+     *           stroke attributes
+     * @param clip the current clip in effect in device coordinates
+     * @param bs if non-null, a {@code BasicStroke} whose attributes
+     *           should be applied to this operation
+     * @param thin true if the transformed stroke attributes are smaller
+     *             than the minimum dropout pen width
+     * @param normalize true if the {@code VALUE_STROKE_NORMALIZE}
+     *                  {@code RenderingHint} is in effect
+     * @param bbox returns the bounds of the iteration
+     * @return the {@code AATileGenerator} instance to be consulted
+     *         for tile coverages, or null if there is no output to render
+     * @since 1.7
+     */
+    @Override
+    public AATileGenerator getAATileGenerator(Shape s,
+                                              AffineTransform at,
+                                              Region clip,
+                                              BasicStroke bs,
+                                              boolean thin,
+                                              boolean normalize,
+                                              int[] bbox)
+    {
+        MarlinTileGenerator ptg = null;
+        DRenderer r = null;
+
+        final DRendererContext rdrCtx = getRendererContext();
+        try {
+            if (DO_CLIP || (DO_CLIP_RUNTIME_ENABLE && MarlinProperties.isDoClipAtRuntime())) {
+                // Define the initial clip bounds:
+                final double[] clipRect = rdrCtx.clipRect;
+
+                if (TEST_CLIP) {
+                    double small = clip.getHeight() / 8.0d;
+                    double half = (clip.getLoY() + clip.getHeight()) / 2.0d;
+                    clipRect[0] = half - small;
+                    clipRect[1] = half + small;
+                    small = clip.getWidth() / 4.0d;
+                    half = (clip.getLoX() + clip.getWidth()) / 2.0d;
+                    clipRect[2] = half - small;
+                    clipRect[3] = half + small;
+                } else {
+                    clipRect[0] = clip.getLoY();
+                    clipRect[1] = clip.getLoY() + clip.getHeight();
+                    clipRect[2] = clip.getLoX();
+                    clipRect[3] = clip.getLoX() + clip.getWidth();
+                }
+
+                // Enable clipping:
+                rdrCtx.doClip = true;
+            }
+
+            // Test if at is identity:
+            final AffineTransform _at = (at != null && !at.isIdentity()) ? at
+                                        : null;
+
+            final NormMode norm = (normalize) ? NormMode.ON_WITH_AA : NormMode.OFF;
+
+            if (bs == null) {
+                // fill shape:
+                final PathIterator pi = norm.getNormalizingPathIterator(rdrCtx,
+                                                 s.getPathIterator(_at));
+
+                // note: Winding rule may be EvenOdd ONLY for fill operations !
+                r = rdrCtx.renderer.init(clip.getLoX(), clip.getLoY(),
+                                         clip.getWidth(), clip.getHeight(),
+                                         pi.getWindingRule());
+
+                DPathConsumer2D pc2d = r;
+
+                if (DO_CLIP_FILL && rdrCtx.doClip) {
+                    if (DO_TRACE_PATH) {
+                        // trace Filler:
+                        pc2d = rdrCtx.transformerPC2D.traceFiller(pc2d);
+                    }
+                    pc2d = rdrCtx.transformerPC2D.pathClipper(pc2d);
+                }
+
+                if (DO_TRACE_PATH) {
+                    // trace Input:
+                    pc2d = rdrCtx.transformerPC2D.traceInput(pc2d);
+                }
+
+                // TODO: subdivide quad/cubic curves into monotonic curves ?
+                pathTo(rdrCtx, pi, pc2d);
+
+            } else {
+                // draw shape with given stroke:
+                r = rdrCtx.renderer.init(clip.getLoX(), clip.getLoY(),
+                                         clip.getWidth(), clip.getHeight(),
+                                         WIND_NON_ZERO);
+
+                strokeTo(rdrCtx, s, _at, bs, thin, norm, true, r);
+            }
+            if (r.endRendering()) {
+                ptg = rdrCtx.ptg.init();
+                ptg.getBbox(bbox);
+                // note: do not returnRendererContext(rdrCtx)
+                // as it will be called later by MarlinTileGenerator.dispose()
+                r = null;
+            }
+        } finally {
+            if (r != null) {
+                // dispose renderer and recycle the RendererContext instance:
+                r.dispose();
+            }
+        }
+
+        // Return null to cancel AA tile generation (nothing to render)
+        return ptg;
+    }
+
+    @Override
+    public AATileGenerator getAATileGenerator(double x, double y,
+                                              double dx1, double dy1,
+                                              double dx2, double dy2,
+                                              double lw1, double lw2,
+                                              Region clip,
+                                              int[] bbox)
+    {
+        // REMIND: Deal with large coordinates!
+        double ldx1, ldy1, ldx2, ldy2;
+        boolean innerpgram = (lw1 > 0.0d && lw2 > 0.0d);
+
+        if (innerpgram) {
+            ldx1 = dx1 * lw1;
+            ldy1 = dy1 * lw1;
+            ldx2 = dx2 * lw2;
+            ldy2 = dy2 * lw2;
+            x -= (ldx1 + ldx2) / 2.0d;
+            y -= (ldy1 + ldy2) / 2.0d;
+            dx1 += ldx1;
+            dy1 += ldy1;
+            dx2 += ldx2;
+            dy2 += ldy2;
+            if (lw1 > 1.0d && lw2 > 1.0d) {
+                // Inner parallelogram was entirely consumed by stroke...
+                innerpgram = false;
+            }
+        } else {
+            ldx1 = ldy1 = ldx2 = ldy2 = 0.0d;
+        }
+
+        MarlinTileGenerator ptg = null;
+        DRenderer r = null;
+
+        final DRendererContext rdrCtx = getRendererContext();
+        try {
+            r = rdrCtx.renderer.init(clip.getLoX(), clip.getLoY(),
+                                     clip.getWidth(), clip.getHeight(),
+                                     WIND_EVEN_ODD);
+
+            r.moveTo( x,  y);
+            r.lineTo( (x+dx1),  (y+dy1));
+            r.lineTo( (x+dx1+dx2),  (y+dy1+dy2));
+            r.lineTo( (x+dx2),  (y+dy2));
+            r.closePath();
+
+            if (innerpgram) {
+                x += ldx1 + ldx2;
+                y += ldy1 + ldy2;
+                dx1 -= 2.0d * ldx1;
+                dy1 -= 2.0d * ldy1;
+                dx2 -= 2.0d * ldx2;
+                dy2 -= 2.0d * ldy2;
+                r.moveTo( x,  y);
+                r.lineTo( (x+dx1),  (y+dy1));
+                r.lineTo( (x+dx1+dx2),  (y+dy1+dy2));
+                r.lineTo( (x+dx2),  (y+dy2));
+                r.closePath();
+            }
+            r.pathDone();
+
+            if (r.endRendering()) {
+                ptg = rdrCtx.ptg.init();
+                ptg.getBbox(bbox);
+                // note: do not returnRendererContext(rdrCtx)
+                // as it will be called later by MarlinTileGenerator.dispose()
+                r = null;
+            }
+        } finally {
+            if (r != null) {
+                // dispose renderer and recycle the RendererContext instance:
+                r.dispose();
+            }
+        }
+
+        // Return null to cancel AA tile generation (nothing to render)
+        return ptg;
+    }
+
+    /**
+     * Returns the minimum pen width that the antialiasing rasterizer
+     * can represent without dropouts occuring.
+     * @since 1.7
+     */
+    @Override
+    public float getMinimumAAPenSize() {
+        return MIN_PEN_SIZE;
+    }
+
+    static {
+        if (PathIterator.WIND_NON_ZERO != WIND_NON_ZERO ||
+            PathIterator.WIND_EVEN_ODD != WIND_EVEN_ODD ||
+            BasicStroke.JOIN_MITER != JOIN_MITER ||
+            BasicStroke.JOIN_ROUND != JOIN_ROUND ||
+            BasicStroke.JOIN_BEVEL != JOIN_BEVEL ||
+            BasicStroke.CAP_BUTT != CAP_BUTT ||
+            BasicStroke.CAP_ROUND != CAP_ROUND ||
+            BasicStroke.CAP_SQUARE != CAP_SQUARE)
+        {
+            throw new InternalError("mismatched renderer constants");
+        }
+    }
+
+    // --- DRendererContext handling ---
+    // use ThreadLocal or ConcurrentLinkedQueue to get one DRendererContext
+    private static final boolean USE_THREAD_LOCAL;
+
+    // reference type stored in either TL or CLQ
+    static final int REF_TYPE;
+
+    // Per-thread DRendererContext
+    private static final ReentrantContextProvider<DRendererContext> RDR_CTX_PROVIDER;
+
+    // Static initializer to use TL or CLQ mode
+    static {
+        USE_THREAD_LOCAL = MarlinProperties.isUseThreadLocal();
+
+        // Soft reference by default:
+        final String refType = AccessController.doPrivileged(
+                            new GetPropertyAction("sun.java2d.renderer.useRef",
+                            "soft"));
+
+        // Java 1.6 does not support strings in switch:
+        if ("hard".equalsIgnoreCase(refType)) {
+            REF_TYPE = ReentrantContextProvider.REF_HARD;
+        } else if ("weak".equalsIgnoreCase(refType)) {
+            REF_TYPE = ReentrantContextProvider.REF_WEAK;
+        } else {
+            REF_TYPE = ReentrantContextProvider.REF_SOFT;
+        }
+
+        if (USE_THREAD_LOCAL) {
+            RDR_CTX_PROVIDER = new ReentrantContextProviderTL<DRendererContext>(REF_TYPE)
+                {
+                    @Override
+                    protected DRendererContext newContext() {
+                        return DRendererContext.createContext();
+                    }
+                };
+        } else {
+            RDR_CTX_PROVIDER = new ReentrantContextProviderCLQ<DRendererContext>(REF_TYPE)
+                {
+                    @Override
+                    protected DRendererContext newContext() {
+                        return DRendererContext.createContext();
+                    }
+                };
+        }
+    }
+
+    private static boolean SETTINGS_LOGGED = !ENABLE_LOGS;
+
+    private static void logSettings(final String reClass) {
+        // log information at startup
+        if (SETTINGS_LOGGED) {
+            return;
+        }
+        SETTINGS_LOGGED = true;
+
+        String refType;
+        switch (REF_TYPE) {
+            default:
+            case ReentrantContextProvider.REF_HARD:
+                refType = "hard";
+                break;
+            case ReentrantContextProvider.REF_SOFT:
+                refType = "soft";
+                break;
+            case ReentrantContextProvider.REF_WEAK:
+                refType = "weak";
+                break;
+        }
+
+        logInfo("=========================================================="
+                + "=====================");
+
+        logInfo("Marlin software rasterizer           = ENABLED");
+        logInfo("Version                              = ["
+                + Version.getVersion() + "]");
+        logInfo("sun.java2d.renderer                  = "
+                + reClass);
+        logInfo("sun.java2d.renderer.useThreadLocal   = "
+                + USE_THREAD_LOCAL);
+        logInfo("sun.java2d.renderer.useRef           = "
+                + refType);
+
+        logInfo("sun.java2d.renderer.edges            = "
+                + MarlinConst.INITIAL_EDGES_COUNT);
+        logInfo("sun.java2d.renderer.pixelWidth       = "
+                + MarlinConst.INITIAL_PIXEL_WIDTH);
+        logInfo("sun.java2d.renderer.pixelHeight      = "
+                + MarlinConst.INITIAL_PIXEL_HEIGHT);
+
+        logInfo("sun.java2d.renderer.subPixel_log2_X  = "
+                + MarlinConst.SUBPIXEL_LG_POSITIONS_X);
+        logInfo("sun.java2d.renderer.subPixel_log2_Y  = "
+                + MarlinConst.SUBPIXEL_LG_POSITIONS_Y);
+
+        logInfo("sun.java2d.renderer.tileSize_log2    = "
+                + MarlinConst.TILE_H_LG);
+        logInfo("sun.java2d.renderer.tileWidth_log2   = "
+                + MarlinConst.TILE_W_LG);
+        logInfo("sun.java2d.renderer.blockSize_log2   = "
+                + MarlinConst.BLOCK_SIZE_LG);
+
+        // RLE / blockFlags settings
+
+        logInfo("sun.java2d.renderer.forceRLE         = "
+                + MarlinProperties.isForceRLE());
+        logInfo("sun.java2d.renderer.forceNoRLE       = "
+                + MarlinProperties.isForceNoRLE());
+        logInfo("sun.java2d.renderer.useTileFlags     = "
+                + MarlinProperties.isUseTileFlags());
+        logInfo("sun.java2d.renderer.useTileFlags.useHeuristics = "
+                + MarlinProperties.isUseTileFlagsWithHeuristics());
+        logInfo("sun.java2d.renderer.rleMinWidth      = "
+                + MarlinCache.RLE_MIN_WIDTH);
+
+        // optimisation parameters
+        logInfo("sun.java2d.renderer.useSimplifier    = "
+                + MarlinConst.USE_SIMPLIFIER);
+        logInfo("sun.java2d.renderer.usePathSimplifier= "
+                + MarlinConst.USE_PATH_SIMPLIFIER);
+        logInfo("sun.java2d.renderer.pathSimplifier.pixTol = "
+                + MarlinProperties.getPathSimplifierPixelTolerance());
+
+        logInfo("sun.java2d.renderer.clip             = "
+                + MarlinProperties.isDoClip());
+        logInfo("sun.java2d.renderer.clip.runtime.enable = "
+                + MarlinProperties.isDoClipRuntimeFlag());
+
+        logInfo("sun.java2d.renderer.clip.subdivider  = "
+                + MarlinProperties.isDoClipSubdivider());
+        logInfo("sun.java2d.renderer.clip.subdivider.minLength = "
+                + MarlinProperties.getSubdividerMinLength());
+
+        // debugging parameters
+        logInfo("sun.java2d.renderer.doStats          = "
+                + MarlinConst.DO_STATS);
+        logInfo("sun.java2d.renderer.doMonitors       = "
+                + MarlinConst.DO_MONITORS);
+        logInfo("sun.java2d.renderer.doChecks         = "
+                + MarlinConst.DO_CHECKS);
+
+        // logging parameters
+        logInfo("sun.java2d.renderer.useLogger        = "
+                + MarlinConst.USE_LOGGER);
+        logInfo("sun.java2d.renderer.logCreateContext = "
+                + MarlinConst.LOG_CREATE_CONTEXT);
+        logInfo("sun.java2d.renderer.logUnsafeMalloc  = "
+                + MarlinConst.LOG_UNSAFE_MALLOC);
+
+        // quality settings
+        logInfo("sun.java2d.renderer.curve_len_err    = "
+                + MarlinProperties.getCurveLengthError());
+        logInfo("sun.java2d.renderer.cubic_dec_d2     = "
+                + MarlinProperties.getCubicDecD2());
+        logInfo("sun.java2d.renderer.cubic_inc_d1     = "
+                + MarlinProperties.getCubicIncD1());
+        logInfo("sun.java2d.renderer.quad_dec_d2      = "
+                + MarlinProperties.getQuadDecD2());
+
+        logInfo("Renderer settings:");
+        logInfo("CUB_DEC_BND  = " + DRenderer.CUB_DEC_BND);
+        logInfo("CUB_INC_BND  = " + DRenderer.CUB_INC_BND);
+        logInfo("QUAD_DEC_BND = " + DRenderer.QUAD_DEC_BND);
+
+        logInfo("INITIAL_EDGES_CAPACITY               = "
+                + MarlinConst.INITIAL_EDGES_CAPACITY);
+        logInfo("INITIAL_CROSSING_COUNT               = "
+                + DRenderer.INITIAL_CROSSING_COUNT);
+
+        logInfo("=========================================================="
+                + "=====================");
+    }
+
+    /**
+     * Get the DRendererContext instance dedicated to the current thread
+     * @return DRendererContext instance
+     */
+    @SuppressWarnings({"unchecked"})
+    static DRendererContext getRendererContext() {
+        final DRendererContext rdrCtx = RDR_CTX_PROVIDER.acquire();
+        if (DO_MONITORS) {
+            rdrCtx.stats.mon_pre_getAATileGenerator.start();
+        }
+        return rdrCtx;
+    }
+
+    /**
+     * Reset and return the given DRendererContext instance for reuse
+     * @param rdrCtx DRendererContext instance
+     */
+    static void returnRendererContext(final DRendererContext rdrCtx) {
+        rdrCtx.dispose();
+
+        if (DO_MONITORS) {
+            rdrCtx.stats.mon_pre_getAATileGenerator.stop();
+        }
+        RDR_CTX_PROVIDER.release(rdrCtx);
+    }
+}
diff --git a/src/share/classes/sun/java2d/marlin/DPathConsumer2D.java b/src/share/classes/sun/java2d/marlin/DPathConsumer2D.java
new file mode 100644
index 0000000..9cb3f1c
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/DPathConsumer2D.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d.marlin;
+
+public interface DPathConsumer2D {
+    /**
+     * @see java.awt.geom.Path2D.Float#moveTo
+     */
+    public void moveTo(double x, double y);
+
+    /**
+     * @see java.awt.geom.Path2D.Float#lineTo
+     */
+    public void lineTo(double x, double y);
+
+    /**
+     * @see java.awt.geom.Path2D.Float#quadTo
+     */
+    public void quadTo(double x1, double y1,
+                       double x2, double y2);
+
+    /**
+     * @see java.awt.geom.Path2D.Float#curveTo
+     */
+    public void curveTo(double x1, double y1,
+                        double x2, double y2,
+                        double x3, double y3);
+
+    /**
+     * @see java.awt.geom.Path2D.Float#closePath
+     */
+    public void closePath();
+
+    /**
+     * Called after the last segment of the last subpath when the
+     * iteration of the path segments is completely done.  This
+     * method serves to trigger the end of path processing in the
+     * consumer that would normally be triggered when a
+     * {@link java.awt.geom.PathIterator PathIterator}
+     * returns {@code true} from its {@code done} method.
+     */
+    public void pathDone();
+
+    /**
+     * If a given PathConsumer performs all or most of its work
+     * natively then it can return a (non-zero) pointer to a
+     * native function vector that defines C functions for all
+     * of the above methods.
+     * The specific pointer it returns is a pointer to a
+     * PathConsumerVec structure as defined in the include file
+     * src/share/native/sun/java2d/pipe/PathConsumer2D.h
+     * @return a native pointer to a PathConsumerVec structure.
+     */
+    public long getNativeConsumer();
+}
diff --git a/src/share/classes/sun/java2d/marlin/DPathSimplifier.java b/src/share/classes/sun/java2d/marlin/DPathSimplifier.java
new file mode 100644
index 0000000..8bbe5b7
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/DPathSimplifier.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package sun.java2d.marlin;
+
+final class DPathSimplifier implements DPathConsumer2D {
+
+    // distance threshold in pixels (device)
+    private static final double PIX_THRESHOLD = MarlinProperties.getPathSimplifierPixelTolerance();
+
+    private static final double SQUARE_TOLERANCE = PIX_THRESHOLD * PIX_THRESHOLD;
+
+    // members:
+    private DPathConsumer2D delegate;
+    private double cx, cy;
+
+    DPathSimplifier() {
+    }
+
+    DPathSimplifier init(final DPathConsumer2D delegate) {
+        this.delegate = delegate;
+        return this; // fluent API
+    }
+
+    @Override
+    public void pathDone() {
+        delegate.pathDone();
+    }
+
+    @Override
+    public void closePath() {
+        delegate.closePath();
+    }
+
+    @Override
+    public long getNativeConsumer() {
+        return 0;
+    }
+
+    @Override
+    public void quadTo(final double x1, final double y1,
+                       final double xe, final double ye)
+    {
+        // Test if curve is too small:
+        double dx = (xe - cx);
+        double dy = (ye - cy);
+
+        if ((dx * dx + dy * dy) <= SQUARE_TOLERANCE) {
+            // check control points P1:
+            dx = (x1 - cx);
+            dy = (y1 - cy);
+
+            if ((dx * dx + dy * dy) <= SQUARE_TOLERANCE) {
+                return;
+            }
+        }
+        delegate.quadTo(x1, y1, xe, ye);
+        // final end point:
+        cx = xe;
+        cy = ye;
+    }
+
+    @Override
+    public void curveTo(final double x1, final double y1,
+                        final double x2, final double y2,
+                        final double xe, final double ye)
+    {
+        // Test if curve is too small:
+        double dx = (xe - cx);
+        double dy = (ye - cy);
+
+        if ((dx * dx + dy * dy) <= SQUARE_TOLERANCE) {
+            // check control points P1:
+            dx = (x1 - cx);
+            dy = (y1 - cy);
+
+            if ((dx * dx + dy * dy) <= SQUARE_TOLERANCE) {
+                // check control points P2:
+                dx = (x2 - cx);
+                dy = (y2 - cy);
+
+                if ((dx * dx + dy * dy) <= SQUARE_TOLERANCE) {
+                    return;
+                }
+            }
+        }
+        delegate.curveTo(x1, y1, x2, y2, xe, ye);
+        // final end point:
+        cx = xe;
+        cy = ye;
+    }
+
+    @Override
+    public void moveTo(final double xe, final double ye) {
+        delegate.moveTo(xe, ye);
+        // starting point:
+        cx = xe;
+        cy = ye;
+    }
+
+    @Override
+    public void lineTo(final double xe, final double ye) {
+        // Test if segment is too small:
+        double dx = (xe - cx);
+        double dy = (ye - cy);
+
+        if ((dx * dx + dy * dy) <= SQUARE_TOLERANCE) {
+            return;
+        }
+        delegate.lineTo(xe, ye);
+        // final end point:
+        cx = xe;
+        cy = ye;
+    }
+}
diff --git a/src/share/classes/sun/java2d/marlin/DRenderer.java b/src/share/classes/sun/java2d/marlin/DRenderer.java
new file mode 100644
index 0000000..27f479a
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/DRenderer.java
@@ -0,0 +1,1539 @@
+/*
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d.marlin;
+
+import static sun.java2d.marlin.OffHeapArray.SIZE_INT;
+//import jdk.internal.misc.Unsafe;
+import sun.misc.Unsafe;
+
+final class DRenderer implements DPathConsumer2D, MarlinRenderer {
+
+    static final boolean DISABLE_RENDER = false;
+
+    static final boolean ENABLE_BLOCK_FLAGS = MarlinProperties.isUseTileFlags();
+    static final boolean ENABLE_BLOCK_FLAGS_HEURISTICS = MarlinProperties.isUseTileFlagsWithHeuristics();
+
+    private static final int ALL_BUT_LSB = 0xFFFFFFFE;
+    private static final int ERR_STEP_MAX = 0x7FFFFFFF; // = 2^31 - 1
+
+    private static final double POWER_2_TO_32 = 0x1.0p32d;
+
+    // use double to make tosubpix methods faster (no int to double conversion)
+    static final double SUBPIXEL_SCALE_X = SUBPIXEL_POSITIONS_X;
+    static final double SUBPIXEL_SCALE_Y = SUBPIXEL_POSITIONS_Y;
+    static final int SUBPIXEL_MASK_X = SUBPIXEL_POSITIONS_X - 1;
+    static final int SUBPIXEL_MASK_Y = SUBPIXEL_POSITIONS_Y - 1;
+
+    static final double RDR_OFFSET_X = 0.5d / SUBPIXEL_SCALE_X;
+    static final double RDR_OFFSET_Y = 0.5d / SUBPIXEL_SCALE_Y;
+
+    // number of subpixels corresponding to a tile line
+    private static final int SUBPIXEL_TILE
+        = TILE_H << SUBPIXEL_LG_POSITIONS_Y;
+
+    // 2176 pixels (height) x 8 subpixels = 68K
+    static final int INITIAL_BUCKET_ARRAY
+        = INITIAL_PIXEL_HEIGHT * SUBPIXEL_POSITIONS_Y;
+
+    // crossing capacity = edges count / 4 ~ 1024
+    static final int INITIAL_CROSSING_COUNT = INITIAL_EDGES_COUNT >> 2;
+
+    // common to all types of input path segments.
+    // OFFSET as bytes
+    // only integer values:
+    public static final long OFF_CURX_OR  = 0;
+    public static final long OFF_ERROR    = OFF_CURX_OR  + SIZE_INT;
+    public static final long OFF_BUMP_X   = OFF_ERROR    + SIZE_INT;
+    public static final long OFF_BUMP_ERR = OFF_BUMP_X   + SIZE_INT;
+    public static final long OFF_NEXT     = OFF_BUMP_ERR + SIZE_INT;
+    public static final long OFF_YMAX     = OFF_NEXT     + SIZE_INT;
+
+    // size of one edge in bytes
+    public static final int SIZEOF_EDGE_BYTES = (int)(OFF_YMAX + SIZE_INT);
+
+    // curve break into lines
+    // cubic error in subpixels to decrement step
+    private static final double CUB_DEC_ERR_SUBPIX
+        = MarlinProperties.getCubicDecD2() * (SUBPIXEL_POSITIONS_X / 8.0d); // 1.0 / 8th pixel
+    // cubic error in subpixels to increment step
+    private static final double CUB_INC_ERR_SUBPIX
+        = MarlinProperties.getCubicIncD1() * (SUBPIXEL_POSITIONS_X / 8.0d); // 0.4 / 8th pixel
+    // scale factor for Y-axis contribution to quad / cubic errors:
+    public static final double SCALE_DY = ((double) SUBPIXEL_POSITIONS_X) / SUBPIXEL_POSITIONS_Y;
+
+    // TestNonAARasterization (JDK-8170879): cubics
+    // bad paths (59294/100000 == 59,29%, 94335 bad pixels (avg = 1,59), 3966 warnings (avg = 0,07)
+// 2018
+    // 1.0 / 0.2: bad paths (67194/100000 == 67,19%, 117394 bad pixels (avg = 1,75 - max =  9), 4042 warnings (avg = 0,06)
+
+    // cubic bind length to decrement step
+    public static final double CUB_DEC_BND
+        = 8.0d * CUB_DEC_ERR_SUBPIX;
+    // cubic bind length to increment step
+    public static final double CUB_INC_BND
+        = 8.0d * CUB_INC_ERR_SUBPIX;
+
+    // cubic countlg
+    public static final int CUB_COUNT_LG = 2;
+    // cubic count = 2^countlg
+    private static final int CUB_COUNT = 1 << CUB_COUNT_LG;
+    // cubic count^2 = 4^countlg
+    private static final int CUB_COUNT_2 = 1 << (2 * CUB_COUNT_LG);
+    // cubic count^3 = 8^countlg
+    private static final int CUB_COUNT_3 = 1 << (3 * CUB_COUNT_LG);
+    // cubic dt = 1 / count
+    private static final double CUB_INV_COUNT = 1.0d / CUB_COUNT;
+    // cubic dt^2 = 1 / count^2 = 1 / 4^countlg
+    private static final double CUB_INV_COUNT_2 = 1.0d / CUB_COUNT_2;
+    // cubic dt^3 = 1 / count^3 = 1 / 8^countlg
+    private static final double CUB_INV_COUNT_3 = 1.0d / CUB_COUNT_3;
+
+    // quad break into lines
+    // quadratic error in subpixels
+    private static final double QUAD_DEC_ERR_SUBPIX
+        = MarlinProperties.getQuadDecD2() * (SUBPIXEL_POSITIONS_X / 8.0d); // 0.5 / 8th pixel
+
+    // TestNonAARasterization (JDK-8170879): quads
+    // bad paths (62916/100000 == 62,92%, 103818 bad pixels (avg = 1,65), 6514 warnings (avg = 0,10)
+// 2018
+    // 0.50px  = bad paths (62915/100000 == 62,92%, 103810 bad pixels (avg = 1,65), 6512 warnings (avg = 0,10)
+
+    // quadratic bind length to decrement step
+    public static final double QUAD_DEC_BND
+        = 8.0d * QUAD_DEC_ERR_SUBPIX;
+
+//////////////////////////////////////////////////////////////////////////////
+//  SCAN LINE
+//////////////////////////////////////////////////////////////////////////////
+    // crossings ie subpixel edge x coordinates
+    private int[] crossings;
+    // auxiliary storage for crossings (merge sort)
+    private int[] aux_crossings;
+
+    // indices into the segment pointer lists. They indicate the "active"
+    // sublist in the segment lists (the portion of the list that contains
+    // all the segments that cross the next scan line).
+    private int edgeCount;
+    private int[] edgePtrs;
+    // auxiliary storage for edge pointers (merge sort)
+    private int[] aux_edgePtrs;
+
+    // max used for both edgePtrs and crossings (stats only)
+    private int activeEdgeMaxUsed;
+
+    // crossings ref (dirty)
+    private final IntArrayCache.Reference crossings_ref;
+    // edgePtrs ref (dirty)
+    private final IntArrayCache.Reference edgePtrs_ref;
+    // merge sort initial arrays (large enough to satisfy most usages) (1024)
+    // aux_crossings ref (dirty)
+    private final IntArrayCache.Reference aux_crossings_ref;
+    // aux_edgePtrs ref (dirty)
+    private final IntArrayCache.Reference aux_edgePtrs_ref;
+
+//////////////////////////////////////////////////////////////////////////////
+//  EDGE LIST
+//////////////////////////////////////////////////////////////////////////////
+    private int edgeMinY = Integer.MAX_VALUE;
+    private int edgeMaxY = Integer.MIN_VALUE;
+    private double edgeMinX = Double.POSITIVE_INFINITY;
+    private double edgeMaxX = Double.NEGATIVE_INFINITY;
+
+    // edges [ints] stored in off-heap memory
+    private final OffHeapArray edges;
+
+    private int[] edgeBuckets;
+    private int[] edgeBucketCounts; // 2*newedges + (1 if pruning needed)
+    // used range for edgeBuckets / edgeBucketCounts
+    private int buckets_minY;
+    private int buckets_maxY;
+
+    // edgeBuckets ref (clean)
+    private final IntArrayCache.Reference edgeBuckets_ref;
+    // edgeBucketCounts ref (clean)
+    private final IntArrayCache.Reference edgeBucketCounts_ref;
+
+    // Flattens using adaptive forward differencing. This only carries out
+    // one iteration of the AFD loop. All it does is update AFD variables (i.e.
+    // X0, Y0, D*[X|Y], COUNT; not variables used for computing scanline crossings).
+    private void quadBreakIntoLinesAndAdd(double x0, double y0,
+                                          final DCurve c,
+                                          final double x2, final double y2)
+    {
+        int count = 1; // dt = 1 / count
+
+        // maximum(ddX|Y) = norm(dbx, dby) * dt^2 (= 1)
+        double maxDD = Math.abs(c.dbx) + Math.abs(c.dby) * SCALE_DY;
+
+        final double _DEC_BND = QUAD_DEC_BND;
+
+        while (maxDD >= _DEC_BND) {
+            // divide step by half:
+            maxDD /= 4.0d; // error divided by 2^2 = 4
+
+            count <<= 1;
+            if (DO_STATS) {
+                rdrCtx.stats.stat_rdr_quadBreak_dec.add(count);
+            }
+        }
+
+        final int nL = count; // line count
+
+        if (count > 1) {
+            final double icount = 1.0d / count; // dt
+            final double icount2 = icount * icount; // dt^2
+
+            final double ddx = c.dbx * icount2;
+            final double ddy = c.dby * icount2;
+            double dx = c.bx * icount2 + c.cx * icount;
+            double dy = c.by * icount2 + c.cy * icount;
+
+            // we use x0, y0 to walk the line
+            for (double x1 = x0, y1 = y0; --count > 0; dx += ddx, dy += ddy) {
+                x1 += dx;
+                y1 += dy;
+
+                addLine(x0, y0, x1, y1);
+                x0 = x1;
+                y0 = y1;
+            }
+        }
+        addLine(x0, y0, x2, y2);
+
+        if (DO_STATS) {
+            rdrCtx.stats.stat_rdr_quadBreak.add(nL);
+        }
+    }
+
+    // x0, y0 and x3,y3 are the endpoints of the curve. We could compute these
+    // using c.xat(0),c.yat(0) and c.xat(1),c.yat(1), but this might introduce
+    // numerical errors, and our callers already have the exact values.
+    // Another alternative would be to pass all the control points, and call
+    // c.set here, but then too many numbers are passed around.
+    private void curveBreakIntoLinesAndAdd(double x0, double y0,
+                                           final DCurve c,
+                                           final double x3, final double y3)
+    {
+        int count            = CUB_COUNT;
+        final double icount  = CUB_INV_COUNT;   // dt
+        final double icount2 = CUB_INV_COUNT_2; // dt^2
+        final double icount3 = CUB_INV_COUNT_3; // dt^3
+
+        // the dx and dy refer to forward differencing variables, not the last
+        // coefficients of the "points" polynomial
+        double dddx, dddy, ddx, ddy, dx, dy;
+        dddx = 2.0d * c.dax * icount3;
+        dddy = 2.0d * c.day * icount3;
+        ddx = dddx + c.dbx * icount2;
+        ddy = dddy + c.dby * icount2;
+        dx = c.ax * icount3 + c.bx * icount2 + c.cx * icount;
+        dy = c.ay * icount3 + c.by * icount2 + c.cy * icount;
+
+        int nL = 0; // line count
+
+        final double _DEC_BND = CUB_DEC_BND;
+        final double _INC_BND = CUB_INC_BND;
+        final double _SCALE_DY = SCALE_DY;
+
+        // we use x0, y0 to walk the line
+        for (double x1 = x0, y1 = y0; count > 0; ) {
+            // inc / dec => ratio ~ 5 to minimize upscale / downscale but minimize edges
+
+            // double step:
+            // can only do this on even "count" values, because we must divide count by 2
+            while ((count % 2 == 0)
+                    && ((Math.abs(ddx) + Math.abs(ddy) * _SCALE_DY) <= _INC_BND
+//                     && (Math.abs(ddx + dddx) + Math.abs(ddy + dddy) * _SCALE_DY) <= _INC_BND
+                  )) {
+                dx = 2.0d * dx + ddx;
+                dy = 2.0d * dy + ddy;
+                ddx = 4.0d * (ddx + dddx);
+                ddy = 4.0d * (ddy + dddy);
+                dddx *= 8.0d;
+                dddy *= 8.0d;
+
+                count >>= 1;
+                if (DO_STATS) {
+                    rdrCtx.stats.stat_rdr_curveBreak_inc.add(count);
+                }
+            }
+
+            // divide step by half:
+            while ((Math.abs(ddx) + Math.abs(ddy) * _SCALE_DY) >= _DEC_BND
+//                || (Math.abs(ddx + dddx) + Math.abs(ddy + dddy) * _SCALE_DY) >= _DEC_BND
+                  ) {
+                dddx /= 8.0d;
+                dddy /= 8.0d;
+                ddx = ddx / 4.0d - dddx;
+                ddy = ddy / 4.0d - dddy;
+                dx = (dx - ddx) / 2.0d;
+                dy = (dy - ddy) / 2.0d;
+
+                count <<= 1;
+                if (DO_STATS) {
+                    rdrCtx.stats.stat_rdr_curveBreak_dec.add(count);
+                }
+            }
+            if (--count == 0) {
+                break;
+            }
+
+            x1 += dx;
+            y1 += dy;
+            dx += ddx;
+            dy += ddy;
+            ddx += dddx;
+            ddy += dddy;
+
+            addLine(x0, y0, x1, y1);
+            x0 = x1;
+            y0 = y1;
+        }
+        addLine(x0, y0, x3, y3);
+
+        if (DO_STATS) {
+            rdrCtx.stats.stat_rdr_curveBreak.add(nL + 1);
+        }
+    }
+
+    private void addLine(double x1, double y1, double x2, double y2) {
+        if (DO_MONITORS) {
+            rdrCtx.stats.mon_rdr_addLine.start();
+        }
+        if (DO_STATS) {
+            rdrCtx.stats.stat_rdr_addLine.add(1);
+        }
+        int or = 1; // orientation of the line. 1 if y increases, 0 otherwise.
+        if (y2 < y1) {
+            or = 0;
+            double tmp = y2;
+            y2 = y1;
+            y1 = tmp;
+            tmp = x2;
+            x2 = x1;
+            x1 = tmp;
+        }
+
+        // convert subpixel coordinates [double] into pixel positions [int]
+
+        // The index of the pixel that holds the next HPC is at ceil(trueY - 0.5)
+        // Since y1 and y2 are biased by -0.5 in tosubpixy(), this is simply
+        // ceil(y1) or ceil(y2)
+        // upper integer (inclusive)
+        final int firstCrossing = FloatMath.max(FloatMath.ceil_int(y1), boundsMinY);
+
+        // note: use boundsMaxY (last Y exclusive) to compute correct coverage
+        // upper integer (exclusive)
+        final int lastCrossing  = FloatMath.min(FloatMath.ceil_int(y2), boundsMaxY);
+
+        /* skip horizontal lines in pixel space and clip edges
+           out of y range [boundsMinY; boundsMaxY] */
+        if (firstCrossing >= lastCrossing) {
+            if (DO_MONITORS) {
+                rdrCtx.stats.mon_rdr_addLine.stop();
+            }
+            if (DO_STATS) {
+                rdrCtx.stats.stat_rdr_addLine_skip.add(1);
+            }
+            return;
+        }
+
+        // edge min/max X/Y are in subpixel space (half-open interval):
+        // note: Use integer crossings to ensure consistent range within
+        // edgeBuckets / edgeBucketCounts arrays in case of NaN values (int = 0)
+        if (firstCrossing < edgeMinY) {
+            edgeMinY = firstCrossing;
+        }
+        if (lastCrossing > edgeMaxY) {
+            edgeMaxY = lastCrossing;
+        }
+
+        final double slope = (x1 - x2) / (y1 - y2);
+
+        if (slope >= 0.0d) { // <==> x1 < x2
+            if (x1 < edgeMinX) {
+                edgeMinX = x1;
+            }
+            if (x2 > edgeMaxX) {
+                edgeMaxX = x2;
+            }
+        } else {
+            if (x2 < edgeMinX) {
+                edgeMinX = x2;
+            }
+            if (x1 > edgeMaxX) {
+                edgeMaxX = x1;
+            }
+        }
+
+        // local variables for performance:
+        final int _SIZEOF_EDGE_BYTES = SIZEOF_EDGE_BYTES;
+
+        final OffHeapArray _edges = edges;
+
+        // get free pointer (ie length in bytes)
+        final int edgePtr = _edges.used;
+
+        // use substraction to avoid integer overflow:
+        if (_edges.length - edgePtr < _SIZEOF_EDGE_BYTES) {
+            // suppose _edges.length > _SIZEOF_EDGE_BYTES
+            // so doubling size is enough to add needed bytes
+            // note: throw IOOB if neededSize > 2Gb:
+            final long edgeNewSize = ArrayCacheConst.getNewLargeSize(
+                                        _edges.length,
+                                        edgePtr + _SIZEOF_EDGE_BYTES);
+
+            if (DO_STATS) {
+                rdrCtx.stats.stat_rdr_edges_resizes.add(edgeNewSize);
+            }
+            _edges.resize(edgeNewSize);
+        }
+
+
+        final Unsafe _unsafe = OffHeapArray.UNSAFE;
+        final long SIZE_INT = 4L;
+        long addr   = _edges.address + edgePtr;
+
+        // The x value must be bumped up to its position at the next HPC we will evaluate.
+        // "firstcrossing" is the (sub)pixel number where the next crossing occurs
+        // thus, the actual coordinate of the next HPC is "firstcrossing + 0.5"
+        // so the Y distance we cover is "firstcrossing + 0.5 - trueY".
+        // Note that since y1 (and y2) are already biased by -0.5 in tosubpixy(), we have
+        // y1 = trueY - 0.5
+        // trueY = y1 + 0.5
+        // firstcrossing + 0.5 - trueY = firstcrossing + 0.5 - (y1 + 0.5)
+        //                             = firstcrossing - y1
+        // The x coordinate at that HPC is then:
+        // x1_intercept = x1 + (firstcrossing - y1) * slope
+        // The next VPC is then given by:
+        // VPC index = ceil(x1_intercept - 0.5), or alternately
+        // VPC index = floor(x1_intercept - 0.5 + 1 - epsilon)
+        // epsilon is hard to pin down in floating point, but easy in fixed point, so if
+        // we convert to fixed point then these operations get easier:
+        // long x1_fixed = x1_intercept * 2^32;  (fixed point 32.32 format)
+        // curx = next VPC = fixed_floor(x1_fixed - 2^31 + 2^32 - 1)
+        //                 = fixed_floor(x1_fixed + 2^31 - 1)
+        //                 = fixed_floor(x1_fixed + 0x7FFFFFFF)
+        // and error       = fixed_fract(x1_fixed + 0x7FFFFFFF)
+        final double x1_intercept = x1 + (firstCrossing - y1) * slope;
+
+        // inlined scalb(x1_intercept, 32):
+        final long x1_fixed_biased = ((long) (POWER_2_TO_32 * x1_intercept))
+                                     + 0x7FFFFFFFL;
+        // curx:
+        // last bit corresponds to the orientation
+        _unsafe.putInt(addr, (((int) (x1_fixed_biased >> 31L)) & ALL_BUT_LSB) | or);
+        addr += SIZE_INT;
+        _unsafe.putInt(addr,  ((int)  x1_fixed_biased) >>> 1);
+        addr += SIZE_INT;
+
+        // inlined scalb(slope, 32):
+        final long slope_fixed = (long) (POWER_2_TO_32 * slope);
+
+        // last bit set to 0 to keep orientation:
+        _unsafe.putInt(addr, (((int) (slope_fixed >> 31L)) & ALL_BUT_LSB));
+        addr += SIZE_INT;
+        _unsafe.putInt(addr,  ((int)  slope_fixed) >>> 1);
+        addr += SIZE_INT;
+
+        final int[] _edgeBuckets      = edgeBuckets;
+        final int[] _edgeBucketCounts = edgeBucketCounts;
+
+        final int _boundsMinY = boundsMinY;
+
+        // each bucket is a linked list. this method adds ptr to the
+        // start of the "bucket"th linked list.
+        final int bucketIdx = firstCrossing - _boundsMinY;
+
+        // pointer from bucket
+        _unsafe.putInt(addr, _edgeBuckets[bucketIdx]);
+        addr += SIZE_INT;
+        // y max (exclusive)
+        _unsafe.putInt(addr,  lastCrossing);
+
+        // Update buckets:
+        // directly the edge struct "pointer"
+        _edgeBuckets[bucketIdx]       = edgePtr;
+        _edgeBucketCounts[bucketIdx] += 2; // 1 << 1
+        // last bit means edge end
+        _edgeBucketCounts[lastCrossing - _boundsMinY] |= 0x1;
+
+        // update free pointer (ie length in bytes)
+        _edges.used += _SIZEOF_EDGE_BYTES;
+
+        if (DO_MONITORS) {
+            rdrCtx.stats.mon_rdr_addLine.stop();
+        }
+    }
+
+// END EDGE LIST
+//////////////////////////////////////////////////////////////////////////////
+
+    // Cache to store RLE-encoded coverage mask of the current primitive
+    final MarlinCache cache;
+
+    // Bounds of the drawing region, at subpixel precision.
+    private int boundsMinX, boundsMinY, boundsMaxX, boundsMaxY;
+
+    // Current winding rule
+    private int windingRule;
+
+    // Current drawing position, i.e., final point of last segment
+    private double x0, y0;
+
+    // Position of most recent 'moveTo' command
+    private double sx0, sy0;
+
+    // per-thread renderer context
+    final DRendererContext rdrCtx;
+    // dirty curve
+    private final DCurve curve;
+
+    // clean alpha array (zero filled)
+    private int[] alphaLine;
+
+    // alphaLine ref (clean)
+    private final IntArrayCache.Reference alphaLine_ref;
+
+    private boolean enableBlkFlags = false;
+    private boolean prevUseBlkFlags = false;
+
+    /* block flags (0|1) */
+    private int[] blkFlags;
+
+    // blkFlags ref (clean)
+    private final IntArrayCache.Reference blkFlags_ref;
+
+    DRenderer(final DRendererContext rdrCtx) {
+        this.rdrCtx = rdrCtx;
+        this.curve = rdrCtx.curve;
+        this.cache = rdrCtx.cache;
+
+        this.edges = rdrCtx.newOffHeapArray(INITIAL_EDGES_CAPACITY); // 96K
+
+        edgeBuckets_ref      = rdrCtx.newCleanIntArrayRef(INITIAL_BUCKET_ARRAY); // 64K
+        edgeBucketCounts_ref = rdrCtx.newCleanIntArrayRef(INITIAL_BUCKET_ARRAY); // 64K
+
+        edgeBuckets      = edgeBuckets_ref.initial;
+        edgeBucketCounts = edgeBucketCounts_ref.initial;
+
+        // 4096 pixels large
+        alphaLine_ref = rdrCtx.newCleanIntArrayRef(INITIAL_AA_ARRAY); // 16K
+        alphaLine     = alphaLine_ref.initial;
+
+        crossings_ref     = rdrCtx.newDirtyIntArrayRef(INITIAL_CROSSING_COUNT); // 2K
+        aux_crossings_ref = rdrCtx.newDirtyIntArrayRef(INITIAL_CROSSING_COUNT); // 2K
+        edgePtrs_ref      = rdrCtx.newDirtyIntArrayRef(INITIAL_CROSSING_COUNT); // 2K
+        aux_edgePtrs_ref  = rdrCtx.newDirtyIntArrayRef(INITIAL_CROSSING_COUNT); // 2K
+
+        crossings     = crossings_ref.initial;
+        aux_crossings = aux_crossings_ref.initial;
+        edgePtrs      = edgePtrs_ref.initial;
+        aux_edgePtrs  = aux_edgePtrs_ref.initial;
+
+        blkFlags_ref = rdrCtx.newCleanIntArrayRef(INITIAL_ARRAY); // 1K = 1 tile line
+        blkFlags     = blkFlags_ref.initial;
+    }
+
+    DRenderer init(final int pix_boundsX, final int pix_boundsY,
+                  final int pix_boundsWidth, final int pix_boundsHeight,
+                  final int windingRule)
+    {
+        this.windingRule = windingRule;
+
+        // bounds as half-open intervals: minX <= x < maxX and minY <= y < maxY
+        this.boundsMinX =  pix_boundsX << SUBPIXEL_LG_POSITIONS_X;
+        this.boundsMaxX =
+            (pix_boundsX + pix_boundsWidth) << SUBPIXEL_LG_POSITIONS_X;
+        this.boundsMinY =  pix_boundsY << SUBPIXEL_LG_POSITIONS_Y;
+        this.boundsMaxY =
+            (pix_boundsY + pix_boundsHeight) << SUBPIXEL_LG_POSITIONS_Y;
+
+        if (DO_LOG_BOUNDS) {
+            MarlinUtils.logInfo("boundsXY = [" + boundsMinX + " ... "
+                                + boundsMaxX + "[ [" + boundsMinY + " ... "
+                                + boundsMaxY + "[");
+        }
+
+        // see addLine: ceil(boundsMaxY) => boundsMaxY + 1
+        // +1 for edgeBucketCounts
+        final int edgeBucketsLength = (boundsMaxY - boundsMinY) + 1;
+
+        if (edgeBucketsLength > INITIAL_BUCKET_ARRAY) {
+            if (DO_STATS) {
+                rdrCtx.stats.stat_array_renderer_edgeBuckets
+                    .add(edgeBucketsLength);
+                rdrCtx.stats.stat_array_renderer_edgeBucketCounts
+                    .add(edgeBucketsLength);
+            }
+            edgeBuckets = edgeBuckets_ref.getArray(edgeBucketsLength);
+            edgeBucketCounts = edgeBucketCounts_ref.getArray(edgeBucketsLength);
+        }
+
+        edgeMinY = Integer.MAX_VALUE;
+        edgeMaxY = Integer.MIN_VALUE;
+        edgeMinX = Double.POSITIVE_INFINITY;
+        edgeMaxX = Double.NEGATIVE_INFINITY;
+
+        // reset used mark:
+        edgeCount = 0;
+        activeEdgeMaxUsed = 0;
+        edges.used = 0;
+
+        return this; // fluent API
+    }
+
+    /**
+     * Disposes this renderer and recycle it clean up before reusing this instance
+     */
+    void dispose() {
+        if (DO_STATS) {
+            rdrCtx.stats.stat_rdr_activeEdges.add(activeEdgeMaxUsed);
+            rdrCtx.stats.stat_rdr_edges.add(edges.used);
+            rdrCtx.stats.stat_rdr_edges_count.add(edges.used / SIZEOF_EDGE_BYTES);
+            rdrCtx.stats.hist_rdr_edges_count.add(edges.used / SIZEOF_EDGE_BYTES);
+            rdrCtx.stats.totalOffHeap += edges.length;
+        }
+        // Return arrays:
+        crossings = crossings_ref.putArray(crossings);
+        aux_crossings = aux_crossings_ref.putArray(aux_crossings);
+
+        edgePtrs = edgePtrs_ref.putArray(edgePtrs);
+        aux_edgePtrs = aux_edgePtrs_ref.putArray(aux_edgePtrs);
+
+        alphaLine = alphaLine_ref.putArray(alphaLine, 0, 0); // already zero filled
+        blkFlags  = blkFlags_ref.putArray(blkFlags, 0, 0); // already zero filled
+
+        if (edgeMinY != Integer.MAX_VALUE) {
+            // if context is maked as DIRTY:
+            if (rdrCtx.dirty) {
+                // may happen if an exception if thrown in the pipeline processing:
+                // clear completely buckets arrays:
+                buckets_minY = 0;
+                buckets_maxY = boundsMaxY - boundsMinY;
+            }
+            // clear only used part
+            edgeBuckets = edgeBuckets_ref.putArray(edgeBuckets, buckets_minY,
+                                                                buckets_maxY);
+            edgeBucketCounts = edgeBucketCounts_ref.putArray(edgeBucketCounts,
+                                                             buckets_minY,
+                                                             buckets_maxY + 1);
+        } else {
+            // unused arrays
+            edgeBuckets = edgeBuckets_ref.putArray(edgeBuckets, 0, 0);
+            edgeBucketCounts = edgeBucketCounts_ref.putArray(edgeBucketCounts, 0, 0);
+        }
+
+        // At last: resize back off-heap edges to initial size
+        if (edges.length != INITIAL_EDGES_CAPACITY) {
+            // note: may throw OOME:
+            edges.resize(INITIAL_EDGES_CAPACITY);
+        }
+        if (DO_CLEAN_DIRTY) {
+            // Force zero-fill dirty arrays:
+            edges.fill(BYTE_0);
+        }
+        if (DO_MONITORS) {
+            rdrCtx.stats.mon_rdr_endRendering.stop();
+        }
+        // recycle the RendererContext instance
+        DMarlinRenderingEngine.returnRendererContext(rdrCtx);
+    }
+
+    private static double tosubpixx(final double pix_x) {
+        return SUBPIXEL_SCALE_X * pix_x;
+    }
+
+    private static double tosubpixy(final double pix_y) {
+        // shift y by -0.5 for fast ceil(y - 0.5):
+        return SUBPIXEL_SCALE_Y * pix_y - 0.5d;
+    }
+
+    @Override
+    public void moveTo(final double pix_x0, final double pix_y0) {
+        closePath();
+        final double sx = tosubpixx(pix_x0);
+        final double sy = tosubpixy(pix_y0);
+        this.sx0 = sx;
+        this.sy0 = sy;
+        this.x0 = sx;
+        this.y0 = sy;
+    }
+
+    @Override
+    public void lineTo(final double pix_x1, final double pix_y1) {
+        final double x1 = tosubpixx(pix_x1);
+        final double y1 = tosubpixy(pix_y1);
+        addLine(x0, y0, x1, y1);
+        x0 = x1;
+        y0 = y1;
+    }
+
+    @Override
+    public void curveTo(final double pix_x1, final double pix_y1,
+                        final double pix_x2, final double pix_y2,
+                        final double pix_x3, final double pix_y3)
+    {
+        final double xe = tosubpixx(pix_x3);
+        final double ye = tosubpixy(pix_y3);
+        curve.set(x0, y0,
+                tosubpixx(pix_x1), tosubpixy(pix_y1),
+                tosubpixx(pix_x2), tosubpixy(pix_y2),
+                xe, ye);
+        curveBreakIntoLinesAndAdd(x0, y0, curve, xe, ye);
+        x0 = xe;
+        y0 = ye;
+    }
+
+    @Override
+    public void quadTo(final double pix_x1, final double pix_y1,
+                       final double pix_x2, final double pix_y2)
+    {
+        final double xe = tosubpixx(pix_x2);
+        final double ye = tosubpixy(pix_y2);
+        curve.set(x0, y0,
+                tosubpixx(pix_x1), tosubpixy(pix_y1),
+                xe, ye);
+        quadBreakIntoLinesAndAdd(x0, y0, curve, xe, ye);
+        x0 = xe;
+        y0 = ye;
+    }
+
+    @Override
+    public void closePath() {
+        if (x0 != sx0 || y0 != sy0) {
+            addLine(x0, y0, sx0, sy0);
+            x0 = sx0;
+            y0 = sy0;
+        }
+    }
+
+    @Override
+    public void pathDone() {
+        closePath();
+    }
+
+    @Override
+    public long getNativeConsumer() {
+        throw new InternalError("Renderer does not use a native consumer.");
+    }
+
+    private void _endRendering(final int ymin, final int ymax) {
+        if (DISABLE_RENDER) {
+            return;
+        }
+
+        // Get X bounds as true pixel boundaries to compute correct pixel coverage:
+        final int bboxx0 = bbox_spminX;
+        final int bboxx1 = bbox_spmaxX;
+
+        final boolean windingRuleEvenOdd = (windingRule == WIND_EVEN_ODD);
+
+        // Useful when processing tile line by tile line
+        final int[] _alpha = alphaLine;
+
+        // local vars (performance):
+        final MarlinCache _cache = cache;
+        final OffHeapArray _edges = edges;
+        final int[] _edgeBuckets = edgeBuckets;
+        final int[] _edgeBucketCounts = edgeBucketCounts;
+
+        int[] _crossings = this.crossings;
+        int[] _edgePtrs  = this.edgePtrs;
+
+        // merge sort auxiliary storage:
+        int[] _aux_crossings = this.aux_crossings;
+        int[] _aux_edgePtrs  = this.aux_edgePtrs;
+
+        // copy constants:
+        final long _OFF_ERROR    = OFF_ERROR;
+        final long _OFF_BUMP_X   = OFF_BUMP_X;
+        final long _OFF_BUMP_ERR = OFF_BUMP_ERR;
+
+        final long _OFF_NEXT     = OFF_NEXT;
+        final long _OFF_YMAX     = OFF_YMAX;
+
+        final int _ALL_BUT_LSB   = ALL_BUT_LSB;
+        final int _ERR_STEP_MAX  = ERR_STEP_MAX;
+
+        // unsafe I/O:
+        final Unsafe _unsafe = OffHeapArray.UNSAFE;
+        final long    addr0  = _edges.address;
+        long addr;
+        final int _SUBPIXEL_LG_POSITIONS_X = SUBPIXEL_LG_POSITIONS_X;
+        final int _SUBPIXEL_LG_POSITIONS_Y = SUBPIXEL_LG_POSITIONS_Y;
+        final int _SUBPIXEL_MASK_X = SUBPIXEL_MASK_X;
+        final int _SUBPIXEL_MASK_Y = SUBPIXEL_MASK_Y;
+        final int _SUBPIXEL_POSITIONS_X = SUBPIXEL_POSITIONS_X;
+
+        final int _MIN_VALUE = Integer.MIN_VALUE;
+        final int _MAX_VALUE = Integer.MAX_VALUE;
+
+        // Now we iterate through the scanlines. We must tell emitRow the coord
+        // of the first non-transparent pixel, so we must keep accumulators for
+        // the first and last pixels of the section of the current pixel row
+        // that we will emit.
+        // We also need to accumulate pix_bbox, but the iterator does it
+        // for us. We will just get the values from it once this loop is done
+        int minX = _MAX_VALUE;
+        int maxX = _MIN_VALUE;
+
+        int y = ymin;
+        int bucket = y - boundsMinY;
+
+        int numCrossings = this.edgeCount;
+        int edgePtrsLen = _edgePtrs.length;
+        int crossingsLen = _crossings.length;
+        int _arrayMaxUsed = activeEdgeMaxUsed;
+        int ptrLen = 0, newCount, ptrEnd;
+
+        int bucketcount, i, j, ecur;
+        int cross, lastCross;
+        int x0, x1, tmp, sum, prev, curx, curxo, crorientation, err;
+        int pix_x, pix_xmaxm1, pix_xmax;
+
+        int low, high, mid, prevNumCrossings;
+        boolean useBinarySearch;
+
+        final int[] _blkFlags = blkFlags;
+        final int _BLK_SIZE_LG = BLOCK_SIZE_LG;
+        final int _BLK_SIZE = BLOCK_SIZE;
+
+        final boolean _enableBlkFlagsHeuristics = ENABLE_BLOCK_FLAGS_HEURISTICS && this.enableBlkFlags;
+
+        // Use block flags if large pixel span and few crossings:
+        // ie mean(distance between crossings) is high
+        boolean useBlkFlags = this.prevUseBlkFlags;
+
+        final int stroking = rdrCtx.stroking;
+
+        int lastY = -1; // last emited row
+
+
+        // Iteration on scanlines
+        for (; y < ymax; y++, bucket++) {
+            // --- from former ScanLineIterator.next()
+            bucketcount = _edgeBucketCounts[bucket];
+
+            // marker on previously sorted edges:
+            prevNumCrossings = numCrossings;
+
+            // bucketCount indicates new edge / edge end:
+            if (bucketcount != 0) {
+                if (DO_STATS) {
+                    rdrCtx.stats.stat_rdr_activeEdges_updates.add(numCrossings);
+                }
+
+                // last bit set to 1 means that edges ends
+                if ((bucketcount & 0x1) != 0) {
+                    // eviction in active edge list
+                    // cache edges[] address + offset
+                    addr = addr0 + _OFF_YMAX;
+
+                    for (i = 0, newCount = 0; i < numCrossings; i++) {
+                        // get the pointer to the edge
+                        ecur = _edgePtrs[i];
+                        // random access so use unsafe:
+                        if (_unsafe.getInt(addr + ecur) > y) {
+                            _edgePtrs[newCount++] = ecur;
+                        }
+                    }
+                    // update marker on sorted edges minus removed edges:
+                    prevNumCrossings = numCrossings = newCount;
+                }
+
+                ptrLen = bucketcount >> 1; // number of new edge
+
+                if (ptrLen != 0) {
+                    if (DO_STATS) {
+                        rdrCtx.stats.stat_rdr_activeEdges_adds.add(ptrLen);
+                        if (ptrLen > 10) {
+                            rdrCtx.stats.stat_rdr_activeEdges_adds_high.add(ptrLen);
+                        }
+                    }
+                    ptrEnd = numCrossings + ptrLen;
+
+                    if (edgePtrsLen < ptrEnd) {
+                        if (DO_STATS) {
+                            rdrCtx.stats.stat_array_renderer_edgePtrs.add(ptrEnd);
+                        }
+                        this.edgePtrs = _edgePtrs
+                            = edgePtrs_ref.widenArray(_edgePtrs, numCrossings,
+                                                      ptrEnd);
+
+                        edgePtrsLen = _edgePtrs.length;
+                        // Get larger auxiliary storage:
+                        aux_edgePtrs_ref.putArray(_aux_edgePtrs);
+
+                        // use ArrayCache.getNewSize() to use the same growing
+                        // factor than widenArray():
+                        if (DO_STATS) {
+                            rdrCtx.stats.stat_array_renderer_aux_edgePtrs.add(ptrEnd);
+                        }
+                        this.aux_edgePtrs = _aux_edgePtrs
+                            = aux_edgePtrs_ref.getArray(
+                                ArrayCacheConst.getNewSize(numCrossings, ptrEnd)
+                            );
+                    }
+
+                    // cache edges[] address + offset
+                    addr = addr0 + _OFF_NEXT;
+
+                    // add new edges to active edge list:
+                    for (ecur = _edgeBuckets[bucket];
+                         numCrossings < ptrEnd; numCrossings++)
+                    {
+                        // store the pointer to the edge
+                        _edgePtrs[numCrossings] = ecur;
+                        // random access so use unsafe:
+                        ecur = _unsafe.getInt(addr + ecur);
+                    }
+
+                    if (crossingsLen < numCrossings) {
+                        // Get larger array:
+                        crossings_ref.putArray(_crossings);
+
+                        if (DO_STATS) {
+                            rdrCtx.stats.stat_array_renderer_crossings
+                                .add(numCrossings);
+                        }
+                        this.crossings = _crossings
+                            = crossings_ref.getArray(numCrossings);
+
+                        // Get larger auxiliary storage:
+                        aux_crossings_ref.putArray(_aux_crossings);
+
+                        if (DO_STATS) {
+                            rdrCtx.stats.stat_array_renderer_aux_crossings
+                                .add(numCrossings);
+                        }
+                        this.aux_crossings = _aux_crossings
+                            = aux_crossings_ref.getArray(numCrossings);
+
+                        crossingsLen = _crossings.length;
+                    }
+                    if (DO_STATS) {
+                        // update max used mark
+                        if (numCrossings > _arrayMaxUsed) {
+                            _arrayMaxUsed = numCrossings;
+                        }
+                    }
+                } // ptrLen != 0
+            } // bucketCount != 0
+
+
+            if (numCrossings != 0) {
+                /*
+                 * thresholds to switch to optimized merge sort
+                 * for newly added edges + final merge pass.
+                 */
+                if ((ptrLen < 10) || (numCrossings < 40)) {
+                    if (DO_STATS) {
+                        rdrCtx.stats.hist_rdr_crossings.add(numCrossings);
+                        rdrCtx.stats.hist_rdr_crossings_adds.add(ptrLen);
+                    }
+
+                    /*
+                     * threshold to use binary insertion sort instead of
+                     * straight insertion sort (to reduce minimize comparisons).
+                     */
+                    useBinarySearch = (numCrossings >= 20);
+
+                    // if small enough:
+                    lastCross = _MIN_VALUE;
+
+                    for (i = 0; i < numCrossings; i++) {
+                        // get the pointer to the edge
+                        ecur = _edgePtrs[i];
+
+                        /* convert subpixel coordinates into pixel
+                            positions for coming scanline */
+                        /* note: it is faster to always update edges even
+                           if it is removed from AEL for coming or last scanline */
+
+                        // random access so use unsafe:
+                        addr = addr0 + ecur; // ecur + OFF_F_CURX
+
+                        // get current crossing:
+                        curx = _unsafe.getInt(addr);
+
+                        // update crossing with orientation at last bit:
+                        cross = curx;
+
+                        // Increment x using DDA (fixed point):
+                        curx += _unsafe.getInt(addr + _OFF_BUMP_X);
+
+                        // Increment error:
+                        err  =  _unsafe.getInt(addr + _OFF_ERROR)
+                              + _unsafe.getInt(addr + _OFF_BUMP_ERR);
+
+                        // Manual carry handling:
+                        // keep sign and carry bit only and ignore last bit (preserve orientation):
+                        _unsafe.putInt(addr,               curx - ((err >> 30) & _ALL_BUT_LSB));
+                        _unsafe.putInt(addr + _OFF_ERROR, (err & _ERR_STEP_MAX));
+
+                        if (DO_STATS) {
+                            rdrCtx.stats.stat_rdr_crossings_updates.add(numCrossings);
+                        }
+
+                        // insertion sort of crossings:
+                        if (cross < lastCross) {
+                            if (DO_STATS) {
+                                rdrCtx.stats.stat_rdr_crossings_sorts.add(i);
+                            }
+
+                            /* use binary search for newly added edges
+                               in crossings if arrays are large enough */
+                            if (useBinarySearch && (i >= prevNumCrossings)) {
+                                if (DO_STATS) {
+                                    rdrCtx.stats.stat_rdr_crossings_bsearch.add(i);
+                                }
+                                low = 0;
+                                high = i - 1;
+
+                                do {
+                                    // note: use signed shift (not >>>) for performance
+                                    // as indices are small enough to exceed Integer.MAX_VALUE
+                                    mid = (low + high) >> 1;
+
+                                    if (_crossings[mid] < cross) {
+                                        low = mid + 1;
+                                    } else {
+                                        high = mid - 1;
+                                    }
+                                } while (low <= high);
+
+                                for (j = i - 1; j >= low; j--) {
+                                    _crossings[j + 1] = _crossings[j];
+                                    _edgePtrs [j + 1] = _edgePtrs[j];
+                                }
+                                _crossings[low] = cross;
+                                _edgePtrs [low] = ecur;
+
+                            } else {
+                                j = i - 1;
+                                _crossings[i] = _crossings[j];
+                                _edgePtrs[i] = _edgePtrs[j];
+
+                                while ((--j >= 0) && (_crossings[j] > cross)) {
+                                    _crossings[j + 1] = _crossings[j];
+                                    _edgePtrs [j + 1] = _edgePtrs[j];
+                                }
+                                _crossings[j + 1] = cross;
+                                _edgePtrs [j + 1] = ecur;
+                            }
+
+                        } else {
+                            _crossings[i] = lastCross = cross;
+                        }
+                    }
+                } else {
+                    if (DO_STATS) {
+                        rdrCtx.stats.stat_rdr_crossings_msorts.add(numCrossings);
+                        rdrCtx.stats.hist_rdr_crossings_ratio
+                            .add((1000 * ptrLen) / numCrossings);
+                        rdrCtx.stats.hist_rdr_crossings_msorts.add(numCrossings);
+                        rdrCtx.stats.hist_rdr_crossings_msorts_adds.add(ptrLen);
+                    }
+
+                    // Copy sorted data in auxiliary arrays
+                    // and perform insertion sort on almost sorted data
+                    // (ie i < prevNumCrossings):
+
+                    lastCross = _MIN_VALUE;
+
+                    for (i = 0; i < numCrossings; i++) {
+                        // get the pointer to the edge
+                        ecur = _edgePtrs[i];
+
+                        /* convert subpixel coordinates into pixel
+                            positions for coming scanline */
+                        /* note: it is faster to always update edges even
+                           if it is removed from AEL for coming or last scanline */
+
+                        // random access so use unsafe:
+                        addr = addr0 + ecur; // ecur + OFF_F_CURX
+
+                        // get current crossing:
+                        curx = _unsafe.getInt(addr);
+
+                        // update crossing with orientation at last bit:
+                        cross = curx;
+
+                        // Increment x using DDA (fixed point):
+                        curx += _unsafe.getInt(addr + _OFF_BUMP_X);
+
+                        // Increment error:
+                        err  =  _unsafe.getInt(addr + _OFF_ERROR)
+                              + _unsafe.getInt(addr + _OFF_BUMP_ERR);
+
+                        // Manual carry handling:
+                        // keep sign and carry bit only and ignore last bit (preserve orientation):
+                        _unsafe.putInt(addr,               curx - ((err >> 30) & _ALL_BUT_LSB));
+                        _unsafe.putInt(addr + _OFF_ERROR, (err & _ERR_STEP_MAX));
+
+                        if (DO_STATS) {
+                            rdrCtx.stats.stat_rdr_crossings_updates.add(numCrossings);
+                        }
+
+                        if (i >= prevNumCrossings) {
+                            // simply store crossing as edgePtrs is in-place:
+                            // will be copied and sorted efficiently by mergesort later:
+                            _crossings[i]     = cross;
+
+                        } else if (cross < lastCross) {
+                            if (DO_STATS) {
+                                rdrCtx.stats.stat_rdr_crossings_sorts.add(i);
+                            }
+
+                            // (straight) insertion sort of crossings:
+                            j = i - 1;
+                            _aux_crossings[i] = _aux_crossings[j];
+                            _aux_edgePtrs[i] = _aux_edgePtrs[j];
+
+                            while ((--j >= 0) && (_aux_crossings[j] > cross)) {
+                                _aux_crossings[j + 1] = _aux_crossings[j];
+                                _aux_edgePtrs [j + 1] = _aux_edgePtrs[j];
+                            }
+                            _aux_crossings[j + 1] = cross;
+                            _aux_edgePtrs [j + 1] = ecur;
+
+                        } else {
+                            // auxiliary storage:
+                            _aux_crossings[i] = lastCross = cross;
+                            _aux_edgePtrs [i] = ecur;
+                        }
+                    }
+
+                    // use Mergesort using auxiliary arrays (sort only right part)
+                    MergeSort.mergeSortNoCopy(_crossings,     _edgePtrs,
+                                              _aux_crossings, _aux_edgePtrs,
+                                              numCrossings,   prevNumCrossings);
+                }
+
+                // reset ptrLen
+                ptrLen = 0;
+                // --- from former ScanLineIterator.next()
+
+
+                /* note: bboxx0 and bboxx1 must be pixel boundaries
+                   to have correct coverage computation */
+
+                // right shift on crossings to get the x-coordinate:
+                curxo = _crossings[0];
+                x0    = curxo >> 1;
+                if (x0 < minX) {
+                    minX = x0; // subpixel coordinate
+                }
+
+                x1 = _crossings[numCrossings - 1] >> 1;
+                if (x1 > maxX) {
+                    maxX = x1; // subpixel coordinate
+                }
+
+
+                // compute pixel coverages
+                prev = curx = x0;
+                // to turn {0, 1} into {-1, 1}, multiply by 2 and subtract 1.
+                // last bit contains orientation (0 or 1)
+                crorientation = ((curxo & 0x1) << 1) - 1;
+
+                if (windingRuleEvenOdd) {
+                    sum = crorientation;
+
+                    // Even Odd winding rule: take care of mask ie sum(orientations)
+                    for (i = 1; i < numCrossings; i++) {
+                        curxo = _crossings[i];
+                        curx  =  curxo >> 1;
+                        // to turn {0, 1} into {-1, 1}, multiply by 2 and subtract 1.
+                        // last bit contains orientation (0 or 1)
+                        crorientation = ((curxo & 0x1) << 1) - 1;
+
+                        if ((sum & 0x1) != 0) {
+                            // TODO: perform line clipping on left-right sides
+                            // to avoid such bound checks:
+                            x0 = (prev > bboxx0) ? prev : bboxx0;
+
+                            if (curx < bboxx1) {
+                                x1 = curx;
+                            } else {
+                                x1 = bboxx1;
+                                // skip right side (fast exit loop):
+                                i = numCrossings;
+                            }
+
+                            if (x0 < x1) {
+                                x0 -= bboxx0; // turn x0, x1 from coords to indices
+                                x1 -= bboxx0; // in the alpha array.
+
+                                pix_x      =  x0      >> _SUBPIXEL_LG_POSITIONS_X;
+                                pix_xmaxm1 = (x1 - 1) >> _SUBPIXEL_LG_POSITIONS_X;
+
+                                if (pix_x == pix_xmaxm1) {
+                                    // Start and end in same pixel
+                                    tmp = (x1 - x0); // number of subpixels
+                                    _alpha[pix_x    ] += tmp;
+                                    _alpha[pix_x + 1] -= tmp;
+
+                                    if (useBlkFlags) {
+                                        // flag used blocks:
+                                        // note: block processing handles extra pixel:
+                                        _blkFlags[pix_x    >> _BLK_SIZE_LG] = 1;
+                                    }
+                                } else {
+                                    tmp = (x0 & _SUBPIXEL_MASK_X);
+                                    _alpha[pix_x    ]
+                                        += (_SUBPIXEL_POSITIONS_X - tmp);
+                                    _alpha[pix_x + 1]
+                                        += tmp;
+
+                                    pix_xmax = x1 >> _SUBPIXEL_LG_POSITIONS_X;
+
+                                    tmp = (x1 & _SUBPIXEL_MASK_X);
+                                    _alpha[pix_xmax    ]
+                                        -= (_SUBPIXEL_POSITIONS_X - tmp);
+                                    _alpha[pix_xmax + 1]
+                                        -= tmp;
+
+                                    if (useBlkFlags) {
+                                        // flag used blocks:
+                                        // note: block processing handles extra pixel:
+                                        _blkFlags[pix_x    >> _BLK_SIZE_LG] = 1;
+                                        _blkFlags[pix_xmax >> _BLK_SIZE_LG] = 1;
+                                    }
+                                }
+                            }
+                        }
+
+                        sum += crorientation;
+                        prev = curx;
+                    }
+                } else {
+                    // Non-zero winding rule: optimize that case (default)
+                    // and avoid processing intermediate crossings
+                    for (i = 1, sum = 0;; i++) {
+                        sum += crorientation;
+
+                        if (sum != 0) {
+                            // prev = min(curx)
+                            if (prev > curx) {
+                                prev = curx;
+                            }
+                        } else {
+                            // TODO: perform line clipping on left-right sides
+                            // to avoid such bound checks:
+                            x0 = (prev > bboxx0) ? prev : bboxx0;
+
+                            if (curx < bboxx1) {
+                                x1 = curx;
+                            } else {
+                                x1 = bboxx1;
+                                // skip right side (fast exit loop):
+                                i = numCrossings;
+                            }
+
+                            if (x0 < x1) {
+                                x0 -= bboxx0; // turn x0, x1 from coords to indices
+                                x1 -= bboxx0; // in the alpha array.
+
+                                pix_x      =  x0      >> _SUBPIXEL_LG_POSITIONS_X;
+                                pix_xmaxm1 = (x1 - 1) >> _SUBPIXEL_LG_POSITIONS_X;
+
+                                if (pix_x == pix_xmaxm1) {
+                                    // Start and end in same pixel
+                                    tmp = (x1 - x0); // number of subpixels
+                                    _alpha[pix_x    ] += tmp;
+                                    _alpha[pix_x + 1] -= tmp;
+
+                                    if (useBlkFlags) {
+                                        // flag used blocks:
+                                        // note: block processing handles extra pixel:
+                                        _blkFlags[pix_x    >> _BLK_SIZE_LG] = 1;
+                                    }
+                                } else {
+                                    tmp = (x0 & _SUBPIXEL_MASK_X);
+                                    _alpha[pix_x    ]
+                                        += (_SUBPIXEL_POSITIONS_X - tmp);
+                                    _alpha[pix_x + 1]
+                                        += tmp;
+
+                                    pix_xmax = x1 >> _SUBPIXEL_LG_POSITIONS_X;
+
+                                    tmp = (x1 & _SUBPIXEL_MASK_X);
+                                    _alpha[pix_xmax    ]
+                                        -= (_SUBPIXEL_POSITIONS_X - tmp);
+                                    _alpha[pix_xmax + 1]
+                                        -= tmp;
+
+                                    if (useBlkFlags) {
+                                        // flag used blocks:
+                                        // note: block processing handles extra pixel:
+                                        _blkFlags[pix_x    >> _BLK_SIZE_LG] = 1;
+                                        _blkFlags[pix_xmax >> _BLK_SIZE_LG] = 1;
+                                    }
+                                }
+                            }
+                            prev = _MAX_VALUE;
+                        }
+
+                        if (i == numCrossings) {
+                            break;
+                        }
+
+                        curxo = _crossings[i];
+                        curx  =  curxo >> 1;
+                        // to turn {0, 1} into {-1, 1}, multiply by 2 and subtract 1.
+                        // last bit contains orientation (0 or 1)
+                        crorientation = ((curxo & 0x1) << 1) - 1;
+                    }
+                }
+            } // numCrossings > 0
+
+            // even if this last row had no crossings, alpha will be zeroed
+            // from the last emitRow call. But this doesn't matter because
+            // maxX < minX, so no row will be emitted to the MarlinCache.
+            if ((y & _SUBPIXEL_MASK_Y) == _SUBPIXEL_MASK_Y) {
+                lastY = y >> _SUBPIXEL_LG_POSITIONS_Y;
+
+                // convert subpixel to pixel coordinate within boundaries:
+                minX = FloatMath.max(minX, bboxx0) >> _SUBPIXEL_LG_POSITIONS_X;
+                maxX = FloatMath.min(maxX, bboxx1) >> _SUBPIXEL_LG_POSITIONS_X;
+
+                if (maxX >= minX) {
+                    // note: alpha array will be zeroed by copyAARow()
+                    // +1 because alpha [pix_minX; pix_maxX[
+                    // fix range [x0; x1[
+                    // note: if x1=bboxx1, then alpha is written up to bboxx1+1
+                    // inclusive: alpha[bboxx1] ignored, alpha[bboxx1+1] == 0
+                    // (normally so never cleared below)
+                    copyAARow(_alpha, lastY, minX, maxX + 1, useBlkFlags);
+
+                    // speculative for next pixel row (scanline coherence):
+                    if (_enableBlkFlagsHeuristics) {
+                        // Use block flags if large pixel span and few crossings:
+                        // ie mean(distance between crossings) is larger than
+                        // 1 block size;
+
+                        // fast check width:
+                        maxX -= minX;
+
+                        // if stroking: numCrossings /= 2
+                        // => shift numCrossings by 1
+                        // condition = (width / (numCrossings - 1)) > blockSize
+                        useBlkFlags = (maxX > _BLK_SIZE) && (maxX >
+                            (((numCrossings >> stroking) - 1) << _BLK_SIZE_LG));
+
+                        if (DO_STATS) {
+                            tmp = FloatMath.max(1,
+                                    ((numCrossings >> stroking) - 1));
+                            rdrCtx.stats.hist_tile_generator_encoding_dist
+                                .add(maxX / tmp);
+                        }
+                    }
+                } else {
+                    _cache.clearAARow(lastY);
+                }
+                minX = _MAX_VALUE;
+                maxX = _MIN_VALUE;
+            }
+        } // scan line iterator
+
+        // Emit final row
+        y--;
+        y >>= _SUBPIXEL_LG_POSITIONS_Y;
+
+        // convert subpixel to pixel coordinate within boundaries:
+        minX = FloatMath.max(minX, bboxx0) >> _SUBPIXEL_LG_POSITIONS_X;
+        maxX = FloatMath.min(maxX, bboxx1) >> _SUBPIXEL_LG_POSITIONS_X;
+
+        if (maxX >= minX) {
+            // note: alpha array will be zeroed by copyAARow()
+            // +1 because alpha [pix_minX; pix_maxX[
+            // fix range [x0; x1[
+            // note: if x1=bboxx1, then alpha is written up to bboxx1+1
+            // inclusive: alpha[bboxx1] ignored then cleared and
+            // alpha[bboxx1+1] == 0 (normally so never cleared after)
+            copyAARow(_alpha, y, minX, maxX + 1, useBlkFlags);
+        } else if (y != lastY) {
+            _cache.clearAARow(y);
+        }
+
+        // update member:
+        edgeCount = numCrossings;
+        prevUseBlkFlags = useBlkFlags;
+
+        if (DO_STATS) {
+            // update max used mark
+            activeEdgeMaxUsed = _arrayMaxUsed;
+        }
+    }
+
+    boolean endRendering() {
+        if (DO_MONITORS) {
+            rdrCtx.stats.mon_rdr_endRendering.start();
+        }
+        if (edgeMinY == Integer.MAX_VALUE) {
+            return false; // undefined edges bounds
+        }
+
+        // bounds as half-open intervals
+        final int spminX = FloatMath.max(FloatMath.ceil_int(edgeMinX - 0.5d), boundsMinX);
+        final int spmaxX = FloatMath.min(FloatMath.ceil_int(edgeMaxX - 0.5d), boundsMaxX);
+
+        // edge Min/Max Y are already rounded to subpixels within bounds:
+        final int spminY = edgeMinY;
+        final int spmaxY = edgeMaxY;
+
+        buckets_minY = spminY - boundsMinY;
+        buckets_maxY = spmaxY - boundsMinY;
+
+        if (DO_LOG_BOUNDS) {
+            MarlinUtils.logInfo("edgesXY = [" + edgeMinX + " ... " + edgeMaxX
+                                + "[ [" + edgeMinY + " ... " + edgeMaxY + "[");
+            MarlinUtils.logInfo("spXY    = [" + spminX + " ... " + spmaxX
+                                + "[ [" + spminY + " ... " + spmaxY + "[");
+        }
+
+        // test clipping for shapes out of bounds
+        if ((spminX >= spmaxX) || (spminY >= spmaxY)) {
+            return false;
+        }
+
+        // half open intervals
+        // inclusive:
+        final int pminX =  spminX                    >> SUBPIXEL_LG_POSITIONS_X;
+        // exclusive:
+        final int pmaxX = (spmaxX + SUBPIXEL_MASK_X) >> SUBPIXEL_LG_POSITIONS_X;
+        // inclusive:
+        final int pminY =  spminY                    >> SUBPIXEL_LG_POSITIONS_Y;
+        // exclusive:
+        final int pmaxY = (spmaxY + SUBPIXEL_MASK_Y) >> SUBPIXEL_LG_POSITIONS_Y;
+
+        // store BBox to answer ptg.getBBox():
+        this.cache.init(pminX, pminY, pmaxX, pmaxY);
+
+        // Heuristics for using block flags:
+        if (ENABLE_BLOCK_FLAGS) {
+            enableBlkFlags = this.cache.useRLE;
+            prevUseBlkFlags = enableBlkFlags && !ENABLE_BLOCK_FLAGS_HEURISTICS;
+
+            if (enableBlkFlags) {
+                // ensure blockFlags array is large enough:
+                // note: +2 to ensure enough space left at end
+                final int blkLen = ((pmaxX - pminX) >> BLOCK_SIZE_LG) + 2;
+                if (blkLen > INITIAL_ARRAY) {
+                    blkFlags = blkFlags_ref.getArray(blkLen);
+                }
+            }
+        }
+
+        // memorize the rendering bounding box:
+        /* note: bbox_spminX and bbox_spmaxX must be pixel boundaries
+           to have correct coverage computation */
+        // inclusive:
+        bbox_spminX = pminX << SUBPIXEL_LG_POSITIONS_X;
+        // exclusive:
+        bbox_spmaxX = pmaxX << SUBPIXEL_LG_POSITIONS_X;
+        // inclusive:
+        bbox_spminY = spminY;
+        // exclusive:
+        bbox_spmaxY = spmaxY;
+
+        if (DO_LOG_BOUNDS) {
+            MarlinUtils.logInfo("pXY       = [" + pminX + " ... " + pmaxX
+                                + "[ [" + pminY + " ... " + pmaxY + "[");
+            MarlinUtils.logInfo("bbox_spXY = [" + bbox_spminX + " ... "
+                                + bbox_spmaxX + "[ [" + bbox_spminY + " ... "
+                                + bbox_spmaxY + "[");
+        }
+
+        // Prepare alpha line:
+        // add 2 to better deal with the last pixel in a pixel row.
+        final int width = (pmaxX - pminX) + 2;
+
+        // Useful when processing tile line by tile line
+        if (width > INITIAL_AA_ARRAY) {
+            if (DO_STATS) {
+                rdrCtx.stats.stat_array_renderer_alphaline.add(width);
+            }
+            alphaLine = alphaLine_ref.getArray(width);
+        }
+
+        // process first tile line:
+        endRendering(pminY);
+
+        return true;
+    }
+
+    private int bbox_spminX, bbox_spmaxX, bbox_spminY, bbox_spmaxY;
+
+    void endRendering(final int pminY) {
+        if (DO_MONITORS) {
+            rdrCtx.stats.mon_rdr_endRendering_Y.start();
+        }
+
+        final int spminY       = pminY << SUBPIXEL_LG_POSITIONS_Y;
+        final int fixed_spminY = FloatMath.max(bbox_spminY, spminY);
+
+        // avoid rendering for last call to nextTile()
+        if (fixed_spminY < bbox_spmaxY) {
+            // process a complete tile line ie scanlines for 32 rows
+            final int spmaxY = FloatMath.min(bbox_spmaxY, spminY + SUBPIXEL_TILE);
+
+            // process tile line [0 - 32]
+            cache.resetTileLine(pminY);
+
+            // Process only one tile line:
+            _endRendering(fixed_spminY, spmaxY);
+        }
+        if (DO_MONITORS) {
+            rdrCtx.stats.mon_rdr_endRendering_Y.stop();
+        }
+    }
+
+    void copyAARow(final int[] alphaRow,
+                   final int pix_y, final int pix_from, final int pix_to,
+                   final boolean useBlockFlags)
+    {
+        if (DO_MONITORS) {
+            rdrCtx.stats.mon_rdr_copyAARow.start();
+        }
+        if (useBlockFlags) {
+            if (DO_STATS) {
+                rdrCtx.stats.hist_tile_generator_encoding.add(1);
+            }
+            cache.copyAARowRLE_WithBlockFlags(blkFlags, alphaRow, pix_y, pix_from, pix_to);
+        } else {
+            if (DO_STATS) {
+                rdrCtx.stats.hist_tile_generator_encoding.add(0);
+            }
+            cache.copyAARowNoRLE(alphaRow, pix_y, pix_from, pix_to);
+        }
+        if (DO_MONITORS) {
+            rdrCtx.stats.mon_rdr_copyAARow.stop();
+        }
+    }
+}
diff --git a/src/share/classes/sun/java2d/marlin/DRendererContext.java b/src/share/classes/sun/java2d/marlin/DRendererContext.java
new file mode 100644
index 0000000..e2d6234
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/DRendererContext.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d.marlin;
+
+import java.awt.geom.Path2D;
+import java.lang.ref.WeakReference;
+import java.util.concurrent.atomic.AtomicInteger;
+import sun.java2d.ReentrantContext;
+import sun.java2d.marlin.ArrayCacheConst.CacheStats;
+import sun.java2d.marlin.DMarlinRenderingEngine.NormalizingPathIterator;
+import sun.java2d.marlin.DTransformingPathConsumer2D.CurveBasicMonotonizer;
+import sun.java2d.marlin.DTransformingPathConsumer2D.CurveClipSplitter;
+
+/**
+ * This class is a renderer context dedicated to a single thread
+ */
+final class DRendererContext extends ReentrantContext implements IRendererContext {
+
+    // RendererContext creation counter
+    private static final AtomicInteger CTX_COUNT = new AtomicInteger(1);
+
+    /**
+     * Create a new renderer context
+     *
+     * @return new RendererContext instance
+     */
+    static DRendererContext createContext() {
+        return new DRendererContext("ctx"
+                       + Integer.toString(CTX_COUNT.getAndIncrement()));
+    }
+
+    // Smallest object used as Cleaner's parent reference
+    private final Object cleanerObj;
+    // dirty flag indicating an exception occured during pipeline in pathTo()
+    boolean dirty = false;
+    // shared data
+    final double[] double6 = new double[6];
+    // shared curve (dirty) (Renderer / Stroker)
+    final DCurve curve = new DCurve();
+    // MarlinRenderingEngine NormalizingPathIterator NearestPixelCenter:
+    final NormalizingPathIterator nPCPathIterator;
+    // MarlinRenderingEngine NearestPixelQuarter NormalizingPathIterator:
+    final NormalizingPathIterator nPQPathIterator;
+    // MarlinRenderingEngine.TransformingPathConsumer2D
+    final DTransformingPathConsumer2D transformerPC2D;
+    // recycled Path2D instance (weak)
+    private WeakReference<Path2D.Double> refPath2D = null;
+    final DRenderer renderer;
+    final DStroker stroker;
+    // Simplifies out collinear lines
+    final DCollinearSimplifier simplifier = new DCollinearSimplifier();
+    // Simplifies path
+    final DPathSimplifier pathSimplifier = new DPathSimplifier();
+    final DDasher dasher;
+    final MarlinTileGenerator ptg;
+    final MarlinCache cache;
+    // flag indicating the shape is stroked (1) or filled (0)
+    int stroking = 0;
+    // flag indicating to clip the shape
+    boolean doClip = false;
+    // flag indicating if the path is closed or not (in advance) to handle properly caps
+    boolean closedPath = false;
+    // clip rectangle (ymin, ymax, xmin, xmax):
+    final double[] clipRect = new double[4];
+    // CurveBasicMonotonizer instance
+    final CurveBasicMonotonizer monotonizer;
+    // CurveClipSplitter instance
+    final CurveClipSplitter curveClipSplitter;
+
+    // Array caches:
+    /* clean int[] cache (zero-filled) = 5 refs */
+    private final IntArrayCache cleanIntCache = new IntArrayCache(true, 5);
+    /* dirty int[] cache = 5 refs */
+    private final IntArrayCache dirtyIntCache = new IntArrayCache(false, 5);
+    /* dirty double[] cache = 4 refs (2 polystack) */
+    private final DoubleArrayCache dirtyDoubleCache = new DoubleArrayCache(false, 4);
+    /* dirty byte[] cache = 2 ref (2 polystack) */
+    private final ByteArrayCache dirtyByteCache = new ByteArrayCache(false, 2);
+
+    // RendererContext statistics
+    final RendererStats stats;
+
+    final PathConsumer2DAdapter p2dAdapter = new PathConsumer2DAdapter();
+
+
+    /**
+     * Constructor
+     *
+     * @param name context name (debugging)
+     */
+    DRendererContext(final String name) {
+        if (LOG_CREATE_CONTEXT) {
+            MarlinUtils.logInfo("new RendererContext = " + name);
+        }
+        this.cleanerObj = new Object();
+
+        // create first stats (needed by newOffHeapArray):
+        if (DO_STATS || DO_MONITORS) {
+            stats = RendererStats.createInstance(cleanerObj, name);
+            // push cache stats:
+            stats.cacheStats = new CacheStats[] { cleanIntCache.stats,
+                dirtyIntCache.stats, dirtyDoubleCache.stats, dirtyByteCache.stats
+            };
+        } else {
+            stats = null;
+        }
+
+        // NormalizingPathIterator instances:
+        nPCPathIterator = new NormalizingPathIterator.NearestPixelCenter(double6);
+        nPQPathIterator  = new NormalizingPathIterator.NearestPixelQuarter(double6);
+
+        // curve monotonizer & clip subdivider (before transformerPC2D init)
+        monotonizer = new CurveBasicMonotonizer(this);
+        curveClipSplitter = new CurveClipSplitter(this);
+
+        // MarlinRenderingEngine.TransformingPathConsumer2D
+        transformerPC2D = new DTransformingPathConsumer2D(this);
+
+        // Renderer:
+        cache = new MarlinCache(this);
+        renderer = new DRenderer(this); // needs MarlinCache from rdrCtx.cache
+        ptg = new MarlinTileGenerator(stats, renderer, cache);
+
+        stroker = new DStroker(this);
+        dasher = new DDasher(this);
+    }
+
+    /**
+     * Disposes this renderer context:
+     * clean up before reusing this context
+     */
+    void dispose() {
+        if (DO_STATS) {
+            if (stats.totalOffHeap > stats.totalOffHeapMax) {
+                stats.totalOffHeapMax = stats.totalOffHeap;
+            }
+            stats.totalOffHeap = 0L;
+        }
+        stroking   = 0;
+        doClip     = false;
+        closedPath = false;
+
+        // if context is maked as DIRTY:
+        if (dirty) {
+            // may happen if an exception if thrown in the pipeline processing:
+            // force cleanup of all possible pipelined blocks (except Renderer):
+
+            // NormalizingPathIterator instances:
+            this.nPCPathIterator.dispose();
+            this.nPQPathIterator.dispose();
+            // Dasher:
+            this.dasher.dispose();
+            // Stroker:
+            this.stroker.dispose();
+
+            // mark context as CLEAN:
+            dirty = false;
+        }
+    }
+
+    Path2D.Double getPath2D() {
+        // resolve reference:
+        Path2D.Double p2d = (refPath2D != null) ? refPath2D.get() : null;
+
+        // create a new Path2D ?
+        if (p2d == null) {
+            p2d = new Path2D.Double(WIND_NON_ZERO, INITIAL_EDGES_COUNT); // 32K
+
+            // update weak reference:
+            refPath2D = new WeakReference<Path2D.Double>(p2d);
+        }
+        // reset the path anyway:
+        p2d.reset();
+        return p2d;
+    }
+
+    @Override
+    public RendererStats stats() {
+        return stats;
+    }
+
+    @Override
+    public OffHeapArray newOffHeapArray(final long initialSize) {
+        if (DO_STATS) {
+            stats.totalOffHeapInitial += initialSize;
+        }
+        return new OffHeapArray(cleanerObj, initialSize);
+    }
+
+    @Override
+    public IntArrayCache.Reference newCleanIntArrayRef(final int initialSize) {
+        return cleanIntCache.createRef(initialSize);
+    }
+
+    IntArrayCache.Reference newDirtyIntArrayRef(final int initialSize) {
+        return dirtyIntCache.createRef(initialSize);
+    }
+
+    DoubleArrayCache.Reference newDirtyDoubleArrayRef(final int initialSize) {
+        return dirtyDoubleCache.createRef(initialSize);
+    }
+
+    ByteArrayCache.Reference newDirtyByteArrayRef(final int initialSize) {
+        return dirtyByteCache.createRef(initialSize);
+    }
+
+    static final class PathConsumer2DAdapter implements DPathConsumer2D {
+        private sun.awt.geom.PathConsumer2D out;
+
+        PathConsumer2DAdapter() {}
+
+        PathConsumer2DAdapter init(sun.awt.geom.PathConsumer2D out) {
+            this.out = out;
+            return this;
+        }
+
+        @Override
+        public void moveTo(double x0, double y0) {
+            out.moveTo((float)x0, (float)y0);
+        }
+
+        @Override
+        public void lineTo(double x1, double y1) {
+            out.lineTo((float)x1, (float)y1);
+        }
+
+        @Override
+        public void closePath() {
+            out.closePath();
+        }
+
+        @Override
+        public void pathDone() {
+            out.pathDone();
+        }
+
+        @Override
+        public void curveTo(double x1, double y1,
+                            double x2, double y2,
+                            double x3, double y3)
+        {
+            out.curveTo((float)x1, (float)y1,
+                    (float)x2, (float)y2,
+                    (float)x3, (float)y3);
+        }
+
+        @Override
+        public void quadTo(double x1, double y1, double x2, double y2) {
+            out.quadTo((float)x1, (float)y1, (float)x2, (float)y2);
+        }
+
+        @Override
+        public long getNativeConsumer() {
+            throw new InternalError("Not using a native peer");
+        }
+    }
+}
diff --git a/src/share/classes/sun/java2d/marlin/DStroker.java b/src/share/classes/sun/java2d/marlin/DStroker.java
new file mode 100644
index 0000000..628850f
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/DStroker.java
@@ -0,0 +1,1337 @@
+/*
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d.marlin;
+
+import java.util.Arrays;
+import sun.java2d.marlin.DHelpers.PolyStack;
+import sun.java2d.marlin.DTransformingPathConsumer2D.CurveBasicMonotonizer;
+import sun.java2d.marlin.DTransformingPathConsumer2D.CurveClipSplitter;
+
+// TODO: some of the arithmetic here is too verbose and prone to hard to
+// debug typos. We should consider making a small Point/Vector class that
+// has methods like plus(Point), minus(Point), dot(Point), cross(Point)and such
+final class DStroker implements DPathConsumer2D, MarlinConst {
+
+    private static final int MOVE_TO = 0;
+    private static final int DRAWING_OP_TO = 1; // ie. curve, line, or quad
+    private static final int CLOSE = 2;
+
+    // round join threshold = 1 subpixel
+    private static final double ERR_JOIN = (1.0f / MIN_SUBPIXELS);
+    private static final double ROUND_JOIN_THRESHOLD = ERR_JOIN * ERR_JOIN;
+
+    // kappa = (4/3) * (SQRT(2) - 1)
+    private static final double C = (4.0d * (Math.sqrt(2.0d) - 1.0d) / 3.0d);
+
+    // SQRT(2)
+    private static final double SQRT_2 = Math.sqrt(2.0d);
+
+    private DPathConsumer2D out;
+
+    private int capStyle;
+    private int joinStyle;
+
+    private double lineWidth2;
+    private double invHalfLineWidth2Sq;
+
+    private final double[] offset0 = new double[2];
+    private final double[] offset1 = new double[2];
+    private final double[] offset2 = new double[2];
+    private final double[] miter = new double[2];
+    private double miterLimitSq;
+
+    private int prev;
+
+    // The starting point of the path, and the slope there.
+    private double sx0, sy0, sdx, sdy;
+    // the current point and the slope there.
+    private double cx0, cy0, cdx, cdy; // c stands for current
+    // vectors that when added to (sx0,sy0) and (cx0,cy0) respectively yield the
+    // first and last points on the left parallel path. Since this path is
+    // parallel, it's slope at any point is parallel to the slope of the
+    // original path (thought they may have different directions), so these
+    // could be computed from sdx,sdy and cdx,cdy (and vice versa), but that
+    // would be error prone and hard to read, so we keep these anyway.
+    private double smx, smy, cmx, cmy;
+
+    private final PolyStack reverse;
+
+    private final double[] lp = new double[8];
+    private final double[] rp = new double[8];
+
+    // per-thread renderer context
+    final DRendererContext rdrCtx;
+
+    // dirty curve
+    final DCurve curve;
+
+    // Bounds of the drawing region, at pixel precision.
+    private double[] clipRect;
+
+    // the outcode of the current point
+    private int cOutCode = 0;
+
+    // the outcode of the starting point
+    private int sOutCode = 0;
+
+    // flag indicating if the path is opened (clipped)
+    private boolean opened = false;
+    // flag indicating if the starting point's cap is done
+    private boolean capStart = false;
+    // flag indicating to monotonize curves
+    private boolean monotonize;
+
+    private boolean subdivide = false;
+    private final CurveClipSplitter curveSplitter;
+
+    /**
+     * Constructs a <code>DStroker</code>.
+     * @param rdrCtx per-thread renderer context
+     */
+    DStroker(final DRendererContext rdrCtx) {
+        this.rdrCtx = rdrCtx;
+
+        this.reverse = (rdrCtx.stats != null) ?
+            new PolyStack(rdrCtx,
+                    rdrCtx.stats.stat_str_polystack_types,
+                    rdrCtx.stats.stat_str_polystack_curves,
+                    rdrCtx.stats.hist_str_polystack_curves,
+                    rdrCtx.stats.stat_array_str_polystack_curves,
+                    rdrCtx.stats.stat_array_str_polystack_types)
+            : new PolyStack(rdrCtx);
+
+        this.curve = rdrCtx.curve;
+        this.curveSplitter = rdrCtx.curveClipSplitter;
+    }
+
+    /**
+     * Inits the <code>DStroker</code>.
+     *
+     * @param pc2d an output <code>DPathConsumer2D</code>.
+     * @param lineWidth the desired line width in pixels
+     * @param capStyle the desired end cap style, one of
+     * <code>CAP_BUTT</code>, <code>CAP_ROUND</code> or
+     * <code>CAP_SQUARE</code>.
+     * @param joinStyle the desired line join style, one of
+     * <code>JOIN_MITER</code>, <code>JOIN_ROUND</code> or
+     * <code>JOIN_BEVEL</code>.
+     * @param miterLimit the desired miter limit
+     * @param scale scaling factor applied to clip boundaries
+     * @param subdivideCurves true to indicate to subdivide curves, false if dasher does
+     * @return this instance
+     */
+    DStroker init(final DPathConsumer2D pc2d,
+                  final double lineWidth,
+                  final int capStyle,
+                  final int joinStyle,
+                  final double miterLimit,
+                  final double scale,
+                  final boolean subdivideCurves)
+    {
+        this.out = pc2d;
+
+        this.lineWidth2 = lineWidth / 2.0d;
+        this.invHalfLineWidth2Sq = 1.0d / (2.0d * lineWidth2 * lineWidth2);
+        this.monotonize = subdivideCurves;
+
+        this.capStyle = capStyle;
+        this.joinStyle = joinStyle;
+
+        final double limit = miterLimit * lineWidth2;
+        this.miterLimitSq = limit * limit;
+
+        this.prev = CLOSE;
+
+        rdrCtx.stroking = 1;
+
+        if (rdrCtx.doClip) {
+            // Adjust the clipping rectangle with the stroker margin (miter limit, width)
+            double rdrOffX = 0.0d, rdrOffY = 0.0d;
+            double margin = lineWidth2;
+
+            if (capStyle == CAP_SQUARE) {
+                margin *= SQRT_2;
+            }
+            if ((joinStyle == JOIN_MITER) && (margin < limit)) {
+                margin = limit;
+            }
+            if (scale != 1.0d) {
+                margin *= scale;
+                rdrOffX = scale * DRenderer.RDR_OFFSET_X;
+                rdrOffY = scale * DRenderer.RDR_OFFSET_Y;
+            }
+            // add a small rounding error:
+            margin += 1e-3d;
+
+            // bounds as half-open intervals: minX <= x < maxX and minY <= y < maxY
+            // adjust clip rectangle (ymin, ymax, xmin, xmax):
+            final double[] _clipRect = rdrCtx.clipRect;
+            _clipRect[0] -= margin - rdrOffY;
+            _clipRect[1] += margin + rdrOffY;
+            _clipRect[2] -= margin - rdrOffX;
+            _clipRect[3] += margin + rdrOffX;
+            this.clipRect = _clipRect;
+
+            // initialize curve splitter here for stroker & dasher:
+            if (DO_CLIP_SUBDIVIDER) {
+                subdivide = subdivideCurves;
+                // adjust padded clip rectangle:
+                curveSplitter.init();
+            } else {
+                subdivide = false;
+            }
+        } else {
+            this.clipRect = null;
+            this.cOutCode = 0;
+            this.sOutCode = 0;
+        }
+        return this; // fluent API
+    }
+
+    void disableClipping() {
+        this.clipRect = null;
+        this.cOutCode = 0;
+        this.sOutCode = 0;
+    }
+
+    /**
+     * Disposes this stroker:
+     * clean up before reusing this instance
+     */
+    void dispose() {
+        reverse.dispose();
+
+        opened   = false;
+        capStart = false;
+
+        if (DO_CLEAN_DIRTY) {
+            // Force zero-fill dirty arrays:
+            Arrays.fill(offset0, 0.0d);
+            Arrays.fill(offset1, 0.0d);
+            Arrays.fill(offset2, 0.0d);
+            Arrays.fill(miter, 0.0d);
+            Arrays.fill(lp, 0.0d);
+            Arrays.fill(rp, 0.0d);
+        }
+    }
+
+    private static void computeOffset(final double lx, final double ly,
+                                      final double w, final double[] m)
+    {
+        double len = lx*lx + ly*ly;
+        if (len == 0.0d) {
+            m[0] = 0.0d;
+            m[1] = 0.0d;
+        } else {
+            len = Math.sqrt(len);
+            m[0] =  (ly * w) / len;
+            m[1] = -(lx * w) / len;
+        }
+    }
+
+    // Returns true if the vectors (dx1, dy1) and (dx2, dy2) are
+    // clockwise (if dx1,dy1 needs to be rotated clockwise to close
+    // the smallest angle between it and dx2,dy2).
+    // This is equivalent to detecting whether a point q is on the right side
+    // of a line passing through points p1, p2 where p2 = p1+(dx1,dy1) and
+    // q = p2+(dx2,dy2), which is the same as saying p1, p2, q are in a
+    // clockwise order.
+    // NOTE: "clockwise" here assumes coordinates with 0,0 at the bottom left.
+    private static boolean isCW(final double dx1, final double dy1,
+                                final double dx2, final double dy2)
+    {
+        return dx1 * dy2 <= dy1 * dx2;
+    }
+
+    private void mayDrawRoundJoin(double cx, double cy,
+                                  double omx, double omy,
+                                  double mx, double my,
+                                  boolean rev)
+    {
+        if ((omx == 0.0d && omy == 0.0d) || (mx == 0.0d && my == 0.0d)) {
+            return;
+        }
+
+        final double domx = omx - mx;
+        final double domy = omy - my;
+        final double lenSq = domx*domx + domy*domy;
+
+        if (lenSq < ROUND_JOIN_THRESHOLD) {
+            return;
+        }
+
+        if (rev) {
+            omx = -omx;
+            omy = -omy;
+            mx  = -mx;
+            my  = -my;
+        }
+        drawRoundJoin(cx, cy, omx, omy, mx, my, rev);
+    }
+
+    private void drawRoundJoin(double cx, double cy,
+                               double omx, double omy,
+                               double mx, double my,
+                               boolean rev)
+    {
+        // The sign of the dot product of mx,my and omx,omy is equal to the
+        // the sign of the cosine of ext
+        // (ext is the angle between omx,omy and mx,my).
+        final double cosext = omx * mx + omy * my;
+        // If it is >=0, we know that abs(ext) is <= 90 degrees, so we only
+        // need 1 curve to approximate the circle section that joins omx,omy
+        // and mx,my.
+        final int numCurves = (cosext >= 0.0d) ? 1 : 2;
+
+        switch (numCurves) {
+        case 1:
+            drawBezApproxForArc(cx, cy, omx, omy, mx, my, rev);
+            break;
+        case 2:
+            // we need to split the arc into 2 arcs spanning the same angle.
+            // The point we want will be one of the 2 intersections of the
+            // perpendicular bisector of the chord (omx,omy)->(mx,my) and the
+            // circle. We could find this by scaling the vector
+            // (omx+mx, omy+my)/2 so that it has length=lineWidth2 (and thus lies
+            // on the circle), but that can have numerical problems when the angle
+            // between omx,omy and mx,my is close to 180 degrees. So we compute a
+            // normal of (omx,omy)-(mx,my). This will be the direction of the
+            // perpendicular bisector. To get one of the intersections, we just scale
+            // this vector that its length is lineWidth2 (this works because the
+            // perpendicular bisector goes through the origin). This scaling doesn't
+            // have numerical problems because we know that lineWidth2 divided by
+            // this normal's length is at least 0.5 and at most sqrt(2)/2 (because
+            // we know the angle of the arc is > 90 degrees).
+            double nx = my - omy, ny = omx - mx;
+            double nlen = Math.sqrt(nx*nx + ny*ny);
+            double scale = lineWidth2/nlen;
+            double mmx = nx * scale, mmy = ny * scale;
+
+            // if (isCW(omx, omy, mx, my) != isCW(mmx, mmy, mx, my)) then we've
+            // computed the wrong intersection so we get the other one.
+            // The test above is equivalent to if (rev).
+            if (rev) {
+                mmx = -mmx;
+                mmy = -mmy;
+            }
+            drawBezApproxForArc(cx, cy, omx, omy, mmx, mmy, rev);
+            drawBezApproxForArc(cx, cy, mmx, mmy, mx, my, rev);
+            break;
+        default:
+        }
+    }
+
+    // the input arc defined by omx,omy and mx,my must span <= 90 degrees.
+    private void drawBezApproxForArc(final double cx, final double cy,
+                                     final double omx, final double omy,
+                                     final double mx, final double my,
+                                     boolean rev)
+    {
+        final double cosext2 = (omx * mx + omy * my) * invHalfLineWidth2Sq;
+
+        // check round off errors producing cos(ext) > 1 and a NaN below
+        // cos(ext) == 1 implies colinear segments and an empty join anyway
+        if (cosext2 >= 0.5d) {
+            // just return to avoid generating a flat curve:
+            return;
+        }
+
+        // cv is the length of P1-P0 and P2-P3 divided by the radius of the arc
+        // (so, cv assumes the arc has radius 1). P0, P1, P2, P3 are the points that
+        // define the bezier curve we're computing.
+        // It is computed using the constraints that P1-P0 and P3-P2 are parallel
+        // to the arc tangents at the endpoints, and that |P1-P0|=|P3-P2|.
+        double cv = ((4.0d / 3.0d) * Math.sqrt(0.5d - cosext2) /
+                            (1.0d + Math.sqrt(cosext2 + 0.5d)));
+        // if clockwise, we need to negate cv.
+        if (rev) { // rev is equivalent to isCW(omx, omy, mx, my)
+            cv = -cv;
+        }
+        final double x1 = cx + omx;
+        final double y1 = cy + omy;
+        final double x2 = x1 - cv * omy;
+        final double y2 = y1 + cv * omx;
+
+        final double x4 = cx + mx;
+        final double y4 = cy + my;
+        final double x3 = x4 + cv * my;
+        final double y3 = y4 - cv * mx;
+
+        emitCurveTo(x1, y1, x2, y2, x3, y3, x4, y4, rev);
+    }
+
+    private void drawRoundCap(double cx, double cy, double mx, double my) {
+        final double Cmx = C * mx;
+        final double Cmy = C * my;
+        emitCurveTo(cx + mx - Cmy, cy + my + Cmx,
+                    cx - my + Cmx, cy + mx + Cmy,
+                    cx - my,       cy + mx);
+        emitCurveTo(cx - my - Cmx, cy + mx - Cmy,
+                    cx - mx - Cmy, cy - my + Cmx,
+                    cx - mx,       cy - my);
+    }
+
+    // Return the intersection point of the lines (x0, y0) -> (x1, y1)
+    // and (x0p, y0p) -> (x1p, y1p) in m[off] and m[off+1]
+    private static void computeMiter(final double x0, final double y0,
+                                     final double x1, final double y1,
+                                     final double x0p, final double y0p,
+                                     final double x1p, final double y1p,
+                                     final double[] m)
+    {
+        double x10 = x1 - x0;
+        double y10 = y1 - y0;
+        double x10p = x1p - x0p;
+        double y10p = y1p - y0p;
+
+        // if this is 0, the lines are parallel. If they go in the
+        // same direction, there is no intersection so m[off] and
+        // m[off+1] will contain infinity, so no miter will be drawn.
+        // If they go in the same direction that means that the start of the
+        // current segment and the end of the previous segment have the same
+        // tangent, in which case this method won't even be involved in
+        // miter drawing because it won't be called by drawMiter (because
+        // (mx == omx && my == omy) will be true, and drawMiter will return
+        // immediately).
+        double den = x10*y10p - x10p*y10;
+        double t = x10p*(y0-y0p) - y10p*(x0-x0p);
+        t /= den;
+        m[0] = x0 + t*x10;
+        m[1] = y0 + t*y10;
+    }
+
+    // Return the intersection point of the lines (x0, y0) -> (x1, y1)
+    // and (x0p, y0p) -> (x1p, y1p) in m[off] and m[off+1]
+    private static void safeComputeMiter(final double x0, final double y0,
+                                         final double x1, final double y1,
+                                         final double x0p, final double y0p,
+                                         final double x1p, final double y1p,
+                                         final double[] m)
+    {
+        double x10 = x1 - x0;
+        double y10 = y1 - y0;
+        double x10p = x1p - x0p;
+        double y10p = y1p - y0p;
+
+        // if this is 0, the lines are parallel. If they go in the
+        // same direction, there is no intersection so m[off] and
+        // m[off+1] will contain infinity, so no miter will be drawn.
+        // If they go in the same direction that means that the start of the
+        // current segment and the end of the previous segment have the same
+        // tangent, in which case this method won't even be involved in
+        // miter drawing because it won't be called by drawMiter (because
+        // (mx == omx && my == omy) will be true, and drawMiter will return
+        // immediately).
+        double den = x10*y10p - x10p*y10;
+        if (den == 0.0d) {
+            m[2] = (x0 + x0p) / 2.0d;
+            m[3] = (y0 + y0p) / 2.0d;
+        } else {
+            double t = x10p*(y0-y0p) - y10p*(x0-x0p);
+            t /= den;
+            m[2] = x0 + t*x10;
+            m[3] = y0 + t*y10;
+        }
+    }
+
+    private void drawMiter(final double pdx, final double pdy,
+                           final double x0, final double y0,
+                           final double dx, final double dy,
+                           double omx, double omy,
+                           double mx, double my,
+                           boolean rev)
+    {
+        if ((mx == omx && my == omy) ||
+            (pdx == 0.0d && pdy == 0.0d) ||
+            (dx == 0.0d && dy == 0.0d))
+        {
+            return;
+        }
+
+        if (rev) {
+            omx = -omx;
+            omy = -omy;
+            mx  = -mx;
+            my  = -my;
+        }
+
+        computeMiter((x0 - pdx) + omx, (y0 - pdy) + omy, x0 + omx, y0 + omy,
+                     (dx + x0) + mx, (dy + y0) + my, x0 + mx, y0 + my, miter);
+
+        final double miterX = miter[0];
+        final double miterY = miter[1];
+        double lenSq = (miterX-x0)*(miterX-x0) + (miterY-y0)*(miterY-y0);
+
+        // If the lines are parallel, lenSq will be either NaN or +inf
+        // (actually, I'm not sure if the latter is possible. The important
+        // thing is that -inf is not possible, because lenSq is a square).
+        // For both of those values, the comparison below will fail and
+        // no miter will be drawn, which is correct.
+        if (lenSq < miterLimitSq) {
+            emitLineTo(miterX, miterY, rev);
+        }
+    }
+
+    @Override
+    public void moveTo(final double x0, final double y0) {
+        _moveTo(x0, y0, cOutCode);
+        // update starting point:
+        this.sx0 = x0;
+        this.sy0 = y0;
+        this.sdx = 1.0d;
+        this.sdy = 0.0d;
+        this.opened   = false;
+        this.capStart = false;
+
+        if (clipRect != null) {
+            final int outcode = DHelpers.outcode(x0, y0, clipRect);
+            this.cOutCode = outcode;
+            this.sOutCode = outcode;
+        }
+    }
+
+    private void _moveTo(final double x0, final double y0,
+                        final int outcode)
+    {
+        if (prev == MOVE_TO) {
+            this.cx0 = x0;
+            this.cy0 = y0;
+        } else {
+            if (prev == DRAWING_OP_TO) {
+                finish(outcode);
+            }
+            this.prev = MOVE_TO;
+            this.cx0 = x0;
+            this.cy0 = y0;
+            this.cdx = 1.0d;
+            this.cdy = 0.0d;
+        }
+    }
+
+    @Override
+    public void lineTo(final double x1, final double y1) {
+        lineTo(x1, y1, false);
+    }
+
+    private void lineTo(final double x1, final double y1,
+                        final boolean force)
+    {
+        final int outcode0 = this.cOutCode;
+
+        if (!force && clipRect != null) {
+            final int outcode1 = DHelpers.outcode(x1, y1, clipRect);
+
+            // Should clip
+            final int orCode = (outcode0 | outcode1);
+            if (orCode != 0) {
+                final int sideCode = outcode0 & outcode1;
+
+                // basic rejection criteria:
+                if (sideCode == 0) {
+                    // ovelap clip:
+                    if (subdivide) {
+                        // avoid reentrance
+                        subdivide = false;
+                        // subdivide curve => callback with subdivided parts:
+                        boolean ret = curveSplitter.splitLine(cx0, cy0, x1, y1,
+                                                              orCode, this);
+                        // reentrance is done:
+                        subdivide = true;
+                        if (ret) {
+                            return;
+                        }
+                    }
+                    // already subdivided so render it
+                } else {
+                    this.cOutCode = outcode1;
+                    _moveTo(x1, y1, outcode0);
+                    opened = true;
+                    return;
+                }
+            }
+
+            this.cOutCode = outcode1;
+        }
+
+        double dx = x1 - cx0;
+        double dy = y1 - cy0;
+        if (dx == 0.0d && dy == 0.0d) {
+            dx = 1.0d;
+        }
+        computeOffset(dx, dy, lineWidth2, offset0);
+        final double mx = offset0[0];
+        final double my = offset0[1];
+
+        drawJoin(cdx, cdy, cx0, cy0, dx, dy, cmx, cmy, mx, my, outcode0);
+
+        emitLineTo(cx0 + mx, cy0 + my);
+        emitLineTo( x1 + mx,  y1 + my);
+
+        emitLineToRev(cx0 - mx, cy0 - my);
+        emitLineToRev( x1 - mx,  y1 - my);
+
+        this.prev = DRAWING_OP_TO;
+        this.cx0 = x1;
+        this.cy0 = y1;
+        this.cdx = dx;
+        this.cdy = dy;
+        this.cmx = mx;
+        this.cmy = my;
+    }
+
+    @Override
+    public void closePath() {
+        // distinguish empty path at all vs opened path ?
+        if (prev != DRAWING_OP_TO && !opened) {
+            if (prev == CLOSE) {
+                return;
+            }
+            emitMoveTo(cx0, cy0 - lineWidth2);
+
+            this.sdx = 1.0d;
+            this.sdy = 0.0d;
+            this.cdx = 1.0d;
+            this.cdy = 0.0d;
+
+            this.smx = 0.0d;
+            this.smy = -lineWidth2;
+            this.cmx = 0.0d;
+            this.cmy = -lineWidth2;
+
+            finish(cOutCode);
+            return;
+        }
+
+        // basic acceptance criteria
+        if ((sOutCode & cOutCode) == 0) {
+            if (cx0 != sx0 || cy0 != sy0) {
+                lineTo(sx0, sy0, true);
+            }
+
+            drawJoin(cdx, cdy, cx0, cy0, sdx, sdy, cmx, cmy, smx, smy, sOutCode);
+
+            emitLineTo(sx0 + smx, sy0 + smy);
+
+            if (opened) {
+                emitLineTo(sx0 - smx, sy0 - smy);
+            } else {
+                emitMoveTo(sx0 - smx, sy0 - smy);
+            }
+        }
+        // Ignore caps like finish(false)
+        emitReverse();
+
+        this.prev = CLOSE;
+
+        if (opened) {
+            // do not emit close
+            opened = false;
+        } else {
+            emitClose();
+        }
+    }
+
+    private void emitReverse() {
+        reverse.popAll(out);
+    }
+
+    @Override
+    public void pathDone() {
+        if (prev == DRAWING_OP_TO) {
+            finish(cOutCode);
+        }
+
+        out.pathDone();
+
+        // this shouldn't matter since this object won't be used
+        // after the call to this method.
+        this.prev = CLOSE;
+
+        // Dispose this instance:
+        dispose();
+    }
+
+    private void finish(final int outcode) {
+        // Problem: impossible to guess if the path will be closed in advance
+        //          i.e. if caps must be drawn or not ?
+        // Solution: use the ClosedPathDetector before Stroker to determine
+        // if the path is a closed path or not
+        if (!rdrCtx.closedPath) {
+            if (outcode == 0) {
+                // current point = end's cap:
+                if (capStyle == CAP_ROUND) {
+                    drawRoundCap(cx0, cy0, cmx, cmy);
+                } else if (capStyle == CAP_SQUARE) {
+                    emitLineTo(cx0 - cmy + cmx, cy0 + cmx + cmy);
+                    emitLineTo(cx0 - cmy - cmx, cy0 + cmx - cmy);
+                }
+            }
+            emitReverse();
+
+            if (!capStart) {
+                capStart = true;
+
+                if (sOutCode == 0) {
+                    // starting point = initial cap:
+                    if (capStyle == CAP_ROUND) {
+                        drawRoundCap(sx0, sy0, -smx, -smy);
+                    } else if (capStyle == CAP_SQUARE) {
+                        emitLineTo(sx0 + smy - smx, sy0 - smx - smy);
+                        emitLineTo(sx0 + smy + smx, sy0 - smx + smy);
+                    }
+                }
+            }
+        } else {
+            emitReverse();
+        }
+        emitClose();
+    }
+
+    private void emitMoveTo(final double x0, final double y0) {
+        out.moveTo(x0, y0);
+    }
+
+    private void emitLineTo(final double x1, final double y1) {
+        out.lineTo(x1, y1);
+    }
+
+    private void emitLineToRev(final double x1, final double y1) {
+        reverse.pushLine(x1, y1);
+    }
+
+    private void emitLineTo(final double x1, final double y1,
+                            final boolean rev)
+    {
+        if (rev) {
+            emitLineToRev(x1, y1);
+        } else {
+            emitLineTo(x1, y1);
+        }
+    }
+
+    private void emitQuadTo(final double x1, final double y1,
+                            final double x2, final double y2)
+    {
+        out.quadTo(x1, y1, x2, y2);
+    }
+
+    private void emitQuadToRev(final double x0, final double y0,
+                               final double x1, final double y1)
+    {
+        reverse.pushQuad(x0, y0, x1, y1);
+    }
+
+    private void emitCurveTo(final double x1, final double y1,
+                             final double x2, final double y2,
+                             final double x3, final double y3)
+    {
+        out.curveTo(x1, y1, x2, y2, x3, y3);
+    }
+
+    private void emitCurveToRev(final double x0, final double y0,
+                                final double x1, final double y1,
+                                final double x2, final double y2)
+    {
+        reverse.pushCubic(x0, y0, x1, y1, x2, y2);
+    }
+
+    private void emitCurveTo(final double x0, final double y0,
+                             final double x1, final double y1,
+                             final double x2, final double y2,
+                             final double x3, final double y3, final boolean rev)
+    {
+        if (rev) {
+            reverse.pushCubic(x0, y0, x1, y1, x2, y2);
+        } else {
+            out.curveTo(x1, y1, x2, y2, x3, y3);
+        }
+    }
+
+    private void emitClose() {
+        out.closePath();
+    }
+
+    private void drawJoin(double pdx, double pdy,
+                          double x0, double y0,
+                          double dx, double dy,
+                          double omx, double omy,
+                          double mx, double my,
+                          final int outcode)
+    {
+        if (prev != DRAWING_OP_TO) {
+            emitMoveTo(x0 + mx, y0 + my);
+            if (!opened) {
+                this.sdx = dx;
+                this.sdy = dy;
+                this.smx = mx;
+                this.smy = my;
+            }
+        } else {
+            final boolean cw = isCW(pdx, pdy, dx, dy);
+            if (outcode == 0) {
+                if (joinStyle == JOIN_MITER) {
+                    drawMiter(pdx, pdy, x0, y0, dx, dy, omx, omy, mx, my, cw);
+                } else if (joinStyle == JOIN_ROUND) {
+                    mayDrawRoundJoin(x0, y0, omx, omy, mx, my, cw);
+                }
+            }
+            emitLineTo(x0, y0, !cw);
+        }
+        prev = DRAWING_OP_TO;
+    }
+
+    private static boolean within(final double x1, final double y1,
+                                  final double x2, final double y2,
+                                  final double err)
+    {
+        assert err > 0 : "";
+        // compare taxicab distance. ERR will always be small, so using
+        // true distance won't give much benefit
+        return (DHelpers.within(x1, x2, err) && // we want to avoid calling Math.abs
+                DHelpers.within(y1, y2, err));  // this is just as good.
+    }
+
+    private void getLineOffsets(final double x1, final double y1,
+                                final double x2, final double y2,
+                                final double[] left, final double[] right)
+    {
+        computeOffset(x2 - x1, y2 - y1, lineWidth2, offset0);
+        final double mx = offset0[0];
+        final double my = offset0[1];
+        left[0] = x1 + mx;
+        left[1] = y1 + my;
+        left[2] = x2 + mx;
+        left[3] = y2 + my;
+
+        right[0] = x1 - mx;
+        right[1] = y1 - my;
+        right[2] = x2 - mx;
+        right[3] = y2 - my;
+    }
+
+    private int computeOffsetCubic(final double[] pts, final int off,
+                                   final double[] leftOff,
+                                   final double[] rightOff)
+    {
+        // if p1=p2 or p3=p4 it means that the derivative at the endpoint
+        // vanishes, which creates problems with computeOffset. Usually
+        // this happens when this stroker object is trying to widen
+        // a curve with a cusp. What happens is that curveTo splits
+        // the input curve at the cusp, and passes it to this function.
+        // because of inaccuracies in the splitting, we consider points
+        // equal if they're very close to each other.
+        final double x1 = pts[off    ], y1 = pts[off + 1];
+        final double x2 = pts[off + 2], y2 = pts[off + 3];
+        final double x3 = pts[off + 4], y3 = pts[off + 5];
+        final double x4 = pts[off + 6], y4 = pts[off + 7];
+
+        double dx4 = x4 - x3;
+        double dy4 = y4 - y3;
+        double dx1 = x2 - x1;
+        double dy1 = y2 - y1;
+
+        // if p1 == p2 && p3 == p4: draw line from p1->p4, unless p1 == p4,
+        // in which case ignore if p1 == p2
+        final boolean p1eqp2 = within(x1, y1, x2, y2, 6.0d * Math.ulp(y2));
+        final boolean p3eqp4 = within(x3, y3, x4, y4, 6.0d * Math.ulp(y4));
+
+        if (p1eqp2 && p3eqp4) {
+            getLineOffsets(x1, y1, x4, y4, leftOff, rightOff);
+            return 4;
+        } else if (p1eqp2) {
+            dx1 = x3 - x1;
+            dy1 = y3 - y1;
+        } else if (p3eqp4) {
+            dx4 = x4 - x2;
+            dy4 = y4 - y2;
+        }
+
+        // if p2-p1 and p4-p3 are parallel, that must mean this curve is a line
+        double dotsq = (dx1 * dx4 + dy1 * dy4);
+        dotsq *= dotsq;
+        double l1sq = dx1 * dx1 + dy1 * dy1, l4sq = dx4 * dx4 + dy4 * dy4;
+
+        if (DHelpers.within(dotsq, l1sq * l4sq, 4.0d * Math.ulp(dotsq))) {
+            getLineOffsets(x1, y1, x4, y4, leftOff, rightOff);
+            return 4;
+        }
+
+//      What we're trying to do in this function is to approximate an ideal
+//      offset curve (call it I) of the input curve B using a bezier curve Bp.
+//      The constraints I use to get the equations are:
+//
+//      1. The computed curve Bp should go through I(0) and I(1). These are
+//      x1p, y1p, x4p, y4p, which are p1p and p4p. We still need to find
+//      4 variables: the x and y components of p2p and p3p (i.e. x2p, y2p, x3p, y3p).
+//
+//      2. Bp should have slope equal in absolute value to I at the endpoints. So,
+//      (by the way, the operator || in the comments below means "aligned with".
+//      It is defined on vectors, so when we say I'(0) || Bp'(0) we mean that
+//      vectors I'(0) and Bp'(0) are aligned, which is the same as saying
+//      that the tangent lines of I and Bp at 0 are parallel. Mathematically
+//      this means (I'(t) || Bp'(t)) <==> (I'(t) = c * Bp'(t)) where c is some
+//      nonzero constant.)
+//      I'(0) || Bp'(0) and I'(1) || Bp'(1). Obviously, I'(0) || B'(0) and
+//      I'(1) || B'(1); therefore, Bp'(0) || B'(0) and Bp'(1) || B'(1).
+//      We know that Bp'(0) || (p2p-p1p) and Bp'(1) || (p4p-p3p) and the same
+//      is true for any bezier curve; therefore, we get the equations
+//          (1) p2p = c1 * (p2-p1) + p1p
+//          (2) p3p = c2 * (p4-p3) + p4p
+//      We know p1p, p4p, p2, p1, p3, and p4; therefore, this reduces the number
+//      of unknowns from 4 to 2 (i.e. just c1 and c2).
+//      To eliminate these 2 unknowns we use the following constraint:
+//
+//      3. Bp(0.5) == I(0.5). Bp(0.5)=(x,y) and I(0.5)=(xi,yi), and I should note
+//      that I(0.5) is *the only* reason for computing dxm,dym. This gives us
+//          (3) Bp(0.5) = (p1p + 3 * (p2p + p3p) + p4p)/8, which is equivalent to
+//          (4) p2p + p3p = (Bp(0.5)*8 - p1p - p4p) / 3
+//      We can substitute (1) and (2) from above into (4) and we get:
+//          (5) c1*(p2-p1) + c2*(p4-p3) = (Bp(0.5)*8 - p1p - p4p)/3 - p1p - p4p
+//      which is equivalent to
+//          (6) c1*(p2-p1) + c2*(p4-p3) = (4/3) * (Bp(0.5) * 2 - p1p - p4p)
+//
+//      The right side of this is a 2D vector, and we know I(0.5), which gives us
+//      Bp(0.5), which gives us the value of the right side.
+//      The left side is just a matrix vector multiplication in disguise. It is
+//
+//      [x2-x1, x4-x3][c1]
+//      [y2-y1, y4-y3][c2]
+//      which, is equal to
+//      [dx1, dx4][c1]
+//      [dy1, dy4][c2]
+//      At this point we are left with a simple linear system and we solve it by
+//      getting the inverse of the matrix above. Then we use [c1,c2] to compute
+//      p2p and p3p.
+
+        double x = (x1 + 3.0d * (x2 + x3) + x4) / 8.0d;
+        double y = (y1 + 3.0d * (y2 + y3) + y4) / 8.0d;
+        // (dxm,dym) is some tangent of B at t=0.5. This means it's equal to
+        // c*B'(0.5) for some constant c.
+        double dxm = x3 + x4 - x1 - x2, dym = y3 + y4 - y1 - y2;
+
+        // this computes the offsets at t=0, 0.5, 1, using the property that
+        // for any bezier curve the vectors p2-p1 and p4-p3 are parallel to
+        // the (dx/dt, dy/dt) vectors at the endpoints.
+        computeOffset(dx1, dy1, lineWidth2, offset0);
+        computeOffset(dxm, dym, lineWidth2, offset1);
+        computeOffset(dx4, dy4, lineWidth2, offset2);
+        double x1p = x1 + offset0[0]; // start
+        double y1p = y1 + offset0[1]; // point
+        double xi  = x  + offset1[0]; // interpolation
+        double yi  = y  + offset1[1]; // point
+        double x4p = x4 + offset2[0]; // end
+        double y4p = y4 + offset2[1]; // point
+
+        double invdet43 = 4.0d / (3.0d * (dx1 * dy4 - dy1 * dx4));
+
+        double two_pi_m_p1_m_p4x = 2.0d * xi - x1p - x4p;
+        double two_pi_m_p1_m_p4y = 2.0d * yi - y1p - y4p;
+        double c1 = invdet43 * (dy4 * two_pi_m_p1_m_p4x - dx4 * two_pi_m_p1_m_p4y);
+        double c2 = invdet43 * (dx1 * two_pi_m_p1_m_p4y - dy1 * two_pi_m_p1_m_p4x);
+
+        double x2p, y2p, x3p, y3p;
+        x2p = x1p + c1*dx1;
+        y2p = y1p + c1*dy1;
+        x3p = x4p + c2*dx4;
+        y3p = y4p + c2*dy4;
+
+        leftOff[0] = x1p; leftOff[1] = y1p;
+        leftOff[2] = x2p; leftOff[3] = y2p;
+        leftOff[4] = x3p; leftOff[5] = y3p;
+        leftOff[6] = x4p; leftOff[7] = y4p;
+
+        x1p = x1 - offset0[0]; y1p = y1 - offset0[1];
+        xi = xi - 2.0d * offset1[0]; yi = yi - 2.0d * offset1[1];
+        x4p = x4 - offset2[0]; y4p = y4 - offset2[1];
+
+        two_pi_m_p1_m_p4x = 2.0d * xi - x1p - x4p;
+        two_pi_m_p1_m_p4y = 2.0d * yi - y1p - y4p;
+        c1 = invdet43 * (dy4 * two_pi_m_p1_m_p4x - dx4 * two_pi_m_p1_m_p4y);
+        c2 = invdet43 * (dx1 * two_pi_m_p1_m_p4y - dy1 * two_pi_m_p1_m_p4x);
+
+        x2p = x1p + c1*dx1;
+        y2p = y1p + c1*dy1;
+        x3p = x4p + c2*dx4;
+        y3p = y4p + c2*dy4;
+
+        rightOff[0] = x1p; rightOff[1] = y1p;
+        rightOff[2] = x2p; rightOff[3] = y2p;
+        rightOff[4] = x3p; rightOff[5] = y3p;
+        rightOff[6] = x4p; rightOff[7] = y4p;
+        return 8;
+    }
+
+    // compute offset curves using bezier spline through t=0.5 (i.e.
+    // ComputedCurve(0.5) == IdealParallelCurve(0.5))
+    // return the kind of curve in the right and left arrays.
+    private int computeOffsetQuad(final double[] pts, final int off,
+                                  final double[] leftOff,
+                                  final double[] rightOff)
+    {
+        final double x1 = pts[off    ], y1 = pts[off + 1];
+        final double x2 = pts[off + 2], y2 = pts[off + 3];
+        final double x3 = pts[off + 4], y3 = pts[off + 5];
+
+        final double dx3 = x3 - x2;
+        final double dy3 = y3 - y2;
+        final double dx1 = x2 - x1;
+        final double dy1 = y2 - y1;
+
+        // if p1=p2 or p3=p4 it means that the derivative at the endpoint
+        // vanishes, which creates problems with computeOffset. Usually
+        // this happens when this stroker object is trying to widen
+        // a curve with a cusp. What happens is that curveTo splits
+        // the input curve at the cusp, and passes it to this function.
+        // because of inaccuracies in the splitting, we consider points
+        // equal if they're very close to each other.
+
+        // if p1 == p2 && p3 == p4: draw line from p1->p4, unless p1 == p4,
+        // in which case ignore.
+        final boolean p1eqp2 = within(x1, y1, x2, y2, 6.0d * Math.ulp(y2));
+        final boolean p2eqp3 = within(x2, y2, x3, y3, 6.0d * Math.ulp(y3));
+
+        if (p1eqp2 || p2eqp3) {
+            getLineOffsets(x1, y1, x3, y3, leftOff, rightOff);
+            return 4;
+        }
+
+        // if p2-p1 and p4-p3 are parallel, that must mean this curve is a line
+        double dotsq = (dx1 * dx3 + dy1 * dy3);
+        dotsq *= dotsq;
+        double l1sq = dx1 * dx1 + dy1 * dy1, l3sq = dx3 * dx3 + dy3 * dy3;
+
+        if (DHelpers.within(dotsq, l1sq * l3sq, 4.0d * Math.ulp(dotsq))) {
+            getLineOffsets(x1, y1, x3, y3, leftOff, rightOff);
+            return 4;
+        }
+
+        // this computes the offsets at t=0, 0.5, 1, using the property that
+        // for any bezier curve the vectors p2-p1 and p4-p3 are parallel to
+        // the (dx/dt, dy/dt) vectors at the endpoints.
+        computeOffset(dx1, dy1, lineWidth2, offset0);
+        computeOffset(dx3, dy3, lineWidth2, offset1);
+
+        double x1p = x1 + offset0[0]; // start
+        double y1p = y1 + offset0[1]; // point
+        double x3p = x3 + offset1[0]; // end
+        double y3p = y3 + offset1[1]; // point
+        safeComputeMiter(x1p, y1p, x1p+dx1, y1p+dy1, x3p, y3p, x3p-dx3, y3p-dy3, leftOff);
+        leftOff[0] = x1p; leftOff[1] = y1p;
+        leftOff[4] = x3p; leftOff[5] = y3p;
+
+        x1p = x1 - offset0[0]; y1p = y1 - offset0[1];
+        x3p = x3 - offset1[0]; y3p = y3 - offset1[1];
+        safeComputeMiter(x1p, y1p, x1p+dx1, y1p+dy1, x3p, y3p, x3p-dx3, y3p-dy3, rightOff);
+        rightOff[0] = x1p; rightOff[1] = y1p;
+        rightOff[4] = x3p; rightOff[5] = y3p;
+        return 6;
+    }
+
+    @Override
+    public void curveTo(final double x1, final double y1,
+                        final double x2, final double y2,
+                        final double x3, final double y3)
+    {
+        final int outcode0 = this.cOutCode;
+
+        if (clipRect != null) {
+            final int outcode1 = DHelpers.outcode(x1, y1, clipRect);
+            final int outcode2 = DHelpers.outcode(x2, y2, clipRect);
+            final int outcode3 = DHelpers.outcode(x3, y3, clipRect);
+
+            // Should clip
+            final int orCode = (outcode0 | outcode1 | outcode2 | outcode3);
+            if (orCode != 0) {
+                final int sideCode = outcode0 & outcode1 & outcode2 & outcode3;
+
+                // basic rejection criteria:
+                if (sideCode == 0) {
+                    // ovelap clip:
+                    if (subdivide) {
+                        // avoid reentrance
+                        subdivide = false;
+                        // subdivide curve => callback with subdivided parts:
+                        boolean ret = curveSplitter.splitCurve(cx0, cy0, x1, y1,
+                                                               x2, y2, x3, y3,
+                                                               orCode, this);
+                        // reentrance is done:
+                        subdivide = true;
+                        if (ret) {
+                            return;
+                        }
+                    }
+                    // already subdivided so render it
+                } else {
+                    this.cOutCode = outcode3;
+                    _moveTo(x3, y3, outcode0);
+                    opened = true;
+                    return;
+                }
+            }
+
+            this.cOutCode = outcode3;
+        }
+        _curveTo(x1, y1, x2, y2, x3, y3, outcode0);
+    }
+
+    private void _curveTo(final double x1, final double y1,
+                          final double x2, final double y2,
+                          final double x3, final double y3,
+                          final int outcode0)
+    {
+        // need these so we can update the state at the end of this method
+        double dxs = x1 - cx0;
+        double dys = y1 - cy0;
+        double dxf = x3 - x2;
+        double dyf = y3 - y2;
+
+        if ((dxs == 0.0d) && (dys == 0.0d)) {
+            dxs = x2 - cx0;
+            dys = y2 - cy0;
+            if ((dxs == 0.0d) && (dys == 0.0d)) {
+                dxs = x3 - cx0;
+                dys = y3 - cy0;
+            }
+        }
+        if ((dxf == 0.0d) && (dyf == 0.0d)) {
+            dxf = x3 - x1;
+            dyf = y3 - y1;
+            if ((dxf == 0.0d) && (dyf == 0.0d)) {
+                dxf = x3 - cx0;
+                dyf = y3 - cy0;
+            }
+        }
+        if ((dxs == 0.0d) && (dys == 0.0d)) {
+            // this happens if the "curve" is just a point
+            // fix outcode0 for lineTo() call:
+            if (clipRect != null) {
+                this.cOutCode = outcode0;
+            }
+            lineTo(cx0, cy0);
+            return;
+        }
+
+        // if these vectors are too small, normalize them, to avoid future
+        // precision problems.
+        if (Math.abs(dxs) < 0.1d && Math.abs(dys) < 0.1d) {
+            final double len = Math.sqrt(dxs * dxs + dys * dys);
+            dxs /= len;
+            dys /= len;
+        }
+        if (Math.abs(dxf) < 0.1d && Math.abs(dyf) < 0.1d) {
+            final double len = Math.sqrt(dxf * dxf + dyf * dyf);
+            dxf /= len;
+            dyf /= len;
+        }
+
+        computeOffset(dxs, dys, lineWidth2, offset0);
+        drawJoin(cdx, cdy, cx0, cy0, dxs, dys, cmx, cmy, offset0[0], offset0[1], outcode0);
+
+        int nSplits = 0;
+        final double[] mid;
+        final double[] l = lp;
+
+        if (monotonize) {
+            // monotonize curve:
+            final CurveBasicMonotonizer monotonizer
+                = rdrCtx.monotonizer.curve(cx0, cy0, x1, y1, x2, y2, x3, y3);
+
+            nSplits = monotonizer.nbSplits;
+            mid = monotonizer.middle;
+        } else {
+            // use left instead:
+            mid = l;
+            mid[0] = cx0; mid[1] = cy0;
+            mid[2] = x1;  mid[3] = y1;
+            mid[4] = x2;  mid[5] = y2;
+            mid[6] = x3;  mid[7] = y3;
+        }
+        final double[] r = rp;
+
+        int kind = 0;
+        for (int i = 0, off = 0; i <= nSplits; i++, off += 6) {
+            kind = computeOffsetCubic(mid, off, l, r);
+
+            emitLineTo(l[0], l[1]);
+
+            switch(kind) {
+            case 8:
+                emitCurveTo(l[2], l[3], l[4], l[5], l[6], l[7]);
+                emitCurveToRev(r[0], r[1], r[2], r[3], r[4], r[5]);
+                break;
+            case 4:
+                emitLineTo(l[2], l[3]);
+                emitLineToRev(r[0], r[1]);
+                break;
+            default:
+            }
+            emitLineToRev(r[kind - 2], r[kind - 1]);
+        }
+
+        this.prev = DRAWING_OP_TO;
+        this.cx0 = x3;
+        this.cy0 = y3;
+        this.cdx = dxf;
+        this.cdy = dyf;
+        this.cmx = (l[kind - 2] - r[kind - 2]) / 2.0d;
+        this.cmy = (l[kind - 1] - r[kind - 1]) / 2.0d;
+    }
+
+    @Override
+    public void quadTo(final double x1, final double y1,
+                       final double x2, final double y2)
+    {
+        final int outcode0 = this.cOutCode;
+
+        if (clipRect != null) {
+            final int outcode1 = DHelpers.outcode(x1, y1, clipRect);
+            final int outcode2 = DHelpers.outcode(x2, y2, clipRect);
+
+            // Should clip
+            final int orCode = (outcode0 | outcode1 | outcode2);
+            if (orCode != 0) {
+                final int sideCode = outcode0 & outcode1 & outcode2;
+
+                // basic rejection criteria:
+                if (sideCode == 0) {
+                    // ovelap clip:
+                    if (subdivide) {
+                        // avoid reentrance
+                        subdivide = false;
+                        // subdivide curve => call lineTo() with subdivided curves:
+                        boolean ret = curveSplitter.splitQuad(cx0, cy0, x1, y1,
+                                                              x2, y2, orCode, this);
+                        // reentrance is done:
+                        subdivide = true;
+                        if (ret) {
+                            return;
+                        }
+                    }
+                    // already subdivided so render it
+                } else {
+                    this.cOutCode = outcode2;
+                    _moveTo(x2, y2, outcode0);
+                    opened = true;
+                    return;
+                }
+            }
+
+            this.cOutCode = outcode2;
+        }
+        _quadTo(x1, y1, x2, y2, outcode0);
+    }
+
+    private void _quadTo(final double x1, final double y1,
+                         final double x2, final double y2,
+                         final int outcode0)
+    {
+        // need these so we can update the state at the end of this method
+        double dxs = x1 - cx0;
+        double dys = y1 - cy0;
+        double dxf = x2 - x1;
+        double dyf = y2 - y1;
+
+        if (((dxs == 0.0d) && (dys == 0.0d)) || ((dxf == 0.0d) && (dyf == 0.0d))) {
+            dxs = dxf = x2 - cx0;
+            dys = dyf = y2 - cy0;
+        }
+        if ((dxs == 0.0d) && (dys == 0.0d)) {
+            // this happens if the "curve" is just a point
+            // fix outcode0 for lineTo() call:
+            if (clipRect != null) {
+                this.cOutCode = outcode0;
+            }
+            lineTo(cx0, cy0);
+            return;
+        }
+        // if these vectors are too small, normalize them, to avoid future
+        // precision problems.
+        if (Math.abs(dxs) < 0.1d && Math.abs(dys) < 0.1d) {
+            final double len = Math.sqrt(dxs * dxs + dys * dys);
+            dxs /= len;
+            dys /= len;
+        }
+        if (Math.abs(dxf) < 0.1d && Math.abs(dyf) < 0.1d) {
+            final double len = Math.sqrt(dxf * dxf + dyf * dyf);
+            dxf /= len;
+            dyf /= len;
+        }
+        computeOffset(dxs, dys, lineWidth2, offset0);
+        drawJoin(cdx, cdy, cx0, cy0, dxs, dys, cmx, cmy, offset0[0], offset0[1], outcode0);
+
+        int nSplits = 0;
+        final double[] mid;
+        final double[] l = lp;
+
+        if (monotonize) {
+            // monotonize quad:
+            final CurveBasicMonotonizer monotonizer
+                = rdrCtx.monotonizer.quad(cx0, cy0, x1, y1, x2, y2);
+
+            nSplits = monotonizer.nbSplits;
+            mid = monotonizer.middle;
+        } else {
+            // use left instead:
+            mid = l;
+            mid[0] = cx0; mid[1] = cy0;
+            mid[2] = x1;  mid[3] = y1;
+            mid[4] = x2;  mid[5] = y2;
+        }
+        final double[] r = rp;
+
+        int kind = 0;
+        for (int i = 0, off = 0; i <= nSplits; i++, off += 4) {
+            kind = computeOffsetQuad(mid, off, l, r);
+
+            emitLineTo(l[0], l[1]);
+
+            switch(kind) {
+            case 6:
+                emitQuadTo(l[2], l[3], l[4], l[5]);
+                emitQuadToRev(r[0], r[1], r[2], r[3]);
+                break;
+            case 4:
+                emitLineTo(l[2], l[3]);
+                emitLineToRev(r[0], r[1]);
+                break;
+            default:
+            }
+            emitLineToRev(r[kind - 2], r[kind - 1]);
+        }
+
+        this.prev = DRAWING_OP_TO;
+        this.cx0 = x2;
+        this.cy0 = y2;
+        this.cdx = dxf;
+        this.cdy = dyf;
+        this.cmx = (l[kind - 2] - r[kind - 2]) / 2.0d;
+        this.cmy = (l[kind - 1] - r[kind - 1]) / 2.0d;
+    }
+
+    @Override public long getNativeConsumer() {
+        throw new InternalError("Stroker doesn't use a native consumer");
+    }
+}
diff --git a/src/share/classes/sun/java2d/marlin/DTransformingPathConsumer2D.java b/src/share/classes/sun/java2d/marlin/DTransformingPathConsumer2D.java
new file mode 100644
index 0000000..ae60c03
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/DTransformingPathConsumer2D.java
@@ -0,0 +1,1178 @@
+/*
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d.marlin;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Path2D;
+import java.util.Arrays;
+import sun.java2d.marlin.DHelpers.IndexStack;
+import sun.java2d.marlin.DHelpers.PolyStack;
+
+final class DTransformingPathConsumer2D {
+
+    // smaller uncertainty in double variant
+    static final double CLIP_RECT_PADDING = 0.25d;
+
+    private final DRendererContext rdrCtx;
+
+    // recycled ClosedPathDetector instance from detectClosedPath()
+    private final ClosedPathDetector   cpDetector;
+
+    // recycled PathClipFilter instance from pathClipper()
+    private final PathClipFilter       pathClipper;
+
+    // recycled DPathConsumer2D instance from wrapPath2D()
+    private final Path2DWrapper        wp_Path2DWrapper        = new Path2DWrapper();
+
+    // recycled DPathConsumer2D instances from deltaTransformConsumer()
+    private final DeltaScaleFilter     dt_DeltaScaleFilter     = new DeltaScaleFilter();
+    private final DeltaTransformFilter dt_DeltaTransformFilter = new DeltaTransformFilter();
+
+    // recycled DPathConsumer2D instances from inverseDeltaTransformConsumer()
+    private final DeltaScaleFilter     iv_DeltaScaleFilter     = new DeltaScaleFilter();
+    private final DeltaTransformFilter iv_DeltaTransformFilter = new DeltaTransformFilter();
+
+    // recycled PathTracer instances from tracer...() methods
+    private final PathTracer tracerInput      = new PathTracer("[Input]");
+    private final PathTracer tracerCPDetector = new PathTracer("ClosedPathDetector");
+    private final PathTracer tracerFiller     = new PathTracer("Filler");
+    private final PathTracer tracerStroker    = new PathTracer("Stroker");
+    private final PathTracer tracerDasher     = new PathTracer("Dasher");
+
+    DTransformingPathConsumer2D(final DRendererContext rdrCtx) {
+        // used by RendererContext
+        this.rdrCtx = rdrCtx;
+        this.cpDetector = new ClosedPathDetector(rdrCtx);
+        this.pathClipper = new PathClipFilter(rdrCtx);
+    }
+
+    DPathConsumer2D wrapPath2D(Path2D.Double p2d) {
+        return wp_Path2DWrapper.init(p2d);
+    }
+
+    DPathConsumer2D traceInput(DPathConsumer2D out) {
+        return tracerInput.init(out);
+    }
+
+    DPathConsumer2D traceClosedPathDetector(DPathConsumer2D out) {
+        return tracerCPDetector.init(out);
+    }
+
+    DPathConsumer2D traceFiller(DPathConsumer2D out) {
+        return tracerFiller.init(out);
+    }
+
+    DPathConsumer2D traceStroker(DPathConsumer2D out) {
+        return tracerStroker.init(out);
+    }
+
+    DPathConsumer2D traceDasher(DPathConsumer2D out) {
+        return tracerDasher.init(out);
+    }
+
+    DPathConsumer2D detectClosedPath(DPathConsumer2D out) {
+        return cpDetector.init(out);
+    }
+
+    DPathConsumer2D pathClipper(DPathConsumer2D out) {
+        return pathClipper.init(out);
+    }
+
+    DPathConsumer2D deltaTransformConsumer(DPathConsumer2D out,
+                                          AffineTransform at)
+    {
+        if (at == null) {
+            return out;
+        }
+        final double mxx = at.getScaleX();
+        final double mxy = at.getShearX();
+        final double myx = at.getShearY();
+        final double myy = at.getScaleY();
+
+        if (mxy == 0.0d && myx == 0.0d) {
+            if (mxx == 1.0d && myy == 1.0d) {
+                return out;
+            } else {
+                // Scale only
+                if (rdrCtx.doClip) {
+                    // adjust clip rectangle (ymin, ymax, xmin, xmax):
+                    adjustClipScale(rdrCtx.clipRect, mxx, myy);
+                }
+                return dt_DeltaScaleFilter.init(out, mxx, myy);
+            }
+        } else {
+            if (rdrCtx.doClip) {
+                // adjust clip rectangle (ymin, ymax, xmin, xmax):
+                adjustClipInverseDelta(rdrCtx.clipRect, mxx, mxy, myx, myy);
+            }
+            return dt_DeltaTransformFilter.init(out, mxx, mxy, myx, myy);
+        }
+    }
+
+    private static void adjustClipOffset(final double[] clipRect) {
+        clipRect[0] += Renderer.RDR_OFFSET_Y;
+        clipRect[1] += Renderer.RDR_OFFSET_Y;
+        clipRect[2] += Renderer.RDR_OFFSET_X;
+        clipRect[3] += Renderer.RDR_OFFSET_X;
+    }
+
+    private static void adjustClipScale(final double[] clipRect,
+                                        final double mxx, final double myy)
+    {
+        adjustClipOffset(clipRect);
+
+        // Adjust the clipping rectangle (iv_DeltaScaleFilter):
+        clipRect[0] /= myy;
+        clipRect[1] /= myy;
+        clipRect[2] /= mxx;
+        clipRect[3] /= mxx;
+    }
+
+    private static void adjustClipInverseDelta(final double[] clipRect,
+                                               final double mxx, final double mxy,
+                                               final double myx, final double myy)
+    {
+        adjustClipOffset(clipRect);
+
+        // Adjust the clipping rectangle (iv_DeltaTransformFilter):
+        final double det = mxx * myy - mxy * myx;
+        final double imxx =  myy / det;
+        final double imxy = -mxy / det;
+        final double imyx = -myx / det;
+        final double imyy =  mxx / det;
+
+        double xmin, xmax, ymin, ymax;
+        double x, y;
+        // xmin, ymin:
+        x = clipRect[2] * imxx + clipRect[0] * imxy;
+        y = clipRect[2] * imyx + clipRect[0] * imyy;
+
+        xmin = xmax = x;
+        ymin = ymax = y;
+
+        // xmax, ymin:
+        x = clipRect[3] * imxx + clipRect[0] * imxy;
+        y = clipRect[3] * imyx + clipRect[0] * imyy;
+
+        if (x < xmin) { xmin = x; } else if (x > xmax) { xmax = x; }
+        if (y < ymin) { ymin = y; } else if (y > ymax) { ymax = y; }
+
+        // xmin, ymax:
+        x = clipRect[2] * imxx + clipRect[1] * imxy;
+        y = clipRect[2] * imyx + clipRect[1] * imyy;
+
+        if (x < xmin) { xmin = x; } else if (x > xmax) { xmax = x; }
+        if (y < ymin) { ymin = y; } else if (y > ymax) { ymax = y; }
+
+        // xmax, ymax:
+        x = clipRect[3] * imxx + clipRect[1] * imxy;
+        y = clipRect[3] * imyx + clipRect[1] * imyy;
+
+        if (x < xmin) { xmin = x; } else if (x > xmax) { xmax = x; }
+        if (y < ymin) { ymin = y; } else if (y > ymax) { ymax = y; }
+
+        clipRect[0] = ymin;
+        clipRect[1] = ymax;
+        clipRect[2] = xmin;
+        clipRect[3] = xmax;
+    }
+
+    DPathConsumer2D inverseDeltaTransformConsumer(DPathConsumer2D out,
+                                                 AffineTransform at)
+    {
+        if (at == null) {
+            return out;
+        }
+        double mxx = at.getScaleX();
+        double mxy = at.getShearX();
+        double myx = at.getShearY();
+        double myy = at.getScaleY();
+
+        if (mxy == 0.0d && myx == 0.0d) {
+            if (mxx == 1.0d && myy == 1.0d) {
+                return out;
+            } else {
+                return iv_DeltaScaleFilter.init(out, 1.0d/mxx, 1.0d/myy);
+            }
+        } else {
+            final double det = mxx * myy - mxy * myx;
+            return iv_DeltaTransformFilter.init(out,
+                                                myy / det,
+                                               -mxy / det,
+                                               -myx / det,
+                                                mxx / det);
+        }
+    }
+
+    static final class DeltaScaleFilter implements DPathConsumer2D {
+        private DPathConsumer2D out;
+        private double sx, sy;
+
+        DeltaScaleFilter() {}
+
+        DeltaScaleFilter init(DPathConsumer2D out,
+                              double mxx, double myy)
+        {
+            this.out = out;
+            sx = mxx;
+            sy = myy;
+            return this; // fluent API
+        }
+
+        @Override
+        public void moveTo(double x0, double y0) {
+            out.moveTo(x0 * sx, y0 * sy);
+        }
+
+        @Override
+        public void lineTo(double x1, double y1) {
+            out.lineTo(x1 * sx, y1 * sy);
+        }
+
+        @Override
+        public void quadTo(double x1, double y1,
+                           double x2, double y2)
+        {
+            out.quadTo(x1 * sx, y1 * sy,
+                       x2 * sx, y2 * sy);
+        }
+
+        @Override
+        public void curveTo(double x1, double y1,
+                            double x2, double y2,
+                            double x3, double y3)
+        {
+            out.curveTo(x1 * sx, y1 * sy,
+                        x2 * sx, y2 * sy,
+                        x3 * sx, y3 * sy);
+        }
+
+        @Override
+        public void closePath() {
+            out.closePath();
+        }
+
+        @Override
+        public void pathDone() {
+            out.pathDone();
+        }
+
+        @Override
+        public long getNativeConsumer() {
+            return 0;
+        }
+    }
+
+    static final class DeltaTransformFilter implements DPathConsumer2D {
+        private DPathConsumer2D out;
+        private double mxx, mxy, myx, myy;
+
+        DeltaTransformFilter() {}
+
+        DeltaTransformFilter init(DPathConsumer2D out,
+                                  double mxx, double mxy,
+                                  double myx, double myy)
+        {
+            this.out = out;
+            this.mxx = mxx;
+            this.mxy = mxy;
+            this.myx = myx;
+            this.myy = myy;
+            return this; // fluent API
+        }
+
+        @Override
+        public void moveTo(double x0, double y0) {
+            out.moveTo(x0 * mxx + y0 * mxy,
+                       x0 * myx + y0 * myy);
+        }
+
+        @Override
+        public void lineTo(double x1, double y1) {
+            out.lineTo(x1 * mxx + y1 * mxy,
+                       x1 * myx + y1 * myy);
+        }
+
+        @Override
+        public void quadTo(double x1, double y1,
+                           double x2, double y2)
+        {
+            out.quadTo(x1 * mxx + y1 * mxy,
+                       x1 * myx + y1 * myy,
+                       x2 * mxx + y2 * mxy,
+                       x2 * myx + y2 * myy);
+        }
+
+        @Override
+        public void curveTo(double x1, double y1,
+                            double x2, double y2,
+                            double x3, double y3)
+        {
+            out.curveTo(x1 * mxx + y1 * mxy,
+                        x1 * myx + y1 * myy,
+                        x2 * mxx + y2 * mxy,
+                        x2 * myx + y2 * myy,
+                        x3 * mxx + y3 * mxy,
+                        x3 * myx + y3 * myy);
+        }
+
+        @Override
+        public void closePath() {
+            out.closePath();
+        }
+
+        @Override
+        public void pathDone() {
+            out.pathDone();
+        }
+
+        @Override
+        public long getNativeConsumer() {
+            return 0;
+        }
+    }
+
+    static final class Path2DWrapper implements DPathConsumer2D {
+        private Path2D.Double p2d;
+
+        Path2DWrapper() {}
+
+        Path2DWrapper init(Path2D.Double p2d) {
+            this.p2d = p2d;
+            return this;
+        }
+
+        @Override
+        public void moveTo(double x0, double y0) {
+            p2d.moveTo(x0, y0);
+        }
+
+        @Override
+        public void lineTo(double x1, double y1) {
+            p2d.lineTo(x1, y1);
+        }
+
+        @Override
+        public void closePath() {
+            p2d.closePath();
+        }
+
+        @Override
+        public void pathDone() {}
+
+        @Override
+        public void curveTo(double x1, double y1,
+                            double x2, double y2,
+                            double x3, double y3)
+        {
+            p2d.curveTo(x1, y1, x2, y2, x3, y3);
+        }
+
+        @Override
+        public void quadTo(double x1, double y1, double x2, double y2) {
+            p2d.quadTo(x1, y1, x2, y2);
+        }
+
+        @Override
+        public long getNativeConsumer() {
+            throw new InternalError("Not using a native peer");
+        }
+    }
+
+    static final class ClosedPathDetector implements DPathConsumer2D {
+
+        private final DRendererContext rdrCtx;
+        private final PolyStack stack;
+
+        private DPathConsumer2D out;
+
+        ClosedPathDetector(final DRendererContext rdrCtx) {
+            this.rdrCtx = rdrCtx;
+            this.stack = (rdrCtx.stats != null) ?
+                new PolyStack(rdrCtx,
+                        rdrCtx.stats.stat_cpd_polystack_types,
+                        rdrCtx.stats.stat_cpd_polystack_curves,
+                        rdrCtx.stats.hist_cpd_polystack_curves,
+                        rdrCtx.stats.stat_array_cpd_polystack_curves,
+                        rdrCtx.stats.stat_array_cpd_polystack_types)
+                : new PolyStack(rdrCtx);
+        }
+
+        ClosedPathDetector init(DPathConsumer2D out) {
+            this.out = out;
+            return this; // fluent API
+        }
+
+        /**
+         * Disposes this instance:
+         * clean up before reusing this instance
+         */
+        void dispose() {
+            stack.dispose();
+        }
+
+        @Override
+        public void pathDone() {
+            // previous path is not closed:
+            finish(false);
+            out.pathDone();
+
+            // TODO: fix possible leak if exception happened
+            // Dispose this instance:
+            dispose();
+        }
+
+        @Override
+        public void closePath() {
+            // path is closed
+            finish(true);
+            out.closePath();
+        }
+
+        @Override
+        public void moveTo(double x0, double y0) {
+            // previous path is not closed:
+            finish(false);
+            out.moveTo(x0, y0);
+        }
+
+        private void finish(final boolean closed) {
+            rdrCtx.closedPath = closed;
+            stack.pullAll(out);
+        }
+
+        @Override
+        public void lineTo(double x1, double y1) {
+            stack.pushLine(x1, y1);
+        }
+
+        @Override
+        public void curveTo(double x3, double y3,
+                            double x2, double y2,
+                            double x1, double y1)
+        {
+            stack.pushCubic(x1, y1, x2, y2, x3, y3);
+        }
+
+        @Override
+        public void quadTo(double x2, double y2, double x1, double y1) {
+            stack.pushQuad(x1, y1, x2, y2);
+        }
+
+        @Override
+        public long getNativeConsumer() {
+            throw new InternalError("Not using a native peer");
+        }
+    }
+
+    static final class PathClipFilter implements DPathConsumer2D {
+
+        private DPathConsumer2D out;
+
+        // Bounds of the drawing region, at pixel precision.
+        private final double[] clipRect;
+
+        private final double[] corners = new double[8];
+        private boolean init_corners = false;
+
+        private final IndexStack stack;
+
+        // the current outcode of the current sub path
+        private int cOutCode = 0;
+
+        // the cumulated (and) outcode of the complete path
+        private int gOutCode = MarlinConst.OUTCODE_MASK_T_B_L_R;
+
+        private boolean outside = false;
+
+        // The current point (TODO stupid repeated info)
+        private double cx0, cy0;
+
+        // The current point OUTSIDE
+        private double cox0, coy0;
+
+        private boolean subdivide = MarlinConst.DO_CLIP_SUBDIVIDER;
+        private final CurveClipSplitter curveSplitter;
+
+        PathClipFilter(final DRendererContext rdrCtx) {
+            this.clipRect = rdrCtx.clipRect;
+            this.curveSplitter = rdrCtx.curveClipSplitter;
+
+            this.stack = (rdrCtx.stats != null) ?
+                new IndexStack(rdrCtx,
+                        rdrCtx.stats.stat_pcf_idxstack_indices,
+                        rdrCtx.stats.hist_pcf_idxstack_indices,
+                        rdrCtx.stats.stat_array_pcf_idxstack_indices)
+                : new IndexStack(rdrCtx);
+        }
+
+        PathClipFilter init(final DPathConsumer2D out) {
+            this.out = out;
+
+            // Adjust the clipping rectangle with the renderer offsets
+            final double rdrOffX = DRenderer.RDR_OFFSET_X;
+            final double rdrOffY = DRenderer.RDR_OFFSET_Y;
+
+            // add a small rounding error:
+            final double margin = 1e-3d;
+
+            final double[] _clipRect = this.clipRect;
+            _clipRect[0] -= margin - rdrOffY;
+            _clipRect[1] += margin + rdrOffY;
+            _clipRect[2] -= margin - rdrOffX;
+            _clipRect[3] += margin + rdrOffX;
+
+            if (MarlinConst.DO_CLIP_SUBDIVIDER) {
+                // adjust padded clip rectangle:
+                curveSplitter.init();
+            }
+
+            this.init_corners = true;
+            this.gOutCode = MarlinConst.OUTCODE_MASK_T_B_L_R;
+
+            return this; // fluent API
+        }
+
+        /**
+         * Disposes this instance:
+         * clean up before reusing this instance
+         */
+        void dispose() {
+            stack.dispose();
+        }
+
+        private void finishPath() {
+            if (outside) {
+                // criteria: inside or totally outside ?
+                if (gOutCode == 0) {
+                    finish();
+                } else {
+                    this.outside = false;
+                    stack.reset();
+                }
+            }
+        }
+
+        private void finish() {
+            this.outside = false;
+
+            if (!stack.isEmpty()) {
+                if (init_corners) {
+                    init_corners = false;
+
+                    final double[] _corners = corners;
+                    final double[] _clipRect = clipRect;
+                    // Top Left (0):
+                    _corners[0] = _clipRect[2];
+                    _corners[1] = _clipRect[0];
+                    // Bottom Left (1):
+                    _corners[2] = _clipRect[2];
+                    _corners[3] = _clipRect[1];
+                    // Top right (2):
+                    _corners[4] = _clipRect[3];
+                    _corners[5] = _clipRect[0];
+                    // Bottom Right (3):
+                    _corners[6] = _clipRect[3];
+                    _corners[7] = _clipRect[1];
+                }
+                stack.pullAll(corners, out);
+            }
+            out.lineTo(cox0, coy0);
+            this.cx0 = cox0;
+            this.cy0 = coy0;
+        }
+
+        @Override
+        public void pathDone() {
+            finishPath();
+
+            out.pathDone();
+
+            // TODO: fix possible leak if exception happened
+            // Dispose this instance:
+            dispose();
+        }
+
+        @Override
+        public void closePath() {
+            finishPath();
+
+            out.closePath();
+        }
+
+        @Override
+        public void moveTo(final double x0, final double y0) {
+            finishPath();
+
+            this.cOutCode = DHelpers.outcode(x0, y0, clipRect);
+            this.outside = false;
+            out.moveTo(x0, y0);
+            this.cx0 = x0;
+            this.cy0 = y0;
+        }
+
+        @Override
+        public void lineTo(final double xe, final double ye) {
+            final int outcode0 = this.cOutCode;
+            final int outcode1 = DHelpers.outcode(xe, ye, clipRect);
+
+            // Should clip
+            final int orCode = (outcode0 | outcode1);
+            if (orCode != 0) {
+                final int sideCode = (outcode0 & outcode1);
+
+                // basic rejection criteria:
+                if (sideCode == 0) {
+                    // ovelap clip:
+                    if (subdivide) {
+                        // avoid reentrance
+                        subdivide = false;
+                        boolean ret;
+                        // subdivide curve => callback with subdivided parts:
+                        if (outside) {
+                            ret = curveSplitter.splitLine(cox0, coy0, xe, ye,
+                                                          orCode, this);
+                        } else {
+                            ret = curveSplitter.splitLine(cx0, cy0, xe, ye,
+                                                          orCode, this);
+                        }
+                        // reentrance is done:
+                        subdivide = true;
+                        if (ret) {
+                            return;
+                        }
+                    }
+                    // already subdivided so render it
+                } else {
+                    this.cOutCode = outcode1;
+                    this.gOutCode &= sideCode;
+                    // keep last point coordinate before entering the clip again:
+                    this.outside = true;
+                    this.cox0 = xe;
+                    this.coy0 = ye;
+
+                    clip(sideCode, outcode0, outcode1);
+                    return;
+                }
+            }
+
+            this.cOutCode = outcode1;
+            this.gOutCode = 0;
+
+            if (outside) {
+                finish();
+            }
+            // clipping disabled:
+            out.lineTo(xe, ye);
+            this.cx0 = xe;
+            this.cy0 = ye;
+        }
+
+        private void clip(final int sideCode,
+                          final int outcode0,
+                          final int outcode1)
+        {
+            // corner or cross-boundary on left or right side:
+            if ((outcode0 != outcode1)
+                    && ((sideCode & MarlinConst.OUTCODE_MASK_L_R) != 0))
+            {
+                // combine outcodes:
+                final int mergeCode = (outcode0 | outcode1);
+                final int tbCode = mergeCode & MarlinConst.OUTCODE_MASK_T_B;
+                final int lrCode = mergeCode & MarlinConst.OUTCODE_MASK_L_R;
+                final int off = (lrCode == MarlinConst.OUTCODE_LEFT) ? 0 : 2;
+
+                // add corners to outside stack:
+                switch (tbCode) {
+                    case MarlinConst.OUTCODE_TOP:
+                        stack.push(off); // top
+                        return;
+                    case MarlinConst.OUTCODE_BOTTOM:
+                        stack.push(off + 1); // bottom
+                        return;
+                    default:
+                        // both TOP / BOTTOM:
+                        if ((outcode0 & MarlinConst.OUTCODE_TOP) != 0) {
+                            // top to bottom
+                            stack.push(off); // top
+                            stack.push(off + 1); // bottom
+                        } else {
+                            // bottom to top
+                            stack.push(off + 1); // bottom
+                            stack.push(off); // top
+                        }
+                }
+            }
+        }
+
+        @Override
+        public void curveTo(final double x1, final double y1,
+                            final double x2, final double y2,
+                            final double xe, final double ye)
+        {
+            final int outcode0 = this.cOutCode;
+            final int outcode1 = DHelpers.outcode(x1, y1, clipRect);
+            final int outcode2 = DHelpers.outcode(x2, y2, clipRect);
+            final int outcode3 = DHelpers.outcode(xe, ye, clipRect);
+
+            // Should clip
+            final int orCode = (outcode0 | outcode1 | outcode2 | outcode3);
+            if (orCode != 0) {
+                final int sideCode = outcode0 & outcode1 & outcode2 & outcode3;
+
+                // basic rejection criteria:
+                if (sideCode == 0) {
+                    // ovelap clip:
+                    if (subdivide) {
+                        // avoid reentrance
+                        subdivide = false;
+                        // subdivide curve => callback with subdivided parts:
+                        boolean ret;
+                        if (outside) {
+                            ret = curveSplitter.splitCurve(cox0, coy0, x1, y1,
+                                                           x2, y2, xe, ye,
+                                                           orCode, this);
+                        } else {
+                            ret = curveSplitter.splitCurve(cx0, cy0, x1, y1,
+                                                           x2, y2, xe, ye,
+                                                           orCode, this);
+                        }
+                        // reentrance is done:
+                        subdivide = true;
+                        if (ret) {
+                            return;
+                        }
+                    }
+                    // already subdivided so render it
+                } else {
+                    this.cOutCode = outcode3;
+                    this.gOutCode &= sideCode;
+                    // keep last point coordinate before entering the clip again:
+                    this.outside = true;
+                    this.cox0 = xe;
+                    this.coy0 = ye;
+
+                    clip(sideCode, outcode0, outcode3);
+                    return;
+                }
+            }
+
+            this.cOutCode = outcode3;
+            this.gOutCode = 0;
+
+            if (outside) {
+                finish();
+            }
+            // clipping disabled:
+            out.curveTo(x1, y1, x2, y2, xe, ye);
+            this.cx0 = xe;
+            this.cy0 = ye;
+        }
+
+        @Override
+        public void quadTo(final double x1, final double y1,
+                           final double xe, final double ye)
+        {
+            final int outcode0 = this.cOutCode;
+            final int outcode1 = DHelpers.outcode(x1, y1, clipRect);
+            final int outcode2 = DHelpers.outcode(xe, ye, clipRect);
+
+            // Should clip
+            final int orCode = (outcode0 | outcode1 | outcode2);
+            if (orCode != 0) {
+                final int sideCode = outcode0 & outcode1 & outcode2;
+
+                // basic rejection criteria:
+                if (sideCode == 0) {
+                    // ovelap clip:
+                    if (subdivide) {
+                        // avoid reentrance
+                        subdivide = false;
+                        // subdivide curve => callback with subdivided parts:
+                        boolean ret;
+                        if (outside) {
+                            ret = curveSplitter.splitQuad(cox0, coy0, x1, y1,
+                                                          xe, ye, orCode, this);
+                        } else {
+                            ret = curveSplitter.splitQuad(cx0, cy0, x1, y1,
+                                                          xe, ye, orCode, this);
+                        }
+                        // reentrance is done:
+                        subdivide = true;
+                        if (ret) {
+                            return;
+                        }
+                    }
+                    // already subdivided so render it
+                } else {
+                    this.cOutCode = outcode2;
+                    this.gOutCode &= sideCode;
+                    // keep last point coordinate before entering the clip again:
+                    this.outside = true;
+                    this.cox0 = xe;
+                    this.coy0 = ye;
+
+                    clip(sideCode, outcode0, outcode2);
+                    return;
+                }
+            }
+
+            this.cOutCode = outcode2;
+            this.gOutCode = 0;
+
+            if (outside) {
+                finish();
+            }
+            // clipping disabled:
+            out.quadTo(x1, y1, xe, ye);
+            this.cx0 = xe;
+            this.cy0 = ye;
+        }
+
+        @Override
+        public long getNativeConsumer() {
+            throw new InternalError("Not using a native peer");
+        }
+    }
+
+    static final class CurveClipSplitter {
+
+        static final double LEN_TH = MarlinProperties.getSubdividerMinLength();
+        static final boolean DO_CHECK_LENGTH = (LEN_TH > 0.0d);
+
+        private static final boolean TRACE = false;
+
+        private static final int MAX_N_CURVES = 3 * 4;
+
+        // clip rectangle (ymin, ymax, xmin, xmax):
+        final double[] clipRect;
+
+        // clip rectangle (ymin, ymax, xmin, xmax) including padding:
+        final double[] clipRectPad = new double[4];
+        private boolean init_clipRectPad = false;
+
+        // This is where the curve to be processed is put. We give it
+        // enough room to store all curves.
+        final double[] middle = new double[MAX_N_CURVES * 8 + 2];
+        // t values at subdivision points
+        private final double[] subdivTs = new double[MAX_N_CURVES];
+
+        // dirty curve
+        private final DCurve curve;
+
+        CurveClipSplitter(final DRendererContext rdrCtx) {
+            this.clipRect = rdrCtx.clipRect;
+            this.curve = rdrCtx.curve;
+        }
+
+        void init() {
+            this.init_clipRectPad = true;
+        }
+
+        private void initPaddedClip() {
+            // bounds as half-open intervals: minX <= x < maxX and minY <= y < maxY
+            // adjust padded clip rectangle (ymin, ymax, xmin, xmax):
+            // add a rounding error (curve subdivision ~ 0.1px):
+            final double[] _clipRect = clipRect;
+            final double[] _clipRectPad = clipRectPad;
+
+            _clipRectPad[0] = _clipRect[0] - CLIP_RECT_PADDING;
+            _clipRectPad[1] = _clipRect[1] + CLIP_RECT_PADDING;
+            _clipRectPad[2] = _clipRect[2] - CLIP_RECT_PADDING;
+            _clipRectPad[3] = _clipRect[3] + CLIP_RECT_PADDING;
+
+            if (TRACE) {
+                System.out.println("clip: X [" + _clipRectPad[2] + " .. " + _clipRectPad[3] +"] "
+                                        + "Y ["+ _clipRectPad[0] + " .. " + _clipRectPad[1] +"]");
+            }
+        }
+
+        boolean splitLine(final double x0, final double y0,
+                          final double x1, final double y1,
+                          final int outCodeOR,
+                          final DPathConsumer2D out)
+        {
+            if (TRACE) {
+                System.out.println("divLine P0(" + x0 + ", " + y0 + ") P1(" + x1 + ", " + y1 + ")");
+            }
+
+            if (DO_CHECK_LENGTH && DHelpers.fastLineLen(x0, y0, x1, y1) <= LEN_TH) {
+                return false;
+            }
+
+            final double[] mid = middle;
+            mid[0] = x0;  mid[1] = y0;
+            mid[2] = x1;  mid[3] = y1;
+
+            return subdivideAtIntersections(4, outCodeOR, out);
+        }
+
+        boolean splitQuad(final double x0, final double y0,
+                          final double x1, final double y1,
+                          final double x2, final double y2,
+                          final int outCodeOR,
+                          final DPathConsumer2D out)
+        {
+            if (TRACE) {
+                System.out.println("divQuad P0(" + x0 + ", " + y0 + ") P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2 + ")");
+            }
+
+            if (DO_CHECK_LENGTH && DHelpers.fastQuadLen(x0, y0, x1, y1, x2, y2) <= LEN_TH) {
+                return false;
+            }
+
+            final double[] mid = middle;
+            mid[0] = x0;  mid[1] = y0;
+            mid[2] = x1;  mid[3] = y1;
+            mid[4] = x2;  mid[5] = y2;
+
+            return subdivideAtIntersections(6, outCodeOR, out);
+        }
+
+        boolean splitCurve(final double x0, final double y0,
+                           final double x1, final double y1,
+                           final double x2, final double y2,
+                           final double x3, final double y3,
+                           final int outCodeOR,
+                           final DPathConsumer2D out)
+        {
+            if (TRACE) {
+                System.out.println("divCurve P0(" + x0 + ", " + y0 + ") P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2 + ") P3(" + x3 + ", " + y3 + ")");
+            }
+
+            if (DO_CHECK_LENGTH && DHelpers.fastCurvelen(x0, y0, x1, y1, x2, y2, x3, y3) <= LEN_TH) {
+                return false;
+            }
+
+            final double[] mid = middle;
+            mid[0] = x0;  mid[1] = y0;
+            mid[2] = x1;  mid[3] = y1;
+            mid[4] = x2;  mid[5] = y2;
+            mid[6] = x3;  mid[7] = y3;
+
+            return subdivideAtIntersections(8, outCodeOR, out);
+        }
+
+        private boolean subdivideAtIntersections(final int type, final int outCodeOR,
+                                                 final DPathConsumer2D out)
+        {
+            final double[] mid = middle;
+            final double[] subTs = subdivTs;
+
+            if (init_clipRectPad) {
+                init_clipRectPad = false;
+                initPaddedClip();
+            }
+
+            final int nSplits = DHelpers.findClipPoints(curve, mid, subTs, type,
+                                                        outCodeOR, clipRectPad);
+
+            if (TRACE) {
+                System.out.println("nSplits: "+ nSplits);
+                System.out.println("subTs: "+Arrays.toString(Arrays.copyOfRange(subTs, 0, nSplits)));
+            }
+            if (nSplits == 0) {
+                // only curve support shortcut
+                return false;
+            }
+            double prevT = 0.0d;
+
+            for (int i = 0, off = 0; i < nSplits; i++, off += type) {
+                final double t = subTs[i];
+
+                DHelpers.subdivideAt((t - prevT) / (1.0d - prevT),
+                                     mid, off, mid, off, type);
+                prevT = t;
+
+                if (TRACE) {
+                    System.out.println("Part Curve "+Arrays.toString(Arrays.copyOfRange(mid, off, off + type)));
+                }
+            }
+
+            for (int i = 0, off = 0; i <= nSplits; i++, off += type) {
+                emitCurrent(type, mid, off, out);
+            }
+            return true;
+        }
+
+        static void emitCurrent(final int type, final double[] pts,
+                                final int off, final DPathConsumer2D out)
+        {
+            // if instead of switch (perf + most probable cases first)
+            if (type == 8) {
+                out.curveTo(pts[off + 2], pts[off + 3],
+                            pts[off + 4], pts[off + 5],
+                            pts[off + 6], pts[off + 7]);
+            } else if (type == 4) {
+                out.lineTo(pts[off + 2], pts[off + 3]);
+            } else {
+                out.quadTo(pts[off + 2], pts[off + 3],
+                           pts[off + 4], pts[off + 5]);
+            }
+        }
+    }
+
+    static final class CurveBasicMonotonizer {
+
+        private static final int MAX_N_CURVES = 11;
+
+        // squared half line width (for stroker)
+        private double lw2;
+
+        // number of splitted curves
+        int nbSplits;
+
+        // This is where the curve to be processed is put. We give it
+        // enough room to store all curves.
+        final double[] middle = new double[MAX_N_CURVES * 6 + 2];
+        // t values at subdivision points
+        private final double[] subdivTs = new double[MAX_N_CURVES - 1];
+
+        // dirty curve
+        private final DCurve curve;
+
+        CurveBasicMonotonizer(final DRendererContext rdrCtx) {
+            this.curve = rdrCtx.curve;
+        }
+
+        void init(final double lineWidth) {
+            this.lw2 = (lineWidth * lineWidth) / 4.0d;
+        }
+
+        CurveBasicMonotonizer curve(final double x0, final double y0,
+                                    final double x1, final double y1,
+                                    final double x2, final double y2,
+                                    final double x3, final double y3)
+        {
+            final double[] mid = middle;
+            mid[0] = x0;  mid[1] = y0;
+            mid[2] = x1;  mid[3] = y1;
+            mid[4] = x2;  mid[5] = y2;
+            mid[6] = x3;  mid[7] = y3;
+
+            final double[] subTs = subdivTs;
+            final int nSplits = DHelpers.findSubdivPoints(curve, mid, subTs, 8, lw2);
+
+            double prevT = 0.0d;
+            for (int i = 0, off = 0; i < nSplits; i++, off += 6) {
+                final double t = subTs[i];
+
+                DHelpers.subdivideCubicAt((t - prevT) / (1.0d - prevT),
+                                          mid, off, mid, off, off + 6);
+                prevT = t;
+            }
+
+            this.nbSplits = nSplits;
+            return this;
+        }
+
+        CurveBasicMonotonizer quad(final double x0, final double y0,
+                                   final double x1, final double y1,
+                                   final double x2, final double y2)
+        {
+            final double[] mid = middle;
+            mid[0] = x0;  mid[1] = y0;
+            mid[2] = x1;  mid[3] = y1;
+            mid[4] = x2;  mid[5] = y2;
+
+            final double[] subTs = subdivTs;
+            final int nSplits = DHelpers.findSubdivPoints(curve, mid, subTs, 6, lw2);
+
+            double prevt = 0.0d;
+            for (int i = 0, off = 0; i < nSplits; i++, off += 4) {
+                final double t = subTs[i];
+                DHelpers.subdivideQuadAt((t - prevt) / (1.0d - prevt),
+                                         mid, off, mid, off, off + 4);
+                prevt = t;
+            }
+
+            this.nbSplits = nSplits;
+            return this;
+        }
+    }
+
+    static final class PathTracer implements DPathConsumer2D {
+        private final String prefix;
+        private DPathConsumer2D out;
+
+        PathTracer(String name) {
+            this.prefix = name + ": ";
+        }
+
+        PathTracer init(DPathConsumer2D out) {
+            this.out = out;
+            return this; // fluent API
+        }
+
+        @Override
+        public void moveTo(double x0, double y0) {
+            log("moveTo (" + x0 + ", " + y0 + ')');
+            out.moveTo(x0, y0);
+        }
+
+        @Override
+        public void lineTo(double x1, double y1) {
+            log("lineTo (" + x1 + ", " + y1 + ')');
+            out.lineTo(x1, y1);
+        }
+
+        @Override
+        public void curveTo(double x1, double y1,
+                            double x2, double y2,
+                            double x3, double y3)
+        {
+            log("curveTo P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2  + ") P3(" + x3 + ", " + y3 + ')');
+            out.curveTo(x1, y1, x2, y2, x3, y3);
+        }
+
+        @Override
+        public void quadTo(double x1, double y1, double x2, double y2) {
+            log("quadTo P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2  + ')');
+            out.quadTo(x1, y1, x2, y2);
+        }
+
+        @Override
+        public void closePath() {
+            log("closePath");
+            out.closePath();
+        }
+
+        @Override
+        public void pathDone() {
+            log("pathDone");
+            out.pathDone();
+        }
+
+        private void log(final String message) {
+            System.out.println(prefix + message);
+        }
+
+        @Override
+        public long getNativeConsumer() {
+            throw new InternalError("Not using a native peer");
+        }
+    }
+}
diff --git a/src/share/classes/sun/java2d/marlin/Dasher.java b/src/share/classes/sun/java2d/marlin/Dasher.java
index 890bbf5..561347e 100644
--- a/src/share/classes/sun/java2d/marlin/Dasher.java
+++ b/src/share/classes/sun/java2d/marlin/Dasher.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, 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
@@ -27,6 +27,8 @@
 
 import java.util.Arrays;
 import sun.awt.geom.PathConsumer2D;
+import sun.java2d.marlin.TransformingPathConsumer2D.CurveBasicMonotonizer;
+import sun.java2d.marlin.TransformingPathConsumer2D.CurveClipSplitter;
 
 /**
  * The <code>Dasher</code> class takes a series of linear commands
@@ -39,11 +41,17 @@
  * semantics are unclear.
  *
  */
-final class Dasher implements sun.awt.geom.PathConsumer2D, MarlinConst {
+final class Dasher implements PathConsumer2D, MarlinConst {
 
-    static final int REC_LIMIT = 4;
-    static final float ERR = 0.01f;
-    static final float MIN_T_INC = 1f / (1 << REC_LIMIT);
+    /* huge circle with radius ~ 2E9 only needs 12 subdivision levels */
+    static final int REC_LIMIT = 16;
+    static final float CURVE_LEN_ERR = MarlinProperties.getCurveLengthError(); // 0.01
+    static final float MIN_T_INC = 1.0f / (1 << REC_LIMIT);
+
+    // More than 24 bits of mantissa means we can no longer accurately
+    // measure the number of times cycled through the dash array so we
+    // punt and override the phase to just be 0 past that point.
+    static final float MAX_CYCLES = 16000000.0f;
 
     private PathConsumer2D out;
     private float[] dash;
@@ -59,8 +67,10 @@
     private boolean dashOn;
     private float phase;
 
-    private float sx, sy;
-    private float x0, y0;
+    // The starting point of the path
+    private float sx0, sy0;
+    // the current point
+    private float cx0, cy0;
 
     // temporary storage for the current curve
     private final float[] curCurvepts;
@@ -68,15 +78,36 @@
     // per-thread renderer context
     final RendererContext rdrCtx;
 
-    // dashes array (dirty)
-    final float[] dashes_initial = new float[INITIAL_ARRAY];
-
     // flag to recycle dash array copy
     boolean recycleDashes;
 
-    // per-thread initial arrays (large enough to satisfy most usages
-    // +1 to avoid recycling in Helpers.widenArray()
-    private final float[] firstSegmentsBuffer_initial = new float[INITIAL_ARRAY + 1];
+    // We don't emit the first dash right away. If we did, caps would be
+    // drawn on it, but we need joins to be drawn if there's a closePath()
+    // So, we store the path elements that make up the first dash in the
+    // buffer below.
+    private float[] firstSegmentsBuffer; // dynamic array
+    private int firstSegidx;
+
+    // dashes ref (dirty)
+    final FloatArrayCache.Reference dashes_ref;
+    // firstSegmentsBuffer ref (dirty)
+    final FloatArrayCache.Reference firstSegmentsBuffer_ref;
+
+    // Bounds of the drawing region, at pixel precision.
+    private float[] clipRect;
+
+    // the outcode of the current point
+    private int cOutCode = 0;
+
+    private boolean subdivide = DO_CLIP_SUBDIVIDER;
+
+    private final LengthIterator li = new LengthIterator();
+
+    private final CurveClipSplitter curveSplitter;
+
+    private float cycleLen;
+    private boolean outside;
+    private float totalSkipLen;
 
     /**
      * Constructs a <code>Dasher</code>.
@@ -85,11 +116,16 @@
     Dasher(final RendererContext rdrCtx) {
         this.rdrCtx = rdrCtx;
 
-        firstSegmentsBuffer = firstSegmentsBuffer_initial;
+        dashes_ref = rdrCtx.newDirtyFloatArrayRef(INITIAL_ARRAY); // 1K
+
+        firstSegmentsBuffer_ref = rdrCtx.newDirtyFloatArrayRef(INITIAL_ARRAY); // 1K
+        firstSegmentsBuffer     = firstSegmentsBuffer_ref.initial;
 
         // we need curCurvepts to be able to contain 2 curves because when
         // dashing curves, we need to subdivide it
         curCurvepts = new float[8 * 2];
+
+        this.curveSplitter = rdrCtx.curveClipSplitter;
     }
 
     /**
@@ -105,32 +141,72 @@
     Dasher init(final PathConsumer2D out, float[] dash, int dashLen,
                 float phase, boolean recycleDashes)
     {
-        if (phase < 0f) {
-            throw new IllegalArgumentException("phase < 0 !");
-        }
         this.out = out;
 
         // Normalize so 0 <= phase < dash[0]
-        int idx = 0;
+        int sidx = 0;
         dashOn = true;
-        float d;
-        while (phase >= (d = dash[idx])) {
-            phase -= d;
-            idx = (idx + 1) % dashLen;
-            dashOn = !dashOn;
+
+        float sum = 0.0f;
+        for (float d : dash) {
+            sum += d;
+        }
+        this.cycleLen = sum;
+
+        float cycles = phase / sum;
+        if (phase < 0.0f) {
+            if (-cycles >= MAX_CYCLES) {
+                phase = 0.0f;
+            } else {
+                int fullcycles = FloatMath.floor_int(-cycles);
+                if ((fullcycles & dash.length & 1) != 0) {
+                    dashOn = !dashOn;
+                }
+                phase += fullcycles * sum;
+                while (phase < 0.0f) {
+                    if (--sidx < 0) {
+                        sidx = dash.length - 1;
+                    }
+                    phase += dash[sidx];
+                    dashOn = !dashOn;
+                }
+            }
+        } else if (phase > 0.0f) {
+            if (cycles >= MAX_CYCLES) {
+                phase = 0.0f;
+            } else {
+                int fullcycles = FloatMath.floor_int(cycles);
+                if ((fullcycles & dash.length & 1) != 0) {
+                    dashOn = !dashOn;
+                }
+                phase -= fullcycles * sum;
+                float d;
+                while (phase >= (d = dash[sidx])) {
+                    phase -= d;
+                    sidx = (sidx + 1) % dash.length;
+                    dashOn = !dashOn;
+                }
+            }
         }
 
         this.dash = dash;
         this.dashLen = dashLen;
-        this.startPhase = this.phase = phase;
+        this.phase = phase;
+        this.startPhase = phase;
         this.startDashOn = dashOn;
-        this.startIdx = idx;
+        this.startIdx = sidx;
         this.starting = true;
-        needsMoveTo = false;
-        firstSegidx = 0;
+        this.needsMoveTo = false;
+        this.firstSegidx = 0;
 
         this.recycleDashes = recycleDashes;
 
+        if (rdrCtx.doClip) {
+            this.clipRect = rdrCtx.clipRect;
+        } else {
+            this.clipRect = null;
+            this.cOutCode = 0;
+        }
         return this; // fluent API
     }
 
@@ -141,49 +217,69 @@
     void dispose() {
         if (DO_CLEAN_DIRTY) {
             // Force zero-fill dirty arrays:
-            Arrays.fill(curCurvepts, 0f);
-            Arrays.fill(firstSegmentsBuffer, 0f);
+            Arrays.fill(curCurvepts, 0.0f);
         }
         // Return arrays:
-        if (recycleDashes && dash != dashes_initial) {
-            rdrCtx.putDirtyFloatArray(dash);
-            dash = null;
+        if (recycleDashes) {
+            dash = dashes_ref.putArray(dash);
         }
+        firstSegmentsBuffer = firstSegmentsBuffer_ref.putArray(firstSegmentsBuffer);
+    }
 
-        if (firstSegmentsBuffer != firstSegmentsBuffer_initial) {
-            rdrCtx.putDirtyFloatArray(firstSegmentsBuffer);
-            firstSegmentsBuffer = firstSegmentsBuffer_initial;
+    float[] copyDashArray(final float[] dashes) {
+        final int len = dashes.length;
+        final float[] newDashes;
+        if (len <= MarlinConst.INITIAL_ARRAY) {
+            newDashes = dashes_ref.initial;
+        } else {
+            if (DO_STATS) {
+                rdrCtx.stats.stat_array_dasher_dasher.add(len);
+            }
+            newDashes = dashes_ref.getArray(len);
         }
+        System.arraycopy(dashes, 0, newDashes, 0, len);
+        return newDashes;
     }
 
     @Override
-    public void moveTo(float x0, float y0) {
-        if (firstSegidx > 0) {
-            out.moveTo(sx, sy);
+    public void moveTo(final float x0, final float y0) {
+        if (firstSegidx != 0) {
+            out.moveTo(sx0, sy0);
             emitFirstSegments();
         }
-        needsMoveTo = true;
+        this.needsMoveTo = true;
         this.idx = startIdx;
         this.dashOn = this.startDashOn;
         this.phase = this.startPhase;
-        this.sx = this.x0 = x0;
-        this.sy = this.y0 = y0;
+        this.cx0 = x0;
+        this.cy0 = y0;
+
+        // update starting point:
+        this.sx0 = x0;
+        this.sy0 = y0;
         this.starting = true;
+
+        if (clipRect != null) {
+            final int outcode = Helpers.outcode(x0, y0, clipRect);
+            this.cOutCode = outcode;
+            this.outside = false;
+            this.totalSkipLen = 0.0f;
+        }
     }
 
     private void emitSeg(float[] buf, int off, int type) {
         switch (type) {
         case 8:
-            out.curveTo(buf[off+0], buf[off+1],
-                        buf[off+2], buf[off+3],
-                        buf[off+4], buf[off+5]);
+            out.curveTo(buf[off    ], buf[off + 1],
+                        buf[off + 2], buf[off + 3],
+                        buf[off + 4], buf[off + 5]);
             return;
         case 6:
-            out.quadTo(buf[off+0], buf[off+1],
-                       buf[off+2], buf[off+3]);
+            out.quadTo(buf[off    ], buf[off + 1],
+                       buf[off + 2], buf[off + 3]);
             return;
         case 4:
-            out.lineTo(buf[off], buf[off+1]);
+            out.lineTo(buf[off], buf[off + 1]);
             return;
         default:
         }
@@ -192,66 +288,125 @@
     private void emitFirstSegments() {
         final float[] fSegBuf = firstSegmentsBuffer;
 
-        for (int i = 0; i < firstSegidx; ) {
+        for (int i = 0, len = firstSegidx; i < len; ) {
             int type = (int)fSegBuf[i];
             emitSeg(fSegBuf, i + 1, type);
             i += (type - 1);
         }
         firstSegidx = 0;
     }
-    // We don't emit the first dash right away. If we did, caps would be
-    // drawn on it, but we need joins to be drawn if there's a closePath()
-    // So, we store the path elements that make up the first dash in the
-    // buffer below.
-    private float[] firstSegmentsBuffer; // dynamic array
-    private int firstSegidx;
 
     // precondition: pts must be in relative coordinates (relative to x0,y0)
-    // fullCurve is true iff the curve in pts has not been split.
-    private void goTo(float[] pts, int off, final int type) {
-        float x = pts[off + type - 4];
-        float y = pts[off + type - 3];
-        if (dashOn) {
+    private void goTo(final float[] pts, final int off, final int type,
+                      final boolean on)
+    {
+        final int index = off + type;
+        final float x = pts[index - 4];
+        final float y = pts[index - 3];
+/*
+        if (type == 8) {
+            System.out.println("seg["+on+"] len: "
+                    +Helpers.curvelen(pts[off - 2], pts[off - 1],
+                            pts[off    ], pts[off + 1],
+                        pts[off + 2], pts[off + 3],
+                        pts[off + 4], pts[off + 5]));
+        }
+*/
+        if (on) {
             if (starting) {
-                int len = type - 2 + 1;
-                int segIdx = firstSegidx;
-                float[] buf = firstSegmentsBuffer;
-                if (segIdx + len  > buf.length) {
-                    if (DO_STATS) {
-                        rdrCtx.stats.stat_array_dasher_firstSegmentsBuffer
-                            .add(segIdx + len);
-                    }
-                    firstSegmentsBuffer = buf
-                        = rdrCtx.widenDirtyFloatArray(buf, segIdx, segIdx + len);
-                }
-                buf[segIdx++] = type;
-                len--;
-                // small arraycopy (2, 4 or 6) but with offset:
-                System.arraycopy(pts, off, buf, segIdx, len);
-                segIdx += len;
-                firstSegidx = segIdx;
+                goTo_starting(pts, off, type);
             } else {
                 if (needsMoveTo) {
-                    out.moveTo(x0, y0);
                     needsMoveTo = false;
+                    out.moveTo(cx0, cy0);
                 }
                 emitSeg(pts, off, type);
             }
         } else {
-            starting = false;
+            if (starting) {
+                // low probability test (hotspot)
+                starting = false;
+            }
             needsMoveTo = true;
         }
-        this.x0 = x;
-        this.y0 = y;
+        this.cx0 = x;
+        this.cy0 = y;
+    }
+
+    private void goTo_starting(final float[] pts, final int off, final int type) {
+        int len = type - 1; // - 2 + 1
+        int segIdx = firstSegidx;
+        float[] buf = firstSegmentsBuffer;
+
+        if (segIdx + len  > buf.length) {
+            if (DO_STATS) {
+                rdrCtx.stats.stat_array_dasher_firstSegmentsBuffer
+                    .add(segIdx + len);
+            }
+            firstSegmentsBuffer = buf
+                = firstSegmentsBuffer_ref.widenArray(buf, segIdx,
+                                                     segIdx + len);
+        }
+        buf[segIdx++] = type;
+        len--;
+        // small arraycopy (2, 4 or 6) but with offset:
+        System.arraycopy(pts, off, buf, segIdx, len);
+        firstSegidx = segIdx + len;
     }
 
     @Override
-    public void lineTo(float x1, float y1) {
-        float dx = x1 - x0;
-        float dy = y1 - y0;
+    public void lineTo(final float x1, final float y1) {
+        final int outcode0 = this.cOutCode;
 
-        float len = dx*dx + dy*dy;
-        if (len == 0f) {
+        if (clipRect != null) {
+            final int outcode1 = Helpers.outcode(x1, y1, clipRect);
+
+            // Should clip
+            final int orCode = (outcode0 | outcode1);
+
+            if (orCode != 0) {
+                final int sideCode = outcode0 & outcode1;
+
+                // basic rejection criteria:
+                if (sideCode == 0) {
+                    // ovelap clip:
+                    if (subdivide) {
+                        // avoid reentrance
+                        subdivide = false;
+                        // subdivide curve => callback with subdivided parts:
+                        boolean ret = curveSplitter.splitLine(cx0, cy0, x1, y1,
+                                                              orCode, this);
+                        // reentrance is done:
+                        subdivide = true;
+                        if (ret) {
+                            return;
+                        }
+                    }
+                    // already subdivided so render it
+                } else {
+                    this.cOutCode = outcode1;
+                    skipLineTo(x1, y1);
+                    return;
+                }
+            }
+
+            this.cOutCode = outcode1;
+
+            if (this.outside) {
+                this.outside = false;
+                // Adjust current index, phase & dash:
+                skipLen();
+            }
+        }
+        _lineTo(x1, y1);
+    }
+
+    private void _lineTo(final float x1, final float y1) {
+        final float dx = x1 - cx0;
+        final float dy = y1 - cy0;
+
+        float len = dx * dx + dy * dy;
+        if (len == 0.0f) {
             return;
         }
         len = (float) Math.sqrt(len);
@@ -263,96 +418,212 @@
 
         final float[] _curCurvepts = curCurvepts;
         final float[] _dash = dash;
+        final int _dashLen = this.dashLen;
 
-        float leftInThisDashSegment;
-        float dashdx, dashdy, p;
+        int _idx = idx;
+        boolean _dashOn = dashOn;
+        float _phase = phase;
+
+        float leftInThisDashSegment, d;
 
         while (true) {
-            leftInThisDashSegment = _dash[idx] - phase;
+            d = _dash[_idx];
+            leftInThisDashSegment = d - _phase;
 
             if (len <= leftInThisDashSegment) {
                 _curCurvepts[0] = x1;
                 _curCurvepts[1] = y1;
-                goTo(_curCurvepts, 0, 4);
+
+                goTo(_curCurvepts, 0, 4, _dashOn);
 
                 // Advance phase within current dash segment
-                phase += len;
+                _phase += len;
+
                 // TODO: compare float values using epsilon:
                 if (len == leftInThisDashSegment) {
-                    phase = 0f;
-                    idx = (idx + 1) % dashLen;
-                    dashOn = !dashOn;
+                    _phase = 0.0f;
+                    _idx = (_idx + 1) % _dashLen;
+                    _dashOn = !_dashOn;
                 }
-                return;
+                break;
             }
 
-            dashdx = _dash[idx] * cx;
-            dashdy = _dash[idx] * cy;
-
-            if (phase == 0f) {
-                _curCurvepts[0] = x0 + dashdx;
-                _curCurvepts[1] = y0 + dashdy;
+            if (_phase == 0.0f) {
+                _curCurvepts[0] = cx0 + d * cx;
+                _curCurvepts[1] = cy0 + d * cy;
             } else {
-                p = leftInThisDashSegment / _dash[idx];
-                _curCurvepts[0] = x0 + p * dashdx;
-                _curCurvepts[1] = y0 + p * dashdy;
+                _curCurvepts[0] = cx0 + leftInThisDashSegment * cx;
+                _curCurvepts[1] = cy0 + leftInThisDashSegment * cy;
             }
 
-            goTo(_curCurvepts, 0, 4);
+            goTo(_curCurvepts, 0, 4, _dashOn);
 
             len -= leftInThisDashSegment;
             // Advance to next dash segment
-            idx = (idx + 1) % dashLen;
-            dashOn = !dashOn;
-            phase = 0f;
+            _idx = (_idx + 1) % _dashLen;
+            _dashOn = !_dashOn;
+            _phase = 0.0f;
         }
+        // Save local state:
+        idx = _idx;
+        dashOn = _dashOn;
+        phase = _phase;
     }
 
-    // shared instance in Dasher
-    private final LengthIterator li = new LengthIterator();
+    private void skipLineTo(final float x1, final float y1) {
+        final float dx = x1 - cx0;
+        final float dy = y1 - cy0;
+
+        float len = dx * dx + dy * dy;
+        if (len != 0.0f) {
+            len = (float)Math.sqrt(len);
+        }
+
+        // Accumulate skipped length:
+        this.outside = true;
+        this.totalSkipLen += len;
+
+        // Fix initial move:
+        this.needsMoveTo = true;
+        this.starting = false;
+
+        this.cx0 = x1;
+        this.cy0 = y1;
+    }
+
+    public void skipLen() {
+        float len = this.totalSkipLen;
+        this.totalSkipLen = 0.0f;
+
+        final float[] _dash = dash;
+        final int _dashLen = this.dashLen;
+
+        int _idx = idx;
+        boolean _dashOn = dashOn;
+        float _phase = phase;
+
+        // -2 to ensure having 2 iterations of the post-loop
+        // to compensate the remaining phase
+        final long fullcycles = (long)Math.floor(len / cycleLen) - 2L;
+
+        if (fullcycles > 0L) {
+            len -= cycleLen * fullcycles;
+
+            final long iterations = fullcycles * _dashLen;
+            _idx = (int) (iterations + _idx) % _dashLen;
+            _dashOn = (iterations + (_dashOn ? 1L : 0L) & 1L) == 1L;
+        }
+
+        float leftInThisDashSegment, d;
+
+        while (true) {
+            d = _dash[_idx];
+            leftInThisDashSegment = d - _phase;
+
+            if (len <= leftInThisDashSegment) {
+                // Advance phase within current dash segment
+                _phase += len;
+
+                // TODO: compare float values using epsilon:
+                if (len == leftInThisDashSegment) {
+                    _phase = 0.0f;
+                    _idx = (_idx + 1) % _dashLen;
+                    _dashOn = !_dashOn;
+                }
+                break;
+            }
+
+            len -= leftInThisDashSegment;
+            // Advance to next dash segment
+            _idx = (_idx + 1) % _dashLen;
+            _dashOn = !_dashOn;
+            _phase = 0.0f;
+        }
+        // Save local state:
+        idx = _idx;
+        dashOn = _dashOn;
+        phase = _phase;
+    }
 
     // preconditions: curCurvepts must be an array of length at least 2 * type,
     // that contains the curve we want to dash in the first type elements
-    private void somethingTo(int type) {
-        if (pointCurve(curCurvepts, type)) {
+    private void somethingTo(final int type) {
+        final float[] _curCurvepts = curCurvepts;
+        if (pointCurve(_curCurvepts, type)) {
             return;
         }
-        li.initializeIterationOnCurve(curCurvepts, type);
+        final LengthIterator _li = li;
+        final float[] _dash = dash;
+        final int _dashLen = this.dashLen;
+
+        _li.initializeIterationOnCurve(_curCurvepts, type);
+
+        int _idx = idx;
+        boolean _dashOn = dashOn;
+        float _phase = phase;
 
         // initially the current curve is at curCurvepts[0...type]
         int curCurveoff = 0;
-        float lastSplitT = 0f;
+        float prevT = 0.0f;
         float t;
-        float leftInThisDashSegment = dash[idx] - phase;
+        float leftInThisDashSegment = _dash[_idx] - _phase;
 
-        while ((t = li.next(leftInThisDashSegment)) < 1f) {
-            if (t != 0f) {
-                Helpers.subdivideAt((t - lastSplitT) / (1f - lastSplitT),
-                                    curCurvepts, curCurveoff,
-                                    curCurvepts, 0,
-                                    curCurvepts, type, type);
-                lastSplitT = t;
-                goTo(curCurvepts, 2, type);
+        while ((t = _li.next(leftInThisDashSegment)) < 1.0f) {
+            if (t != 0.0f) {
+                Helpers.subdivideAt((t - prevT) / (1.0f - prevT),
+                                    _curCurvepts, curCurveoff,
+                                    _curCurvepts, 0, type);
+                prevT = t;
+                goTo(_curCurvepts, 2, type, _dashOn);
                 curCurveoff = type;
             }
             // Advance to next dash segment
-            idx = (idx + 1) % dashLen;
-            dashOn = !dashOn;
-            phase = 0f;
-            leftInThisDashSegment = dash[idx];
+            _idx = (_idx + 1) % _dashLen;
+            _dashOn = !_dashOn;
+            _phase = 0.0f;
+            leftInThisDashSegment = _dash[_idx];
         }
-        goTo(curCurvepts, curCurveoff+2, type);
-        phase += li.lastSegLen();
-        if (phase >= dash[idx]) {
-            phase = 0f;
-            idx = (idx + 1) % dashLen;
-            dashOn = !dashOn;
+
+        goTo(_curCurvepts, curCurveoff + 2, type, _dashOn);
+
+        _phase += _li.lastSegLen();
+        if (_phase >= _dash[_idx]) {
+            _phase = 0.0f;
+            _idx = (_idx + 1) % _dashLen;
+            _dashOn = !_dashOn;
         }
+        // Save local state:
+        idx = _idx;
+        dashOn = _dashOn;
+        phase = _phase;
+
         // reset LengthIterator:
-        li.reset();
+        _li.reset();
     }
 
-    private static boolean pointCurve(float[] curve, int type) {
+    private void skipSomethingTo(final int type) {
+        final float[] _curCurvepts = curCurvepts;
+        if (pointCurve(_curCurvepts, type)) {
+            return;
+        }
+        final LengthIterator _li = li;
+
+        _li.initializeIterationOnCurve(_curCurvepts, type);
+
+        // In contrary to somethingTo(),
+        // just estimate properly the curve length:
+        final float len = _li.totalLength();
+
+        // Accumulate skipped length:
+        this.outside = true;
+        this.totalSkipLen += len;
+
+        // Fix initial move:
+        this.needsMoveTo = true;
+        this.starting = false;
+    }
+
+    private static boolean pointCurve(final float[] curve, final int type) {
         for (int i = 2; i < type; i++) {
             if (curve[i] != curve[i-2]) {
                 return false;
@@ -375,15 +646,14 @@
     // tree; however, the trees we are interested in have the property that
     // every non leaf node has exactly 2 children
     static final class LengthIterator {
-        private enum Side {LEFT, RIGHT};
         // Holds the curves at various levels of the recursion. The root
         // (i.e. the original curve) is at recCurveStack[0] (but then it
         // gets subdivided, the left half is put at 1, so most of the time
         // only the right half of the original curve is at 0)
         private final float[][] recCurveStack; // dirty
-        // sides[i] indicates whether the node at level i+1 in the path from
+        // sidesRight[i] indicates whether the node at level i+1 in the path from
         // the root to the current leaf is a left or right child of its parent.
-        private final Side[] sides; // dirty
+        private final boolean[] sidesRight; // dirty
         private int curveType;
         // lastT and nextT delimit the current leaf.
         private float nextT;
@@ -399,12 +669,12 @@
 
         // the lengths of the lines of the control polygon. Only its first
         // curveType/2 - 1 elements are valid. This is an optimization. See
-        // next(float) for more detail.
+        // next() for more detail.
         private final float[] curLeafCtrlPolyLengths = new float[3];
 
         LengthIterator() {
             this.recCurveStack = new float[REC_LIMIT + 1][8];
-            this.sides = new Side[REC_LIMIT];
+            this.sidesRight = new boolean[REC_LIMIT];
             // if any methods are called without first initializing this object
             // on a curve, we want it to fail ASAP.
             this.nextT = Float.MAX_VALUE;
@@ -424,49 +694,49 @@
             if (DO_CLEAN_DIRTY) {
                 final int recLimit = recCurveStack.length - 1;
                 for (int i = recLimit; i >= 0; i--) {
-                    Arrays.fill(recCurveStack[i], 0f);
+                    Arrays.fill(recCurveStack[i], 0.0f);
                 }
-                Arrays.fill(sides, Side.LEFT);
-                Arrays.fill(curLeafCtrlPolyLengths, 0f);
-                Arrays.fill(nextRoots, 0f);
-                Arrays.fill(flatLeafCoefCache, 0f);
-                flatLeafCoefCache[2] = -1f;
+                Arrays.fill(sidesRight, false);
+                Arrays.fill(curLeafCtrlPolyLengths, 0.0f);
+                Arrays.fill(nextRoots, 0.0f);
+                Arrays.fill(flatLeafCoefCache, 0.0f);
+                flatLeafCoefCache[2] = -1.0f;
             }
         }
 
-        void initializeIterationOnCurve(float[] pts, int type) {
+        void initializeIterationOnCurve(final float[] pts, final int type) {
             // optimize arraycopy (8 values faster than 6 = type):
             System.arraycopy(pts, 0, recCurveStack[0], 0, 8);
             this.curveType = type;
             this.recLevel = 0;
-            this.lastT = 0f;
-            this.lenAtLastT = 0f;
-            this.nextT = 0f;
-            this.lenAtNextT = 0f;
+            this.lastT = 0.0f;
+            this.lenAtLastT = 0.0f;
+            this.nextT = 0.0f;
+            this.lenAtNextT = 0.0f;
             goLeft(); // initializes nextT and lenAtNextT properly
-            this.lenAtLastSplit = 0f;
+            this.lenAtLastSplit = 0.0f;
             if (recLevel > 0) {
-                this.sides[0] = Side.LEFT;
+                this.sidesRight[0] = false;
                 this.done = false;
             } else {
                 // the root of the tree is a leaf so we're done.
-                this.sides[0] = Side.RIGHT;
+                this.sidesRight[0] = true;
                 this.done = true;
             }
-            this.lastSegLen = 0f;
+            this.lastSegLen = 0.0f;
         }
 
         // 0 == false, 1 == true, -1 == invalid cached value.
         private int cachedHaveLowAcceleration = -1;
 
-        private boolean haveLowAcceleration(float err) {
+        private boolean haveLowAcceleration(final float err) {
             if (cachedHaveLowAcceleration == -1) {
                 final float len1 = curLeafCtrlPolyLengths[0];
                 final float len2 = curLeafCtrlPolyLengths[1];
                 // the test below is equivalent to !within(len1/len2, 1, err).
                 // It is using a multiplication instead of a division, so it
                 // should be a bit faster.
-                if (!Helpers.within(len1, len2, err*len2)) {
+                if (!Helpers.within(len1, len2, err * len2)) {
                     cachedHaveLowAcceleration = 0;
                     return false;
                 }
@@ -497,7 +767,7 @@
         // form (see inside next() for what that means). The cache is
         // invalid when it's third element is negative, since in any
         // valid flattened curve, this would be >= 0.
-        private final float[] flatLeafCoefCache = new float[]{0f, 0f, -1f, 0f};
+        private final float[] flatLeafCoefCache = new float[]{0.0f, 0.0f, -1.0f, 0.0f};
 
         // returns the t value where the remaining curve should be split in
         // order for the left subdivided curve to have length len. If len
@@ -507,7 +777,7 @@
             while (lenAtNextT < targetLength) {
                 if (done) {
                     lastSegLen = lenAtNextT - lenAtLastSplit;
-                    return 1f;
+                    return 1.0f;
                 }
                 goToNextLeaf();
             }
@@ -524,19 +794,19 @@
                 // gives us the desired length.
                 final float[] _flatLeafCoefCache = flatLeafCoefCache;
 
-                if (_flatLeafCoefCache[2] < 0) {
-                    float x = 0f + curLeafCtrlPolyLengths[0],
-                          y = x  + curLeafCtrlPolyLengths[1];
+                if (_flatLeafCoefCache[2] < 0.0f) {
+                    float x =     curLeafCtrlPolyLengths[0],
+                          y = x + curLeafCtrlPolyLengths[1];
                     if (curveType == 8) {
                         float z = y + curLeafCtrlPolyLengths[2];
-                        _flatLeafCoefCache[0] = 3f * (x - y) + z;
-                        _flatLeafCoefCache[1] = 3f * (y - 2f * x);
-                        _flatLeafCoefCache[2] = 3f * x;
+                        _flatLeafCoefCache[0] = 3.0f * (x - y) + z;
+                        _flatLeafCoefCache[1] = 3.0f * (y - 2.0f * x);
+                        _flatLeafCoefCache[2] = 3.0f * x;
                         _flatLeafCoefCache[3] = -z;
                     } else if (curveType == 6) {
-                        _flatLeafCoefCache[0] = 0f;
-                        _flatLeafCoefCache[1] = y - 2f * x;
-                        _flatLeafCoefCache[2] = 2f * x;
+                        _flatLeafCoefCache[0] = 0.0f;
+                        _flatLeafCoefCache[1] = y - 2.0f * x;
+                        _flatLeafCoefCache[2] = 2.0f * x;
                         _flatLeafCoefCache[3] = -y;
                     }
                 }
@@ -548,7 +818,8 @@
                 // we use cubicRootsInAB here, because we want only roots in 0, 1,
                 // and our quadratic root finder doesn't filter, so it's just a
                 // matter of convenience.
-                int n = Helpers.cubicRootsInAB(a, b, c, d, nextRoots, 0, 0, 1);
+                final int n = Helpers.cubicRootsInAB(a, b, c, d, nextRoots, 0, 0.0f, 1.0f);
+// TODO: check NaN is impossible
                 if (n == 1 && !Float.isNaN(nextRoots[0])) {
                     t = nextRoots[0];
                 }
@@ -556,8 +827,8 @@
             // t is relative to the current leaf, so we must make it a valid parameter
             // of the original curve.
             t = t * (nextT - lastT) + lastT;
-            if (t >= 1f) {
-                t = 1f;
+            if (t >= 1.0f) {
+                t = 1.0f;
                 done = true;
             }
             // even if done = true, if we're here, that means targetLength
@@ -569,6 +840,16 @@
             return t;
         }
 
+        float totalLength() {
+            while (!done) {
+                goToNextLeaf();
+            }
+            // reset LengthIterator:
+            reset();
+
+            return lenAtNextT;
+        }
+
         float lastSegLen() {
             return lastSegLen;
         }
@@ -578,11 +859,11 @@
         private void goToNextLeaf() {
             // We must go to the first ancestor node that has an unvisited
             // right child.
+            final boolean[] _sides = sidesRight;
             int _recLevel = recLevel;
-            final Side[] _sides = sides;
-
             _recLevel--;
-            while(_sides[_recLevel] == Side.RIGHT) {
+
+            while(_sides[_recLevel]) {
                 if (_recLevel == 0) {
                     recLevel = 0;
                     done = true;
@@ -591,32 +872,31 @@
                 _recLevel--;
             }
 
-            _sides[_recLevel] = Side.RIGHT;
+            _sides[_recLevel] = true;
             // optimize arraycopy (8 values faster than 6 = type):
-            System.arraycopy(recCurveStack[_recLevel], 0,
-                             recCurveStack[_recLevel+1], 0, 8);
-            _recLevel++;
-
+            System.arraycopy(recCurveStack[_recLevel++], 0,
+                             recCurveStack[_recLevel], 0, 8);
             recLevel = _recLevel;
             goLeft();
         }
 
         // go to the leftmost node from the current node. Return its length.
         private void goLeft() {
-            float len = onLeaf();
-            if (len >= 0f) {
+            final float len = onLeaf();
+            if (len >= 0.0f) {
                 lastT = nextT;
                 lenAtLastT = lenAtNextT;
                 nextT += (1 << (REC_LIMIT - recLevel)) * MIN_T_INC;
                 lenAtNextT += len;
                 // invalidate caches
-                flatLeafCoefCache[2] = -1f;
+                flatLeafCoefCache[2] = -1.0f;
                 cachedHaveLowAcceleration = -1;
             } else {
-                Helpers.subdivide(recCurveStack[recLevel], 0,
-                                  recCurveStack[recLevel+1], 0,
-                                  recCurveStack[recLevel], 0, curveType);
-                sides[recLevel] = Side.LEFT;
+                Helpers.subdivide(recCurveStack[recLevel],
+                                  recCurveStack[recLevel + 1],
+                                  recCurveStack[recLevel], curveType);
+
+                sidesRight[recLevel] = false;
                 recLevel++;
                 goLeft();
             }
@@ -625,67 +905,226 @@
         // this is a bit of a hack. It returns -1 if we're not on a leaf, and
         // the length of the leaf if we are on a leaf.
         private float onLeaf() {
-            float[] curve = recCurveStack[recLevel];
-            float polyLen = 0f;
+            final float[] curve = recCurveStack[recLevel];
+            final int _curveType = curveType;
+            float polyLen = 0.0f;
 
             float x0 = curve[0], y0 = curve[1];
-            for (int i = 2; i < curveType; i += 2) {
-                final float x1 = curve[i], y1 = curve[i+1];
+            for (int i = 2; i < _curveType; i += 2) {
+                final float x1 = curve[i], y1 = curve[i + 1];
                 final float len = Helpers.linelen(x0, y0, x1, y1);
                 polyLen += len;
-                curLeafCtrlPolyLengths[i/2 - 1] = len;
+                curLeafCtrlPolyLengths[(i >> 1) - 1] = len;
                 x0 = x1;
                 y0 = y1;
             }
 
-            final float lineLen = Helpers.linelen(curve[0], curve[1],
-                                                  curve[curveType-2],
-                                                  curve[curveType-1]);
-            if ((polyLen - lineLen) < ERR || recLevel == REC_LIMIT) {
-                return (polyLen + lineLen) / 2f;
+            final float lineLen = Helpers.linelen(curve[0], curve[1], x0, y0);
+
+            if ((polyLen - lineLen) < CURVE_LEN_ERR || recLevel == REC_LIMIT) {
+/*
+                if (recLevel == REC_LIMIT) {
+                    System.out.println("REC_LIMIT[" + recLevel + "] reached !");
+                }
+*/
+                return (polyLen + lineLen) / 2.0f;
             }
-            return -1f;
+            return -1.0f;
         }
     }
 
     @Override
-    public void curveTo(float x1, float y1,
-                        float x2, float y2,
-                        float x3, float y3)
+    public void curveTo(final float x1, final float y1,
+                        final float x2, final float y2,
+                        final float x3, final float y3)
+    {
+        final int outcode0 = this.cOutCode;
+
+        if (clipRect != null) {
+            final int outcode1 = Helpers.outcode(x1, y1, clipRect);
+            final int outcode2 = Helpers.outcode(x2, y2, clipRect);
+            final int outcode3 = Helpers.outcode(x3, y3, clipRect);
+
+            // Should clip
+            final int orCode = (outcode0 | outcode1 | outcode2 | outcode3);
+            if (orCode != 0) {
+                final int sideCode = outcode0 & outcode1 & outcode2 & outcode3;
+
+                // basic rejection criteria:
+                if (sideCode == 0) {
+                    // ovelap clip:
+                    if (subdivide) {
+                        // avoid reentrance
+                        subdivide = false;
+                        // subdivide curve => callback with subdivided parts:
+                        boolean ret = curveSplitter.splitCurve(cx0, cy0, x1, y1, x2, y2, x3, y3,
+                                                               orCode, this);
+                        // reentrance is done:
+                        subdivide = true;
+                        if (ret) {
+                            return;
+                        }
+                    }
+                    // already subdivided so render it
+                } else {
+                    this.cOutCode = outcode3;
+                    skipCurveTo(x1, y1, x2, y2, x3, y3);
+                    return;
+                }
+            }
+
+            this.cOutCode = outcode3;
+
+            if (this.outside) {
+                this.outside = false;
+                // Adjust current index, phase & dash:
+                skipLen();
+            }
+        }
+        _curveTo(x1, y1, x2, y2, x3, y3);
+    }
+
+    private void _curveTo(final float x1, final float y1,
+                          final float x2, final float y2,
+                          final float x3, final float y3)
     {
         final float[] _curCurvepts = curCurvepts;
-        _curCurvepts[0] = x0;        _curCurvepts[1] = y0;
-        _curCurvepts[2] = x1;        _curCurvepts[3] = y1;
-        _curCurvepts[4] = x2;        _curCurvepts[5] = y2;
-        _curCurvepts[6] = x3;        _curCurvepts[7] = y3;
-        somethingTo(8);
+
+        // monotonize curve:
+        final CurveBasicMonotonizer monotonizer
+            = rdrCtx.monotonizer.curve(cx0, cy0, x1, y1, x2, y2, x3, y3);
+
+        final int nSplits = monotonizer.nbSplits;
+        final float[] mid = monotonizer.middle;
+
+        for (int i = 0, off = 0; i <= nSplits; i++, off += 6) {
+/*
+            System.out.println("Part Curve "+Arrays.toString(Arrays.copyOfRange(mid, off, off + 8)));
+*/
+            // optimize arraycopy (8 values faster than 6 = type):
+            System.arraycopy(mid, off, _curCurvepts, 0, 8);
+
+            somethingTo(8);
+        }
+    }
+
+    private void skipCurveTo(final float x1, final float y1,
+                             final float x2, final float y2,
+                             final float x3, final float y3)
+    {
+        final float[] _curCurvepts = curCurvepts;
+        _curCurvepts[0] = cx0; _curCurvepts[1] = cy0;
+        _curCurvepts[2] = x1;  _curCurvepts[3] = y1;
+        _curCurvepts[4] = x2;  _curCurvepts[5] = y2;
+        _curCurvepts[6] = x3;  _curCurvepts[7] = y3;
+
+        skipSomethingTo(8);
+
+        this.cx0 = x3;
+        this.cy0 = y3;
     }
 
     @Override
-    public void quadTo(float x1, float y1, float x2, float y2) {
+    public void quadTo(final float x1, final float y1,
+                       final float x2, final float y2)
+    {
+        final int outcode0 = this.cOutCode;
+
+        if (clipRect != null) {
+            final int outcode1 = Helpers.outcode(x1, y1, clipRect);
+            final int outcode2 = Helpers.outcode(x2, y2, clipRect);
+
+            // Should clip
+            final int orCode = (outcode0 | outcode1 | outcode2);
+            if (orCode != 0) {
+                final int sideCode = outcode0 & outcode1 & outcode2;
+
+                // basic rejection criteria:
+                if (sideCode == 0) {
+                    // ovelap clip:
+                    if (subdivide) {
+                        // avoid reentrance
+                        subdivide = false;
+                        // subdivide curve => call lineTo() with subdivided curves:
+                        boolean ret = curveSplitter.splitQuad(cx0, cy0, x1, y1,
+                                                              x2, y2, orCode, this);
+                        // reentrance is done:
+                        subdivide = true;
+                        if (ret) {
+                            return;
+                        }
+                    }
+                    // already subdivided so render it
+                } else {
+                    this.cOutCode = outcode2;
+                    skipQuadTo(x1, y1, x2, y2);
+                    return;
+                }
+            }
+
+            this.cOutCode = outcode2;
+
+            if (this.outside) {
+                this.outside = false;
+                // Adjust current index, phase & dash:
+                skipLen();
+            }
+        }
+        _quadTo(x1, y1, x2, y2);
+    }
+
+    private void _quadTo(final float x1, final float y1,
+                         final float x2, final float y2)
+    {
         final float[] _curCurvepts = curCurvepts;
-        _curCurvepts[0] = x0;        _curCurvepts[1] = y0;
-        _curCurvepts[2] = x1;        _curCurvepts[3] = y1;
-        _curCurvepts[4] = x2;        _curCurvepts[5] = y2;
-        somethingTo(6);
+
+        // monotonize quad:
+        final CurveBasicMonotonizer monotonizer
+            = rdrCtx.monotonizer.quad(cx0, cy0, x1, y1, x2, y2);
+
+        final int nSplits = monotonizer.nbSplits;
+        final float[] mid = monotonizer.middle;
+
+        for (int i = 0, off = 0; i <= nSplits; i++, off += 4) {
+            // optimize arraycopy (8 values faster than 6 = type):
+            System.arraycopy(mid, off, _curCurvepts, 0, 8);
+
+            somethingTo(6);
+        }
+    }
+
+    private void skipQuadTo(final float x1, final float y1,
+                            final float x2, final float y2)
+    {
+        final float[] _curCurvepts = curCurvepts;
+        _curCurvepts[0] = cx0; _curCurvepts[1] = cy0;
+        _curCurvepts[2] = x1;  _curCurvepts[3] = y1;
+        _curCurvepts[4] = x2;  _curCurvepts[5] = y2;
+
+        skipSomethingTo(6);
+
+        this.cx0 = x2;
+        this.cy0 = y2;
     }
 
     @Override
     public void closePath() {
-        lineTo(sx, sy);
-        if (firstSegidx > 0) {
+        if (cx0 != sx0 || cy0 != sy0) {
+            lineTo(sx0, sy0);
+        }
+        if (firstSegidx != 0) {
             if (!dashOn || needsMoveTo) {
-                out.moveTo(sx, sy);
+                out.moveTo(sx0, sy0);
             }
             emitFirstSegments();
         }
-        moveTo(sx, sy);
+        moveTo(sx0, sy0);
     }
 
     @Override
     public void pathDone() {
-        if (firstSegidx > 0) {
-            out.moveTo(sx, sy);
+        if (firstSegidx != 0) {
+            out.moveTo(sx0, sy0);
             emitFirstSegments();
         }
         out.pathDone();
diff --git a/src/share/classes/sun/java2d/marlin/DoubleArrayCache.java b/src/share/classes/sun/java2d/marlin/DoubleArrayCache.java
new file mode 100644
index 0000000..bbd6853
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/DoubleArrayCache.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d.marlin;
+
+import static sun.java2d.marlin.ArrayCacheConst.ARRAY_SIZES;
+import static sun.java2d.marlin.ArrayCacheConst.BUCKETS;
+import static sun.java2d.marlin.ArrayCacheConst.MAX_ARRAY_SIZE;
+import static sun.java2d.marlin.MarlinUtils.logInfo;
+import static sun.java2d.marlin.MarlinUtils.logException;
+
+import java.lang.ref.WeakReference;
+import java.util.Arrays;
+
+import sun.java2d.marlin.ArrayCacheConst.BucketStats;
+import sun.java2d.marlin.ArrayCacheConst.CacheStats;
+
+/*
+ * Note that the [BYTE/INT/FLOAT/DOUBLE]ArrayCache files are nearly identical except
+ * for a few type and name differences. Typically, the [BYTE]ArrayCache.java file
+ * is edited manually and then [INT/FLOAT/DOUBLE]ArrayCache.java
+ * files are generated with the following command lines:
+ */
+// % sed -e 's/(b\yte)[ ]*//g' -e 's/b\yte/int/g' -e 's/B\yte/Int/g' < B\yteArrayCache.java > IntArrayCache.java
+// % sed -e 's/(b\yte)[ ]*0/0.0f/g' -e 's/(b\yte)[ ]*/(float) /g' -e 's/b\yte/float/g' -e 's/B\yte/Float/g' < B\yteArrayCache.java > FloatArrayCache.java
+// % sed -e 's/(b\yte)[ ]*0/0.0d/g' -e 's/(b\yte)[ ]*/(double) /g' -e 's/b\yte/double/g' -e 's/B\yte/Double/g' < B\yteArrayCache.java > DoubleArrayCache.java
+
+final class DoubleArrayCache implements MarlinConst {
+
+    final boolean clean;
+    private final int bucketCapacity;
+    private WeakReference<Bucket[]> refBuckets = null;
+    final CacheStats stats;
+
+    DoubleArrayCache(final boolean clean, final int bucketCapacity) {
+        this.clean = clean;
+        this.bucketCapacity = bucketCapacity;
+        this.stats = (DO_STATS) ?
+            new CacheStats(getLogPrefix(clean) + "DoubleArrayCache") : null;
+    }
+
+    Bucket getCacheBucket(final int length) {
+        final int bucket = ArrayCacheConst.getBucket(length);
+        return getBuckets()[bucket];
+    }
+
+    private Bucket[] getBuckets() {
+        // resolve reference:
+        Bucket[] buckets = (refBuckets != null) ? refBuckets.get() : null;
+
+        // create a new buckets ?
+        if (buckets == null) {
+            buckets = new Bucket[BUCKETS];
+
+            for (int i = 0; i < BUCKETS; i++) {
+                buckets[i] = new Bucket(clean, ARRAY_SIZES[i], bucketCapacity,
+                        (DO_STATS) ? stats.bucketStats[i] : null);
+            }
+
+            // update weak reference:
+            refBuckets = new WeakReference<Bucket[]>(buckets);
+        }
+        return buckets;
+    }
+
+    Reference createRef(final int initialSize) {
+        return new Reference(this, initialSize);
+    }
+
+    static final class Reference {
+
+        // initial array reference (direct access)
+        final double[] initial;
+        private final boolean clean;
+        private final DoubleArrayCache cache;
+
+        Reference(final DoubleArrayCache cache, final int initialSize) {
+            this.cache = cache;
+            this.clean = cache.clean;
+            this.initial = createArray(initialSize);
+            if (DO_STATS) {
+                cache.stats.totalInitial += initialSize;
+            }
+        }
+
+        double[] getArray(final int length) {
+            if (length <= MAX_ARRAY_SIZE) {
+                return cache.getCacheBucket(length).getArray();
+            }
+            if (DO_STATS) {
+                cache.stats.oversize++;
+            }
+            if (DO_LOG_OVERSIZE) {
+                logInfo(getLogPrefix(clean) + "DoubleArrayCache: "
+                        + "getArray[oversize]: length=\t" + length);
+            }
+            return createArray(length);
+        }
+
+        double[] widenArray(final double[] array, final int usedSize,
+                          final int needSize)
+        {
+            final int length = array.length;
+            if (DO_CHECKS && length >= needSize) {
+                return array;
+            }
+            if (DO_STATS) {
+                cache.stats.resize++;
+            }
+
+            // maybe change bucket:
+            // ensure getNewSize() > newSize:
+            final double[] res = getArray(ArrayCacheConst.getNewSize(usedSize, needSize));
+
+            // use wrapper to ensure proper copy:
+            System.arraycopy(array, 0, res, 0, usedSize); // copy only used elements
+
+            // maybe return current array:
+            putArray(array, 0, usedSize); // ensure array is cleared
+
+            if (DO_LOG_WIDEN_ARRAY) {
+                logInfo(getLogPrefix(clean) + "DoubleArrayCache: "
+                        + "widenArray[" + res.length
+                        + "]: usedSize=\t" + usedSize + "\tlength=\t" + length
+                        + "\tneeded length=\t" + needSize);
+            }
+            return res;
+        }
+
+        double[] putArray(final double[] array)
+        {
+            // dirty array helper:
+            return putArray(array, 0, array.length);
+        }
+
+        double[] putArray(final double[] array, final int fromIndex,
+                        final int toIndex)
+        {
+            if (array.length <= MAX_ARRAY_SIZE) {
+                if ((clean || DO_CLEAN_DIRTY) && (toIndex != 0)) {
+                    // clean-up array of dirty part[fromIndex; toIndex[
+                    fill(array, fromIndex, toIndex, 0.0d);
+                }
+                // ensure to never store initial arrays in cache:
+                if (array != initial) {
+                    cache.getCacheBucket(array.length).putArray(array);
+                }
+            }
+            return initial;
+        }
+    }
+
+    static final class Bucket {
+
+        private int tail = 0;
+        private final int arraySize;
+        private final boolean clean;
+        private final double[][] arrays;
+        private final BucketStats stats;
+
+        Bucket(final boolean clean, final int arraySize,
+               final int capacity, final BucketStats stats)
+        {
+            this.arraySize = arraySize;
+            this.clean = clean;
+            this.stats = stats;
+            this.arrays = new double[capacity][];
+        }
+
+        double[] getArray() {
+            if (DO_STATS) {
+                stats.getOp++;
+            }
+            // use cache:
+            if (tail != 0) {
+                final double[] array = arrays[--tail];
+                arrays[tail] = null;
+                return array;
+            }
+            if (DO_STATS) {
+                stats.createOp++;
+            }
+            return createArray(arraySize);
+        }
+
+        void putArray(final double[] array)
+        {
+            if (DO_CHECKS && (array.length != arraySize)) {
+                logInfo(getLogPrefix(clean) + "DoubleArrayCache: "
+                        + "bad length = " + array.length);
+                return;
+            }
+            if (DO_STATS) {
+                stats.returnOp++;
+            }
+            // fill cache:
+            if (arrays.length > tail) {
+                arrays[tail++] = array;
+
+                if (DO_STATS) {
+                    stats.updateMaxSize(tail);
+                }
+            } else if (DO_CHECKS) {
+                logInfo(getLogPrefix(clean) + "DoubleArrayCache: "
+                        + "array capacity exceeded !");
+            }
+        }
+    }
+
+    static double[] createArray(final int length) {
+        return new double[length];
+    }
+
+    static void fill(final double[] array, final int fromIndex,
+                     final int toIndex, final double value)
+    {
+        // clear array data:
+        Arrays.fill(array, fromIndex, toIndex, value);
+        if (DO_CHECKS) {
+            check(array, fromIndex, toIndex, value);
+        }
+    }
+
+    static void check(final double[] array, final int fromIndex,
+                      final int toIndex, final double value)
+    {
+        if (DO_CHECKS) {
+            // check zero on full array:
+            for (int i = 0; i < array.length; i++) {
+                if (array[i] != value) {
+                    logException("Invalid value at: " + i + " = " + array[i]
+                            + " from: " + fromIndex + " to: " + toIndex + "\n"
+                            + Arrays.toString(array), new Throwable());
+
+                    // ensure array is correctly filled:
+                    Arrays.fill(array, value);
+
+                    return;
+                }
+            }
+        }
+    }
+
+    static String getLogPrefix(final boolean clean) {
+        return (clean) ? "Clean" : "Dirty";
+    }
+}
diff --git a/src/share/classes/sun/java2d/marlin/FloatArrayCache.java b/src/share/classes/sun/java2d/marlin/FloatArrayCache.java
index 87876b8..ff84aa6 100644
--- a/src/share/classes/sun/java2d/marlin/FloatArrayCache.java
+++ b/src/share/classes/sun/java2d/marlin/FloatArrayCache.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, 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
@@ -25,107 +25,219 @@
 
 package sun.java2d.marlin;
 
-import java.util.ArrayDeque;
-import java.util.Arrays;
-import static sun.java2d.marlin.MarlinUtils.logException;
+import static sun.java2d.marlin.ArrayCacheConst.ARRAY_SIZES;
+import static sun.java2d.marlin.ArrayCacheConst.BUCKETS;
+import static sun.java2d.marlin.ArrayCacheConst.MAX_ARRAY_SIZE;
 import static sun.java2d.marlin.MarlinUtils.logInfo;
+import static sun.java2d.marlin.MarlinUtils.logException;
+
+import java.lang.ref.WeakReference;
+import java.util.Arrays;
+
+import sun.java2d.marlin.ArrayCacheConst.BucketStats;
+import sun.java2d.marlin.ArrayCacheConst.CacheStats;
+
+/*
+ * Note that the [BYTE/INT/FLOAT/DOUBLE]ArrayCache files are nearly identical except
+ * for a few type and name differences. Typically, the [BYTE]ArrayCache.java file
+ * is edited manually and then [INT/FLOAT/DOUBLE]ArrayCache.java
+ * files are generated with the following command lines:
+ */
+// % sed -e 's/(b\yte)[ ]*//g' -e 's/b\yte/int/g' -e 's/B\yte/Int/g' < B\yteArrayCache.java > IntArrayCache.java
+// % sed -e 's/(b\yte)[ ]*0/0.0f/g' -e 's/(b\yte)[ ]*/(float) /g' -e 's/b\yte/float/g' -e 's/B\yte/Float/g' < B\yteArrayCache.java > FloatArrayCache.java
+// % sed -e 's/(b\yte)[ ]*0/0.0d/g' -e 's/(b\yte)[ ]*/(double) /g' -e 's/b\yte/double/g' -e 's/B\yte/Double/g' < B\yteArrayCache.java > DoubleArrayCache.java
 
 final class FloatArrayCache implements MarlinConst {
 
-    private final int arraySize;
-    private final ArrayDeque<float[]> floatArrays;
-    // stats
-    private int getOp = 0;
-    private int createOp = 0;
-    private int returnOp = 0;
+    final boolean clean;
+    private final int bucketCapacity;
+    private WeakReference<Bucket[]> refBuckets = null;
+    final CacheStats stats;
 
-    void dumpStats() {
-        if (getOp > 0) {
-            logInfo("FloatArrayCache[" + arraySize + "]: get: " + getOp
-                    + " created: " + createOp + " - returned: " + returnOp
-                    + " :: cache size: " + floatArrays.size());
-        }
+    FloatArrayCache(final boolean clean, final int bucketCapacity) {
+        this.clean = clean;
+        this.bucketCapacity = bucketCapacity;
+        this.stats = (DO_STATS) ?
+            new CacheStats(getLogPrefix(clean) + "FloatArrayCache") : null;
     }
 
-    FloatArrayCache(final int arraySize) {
-        this.arraySize = arraySize;
-        // small but enough: almost 1 cache line
-        this.floatArrays = new ArrayDeque<float[]>(6);
+    Bucket getCacheBucket(final int length) {
+        final int bucket = ArrayCacheConst.getBucket(length);
+        return getBuckets()[bucket];
     }
 
-    float[] getArray() {
-        if (DO_STATS) {
-            getOp++;
-        }
+    private Bucket[] getBuckets() {
+        // resolve reference:
+        Bucket[] buckets = (refBuckets != null) ? refBuckets.get() : null;
 
-        // use cache
-        final float[] array = floatArrays.pollLast();
+        // create a new buckets ?
+        if (buckets == null) {
+            buckets = new Bucket[BUCKETS];
 
-        if (array != null) {
-            return array;
-        }
-
-        if (DO_STATS) {
-            createOp++;
-        }
-
-        return new float[arraySize];
-    }
-
-    void putDirtyArray(final float[] array, final int length) {
-        if (length != arraySize) {
-            if (DO_CHECKS) {
-                MarlinUtils.logInfo("ArrayCache: bad length = " + length);
+            for (int i = 0; i < BUCKETS; i++) {
+                buckets[i] = new Bucket(clean, ARRAY_SIZES[i], bucketCapacity,
+                        (DO_STATS) ? stats.bucketStats[i] : null);
             }
-            return;
-        }
-        if (DO_STATS) {
-            returnOp++;
-        }
 
-        // NO clean-up of array data = DIRTY ARRAY
-
-        if (DO_CLEAN_DIRTY) {
-            // Force zero-fill dirty arrays:
-            Arrays.fill(array, 0, array.length, 0f);
+            // update weak reference:
+            refBuckets = new WeakReference<Bucket[]>(buckets);
         }
-
-        // fill cache:
-        floatArrays.addLast(array);
+        return buckets;
     }
 
-    void putArray(final float[] array, final int length,
-                  final int fromIndex, final int toIndex)
-    {
-        if (length != arraySize) {
-            if (DO_CHECKS) {
-                MarlinUtils.logInfo("ArrayCache: bad length = " + length);
+    Reference createRef(final int initialSize) {
+        return new Reference(this, initialSize);
+    }
+
+    static final class Reference {
+
+        // initial array reference (direct access)
+        final float[] initial;
+        private final boolean clean;
+        private final FloatArrayCache cache;
+
+        Reference(final FloatArrayCache cache, final int initialSize) {
+            this.cache = cache;
+            this.clean = cache.clean;
+            this.initial = createArray(initialSize);
+            if (DO_STATS) {
+                cache.stats.totalInitial += initialSize;
             }
-            return;
-        }
-        if (DO_STATS) {
-            returnOp++;
         }
 
-        // clean-up array of dirty part[fromIndex; toIndex[
-        fill(array, fromIndex, toIndex, 0f);
+        float[] getArray(final int length) {
+            if (length <= MAX_ARRAY_SIZE) {
+                return cache.getCacheBucket(length).getArray();
+            }
+            if (DO_STATS) {
+                cache.stats.oversize++;
+            }
+            if (DO_LOG_OVERSIZE) {
+                logInfo(getLogPrefix(clean) + "FloatArrayCache: "
+                        + "getArray[oversize]: length=\t" + length);
+            }
+            return createArray(length);
+        }
 
-        // fill cache:
-        floatArrays.addLast(array);
+        float[] widenArray(final float[] array, final int usedSize,
+                          final int needSize)
+        {
+            final int length = array.length;
+            if (DO_CHECKS && length >= needSize) {
+                return array;
+            }
+            if (DO_STATS) {
+                cache.stats.resize++;
+            }
+
+            // maybe change bucket:
+            // ensure getNewSize() > newSize:
+            final float[] res = getArray(ArrayCacheConst.getNewSize(usedSize, needSize));
+
+            // use wrapper to ensure proper copy:
+            System.arraycopy(array, 0, res, 0, usedSize); // copy only used elements
+
+            // maybe return current array:
+            putArray(array, 0, usedSize); // ensure array is cleared
+
+            if (DO_LOG_WIDEN_ARRAY) {
+                logInfo(getLogPrefix(clean) + "FloatArrayCache: "
+                        + "widenArray[" + res.length
+                        + "]: usedSize=\t" + usedSize + "\tlength=\t" + length
+                        + "\tneeded length=\t" + needSize);
+            }
+            return res;
+        }
+
+        float[] putArray(final float[] array)
+        {
+            // dirty array helper:
+            return putArray(array, 0, array.length);
+        }
+
+        float[] putArray(final float[] array, final int fromIndex,
+                        final int toIndex)
+        {
+            if (array.length <= MAX_ARRAY_SIZE) {
+                if ((clean || DO_CLEAN_DIRTY) && (toIndex != 0)) {
+                    // clean-up array of dirty part[fromIndex; toIndex[
+                    fill(array, fromIndex, toIndex, 0.0f);
+                }
+                // ensure to never store initial arrays in cache:
+                if (array != initial) {
+                    cache.getCacheBucket(array.length).putArray(array);
+                }
+            }
+            return initial;
+        }
+    }
+
+    static final class Bucket {
+
+        private int tail = 0;
+        private final int arraySize;
+        private final boolean clean;
+        private final float[][] arrays;
+        private final BucketStats stats;
+
+        Bucket(final boolean clean, final int arraySize,
+               final int capacity, final BucketStats stats)
+        {
+            this.arraySize = arraySize;
+            this.clean = clean;
+            this.stats = stats;
+            this.arrays = new float[capacity][];
+        }
+
+        float[] getArray() {
+            if (DO_STATS) {
+                stats.getOp++;
+            }
+            // use cache:
+            if (tail != 0) {
+                final float[] array = arrays[--tail];
+                arrays[tail] = null;
+                return array;
+            }
+            if (DO_STATS) {
+                stats.createOp++;
+            }
+            return createArray(arraySize);
+        }
+
+        void putArray(final float[] array)
+        {
+            if (DO_CHECKS && (array.length != arraySize)) {
+                logInfo(getLogPrefix(clean) + "FloatArrayCache: "
+                        + "bad length = " + array.length);
+                return;
+            }
+            if (DO_STATS) {
+                stats.returnOp++;
+            }
+            // fill cache:
+            if (arrays.length > tail) {
+                arrays[tail++] = array;
+
+                if (DO_STATS) {
+                    stats.updateMaxSize(tail);
+                }
+            } else if (DO_CHECKS) {
+                logInfo(getLogPrefix(clean) + "FloatArrayCache: "
+                        + "array capacity exceeded !");
+            }
+        }
+    }
+
+    static float[] createArray(final int length) {
+        return new float[length];
     }
 
     static void fill(final float[] array, final int fromIndex,
                      final int toIndex, final float value)
     {
         // clear array data:
-        /*
-         * Arrays.fill is faster than System.arraycopy(empty array)
-         * or Unsafe.setMemory(byte 0)
-         */
-        if (toIndex != 0) {
-            Arrays.fill(array, fromIndex, toIndex, value);
-        }
-
+        Arrays.fill(array, fromIndex, toIndex, value);
         if (DO_CHECKS) {
             check(array, fromIndex, toIndex, value);
         }
@@ -150,4 +262,8 @@
             }
         }
     }
+
+    static String getLogPrefix(final boolean clean) {
+        return (clean) ? "Clean" : "Dirty";
+    }
 }
diff --git a/src/share/classes/sun/java2d/marlin/FloatMath.java b/src/share/classes/sun/java2d/marlin/FloatMath.java
index 81dc6f7..56e4488 100644
--- a/src/share/classes/sun/java2d/marlin/FloatMath.java
+++ b/src/share/classes/sun/java2d/marlin/FloatMath.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, 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
@@ -22,9 +22,8 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-package sun.java2d.marlin;
 
-import sun.misc.FloatConsts;
+package sun.java2d.marlin;
 
 /**
  * Faster Math ceil / floor routines derived from StrictMath
@@ -34,17 +33,17 @@
     // overflow / NaN handling enabled:
     static final boolean CHECK_OVERFLOW = true;
     static final boolean CHECK_NAN = true;
+    // Copied from sun.misc.FloatConsts:
+    public static final int FLOAT_SIGNIFICAND_WIDTH = 24;   // sun.misc.FloatConsts.SIGNIFICAND_WIDTH
+    public static final int FLOAT_EXP_BIAS = 127;           // sun.misc.FloatConsts.EXP_BIAS
+    public static final int FLOAT_EXP_BIT_MASK = 2139095040;// sun.misc.FloatConsts.EXP_BIT_MASK
+    public static final int FLOAT_SIGNIF_BIT_MASK = 8388607;// sun.misc.FloatConsts.SIGNIF_BIT_MASK
 
     private FloatMath() {
         // utility class
     }
 
     // faster inlined min/max functions in the branch prediction is high
-    static float max(final float a, final float b) {
-        // no NaN handling
-        return (a >= b) ? a : b;
-    }
-
     static int max(final int a, final int b) {
         return (a >= b) ? a : b;
     }
@@ -77,9 +76,9 @@
         // compute only once Float.floatToRawIntBits(a)
         final int doppel = Float.floatToRawIntBits(a);
 
-        final int exponent = ((doppel & FloatConsts.EXP_BIT_MASK)
-                >> (FloatConsts.SIGNIFICAND_WIDTH - 1))
-                - FloatConsts.EXP_BIAS;
+        final int exponent = ((doppel & FLOAT_EXP_BIT_MASK)
+                >> (FLOAT_SIGNIFICAND_WIDTH - 1))
+                - FLOAT_EXP_BIAS;
 
         if (exponent < 0) {
             /*
@@ -87,8 +86,8 @@
              * floorOrceil(-0.0) => -0.0
              * floorOrceil(+0.0) => +0.0
              */
-            return ((a == 0) ? a :
-                    ( (a < 0f) ? -0f : 1f) );
+            return ((a == 0.0f) ? a :
+                    ( (a < 0.0f) ? -0.0f : 1.0f) );
         }
         if (CHECK_OVERFLOW && (exponent >= 23)) { // 52 for double
             /*
@@ -101,7 +100,7 @@
         assert exponent >= 0 && exponent <= 22; // 51 for double
 
         final int intpart = doppel
-                & (~(FloatConsts.SIGNIF_BIT_MASK >> exponent));
+                & (~(FLOAT_SIGNIF_BIT_MASK >> exponent));
 
         if (intpart == doppel) {
             return a; // integral value (including 0)
@@ -134,9 +133,9 @@
         // compute only once Float.floatToRawIntBits(a)
         final int doppel = Float.floatToRawIntBits(a);
 
-        final int exponent = ((doppel & FloatConsts.EXP_BIT_MASK)
-                >> (FloatConsts.SIGNIFICAND_WIDTH - 1))
-                - FloatConsts.EXP_BIAS;
+        final int exponent = ((doppel & FLOAT_EXP_BIT_MASK)
+                >> (FLOAT_SIGNIFICAND_WIDTH - 1))
+                - FLOAT_EXP_BIAS;
 
         if (exponent < 0) {
             /*
@@ -144,8 +143,8 @@
              * floorOrceil(-0.0) => -0.0
              * floorOrceil(+0.0) => +0.0
              */
-            return ((a == 0) ? a :
-                    ( (a < 0f) ? -1f : 0f) );
+            return ((a == 0.0f) ? a :
+                    ( (a < 0.0f) ? -1.0f : 0.0f) );
         }
         if (CHECK_OVERFLOW && (exponent >= 23)) { // 52 for double
             /*
@@ -158,7 +157,7 @@
         assert exponent >= 0 && exponent <= 22; // 51 for double
 
         final int intpart = doppel
-                & (~(FloatConsts.SIGNIF_BIT_MASK >> exponent));
+                & (~(FLOAT_SIGNIF_BIT_MASK >> exponent));
 
         if (intpart == doppel) {
             return a; // integral value (including 0)
@@ -191,6 +190,26 @@
     }
 
     /**
+     * Faster alternative to ceil(double) optimized for the integer domain
+     * and supporting NaN and +/-Infinity.
+     *
+     * @param a a value.
+     * @return the largest (closest to positive infinity) integer value
+     * that less than or equal to the argument and is equal to a mathematical
+     * integer.
+     */
+    public static int ceil_int(final double a) {
+        final int intpart = (int) a;
+
+        if (a <= intpart
+                || (CHECK_OVERFLOW && intpart == Integer.MAX_VALUE)
+                || CHECK_NAN && Double.isNaN(a)) {
+            return intpart;
+        }
+        return intpart + 1;
+    }
+
+    /**
      * Faster alternative to floor(float) optimized for the integer domain
      * and supporting NaN and +/-Infinity.
      *
@@ -209,4 +228,24 @@
         }
         return intpart - 1;
     }
+
+    /**
+     * Faster alternative to floor(double) optimized for the integer domain
+     * and supporting NaN and +/-Infinity.
+     *
+     * @param a a value.
+     * @return the largest (closest to positive infinity) floating-point value
+     * that less than or equal to the argument and is equal to a mathematical
+     * integer.
+     */
+    public static int floor_int(final double a) {
+        final int intpart = (int) a;
+
+        if (a >= intpart
+                || (CHECK_OVERFLOW && intpart == Integer.MIN_VALUE)
+                || CHECK_NAN && Double.isNaN(a)) {
+            return intpart;
+        }
+        return intpart - 1;
+    }
 }
diff --git a/src/share/classes/sun/java2d/marlin/Helpers.java b/src/share/classes/sun/java2d/marlin/Helpers.java
index 0b0277d..0aa55f7 100644
--- a/src/share/classes/sun/java2d/marlin/Helpers.java
+++ b/src/share/classes/sun/java2d/marlin/Helpers.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, 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
@@ -25,11 +25,10 @@
 
 package sun.java2d.marlin;
 
-import static java.lang.Math.PI;
-import static java.lang.Math.cos;
-import static java.lang.Math.sqrt;
-import static java.lang.Math.cbrt;
-import static java.lang.Math.acos;
+import java.util.Arrays;
+import sun.awt.geom.PathConsumer2D;
+import sun.java2d.marlin.stats.Histogram;
+import sun.java2d.marlin.stats.StatLong;
 
 final class Helpers implements MarlinConst {
 
@@ -47,58 +46,71 @@
         return (d <= err && d >= -err);
     }
 
-    static int quadraticRoots(final float a, final float b,
-                              final float c, float[] zeroes, final int off)
+    public static float evalCubic(final float a, final float b,
+                                  final float c, final float d,
+                                  final float t)
+    {
+        return t * (t * (t * a + b) + c) + d;
+    }
+
+    public static float evalQuad(final float a, final float b,
+                                 final float c, final float t)
+    {
+        return t * (t * a + b) + c;
+    }
+
+    static int quadraticRoots(final float a, final float b, final float c,
+                              final float[] zeroes, final int off)
     {
         int ret = off;
-        float t;
-        if (a != 0f) {
-            final float dis = b*b - 4*a*c;
-            if (dis > 0f) {
-                final float sqrtDis = (float)Math.sqrt(dis);
+        if (a != 0.0f) {
+            final float dis = b*b - 4.0f * a * c;
+            if (dis > 0.0f) {
+                final float sqrtDis = (float) Math.sqrt(dis);
                 // depending on the sign of b we use a slightly different
                 // algorithm than the traditional one to find one of the roots
                 // so we can avoid adding numbers of different signs (which
                 // might result in loss of precision).
-                if (b >= 0f) {
-                    zeroes[ret++] = (2f * c) / (-b - sqrtDis);
-                    zeroes[ret++] = (-b - sqrtDis) / (2f * a);
+                if (b >= 0.0f) {
+                    zeroes[ret++] = (2.0f * c) / (-b - sqrtDis);
+                    zeroes[ret++] = (-b - sqrtDis) / (2.0f * a);
                 } else {
-                    zeroes[ret++] = (-b + sqrtDis) / (2f * a);
-                    zeroes[ret++] = (2f * c) / (-b + sqrtDis);
+                    zeroes[ret++] = (-b + sqrtDis) / (2.0f * a);
+                    zeroes[ret++] = (2.0f * c) / (-b + sqrtDis);
                 }
-            } else if (dis == 0f) {
-                t = (-b) / (2f * a);
-                zeroes[ret++] = t;
+            } else if (dis == 0.0f) {
+                zeroes[ret++] = -b / (2.0f * a);
             }
-        } else {
-            if (b != 0f) {
-                t = (-c) / b;
-                zeroes[ret++] = t;
-            }
+        } else if (b != 0.0f) {
+            zeroes[ret++] = -c / b;
         }
         return ret - off;
     }
 
     // find the roots of g(t) = d*t^3 + a*t^2 + b*t + c in [A,B)
-    static int cubicRootsInAB(float d, float a, float b, float c,
-                              float[] pts, final int off,
+    public static int cubicRootsInAB(final float d0, float a0, float b0, float c0,
+                              final float[] pts, final int off,
                               final float A, final float B)
     {
-        if (d == 0f) {
-            int num = quadraticRoots(a, b, c, pts, off);
+        if (d0 == 0.0f) {
+            final int num = quadraticRoots(a0, b0, c0, pts, off);
             return filterOutNotInAB(pts, off, num, A, B) - off;
         }
         // From Graphics Gems:
-        // http://tog.acm.org/resources/GraphicsGems/gems/Roots3And4.c
+        // https://github.com/erich666/GraphicsGems/blob/master/gems/Roots3And4.c
         // (also from awt.geom.CubicCurve2D. But here we don't need as
         // much accuracy and we don't want to create arrays so we use
         // our own customized version).
 
         // normal form: x^3 + ax^2 + bx + c = 0
-        a /= d;
-        b /= d;
-        c /= d;
+
+        // 2018.1: Need double precision if d is very small (flat curve) !
+        /*
+         * TODO: cleanup all that code after reading Roots3And4.c
+         */
+        final double a = ((double)a0) / d0;
+        final double b = ((double)b0) / d0;
+        final double c = ((double)c0) / d0;
 
         //  substitute x = y - A/3 to eliminate quadratic term:
         //     x^3 +Px + Q = 0
@@ -108,63 +120,45 @@
         // p = P/3
         // q = Q/2
         // instead and use those values for simplicity of the code.
-        double sq_A = a * a;
-        double p = (1.0/3.0) * ((-1.0/3.0) * sq_A + b);
-        double q = (1.0/2.0) * ((2.0/27.0) * a * sq_A - (1.0/3.0) * a * b + c);
+        final double sub = (1.0d / 3.0d) * a;
+        final double sq_A = a * a;
+        final double p = (1.0d / 3.0d) * ((-1.0d / 3.0d) * sq_A + b);
+        final double q = (1.0d / 2.0d) * ((2.0d / 27.0d) * a * sq_A - sub * b + c);
 
         // use Cardano's formula
 
-        double cb_p = p * p * p;
-        double D = q * q + cb_p;
+        final double cb_p = p * p * p;
+        final double D = q * q + cb_p;
 
         int num;
-        if (D < 0.0) {
+        if (D < 0.0d) {
             // see: http://en.wikipedia.org/wiki/Cubic_function#Trigonometric_.28and_hyperbolic.29_method
-            final double phi = (1.0/3.0) * acos(-q / sqrt(-cb_p));
-            final double t = 2.0 * sqrt(-p);
+            final double phi = (1.0d / 3.0d) * Math.acos(-q / Math.sqrt(-cb_p));
+            final double t = 2.0d * Math.sqrt(-p);
 
-            pts[ off+0 ] =  (float)( t * cos(phi));
-            pts[ off+1 ] =  (float)(-t * cos(phi + (PI / 3.0)));
-            pts[ off+2 ] =  (float)(-t * cos(phi - (PI / 3.0)));
+            pts[off    ] = (float) ( t * Math.cos(phi) - sub);
+            pts[off + 1] = (float) (-t * Math.cos(phi + (Math.PI / 3.0d)) - sub);
+            pts[off + 2] = (float) (-t * Math.cos(phi - (Math.PI / 3.0d)) - sub);
             num = 3;
         } else {
-            final double sqrt_D = sqrt(D);
-            final double u = cbrt(sqrt_D - q);
-            final double v = - cbrt(sqrt_D + q);
+            final double sqrt_D = Math.sqrt(D);
+            final double u =   Math.cbrt(sqrt_D - q);
+            final double v = - Math.cbrt(sqrt_D + q);
 
-            pts[ off ] = (float)(u + v);
+            pts[off    ] = (float) (u + v - sub);
             num = 1;
 
-            if (within(D, 0.0, 1e-8)) {
-                pts[off+1] = -(pts[off] / 2f);
+            if (within(D, 0.0d, 1e-8d)) {
+                pts[off + 1] = (float)((-1.0d / 2.0d) * (u + v) - sub);
                 num = 2;
             }
         }
 
-        final float sub = (1f/3f) * a;
-
-        for (int i = 0; i < num; ++i) {
-            pts[ off+i ] -= sub;
-        }
-
         return filterOutNotInAB(pts, off, num, A, B) - off;
     }
 
-    static float evalCubic(final float a, final float b,
-                           final float c, final float d,
-                           final float t)
-    {
-        return t * (t * (t * a + b) + c) + d;
-    }
-
-    static float evalQuad(final float a, final float b,
-                          final float c, final float t)
-    {
-        return t * (t * a + b) + c;
-    }
-
     // returns the index 1 past the last valid element remaining after filtering
-    static int filterOutNotInAB(float[] nums, final int off, final int len,
+    static int filterOutNotInAB(final float[] nums, final int off, final int len,
                                 final float a, final float b)
     {
         int ret = off;
@@ -176,50 +170,199 @@
         return ret;
     }
 
-    static float polyLineLength(float[] poly, final int off, final int nCoords) {
-        assert nCoords % 2 == 0 && poly.length >= off + nCoords : "";
-        float acc = 0;
-        for (int i = off + 2; i < off + nCoords; i += 2) {
-            acc += linelen(poly[i], poly[i+1], poly[i-2], poly[i-1]);
+    static float fastLineLen(final float x0, final float y0,
+                             final float x1, final float y1)
+    {
+        final float dx = x1 - x0;
+        final float dy = y1 - y0;
+
+        // use manhattan norm:
+        return Math.abs(dx) + Math.abs(dy);
+    }
+
+    static float linelen(final float x0, final float y0,
+                         final float x1, final float y1)
+    {
+        final float dx = x1 - x0;
+        final float dy = y1 - y0;
+        return (float) Math.sqrt(dx * dx + dy * dy);
+    }
+
+    static float fastQuadLen(final float x0, final float y0,
+                             final float x1, final float y1,
+                             final float x2, final float y2)
+    {
+        final float dx1 = x1 - x0;
+        final float dx2 = x2 - x1;
+        final float dy1 = y1 - y0;
+        final float dy2 = y2 - y1;
+
+        // use manhattan norm:
+        return Math.abs(dx1) + Math.abs(dx2)
+             + Math.abs(dy1) + Math.abs(dy2);
+    }
+
+    static float quadlen(final float x0, final float y0,
+                         final float x1, final float y1,
+                         final float x2, final float y2)
+    {
+        return (linelen(x0, y0, x1, y1)
+                + linelen(x1, y1, x2, y2)
+                + linelen(x0, y0, x2, y2)) / 2.0f;
+    }
+
+
+    static float fastCurvelen(final float x0, final float y0,
+                              final float x1, final float y1,
+                              final float x2, final float y2,
+                              final float x3, final float y3)
+    {
+        final float dx1 = x1 - x0;
+        final float dx2 = x2 - x1;
+        final float dx3 = x3 - x2;
+        final float dy1 = y1 - y0;
+        final float dy2 = y2 - y1;
+        final float dy3 = y3 - y2;
+
+        // use manhattan norm:
+        return Math.abs(dx1) + Math.abs(dx2) + Math.abs(dx3)
+             + Math.abs(dy1) + Math.abs(dy2) + Math.abs(dy3);
+    }
+
+    static float curvelen(final float x0, final float y0,
+                          final float x1, final float y1,
+                          final float x2, final float y2,
+                          final float x3, final float y3)
+    {
+        return (linelen(x0, y0, x1, y1)
+              + linelen(x1, y1, x2, y2)
+              + linelen(x2, y2, x3, y3)
+              + linelen(x0, y0, x3, y3)) / 2.0f;
+    }
+
+    // finds values of t where the curve in pts should be subdivided in order
+    // to get good offset curves a distance of w away from the middle curve.
+    // Stores the points in ts, and returns how many of them there were.
+    static int findSubdivPoints(final Curve c, final float[] pts,
+                                final float[] ts, final int type,
+                                final float w2)
+    {
+        final float x12 = pts[2] - pts[0];
+        final float y12 = pts[3] - pts[1];
+        // if the curve is already parallel to either axis we gain nothing
+        // from rotating it.
+        if ((y12 != 0.0f && x12 != 0.0f)) {
+            // we rotate it so that the first vector in the control polygon is
+            // parallel to the x-axis. This will ensure that rotated quarter
+            // circles won't be subdivided.
+            final float hypot = (float)Math.sqrt(x12 * x12 + y12 * y12);
+            final float cos = x12 / hypot;
+            final float sin = y12 / hypot;
+            final float x1 = cos * pts[0] + sin * pts[1];
+            final float y1 = cos * pts[1] - sin * pts[0];
+            final float x2 = cos * pts[2] + sin * pts[3];
+            final float y2 = cos * pts[3] - sin * pts[2];
+            final float x3 = cos * pts[4] + sin * pts[5];
+            final float y3 = cos * pts[5] - sin * pts[4];
+
+            switch(type) {
+            case 8:
+                final float x4 = cos * pts[6] + sin * pts[7];
+                final float y4 = cos * pts[7] - sin * pts[6];
+                c.set(x1, y1, x2, y2, x3, y3, x4, y4);
+                break;
+            case 6:
+                c.set(x1, y1, x2, y2, x3, y3);
+                break;
+            default:
+            }
+        } else {
+            c.set(pts, type);
         }
-        return acc;
+
+        int ret = 0;
+        // we subdivide at values of t such that the remaining rotated
+        // curves are monotonic in x and y.
+        ret += c.dxRoots(ts, ret);
+        ret += c.dyRoots(ts, ret);
+
+        // subdivide at inflection points.
+        if (type == 8) {
+            // quadratic curves can't have inflection points
+            ret += c.infPoints(ts, ret);
+        }
+
+        // now we must subdivide at points where one of the offset curves will have
+        // a cusp. This happens at ts where the radius of curvature is equal to w.
+        ret += c.rootsOfROCMinusW(ts, ret, w2, 0.0001f);
+
+        ret = filterOutNotInAB(ts, 0, ret, 0.0001f, 0.9999f);
+        isort(ts, ret);
+        return ret;
     }
 
-    static float linelen(float x1, float y1, float x2, float y2) {
-        final float dx = x2 - x1;
-        final float dy = y2 - y1;
-        return (float)Math.sqrt(dx*dx + dy*dy);
+    // finds values of t where the curve in pts should be subdivided in order
+    // to get intersections with the given clip rectangle.
+    // Stores the points in ts, and returns how many of them there were.
+    static int findClipPoints(final Curve curve, final float[] pts,
+                              final float[] ts, final int type,
+                              final int outCodeOR,
+                              final float[] clipRect)
+    {
+        curve.set(pts, type);
+
+        // clip rectangle (ymin, ymax, xmin, xmax)
+        int ret = 0;
+
+        if ((outCodeOR & OUTCODE_LEFT) != 0) {
+            ret += curve.xPoints(ts, ret, clipRect[2]);
+        }
+        if ((outCodeOR & OUTCODE_RIGHT) != 0) {
+            ret += curve.xPoints(ts, ret, clipRect[3]);
+        }
+        if ((outCodeOR & OUTCODE_TOP) != 0) {
+            ret += curve.yPoints(ts, ret, clipRect[0]);
+        }
+        if ((outCodeOR & OUTCODE_BOTTOM) != 0) {
+            ret += curve.yPoints(ts, ret, clipRect[1]);
+        }
+        isort(ts, ret);
+        return ret;
     }
 
-    static void subdivide(float[] src, int srcoff, float[] left, int leftoff,
-                          float[] right, int rightoff, int type)
+    static void subdivide(final float[] src,
+                          final float[] left, final float[] right,
+                          final int type)
     {
         switch(type) {
+        case 4:
+            subdivideLine(src, left, right);
+            return;
         case 6:
-            Helpers.subdivideQuad(src, srcoff, left, leftoff, right, rightoff);
+            subdivideQuad(src, left, right);
             return;
         case 8:
-            Helpers.subdivideCubic(src, srcoff, left, leftoff, right, rightoff);
+            subdivideCubic(src, left, right);
             return;
         default:
             throw new InternalError("Unsupported curve type");
         }
     }
 
-    static void isort(float[] a, int off, int len) {
-        for (int i = off + 1, end = off + len; i < end; i++) {
-            float ai = a[i];
-            int j = i - 1;
-            for (; j >= off && a[j] > ai; j--) {
-                a[j+1] = a[j];
+    static void isort(final float[] a, final int len) {
+        for (int i = 1, j; i < len; i++) {
+            final float ai = a[i];
+            j = i - 1;
+            for (; j >= 0 && a[j] > ai; j--) {
+                a[j + 1] = a[j];
             }
-            a[j+1] = ai;
+            a[j + 1] = ai;
         }
     }
 
     // Most of these are copied from classes in java.awt.geom because we need
-    // float versions of these functions, and Line2D, CubicCurve2D,
-    // QuadCurve2D don't provide them.
+    // both single and double precision variants of these functions, and Line2D,
+    // CubicCurve2D, QuadCurve2D don't provide them.
     /**
      * Subdivides the cubic curve specified by the coordinates
      * stored in the <code>src</code> array at indices <code>srcoff</code>
@@ -236,206 +379,625 @@
      * equals (<code>leftoff</code> + 6), in order
      * to avoid allocating extra storage for this common point.
      * @param src the array holding the coordinates for the source curve
-     * @param srcoff the offset into the array of the beginning of the
-     * the 6 source coordinates
      * @param left the array for storing the coordinates for the first
      * half of the subdivided curve
-     * @param leftoff the offset into the array of the beginning of the
-     * the 6 left coordinates
      * @param right the array for storing the coordinates for the second
      * half of the subdivided curve
-     * @param rightoff the offset into the array of the beginning of the
-     * the 6 right coordinates
      * @since 1.7
      */
-    static void subdivideCubic(float[] src, int srcoff,
-                               float[] left, int leftoff,
-                               float[] right, int rightoff)
+    static void subdivideCubic(final float[] src,
+                               final float[] left,
+                               final float[] right)
     {
-        float x1 = src[srcoff + 0];
-        float y1 = src[srcoff + 1];
-        float ctrlx1 = src[srcoff + 2];
-        float ctrly1 = src[srcoff + 3];
-        float ctrlx2 = src[srcoff + 4];
-        float ctrly2 = src[srcoff + 5];
-        float x2 = src[srcoff + 6];
-        float y2 = src[srcoff + 7];
-        if (left != null) {
-            left[leftoff + 0] = x1;
-            left[leftoff + 1] = y1;
-        }
-        if (right != null) {
-            right[rightoff + 6] = x2;
-            right[rightoff + 7] = y2;
-        }
-        x1 = (x1 + ctrlx1) / 2f;
-        y1 = (y1 + ctrly1) / 2f;
-        x2 = (x2 + ctrlx2) / 2f;
-        y2 = (y2 + ctrly2) / 2f;
-        float centerx = (ctrlx1 + ctrlx2) / 2f;
-        float centery = (ctrly1 + ctrly2) / 2f;
-        ctrlx1 = (x1 + centerx) / 2f;
-        ctrly1 = (y1 + centery) / 2f;
-        ctrlx2 = (x2 + centerx) / 2f;
-        ctrly2 = (y2 + centery) / 2f;
-        centerx = (ctrlx1 + ctrlx2) / 2f;
-        centery = (ctrly1 + ctrly2) / 2f;
-        if (left != null) {
-            left[leftoff + 2] = x1;
-            left[leftoff + 3] = y1;
-            left[leftoff + 4] = ctrlx1;
-            left[leftoff + 5] = ctrly1;
-            left[leftoff + 6] = centerx;
-            left[leftoff + 7] = centery;
-        }
-        if (right != null) {
-            right[rightoff + 0] = centerx;
-            right[rightoff + 1] = centery;
-            right[rightoff + 2] = ctrlx2;
-            right[rightoff + 3] = ctrly2;
-            right[rightoff + 4] = x2;
-            right[rightoff + 5] = y2;
+        float  x1 = src[0];
+        float  y1 = src[1];
+        float cx1 = src[2];
+        float cy1 = src[3];
+        float cx2 = src[4];
+        float cy2 = src[5];
+        float  x2 = src[6];
+        float  y2 = src[7];
+
+        left[0]  = x1;
+        left[1]  = y1;
+
+        right[6] = x2;
+        right[7] = y2;
+
+        x1 = (x1 + cx1) / 2.0f;
+        y1 = (y1 + cy1) / 2.0f;
+        x2 = (x2 + cx2) / 2.0f;
+        y2 = (y2 + cy2) / 2.0f;
+
+        float cx = (cx1 + cx2) / 2.0f;
+        float cy = (cy1 + cy2) / 2.0f;
+
+        cx1 = (x1 + cx) / 2.0f;
+        cy1 = (y1 + cy) / 2.0f;
+        cx2 = (x2 + cx) / 2.0f;
+        cy2 = (y2 + cy) / 2.0f;
+        cx  = (cx1 + cx2) / 2.0f;
+        cy  = (cy1 + cy2) / 2.0f;
+
+        left[2] = x1;
+        left[3] = y1;
+        left[4] = cx1;
+        left[5] = cy1;
+        left[6] = cx;
+        left[7] = cy;
+
+        right[0] = cx;
+        right[1] = cy;
+        right[2] = cx2;
+        right[3] = cy2;
+        right[4] = x2;
+        right[5] = y2;
+    }
+
+    static void subdivideCubicAt(final float t,
+                                 final float[] src, final int offS,
+                                 final float[] pts, final int offL, final int offR)
+    {
+        float  x1 = src[offS    ];
+        float  y1 = src[offS + 1];
+        float cx1 = src[offS + 2];
+        float cy1 = src[offS + 3];
+        float cx2 = src[offS + 4];
+        float cy2 = src[offS + 5];
+        float  x2 = src[offS + 6];
+        float  y2 = src[offS + 7];
+
+        pts[offL    ] = x1;
+        pts[offL + 1] = y1;
+
+        pts[offR + 6] = x2;
+        pts[offR + 7] = y2;
+
+        x1 =  x1 + t * (cx1 - x1);
+        y1 =  y1 + t * (cy1 - y1);
+        x2 = cx2 + t * (x2 - cx2);
+        y2 = cy2 + t * (y2 - cy2);
+
+        float cx = cx1 + t * (cx2 - cx1);
+        float cy = cy1 + t * (cy2 - cy1);
+
+        cx1 =  x1 + t * (cx - x1);
+        cy1 =  y1 + t * (cy - y1);
+        cx2 =  cx + t * (x2 - cx);
+        cy2 =  cy + t * (y2 - cy);
+        cx  = cx1 + t * (cx2 - cx1);
+        cy  = cy1 + t * (cy2 - cy1);
+
+        pts[offL + 2] = x1;
+        pts[offL + 3] = y1;
+        pts[offL + 4] = cx1;
+        pts[offL + 5] = cy1;
+        pts[offL + 6] = cx;
+        pts[offL + 7] = cy;
+
+        pts[offR    ] = cx;
+        pts[offR + 1] = cy;
+        pts[offR + 2] = cx2;
+        pts[offR + 3] = cy2;
+        pts[offR + 4] = x2;
+        pts[offR + 5] = y2;
+    }
+
+    static void subdivideLine(final float[] src,
+                              final float[] left,
+                              final float[] right)
+    {
+        float x1 = src[0];
+        float y1 = src[1];
+        float x2 = src[2];
+        float y2 = src[3];
+
+        left[0]  = x1;
+        left[1]  = y1;
+
+        right[2] = x2;
+        right[3] = y2;
+
+        float cx = (x1 + x2) / 2.0f;
+        float cy = (y1 + y2) / 2.0f;
+
+        left[2] = cx;
+        left[3] = cy;
+
+        right[0] = cx;
+        right[1] = cy;
+    }
+
+    static void subdivideQuad(final float[] src,
+                              final float[] left,
+                              final float[] right)
+    {
+        float x1 = src[0];
+        float y1 = src[1];
+        float cx = src[2];
+        float cy = src[3];
+        float x2 = src[4];
+        float y2 = src[5];
+
+        left[0]  = x1;
+        left[1]  = y1;
+
+        right[4] = x2;
+        right[5] = y2;
+
+        x1 = (x1 + cx) / 2.0f;
+        y1 = (y1 + cy) / 2.0f;
+        x2 = (x2 + cx) / 2.0f;
+        y2 = (y2 + cy) / 2.0f;
+        cx = (x1 + x2) / 2.0f;
+        cy = (y1 + y2) / 2.0f;
+
+        left[2] = x1;
+        left[3] = y1;
+        left[4] = cx;
+        left[5] = cy;
+
+        right[0] = cx;
+        right[1] = cy;
+        right[2] = x2;
+        right[3] = y2;
+    }
+
+    static void subdivideQuadAt(final float t,
+                                final float[] src, final int offS,
+                                final float[] pts, final int offL, final int offR)
+    {
+        float x1 = src[offS    ];
+        float y1 = src[offS + 1];
+        float cx = src[offS + 2];
+        float cy = src[offS + 3];
+        float x2 = src[offS + 4];
+        float y2 = src[offS + 5];
+
+        pts[offL    ] = x1;
+        pts[offL + 1] = y1;
+
+        pts[offR + 4] = x2;
+        pts[offR + 5] = y2;
+
+        x1 = x1 + t * (cx - x1);
+        y1 = y1 + t * (cy - y1);
+        x2 = cx + t * (x2 - cx);
+        y2 = cy + t * (y2 - cy);
+        cx = x1 + t * (x2 - x1);
+        cy = y1 + t * (y2 - y1);
+
+        pts[offL + 2] = x1;
+        pts[offL + 3] = y1;
+        pts[offL + 4] = cx;
+        pts[offL + 5] = cy;
+
+        pts[offR    ] = cx;
+        pts[offR + 1] = cy;
+        pts[offR + 2] = x2;
+        pts[offR + 3] = y2;
+    }
+
+    static void subdivideLineAt(final float t,
+                                final float[] src, final int offS,
+                                final float[] pts, final int offL, final int offR)
+    {
+        float x1 = src[offS    ];
+        float y1 = src[offS + 1];
+        float x2 = src[offS + 2];
+        float y2 = src[offS + 3];
+
+        pts[offL    ] = x1;
+        pts[offL + 1] = y1;
+
+        pts[offR + 2] = x2;
+        pts[offR + 3] = y2;
+
+        x1 = x1 + t * (x2 - x1);
+        y1 = y1 + t * (y2 - y1);
+
+        pts[offL + 2] = x1;
+        pts[offL + 3] = y1;
+
+        pts[offR    ] = x1;
+        pts[offR + 1] = y1;
+    }
+
+    static void subdivideAt(final float t,
+                            final float[] src, final int offS,
+                            final float[] pts, final int offL, final int type)
+    {
+        // if instead of switch (perf + most probable cases first)
+        if (type == 8) {
+            subdivideCubicAt(t, src, offS, pts, offL, offL + type);
+        } else if (type == 4) {
+            subdivideLineAt(t, src, offS, pts, offL, offL + type);
+        } else {
+            subdivideQuadAt(t, src, offS, pts, offL, offL + type);
         }
     }
 
+    // From sun.java2d.loops.GeneralRenderer:
 
-    static void subdivideCubicAt(float t, float[] src, int srcoff,
-                                 float[] left, int leftoff,
-                                 float[] right, int rightoff)
+    static int outcode(final float x, final float y,
+                       final float[] clipRect)
     {
-        float x1 = src[srcoff + 0];
-        float y1 = src[srcoff + 1];
-        float ctrlx1 = src[srcoff + 2];
-        float ctrly1 = src[srcoff + 3];
-        float ctrlx2 = src[srcoff + 4];
-        float ctrly2 = src[srcoff + 5];
-        float x2 = src[srcoff + 6];
-        float y2 = src[srcoff + 7];
-        if (left != null) {
-            left[leftoff + 0] = x1;
-            left[leftoff + 1] = y1;
+        int code;
+        if (y < clipRect[0]) {
+            code = OUTCODE_TOP;
+        } else if (y >= clipRect[1]) {
+            code = OUTCODE_BOTTOM;
+        } else {
+            code = 0;
         }
-        if (right != null) {
-            right[rightoff + 6] = x2;
-            right[rightoff + 7] = y2;
+        if (x < clipRect[2]) {
+            code |= OUTCODE_LEFT;
+        } else if (x >= clipRect[3]) {
+            code |= OUTCODE_RIGHT;
         }
-        x1 = x1 + t * (ctrlx1 - x1);
-        y1 = y1 + t * (ctrly1 - y1);
-        x2 = ctrlx2 + t * (x2 - ctrlx2);
-        y2 = ctrly2 + t * (y2 - ctrly2);
-        float centerx = ctrlx1 + t * (ctrlx2 - ctrlx1);
-        float centery = ctrly1 + t * (ctrly2 - ctrly1);
-        ctrlx1 = x1 + t * (centerx - x1);
-        ctrly1 = y1 + t * (centery - y1);
-        ctrlx2 = centerx + t * (x2 - centerx);
-        ctrly2 = centery + t * (y2 - centery);
-        centerx = ctrlx1 + t * (ctrlx2 - ctrlx1);
-        centery = ctrly1 + t * (ctrly2 - ctrly1);
-        if (left != null) {
-            left[leftoff + 2] = x1;
-            left[leftoff + 3] = y1;
-            left[leftoff + 4] = ctrlx1;
-            left[leftoff + 5] = ctrly1;
-            left[leftoff + 6] = centerx;
-            left[leftoff + 7] = centery;
+        return code;
+    }
+
+    // a stack of polynomial curves where each curve shares endpoints with
+    // adjacent ones.
+    static final class PolyStack {
+        private static final byte TYPE_LINETO  = (byte) 0;
+        private static final byte TYPE_QUADTO  = (byte) 1;
+        private static final byte TYPE_CUBICTO = (byte) 2;
+
+        // curves capacity = edges count (8192) = edges x 2 (coords)
+        private static final int INITIAL_CURVES_COUNT = INITIAL_EDGES_COUNT << 1;
+
+        // types capacity = edges count (4096)
+        private static final int INITIAL_TYPES_COUNT = INITIAL_EDGES_COUNT;
+
+        float[] curves;
+        int end;
+        byte[] curveTypes;
+        int numCurves;
+
+        // curves ref (dirty)
+        final FloatArrayCache.Reference curves_ref;
+        // curveTypes ref (dirty)
+        final ByteArrayCache.Reference curveTypes_ref;
+
+        // used marks (stats only)
+        int curveTypesUseMark;
+        int curvesUseMark;
+
+        private final StatLong stat_polystack_types;
+        private final StatLong stat_polystack_curves;
+        private final Histogram hist_polystack_curves;
+        private final StatLong stat_array_polystack_curves;
+        private final StatLong stat_array_polystack_curveTypes;
+
+        PolyStack(final RendererContext rdrCtx) {
+            this(rdrCtx, null, null, null, null, null);
         }
-        if (right != null) {
-            right[rightoff + 0] = centerx;
-            right[rightoff + 1] = centery;
-            right[rightoff + 2] = ctrlx2;
-            right[rightoff + 3] = ctrly2;
-            right[rightoff + 4] = x2;
-            right[rightoff + 5] = y2;
+
+        PolyStack(final RendererContext rdrCtx,
+                  final StatLong stat_polystack_types,
+                  final StatLong stat_polystack_curves,
+                  final Histogram hist_polystack_curves,
+                  final StatLong stat_array_polystack_curves,
+                  final StatLong stat_array_polystack_curveTypes)
+        {
+            curves_ref = rdrCtx.newDirtyFloatArrayRef(INITIAL_CURVES_COUNT); // 32K
+            curves     = curves_ref.initial;
+
+            curveTypes_ref = rdrCtx.newDirtyByteArrayRef(INITIAL_TYPES_COUNT); // 4K
+            curveTypes     = curveTypes_ref.initial;
+            numCurves = 0;
+            end = 0;
+
+            if (DO_STATS) {
+                curveTypesUseMark = 0;
+                curvesUseMark = 0;
+            }
+            this.stat_polystack_types = stat_polystack_types;
+            this.stat_polystack_curves = stat_polystack_curves;
+            this.hist_polystack_curves = hist_polystack_curves;
+            this.stat_array_polystack_curves = stat_array_polystack_curves;
+            this.stat_array_polystack_curveTypes = stat_array_polystack_curveTypes;
+        }
+
+        /**
+         * Disposes this PolyStack:
+         * clean up before reusing this instance
+         */
+        void dispose() {
+            end = 0;
+            numCurves = 0;
+
+            if (DO_STATS) {
+                stat_polystack_types.add(curveTypesUseMark);
+                stat_polystack_curves.add(curvesUseMark);
+                hist_polystack_curves.add(curvesUseMark);
+
+                // reset marks
+                curveTypesUseMark = 0;
+                curvesUseMark = 0;
+            }
+
+            // Return arrays:
+            // curves and curveTypes are kept dirty
+            curves     = curves_ref.putArray(curves);
+            curveTypes = curveTypes_ref.putArray(curveTypes);
+        }
+
+        private void ensureSpace(final int n) {
+            // use substraction to avoid integer overflow:
+            if (curves.length - end < n) {
+                if (DO_STATS) {
+                    stat_array_polystack_curves.add(end + n);
+                }
+                curves = curves_ref.widenArray(curves, end, end + n);
+            }
+            if (curveTypes.length <= numCurves) {
+                if (DO_STATS) {
+                    stat_array_polystack_curveTypes.add(numCurves + 1);
+                }
+                curveTypes = curveTypes_ref.widenArray(curveTypes,
+                                                       numCurves,
+                                                       numCurves + 1);
+            }
+        }
+
+        void pushCubic(float x0, float y0,
+                       float x1, float y1,
+                       float x2, float y2)
+        {
+            ensureSpace(6);
+            curveTypes[numCurves++] = TYPE_CUBICTO;
+            // we reverse the coordinate order to make popping easier
+            final float[] _curves = curves;
+            int e = end;
+            _curves[e++] = x2;    _curves[e++] = y2;
+            _curves[e++] = x1;    _curves[e++] = y1;
+            _curves[e++] = x0;    _curves[e++] = y0;
+            end = e;
+        }
+
+        void pushQuad(float x0, float y0,
+                      float x1, float y1)
+        {
+            ensureSpace(4);
+            curveTypes[numCurves++] = TYPE_QUADTO;
+            final float[] _curves = curves;
+            int e = end;
+            _curves[e++] = x1;    _curves[e++] = y1;
+            _curves[e++] = x0;    _curves[e++] = y0;
+            end = e;
+        }
+
+        void pushLine(float x, float y) {
+            ensureSpace(2);
+            curveTypes[numCurves++] = TYPE_LINETO;
+            curves[end++] = x;    curves[end++] = y;
+        }
+
+        void pullAll(final PathConsumer2D io) {
+            final int nc = numCurves;
+            if (nc == 0) {
+                return;
+            }
+            if (DO_STATS) {
+                // update used marks:
+                if (numCurves > curveTypesUseMark) {
+                    curveTypesUseMark = numCurves;
+                }
+                if (end > curvesUseMark) {
+                    curvesUseMark = end;
+                }
+            }
+            final byte[]  _curveTypes = curveTypes;
+            final float[] _curves = curves;
+            int e = 0;
+
+            for (int i = 0; i < nc; i++) {
+                switch(_curveTypes[i]) {
+                case TYPE_LINETO:
+                    io.lineTo(_curves[e], _curves[e+1]);
+                    e += 2;
+                    continue;
+                case TYPE_QUADTO:
+                    io.quadTo(_curves[e],   _curves[e+1],
+                              _curves[e+2], _curves[e+3]);
+                    e += 4;
+                    continue;
+                case TYPE_CUBICTO:
+                    io.curveTo(_curves[e],   _curves[e+1],
+                               _curves[e+2], _curves[e+3],
+                               _curves[e+4], _curves[e+5]);
+                    e += 6;
+                    continue;
+                default:
+                }
+            }
+            numCurves = 0;
+            end = 0;
+        }
+
+        void popAll(final PathConsumer2D io) {
+            int nc = numCurves;
+            if (nc == 0) {
+                return;
+            }
+            if (DO_STATS) {
+                // update used marks:
+                if (numCurves > curveTypesUseMark) {
+                    curveTypesUseMark = numCurves;
+                }
+                if (end > curvesUseMark) {
+                    curvesUseMark = end;
+                }
+            }
+            final byte[]  _curveTypes = curveTypes;
+            final float[] _curves = curves;
+            int e  = end;
+
+            while (nc != 0) {
+                switch(_curveTypes[--nc]) {
+                case TYPE_LINETO:
+                    e -= 2;
+                    io.lineTo(_curves[e], _curves[e+1]);
+                    continue;
+                case TYPE_QUADTO:
+                    e -= 4;
+                    io.quadTo(_curves[e],   _curves[e+1],
+                              _curves[e+2], _curves[e+3]);
+                    continue;
+                case TYPE_CUBICTO:
+                    e -= 6;
+                    io.curveTo(_curves[e],   _curves[e+1],
+                               _curves[e+2], _curves[e+3],
+                               _curves[e+4], _curves[e+5]);
+                    continue;
+                default:
+                }
+            }
+            numCurves = 0;
+            end = 0;
+        }
+
+        @Override
+        public String toString() {
+            String ret = "";
+            int nc = numCurves;
+            int last = end;
+            int len;
+            while (nc != 0) {
+                switch(curveTypes[--nc]) {
+                case TYPE_LINETO:
+                    len = 2;
+                    ret += "line: ";
+                    break;
+                case TYPE_QUADTO:
+                    len = 4;
+                    ret += "quad: ";
+                    break;
+                case TYPE_CUBICTO:
+                    len = 6;
+                    ret += "cubic: ";
+                    break;
+                default:
+                    len = 0;
+                }
+                last -= len;
+                ret += Arrays.toString(Arrays.copyOfRange(curves, last, last+len))
+                                       + "\n";
+            }
+            return ret;
         }
     }
 
-    static void subdivideQuad(float[] src, int srcoff,
-                              float[] left, int leftoff,
-                              float[] right, int rightoff)
-    {
-        float x1 = src[srcoff + 0];
-        float y1 = src[srcoff + 1];
-        float ctrlx = src[srcoff + 2];
-        float ctrly = src[srcoff + 3];
-        float x2 = src[srcoff + 4];
-        float y2 = src[srcoff + 5];
-        if (left != null) {
-            left[leftoff + 0] = x1;
-            left[leftoff + 1] = y1;
-        }
-        if (right != null) {
-            right[rightoff + 4] = x2;
-            right[rightoff + 5] = y2;
-        }
-        x1 = (x1 + ctrlx) / 2f;
-        y1 = (y1 + ctrly) / 2f;
-        x2 = (x2 + ctrlx) / 2f;
-        y2 = (y2 + ctrly) / 2f;
-        ctrlx = (x1 + x2) / 2f;
-        ctrly = (y1 + y2) / 2f;
-        if (left != null) {
-            left[leftoff + 2] = x1;
-            left[leftoff + 3] = y1;
-            left[leftoff + 4] = ctrlx;
-            left[leftoff + 5] = ctrly;
-        }
-        if (right != null) {
-            right[rightoff + 0] = ctrlx;
-            right[rightoff + 1] = ctrly;
-            right[rightoff + 2] = x2;
-            right[rightoff + 3] = y2;
-        }
-    }
+    // a stack of integer indices
+    static final class IndexStack {
 
-    static void subdivideQuadAt(float t, float[] src, int srcoff,
-                                float[] left, int leftoff,
-                                float[] right, int rightoff)
-    {
-        float x1 = src[srcoff + 0];
-        float y1 = src[srcoff + 1];
-        float ctrlx = src[srcoff + 2];
-        float ctrly = src[srcoff + 3];
-        float x2 = src[srcoff + 4];
-        float y2 = src[srcoff + 5];
-        if (left != null) {
-            left[leftoff + 0] = x1;
-            left[leftoff + 1] = y1;
-        }
-        if (right != null) {
-            right[rightoff + 4] = x2;
-            right[rightoff + 5] = y2;
-        }
-        x1 = x1 + t * (ctrlx - x1);
-        y1 = y1 + t * (ctrly - y1);
-        x2 = ctrlx + t * (x2 - ctrlx);
-        y2 = ctrly + t * (y2 - ctrly);
-        ctrlx = x1 + t * (x2 - x1);
-        ctrly = y1 + t * (y2 - y1);
-        if (left != null) {
-            left[leftoff + 2] = x1;
-            left[leftoff + 3] = y1;
-            left[leftoff + 4] = ctrlx;
-            left[leftoff + 5] = ctrly;
-        }
-        if (right != null) {
-            right[rightoff + 0] = ctrlx;
-            right[rightoff + 1] = ctrly;
-            right[rightoff + 2] = x2;
-            right[rightoff + 3] = y2;
-        }
-    }
+        // integer capacity = edges count / 4 ~ 1024
+        private static final int INITIAL_COUNT = INITIAL_EDGES_COUNT >> 2;
 
-    static void subdivideAt(float t, float[] src, int srcoff,
-                            float[] left, int leftoff,
-                            float[] right, int rightoff, int size)
-    {
-        switch(size) {
-        case 8:
-            subdivideCubicAt(t, src, srcoff, left, leftoff, right, rightoff);
-            return;
-        case 6:
-            subdivideQuadAt(t, src, srcoff, left, leftoff, right, rightoff);
-            return;
+        private int end;
+        private int[] indices;
+
+        // indices ref (dirty)
+        private final IntArrayCache.Reference indices_ref;
+
+        // used marks (stats only)
+        private int indicesUseMark;
+
+        private final StatLong stat_idxstack_indices;
+        private final Histogram hist_idxstack_indices;
+        private final StatLong stat_array_idxstack_indices;
+
+        IndexStack(final RendererContext rdrCtx) {
+            this(rdrCtx, null, null, null);
+        }
+
+        IndexStack(final RendererContext rdrCtx,
+                   final StatLong stat_idxstack_indices,
+                   final Histogram hist_idxstack_indices,
+                   final StatLong stat_array_idxstack_indices)
+        {
+            indices_ref = rdrCtx.newDirtyIntArrayRef(INITIAL_COUNT); // 4K
+            indices     = indices_ref.initial;
+            end = 0;
+
+            if (DO_STATS) {
+                indicesUseMark = 0;
+            }
+            this.stat_idxstack_indices = stat_idxstack_indices;
+            this.hist_idxstack_indices = hist_idxstack_indices;
+            this.stat_array_idxstack_indices = stat_array_idxstack_indices;
+        }
+
+        /**
+         * Disposes this PolyStack:
+         * clean up before reusing this instance
+         */
+        void dispose() {
+            end = 0;
+
+            if (DO_STATS) {
+                stat_idxstack_indices.add(indicesUseMark);
+                hist_idxstack_indices.add(indicesUseMark);
+
+                // reset marks
+                indicesUseMark = 0;
+            }
+
+            // Return arrays:
+            // values is kept dirty
+            indices = indices_ref.putArray(indices);
+        }
+
+        boolean isEmpty() {
+            return (end == 0);
+        }
+
+        void reset() {
+            end = 0;
+        }
+
+        void push(final int v) {
+            // remove redundant values (reverse order):
+            int[] _values = indices;
+            final int nc = end;
+            if (nc != 0) {
+                if (_values[nc - 1] == v) {
+                    // remove both duplicated values:
+                    end--;
+                    return;
+                }
+            }
+            if (_values.length <= nc) {
+                if (DO_STATS) {
+                    stat_array_idxstack_indices.add(nc + 1);
+                }
+                indices = _values = indices_ref.widenArray(_values, nc, nc + 1);
+            }
+            _values[end++] = v;
+
+            if (DO_STATS) {
+                // update used marks:
+                if (end > indicesUseMark) {
+                    indicesUseMark = end;
+                }
+            }
+        }
+
+        void pullAll(final float[] points, final PathConsumer2D io) {
+            final int nc = end;
+            if (nc == 0) {
+                return;
+            }
+            final int[] _values = indices;
+
+            for (int i = 0, j; i < nc; i++) {
+                j = _values[i] << 1;
+                io.lineTo(points[j], points[j + 1]);
+            }
+            end = 0;
         }
     }
 }
diff --git a/src/share/classes/sun/java2d/marlin/IRendererContext.java b/src/share/classes/sun/java2d/marlin/IRendererContext.java
new file mode 100644
index 0000000..ceecc9a
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/IRendererContext.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d.marlin;
+
+interface IRendererContext extends MarlinConst {
+
+    public RendererStats stats();
+
+    public OffHeapArray newOffHeapArray(final long initialSize);
+
+    public IntArrayCache.Reference newCleanIntArrayRef(final int initialSize);
+
+}
diff --git a/src/share/classes/sun/java2d/marlin/IntArrayCache.java b/src/share/classes/sun/java2d/marlin/IntArrayCache.java
index 917e992..a23f39a 100644
--- a/src/share/classes/sun/java2d/marlin/IntArrayCache.java
+++ b/src/share/classes/sun/java2d/marlin/IntArrayCache.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, 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
@@ -25,106 +25,219 @@
 
 package sun.java2d.marlin;
 
-import java.util.ArrayDeque;
-import java.util.Arrays;
-import static sun.java2d.marlin.MarlinUtils.logException;
+import static sun.java2d.marlin.ArrayCacheConst.ARRAY_SIZES;
+import static sun.java2d.marlin.ArrayCacheConst.BUCKETS;
+import static sun.java2d.marlin.ArrayCacheConst.MAX_ARRAY_SIZE;
 import static sun.java2d.marlin.MarlinUtils.logInfo;
+import static sun.java2d.marlin.MarlinUtils.logException;
+
+import java.lang.ref.WeakReference;
+import java.util.Arrays;
+
+import sun.java2d.marlin.ArrayCacheConst.BucketStats;
+import sun.java2d.marlin.ArrayCacheConst.CacheStats;
+
+/*
+ * Note that the [BYTE/INT/FLOAT/DOUBLE]ArrayCache files are nearly identical except
+ * for a few type and name differences. Typically, the [BYTE]ArrayCache.java file
+ * is edited manually and then [INT/FLOAT/DOUBLE]ArrayCache.java
+ * files are generated with the following command lines:
+ */
+// % sed -e 's/(b\yte)[ ]*//g' -e 's/b\yte/int/g' -e 's/B\yte/Int/g' < B\yteArrayCache.java > IntArrayCache.java
+// % sed -e 's/(b\yte)[ ]*0/0.0f/g' -e 's/(b\yte)[ ]*/(float) /g' -e 's/b\yte/float/g' -e 's/B\yte/Float/g' < B\yteArrayCache.java > FloatArrayCache.java
+// % sed -e 's/(b\yte)[ ]*0/0.0d/g' -e 's/(b\yte)[ ]*/(double) /g' -e 's/b\yte/double/g' -e 's/B\yte/Double/g' < B\yteArrayCache.java > DoubleArrayCache.java
 
 final class IntArrayCache implements MarlinConst {
 
-    private final int arraySize;
-    private final ArrayDeque<int[]> intArrays;
-    // stats
-    private int getOp = 0;
-    private int createOp = 0;
-    private int returnOp = 0;
+    final boolean clean;
+    private final int bucketCapacity;
+    private WeakReference<Bucket[]> refBuckets = null;
+    final CacheStats stats;
 
-    void dumpStats() {
-        if (getOp > 0) {
-            logInfo("IntArrayCache[" + arraySize + "]: get: " + getOp
-                    + " created: " + createOp + " - returned: " + returnOp
-                    + " :: cache size: " + intArrays.size());
-        }
+    IntArrayCache(final boolean clean, final int bucketCapacity) {
+        this.clean = clean;
+        this.bucketCapacity = bucketCapacity;
+        this.stats = (DO_STATS) ?
+            new CacheStats(getLogPrefix(clean) + "IntArrayCache") : null;
     }
 
-    IntArrayCache(final int arraySize) {
-        this.arraySize = arraySize;
-        // small but enough: almost 1 cache line
-        this.intArrays = new ArrayDeque<int[]>(6);
+    Bucket getCacheBucket(final int length) {
+        final int bucket = ArrayCacheConst.getBucket(length);
+        return getBuckets()[bucket];
     }
 
-    int[] getArray() {
-        if (DO_STATS) {
-            getOp++;
-        }
+    private Bucket[] getBuckets() {
+        // resolve reference:
+        Bucket[] buckets = (refBuckets != null) ? refBuckets.get() : null;
 
-        // use cache:
-        final int[] array = intArrays.pollLast();
-        if (array != null) {
-            return array;
-        }
+        // create a new buckets ?
+        if (buckets == null) {
+            buckets = new Bucket[BUCKETS];
 
-        if (DO_STATS) {
-            createOp++;
-        }
-
-        return new int[arraySize];
-    }
-
-    void putDirtyArray(final int[] array, final int length) {
-        if (length != arraySize) {
-            if (DO_CHECKS) {
-                MarlinUtils.logInfo("ArrayCache: bad length = " + length);
+            for (int i = 0; i < BUCKETS; i++) {
+                buckets[i] = new Bucket(clean, ARRAY_SIZES[i], bucketCapacity,
+                        (DO_STATS) ? stats.bucketStats[i] : null);
             }
-            return;
-        }
-        if (DO_STATS) {
-            returnOp++;
-        }
 
-        // NO clean-up of array data = DIRTY ARRAY
-
-        if (DO_CLEAN_DIRTY) {
-            // Force zero-fill dirty arrays:
-            Arrays.fill(array, 0, array.length, 0);
+            // update weak reference:
+            refBuckets = new WeakReference<Bucket[]>(buckets);
         }
-
-        // fill cache:
-        intArrays.addLast(array);
+        return buckets;
     }
 
-    void putArray(final int[] array, final int length,
-                  final int fromIndex, final int toIndex)
-    {
-        if (length != arraySize) {
-            if (DO_CHECKS) {
-                MarlinUtils.logInfo("ArrayCache: bad length = " + length);
+    Reference createRef(final int initialSize) {
+        return new Reference(this, initialSize);
+    }
+
+    static final class Reference {
+
+        // initial array reference (direct access)
+        final int[] initial;
+        private final boolean clean;
+        private final IntArrayCache cache;
+
+        Reference(final IntArrayCache cache, final int initialSize) {
+            this.cache = cache;
+            this.clean = cache.clean;
+            this.initial = createArray(initialSize);
+            if (DO_STATS) {
+                cache.stats.totalInitial += initialSize;
             }
-            return;
-        }
-        if (DO_STATS) {
-            returnOp++;
         }
 
-        // clean-up array of dirty part[fromIndex; toIndex[
-        fill(array, fromIndex, toIndex, 0);
+        int[] getArray(final int length) {
+            if (length <= MAX_ARRAY_SIZE) {
+                return cache.getCacheBucket(length).getArray();
+            }
+            if (DO_STATS) {
+                cache.stats.oversize++;
+            }
+            if (DO_LOG_OVERSIZE) {
+                logInfo(getLogPrefix(clean) + "IntArrayCache: "
+                        + "getArray[oversize]: length=\t" + length);
+            }
+            return createArray(length);
+        }
 
-        // fill cache:
-        intArrays.addLast(array);
+        int[] widenArray(final int[] array, final int usedSize,
+                          final int needSize)
+        {
+            final int length = array.length;
+            if (DO_CHECKS && length >= needSize) {
+                return array;
+            }
+            if (DO_STATS) {
+                cache.stats.resize++;
+            }
+
+            // maybe change bucket:
+            // ensure getNewSize() > newSize:
+            final int[] res = getArray(ArrayCacheConst.getNewSize(usedSize, needSize));
+
+            // use wrapper to ensure proper copy:
+            System.arraycopy(array, 0, res, 0, usedSize); // copy only used elements
+
+            // maybe return current array:
+            putArray(array, 0, usedSize); // ensure array is cleared
+
+            if (DO_LOG_WIDEN_ARRAY) {
+                logInfo(getLogPrefix(clean) + "IntArrayCache: "
+                        + "widenArray[" + res.length
+                        + "]: usedSize=\t" + usedSize + "\tlength=\t" + length
+                        + "\tneeded length=\t" + needSize);
+            }
+            return res;
+        }
+
+        int[] putArray(final int[] array)
+        {
+            // dirty array helper:
+            return putArray(array, 0, array.length);
+        }
+
+        int[] putArray(final int[] array, final int fromIndex,
+                        final int toIndex)
+        {
+            if (array.length <= MAX_ARRAY_SIZE) {
+                if ((clean || DO_CLEAN_DIRTY) && (toIndex != 0)) {
+                    // clean-up array of dirty part[fromIndex; toIndex[
+                    fill(array, fromIndex, toIndex, 0);
+                }
+                // ensure to never store initial arrays in cache:
+                if (array != initial) {
+                    cache.getCacheBucket(array.length).putArray(array);
+                }
+            }
+            return initial;
+        }
+    }
+
+    static final class Bucket {
+
+        private int tail = 0;
+        private final int arraySize;
+        private final boolean clean;
+        private final int[][] arrays;
+        private final BucketStats stats;
+
+        Bucket(final boolean clean, final int arraySize,
+               final int capacity, final BucketStats stats)
+        {
+            this.arraySize = arraySize;
+            this.clean = clean;
+            this.stats = stats;
+            this.arrays = new int[capacity][];
+        }
+
+        int[] getArray() {
+            if (DO_STATS) {
+                stats.getOp++;
+            }
+            // use cache:
+            if (tail != 0) {
+                final int[] array = arrays[--tail];
+                arrays[tail] = null;
+                return array;
+            }
+            if (DO_STATS) {
+                stats.createOp++;
+            }
+            return createArray(arraySize);
+        }
+
+        void putArray(final int[] array)
+        {
+            if (DO_CHECKS && (array.length != arraySize)) {
+                logInfo(getLogPrefix(clean) + "IntArrayCache: "
+                        + "bad length = " + array.length);
+                return;
+            }
+            if (DO_STATS) {
+                stats.returnOp++;
+            }
+            // fill cache:
+            if (arrays.length > tail) {
+                arrays[tail++] = array;
+
+                if (DO_STATS) {
+                    stats.updateMaxSize(tail);
+                }
+            } else if (DO_CHECKS) {
+                logInfo(getLogPrefix(clean) + "IntArrayCache: "
+                        + "array capacity exceeded !");
+            }
+        }
+    }
+
+    static int[] createArray(final int length) {
+        return new int[length];
     }
 
     static void fill(final int[] array, final int fromIndex,
                      final int toIndex, final int value)
     {
         // clear array data:
-        /*
-         * Arrays.fill is faster than System.arraycopy(empty array)
-         * or Unsafe.setMemory(byte 0)
-         */
-        if (toIndex != 0) {
-            Arrays.fill(array, fromIndex, toIndex, value);
-        }
-
+        Arrays.fill(array, fromIndex, toIndex, value);
         if (DO_CHECKS) {
             check(array, fromIndex, toIndex, value);
         }
@@ -149,4 +262,8 @@
             }
         }
     }
+
+    static String getLogPrefix(final boolean clean) {
+        return (clean) ? "Clean" : "Dirty";
+    }
 }
diff --git a/src/share/classes/sun/java2d/marlin/META-INF/services/sun.java2d.pipe.RenderingEngine b/src/share/classes/sun/java2d/marlin/META-INF/services/sun.java2d.pipe.RenderingEngine
new file mode 100644
index 0000000..e760a02
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/META-INF/services/sun.java2d.pipe.RenderingEngine
@@ -0,0 +1,3 @@
+#  Marlin Rendering Engine module
+sun.java2d.marlin.MarlinRenderingEngine
+sun.java2d.marlin.DMarlinRenderingEngine
diff --git a/src/share/classes/sun/java2d/marlin/MarlinCache.java b/src/share/classes/sun/java2d/marlin/MarlinCache.java
index 54877a2..3f5e8e1 100644
--- a/src/share/classes/sun/java2d/marlin/MarlinCache.java
+++ b/src/share/classes/sun/java2d/marlin/MarlinCache.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, 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
@@ -25,6 +25,7 @@
 
 package sun.java2d.marlin;
 
+//import jdk.internal.misc.Unsafe;
 import sun.misc.Unsafe;
 
 /**
@@ -43,9 +44,9 @@
     // values are stored as int [x|alpha] where alpha is 8 bits
     static final int RLE_MAX_WIDTH = 1 << (24 - 1);
 
-    // 2048 (pixelSize) alpha values (width) x 32 rows (tile) = 64K bytes
+    // 4096 (pixels) alpha values (width) x 64 rows / 4 (tile) = 64K bytes
     // x1 instead of 4 bytes (RLE) ie 1/4 capacity or average good RLE compression
-    static final long INITIAL_CHUNK_ARRAY = TILE_SIZE * INITIAL_PIXEL_DIM; // 64K
+    static final long INITIAL_CHUNK_ARRAY = TILE_H * INITIAL_PIXEL_WIDTH >> 2; // 64K
 
     // The alpha map used by this object (taken out of our map cache) to convert
     // pixel coverage counts gotten from MarlinCache (which are in the range
@@ -72,17 +73,17 @@
 
     // 1D dirty arrays
     // row index in rowAAChunk[]
-    final long[] rowAAChunkIndex = new long[TILE_SIZE];
+    final long[] rowAAChunkIndex = new long[TILE_H];
     // first pixel (inclusive) for each row
-    final int[] rowAAx0 = new int[TILE_SIZE];
+    final int[] rowAAx0 = new int[TILE_H];
     // last pixel (exclusive) for each row
-    final int[] rowAAx1 = new int[TILE_SIZE];
+    final int[] rowAAx1 = new int[TILE_H];
     // encoding mode (0=raw, 1=RLE encoding) for each row
-    final int[] rowAAEnc = new int[TILE_SIZE];
+    final int[] rowAAEnc = new int[TILE_H];
     // coded length (RLE encoding) for each row
-    final long[] rowAALen = new long[TILE_SIZE];
+    final long[] rowAALen = new long[TILE_H];
     // last position in RLE decoding for each row (getAlpha):
-    final long[] rowAAPos = new long[TILE_SIZE];
+    final long[] rowAAPos = new long[TILE_H];
 
     // dirty off-heap array containing pixel coverages for (32) rows (packed)
     // if encoding=raw, it contains alpha coverage values (val) as integer
@@ -97,29 +98,30 @@
     // x=j*TILE_SIZE+bboxX0.
     int[] touchedTile;
 
-    // per-thread renderer context
-    final RendererContext rdrCtx;
+    // per-thread renderer stats
+    final RendererStats rdrStats;
 
-    // large cached touchedTile (dirty)
-    final int[] touchedTile_initial = new int[INITIAL_ARRAY]; // 1 tile line
+    // touchedTile ref (clean)
+    private final IntArrayCache.Reference touchedTile_ref;
 
     int tileMin, tileMax;
 
     boolean useRLE = false;
 
-    MarlinCache(final RendererContext rdrCtx) {
-        this.rdrCtx = rdrCtx;
+    MarlinCache(final IRendererContext rdrCtx) {
+        this.rdrStats = rdrCtx.stats();
 
-        rowAAChunk = new OffHeapArray(rdrCtx.cleanerObj, INITIAL_CHUNK_ARRAY); // 64K
+        rowAAChunk = rdrCtx.newOffHeapArray(INITIAL_CHUNK_ARRAY); // 64K
 
-        touchedTile = touchedTile_initial;
+        touchedTile_ref = rdrCtx.newCleanIntArrayRef(INITIAL_ARRAY); // 1K = 1 tile line
+        touchedTile     = touchedTile_ref.initial;
 
         // tile used marks:
         tileMin = Integer.MAX_VALUE;
         tileMax = Integer.MIN_VALUE;
     }
 
-    void init(int minx, int miny, int maxx, int maxy, int edgeSumDeltaY)
+    void init(int minx, int miny, int maxx, int maxy)
     {
         // assert maxy >= miny && maxx >= minx;
         bboxX0 = minx;
@@ -138,53 +140,17 @@
             // ie number of primitives:
 
             // fast check min and max width (maxx < 23bits):
-            if (width <= RLE_MIN_WIDTH || width >= RLE_MAX_WIDTH) {
-                useRLE = false;
-            } else {
-                // perimeter approach: how fit the total length into given height:
-
-                // if stroking: meanCrossings /= 2 => divide edgeSumDeltaY by 2
-                final int heightSubPixel
-                    = (((maxy - miny) << SUBPIXEL_LG_POSITIONS_Y) << rdrCtx.stroking);
-
-                // check meanDist > block size:
-                // check width / (meanCrossings - 1) >= RLE_THRESHOLD
-
-                // fast case: (meanCrossingPerPixel <= 2) means 1 span only
-                useRLE = (edgeSumDeltaY <= (heightSubPixel << 1))
-                    // note: already checked (meanCrossingPerPixel <= 2)
-                    // rewritten to avoid division:
-                    || (width * heightSubPixel) >
-                            ((edgeSumDeltaY - heightSubPixel) << BLOCK_SIZE_LG);
-
-                if (DO_TRACE && !useRLE) {
-                    final float meanCrossings
-                        = ((float) edgeSumDeltaY) / heightSubPixel;
-                    final float meanDist = width / (meanCrossings - 1);
-
-                    System.out.println("High complexity: "
-                        + " for bbox[width = " + width
-                        + " height = " + (maxy - miny)
-                        + "] edgeSumDeltaY = " + edgeSumDeltaY
-                        + " heightSubPixel = " + heightSubPixel
-                        + " meanCrossings = "+ meanCrossings
-                        + " meanDist = " + meanDist
-                        + " width =  " + (width * heightSubPixel)
-                        + " <= criteria:  " + ((edgeSumDeltaY - heightSubPixel) << BLOCK_SIZE_LG)
-                    );
-                }
-            }
+            useRLE = (width > RLE_MIN_WIDTH && width < RLE_MAX_WIDTH);
         }
 
         // the ceiling of (maxy - miny + 1) / TILE_SIZE;
-        final int nxTiles = (width + TILE_SIZE) >> TILE_SIZE_LG;
+        final int nxTiles = (width + TILE_W) >> TILE_W_LG;
 
         if (nxTiles > INITIAL_ARRAY) {
             if (DO_STATS) {
-                rdrCtx.stats.stat_array_marlincache_touchedTile
-                    .add(nxTiles);
+                rdrStats.stat_array_marlincache_touchedTile.add(nxTiles);
             }
-            touchedTile = rdrCtx.getIntArray(nxTiles);
+            touchedTile = touchedTile_ref.getArray(nxTiles);
         }
     }
 
@@ -196,11 +162,13 @@
         // Reset touchedTile if needed:
         resetTileLine(0);
 
-        // Return arrays:
-        if (touchedTile != touchedTile_initial) {
-            rdrCtx.putIntArray(touchedTile, 0, 0); // already zero filled
-            touchedTile = touchedTile_initial;
+        if (DO_STATS) {
+            rdrStats.totalOffHeap += rowAAChunk.length;
         }
+
+        // Return arrays:
+        touchedTile = touchedTile_ref.putArray(touchedTile, 0, 0); // already zero filled
+
         // At last: resize back off-heap rowAA to initial size
         if (rowAAChunk.length != INITIAL_CHUNK_ARRAY) {
             // note: may throw OOME:
@@ -218,14 +186,14 @@
 
         // reset current pos
         if (DO_STATS) {
-            rdrCtx.stats.stat_cache_rowAAChunk.add(rowAAChunkPos);
+            rdrStats.stat_cache_rowAAChunk.add(rowAAChunkPos);
         }
         rowAAChunkPos = 0L;
 
         // Reset touchedTile:
         if (tileMin != Integer.MAX_VALUE) {
             if (DO_STATS) {
-                rdrCtx.stats.stat_cache_tiles.add(tileMax - tileMin);
+                rdrStats.stat_cache_tiles.add(tileMax - tileMin);
             }
             // clean only dirty touchedTile:
             if (tileMax == 1) {
@@ -267,10 +235,6 @@
     void copyAARowNoRLE(final int[] alphaRow, final int y,
                    final int px0, final int px1)
     {
-        if (DO_MONITORS) {
-            rdrCtx.stats.mon_rdr_copyAARow.start();
-        }
-
         // skip useless pixels above boundary
         final int px_bbox1 = FloatMath.min(px1, bboxX1);
 
@@ -306,12 +270,12 @@
             expandRowAAChunk(needSize);
         }
         if (DO_STATS) {
-            rdrCtx.stats.stat_cache_rowAA.add(px_bbox1 - px0);
+            rdrStats.stat_cache_rowAA.add(px_bbox1 - px0);
         }
 
         // rowAA contains only alpha values for range[x0; x1[
         final int[] _touchedTile = touchedTile;
-        final int _TILE_SIZE_LG = TILE_SIZE_LG;
+        final int _TILE_SIZE_LG = TILE_W_LG;
 
         final int from = px0      - bboxX0; // first pixel inclusive
         final int to   = px_bbox1 - bboxX0; //  last pixel exclusive
@@ -340,9 +304,9 @@
 
             // store alpha sum (as byte):
             if (val == 0) {
-                _unsafe.putByte(addr_off, (byte)0); // [0..255]
+                _unsafe.putByte(addr_off, (byte)0); // [0-255]
             } else {
-                _unsafe.putByte(addr_off, _unsafe.getByte(addr_alpha + val)); // [0..255]
+                _unsafe.putByte(addr_off, _unsafe.getByte(addr_alpha + val)); // [0-255]
 
                 // update touchedTile
                 _touchedTile[x >> _TILE_SIZE_LG] += val;
@@ -366,25 +330,17 @@
         }
 
         // Clear alpha row for reuse:
-        IntArrayCache.fill(alphaRow, from, px1 - bboxX0, 0);
-
-        if (DO_MONITORS) {
-            rdrCtx.stats.mon_rdr_copyAARow.stop();
-        }
+        IntArrayCache.fill(alphaRow, from, px1 + 1 - bboxX0, 0);
     }
 
     void copyAARowRLE_WithBlockFlags(final int[] blkFlags, final int[] alphaRow,
                       final int y, final int px0, final int px1)
     {
-        if (DO_MONITORS) {
-            rdrCtx.stats.mon_rdr_copyAARow.start();
-        }
-
         // Copy rowAA data into the piscesCache if one is present
         final int _bboxX0 = bboxX0;
 
         // process tile line [0 - 32]
-        final int row  = y - bboxY0;
+        final int row  =   y -  bboxY0;
         final int from = px0 - _bboxX0; // first pixel inclusive
 
         // skip useless pixels above boundary
@@ -416,12 +372,14 @@
         long addr_off = _rowAAChunk.address + initialPos;
 
         final int[] _touchedTile = touchedTile;
-        final int _TILE_SIZE_LG = TILE_SIZE_LG;
+        final int _TILE_SIZE_LG = TILE_W_LG;
         final int _BLK_SIZE_LG  = BLOCK_SIZE_LG;
 
         // traverse flagged blocks:
         final int blkW = (from >> _BLK_SIZE_LG);
         final int blkE = (to   >> _BLK_SIZE_LG) + 1;
+        // ensure last block flag = 0 to process final block:
+        blkFlags[blkE] = 0;
 
         // Perform run-length encoding and store results in the piscesCache
         int val = 0;
@@ -479,7 +437,7 @@
                             } else {
                                 _unsafe.putInt(addr_off,
                                     ((_bboxX0 + cx) << 8)
-                                    | (((int) _unsafe.getByte(addr_alpha + val)) & 0xFF) // [0..255]
+                                    | (((int) _unsafe.getByte(addr_alpha + val)) & 0xFF) // [0-255]
                                 );
 
                                 if (runLen == 1) {
@@ -491,7 +449,7 @@
                             addr_off += SIZE_INT;
 
                             if (DO_STATS) {
-                                rdrCtx.stats.hist_tile_generator_encoding_runLen
+                                rdrStats.hist_tile_generator_encoding_runLen
                                     .add(runLen);
                             }
                             cx0 = cx;
@@ -542,7 +500,7 @@
         } else {
             _unsafe.putInt(addr_off,
                 ((_bboxX0 + to) << 8)
-                | (((int) _unsafe.getByte(addr_alpha + val)) & 0xFF) // [0..255]
+                | (((int) _unsafe.getByte(addr_alpha + val)) & 0xFF) // [0-255]
             );
 
             if (runLen == 1) {
@@ -554,8 +512,7 @@
         addr_off += SIZE_INT;
 
         if (DO_STATS) {
-            rdrCtx.stats.hist_tile_generator_encoding_runLen
-                .add(runLen);
+            rdrStats.hist_tile_generator_encoding_runLen.add(runLen);
         }
 
         long len = (addr_off - _rowAAChunk.address);
@@ -567,8 +524,8 @@
         rowAAChunkPos = len;
 
         if (DO_STATS) {
-            rdrCtx.stats.stat_cache_rowAA.add(rowAALen[row]);
-            rdrCtx.stats.hist_tile_generator_encoding_ratio.add(
+            rdrStats.stat_cache_rowAA.add(rowAALen[row]);
+            rdrStats.hist_tile_generator_encoding_ratio.add(
                 (100 * skip) / (blkE - blkW)
             );
         }
@@ -585,17 +542,10 @@
         }
 
         // Clear alpha row for reuse:
-        if (px1 > bboxX1) {
-            alphaRow[to    ] = 0;
-            alphaRow[to + 1] = 0;
-        }
+        alphaRow[to] = 0;
         if (DO_CHECKS) {
             IntArrayCache.check(blkFlags, blkW, blkE, 0);
-            IntArrayCache.check(alphaRow, from, px1 - bboxX0, 0);
-        }
-
-        if (DO_MONITORS) {
-            rdrCtx.stats.mon_rdr_copyAARow.stop();
+            IntArrayCache.check(alphaRow, from, px1 + 1 - bboxX0, 0);
         }
     }
 
@@ -612,12 +562,12 @@
 
     private void expandRowAAChunk(final long needSize) {
         if (DO_STATS) {
-            rdrCtx.stats.stat_array_marlincache_rowAAChunk
-                .add(needSize);
+            rdrStats.stat_array_marlincache_rowAAChunk.add(needSize);
         }
 
         // note: throw IOOB if neededSize > 2Gb:
-        final long newSize = ArrayCache.getNewLargeSize(rowAAChunk.length, needSize);
+        final long newSize = ArrayCacheConst.getNewLargeSize(rowAAChunk.length,
+                                                             needSize);
 
         rowAAChunk.resize(newSize);
     }
@@ -628,7 +578,7 @@
     {
         // the x and y of the current row, minus bboxX0, bboxY0
         // process tile line [0 - 32]
-        final int _TILE_SIZE_LG = TILE_SIZE_LG;
+        final int _TILE_SIZE_LG = TILE_W_LG;
 
         // update touchedTile
         int tx = (x0 >> _TILE_SIZE_LG);
@@ -665,7 +615,7 @@
     }
 
     int alphaSumInTile(final int x) {
-        return touchedTile[(x - bboxX0) >> TILE_SIZE_LG];
+        return touchedTile[(x - bboxX0) >> TILE_W_LG];
     }
 
     @Override
diff --git a/src/share/classes/sun/java2d/marlin/MarlinConst.java b/src/share/classes/sun/java2d/marlin/MarlinConst.java
index 22bf86d..baf4c2d 100644
--- a/src/share/classes/sun/java2d/marlin/MarlinConst.java
+++ b/src/share/classes/sun/java2d/marlin/MarlinConst.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, 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
@@ -62,6 +62,8 @@
     // enable traces
     static final boolean DO_TRACE = ENABLE_LOGS && false;
 
+    // do flush stats
+    static final boolean DO_FLUSH_STATS = true;
     // do flush monitors
     static final boolean DO_FLUSH_MONITORS = true;
     // use one polling thread to dump statistics/monitors
@@ -72,28 +74,42 @@
     // do clean dirty array
     static final boolean DO_CLEAN_DIRTY = false;
 
-    // flag to use line simplifier
+    // flag to use collinear simplifier
     static final boolean USE_SIMPLIFIER = MarlinProperties.isUseSimplifier();
 
+    // flag to use path simplifier
+    static final boolean USE_PATH_SIMPLIFIER = MarlinProperties.isUsePathSimplifier();
+
+    static final boolean DO_CLIP_SUBDIVIDER = MarlinProperties.isDoClipSubdivider();
+
     // flag to enable logs related bounds checks
     static final boolean DO_LOG_BOUNDS = ENABLE_LOGS && false;
 
-    // Initial Array sizing (initial context capacity) ~ 350K
+    // flag to enable float precision correction
+    static final boolean DO_FIX_FLOAT_PREC = true;
 
-    // 2048 pixel (width x height) for initial capacity
-    static final int INITIAL_PIXEL_DIM
-        = MarlinProperties.getInitialImageSize();
+    // Initial Array sizing (initial context capacity) ~ 450K
+
+    // 4096 pixels (width) for initial capacity
+    static final int INITIAL_PIXEL_WIDTH
+        = MarlinProperties.getInitialPixelWidth();
+    // 2176 pixels (height) for initial capacity
+    static final int INITIAL_PIXEL_HEIGHT
+        = MarlinProperties.getInitialPixelHeight();
 
     // typical array sizes: only odd numbers allowed below
     static final int INITIAL_ARRAY        = 256;
-    static final int INITIAL_SMALL_ARRAY  = 1024;
-    static final int INITIAL_MEDIUM_ARRAY = 4096;
-    static final int INITIAL_LARGE_ARRAY  = 8192;
-    // alpha row dimension
-    static final int INITIAL_AA_ARRAY     = INITIAL_PIXEL_DIM;
 
-    // initial edges (24 bytes) = 24K [ints] = 96K
-    static final int INITIAL_EDGES_CAPACITY = 4096 * 24; // 6 ints per edges
+    // alpha row dimension
+    static final int INITIAL_AA_ARRAY     = INITIAL_PIXEL_WIDTH;
+
+    // 4096 edges for initial capacity
+    static final int INITIAL_EDGES_COUNT = MarlinProperties.getInitialEdges();
+
+    // initial edges = edges count (4096)
+    // 6 ints per edges = 24 bytes
+    // edges capacity = 24 x initial edges = 24 * edges count (4096) = 96K
+    static final int INITIAL_EDGES_CAPACITY = INITIAL_EDGES_COUNT * 24;
 
     // zero value as byte
     static final byte BYTE_0 = (byte) 0;
@@ -104,20 +120,67 @@
     public static final int SUBPIXEL_LG_POSITIONS_Y
         = MarlinProperties.getSubPixel_Log2_Y();
 
+    public static final int MIN_SUBPIXEL_LG_POSITIONS
+        = Math.min(SUBPIXEL_LG_POSITIONS_X, SUBPIXEL_LG_POSITIONS_Y);
+
     // number of subpixels
     public static final int SUBPIXEL_POSITIONS_X = 1 << (SUBPIXEL_LG_POSITIONS_X);
     public static final int SUBPIXEL_POSITIONS_Y = 1 << (SUBPIXEL_LG_POSITIONS_Y);
 
-    public static final float NORM_SUBPIXELS
-        = (float)Math.sqrt(( SUBPIXEL_POSITIONS_X * SUBPIXEL_POSITIONS_X
-                           + SUBPIXEL_POSITIONS_Y * SUBPIXEL_POSITIONS_Y)/2.0);
+    public static final float MIN_SUBPIXELS = 1 << MIN_SUBPIXEL_LG_POSITIONS;
 
     public static final int MAX_AA_ALPHA
-        = SUBPIXEL_POSITIONS_X * SUBPIXEL_POSITIONS_Y;
+        = (SUBPIXEL_POSITIONS_X * SUBPIXEL_POSITIONS_Y);
 
-    public static final int TILE_SIZE_LG = MarlinProperties.getTileSize_Log2();
-    public static final int TILE_SIZE = 1 << TILE_SIZE_LG; // 32 by default
+    public static final int TILE_H_LG = MarlinProperties.getTileSize_Log2();
+    public static final int TILE_H = 1 << TILE_H_LG; // 32 by default
+
+    public static final int TILE_W_LG = MarlinProperties.getTileWidth_Log2();
+    public static final int TILE_W = 1 << TILE_W_LG; // 32 by default
 
     public static final int BLOCK_SIZE_LG = MarlinProperties.getBlockSize_Log2();
     public static final int BLOCK_SIZE    = 1 << BLOCK_SIZE_LG;
+
+    // Constants
+    public static final int WIND_EVEN_ODD = 0;
+    public static final int WIND_NON_ZERO = 1;
+
+    /**
+     * Constant value for join style.
+     */
+    public static final int JOIN_MITER = 0;
+
+    /**
+     * Constant value for join style.
+     */
+    public static final int JOIN_ROUND = 1;
+
+    /**
+     * Constant value for join style.
+     */
+    public static final int JOIN_BEVEL = 2;
+
+    /**
+     * Constant value for end cap style.
+     */
+    public static final int CAP_BUTT = 0;
+
+    /**
+     * Constant value for end cap style.
+     */
+    public static final int CAP_ROUND = 1;
+
+    /**
+     * Constant value for end cap style.
+     */
+    public static final int CAP_SQUARE = 2;
+
+    // Out codes
+    static final int OUTCODE_TOP      = 1;
+    static final int OUTCODE_BOTTOM   = 2;
+    static final int OUTCODE_LEFT     = 4;
+    static final int OUTCODE_RIGHT    = 8;
+    static final int OUTCODE_MASK_T_B = OUTCODE_TOP  | OUTCODE_BOTTOM;
+    static final int OUTCODE_MASK_L_R = OUTCODE_LEFT | OUTCODE_RIGHT;
+    static final int OUTCODE_MASK_T_B_L_R = OUTCODE_MASK_T_B | OUTCODE_MASK_L_R;
 }
diff --git a/src/share/classes/sun/java2d/marlin/MarlinProperties.java b/src/share/classes/sun/java2d/marlin/MarlinProperties.java
index bbee15a..3099b7c 100644
--- a/src/share/classes/sun/java2d/marlin/MarlinProperties.java
+++ b/src/share/classes/sun/java2d/marlin/MarlinProperties.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, 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
@@ -42,43 +42,79 @@
     }
 
     /**
-     * Return the initial pixel size used to define initial arrays
-     * (tile AA chunk, alpha line, buckets)
+     * Return the initial edge capacity used to define initial arrays
+     * (edges, polystack, crossings)
      *
-     * @return 64 < initial pixel size < 32768 (2048 by default)
+     * @return 256 < initial edges < 65536 (4096 by default)
      */
-    public static int getInitialImageSize() {
-        return getInteger("sun.java2d.renderer.pixelsize", 2048, 64, 32 * 1024);
+    public static int getInitialEdges() {
+        return align(
+            getInteger("sun.java2d.renderer.edges", 4096, 64, 64 * 1024),
+            64);
     }
 
     /**
-     * Return the log(2) corresponding to subpixel on x-axis (
+     * Return the initial pixel width used to define initial arrays
+     * (tile AA chunk, alpha line)
      *
-     * @return 1 (2 subpixels) < initial pixel size < 4 (256 subpixels)
-     * (3 by default ie 8 subpixels)
+     * @return 64 < initial pixel size < 32768 (4096 by default)
+     */
+    public static int getInitialPixelWidth() {
+        return align(
+            getInteger("sun.java2d.renderer.pixelWidth", 4096, 64, 32 * 1024),
+            64);
+    }
+
+    /**
+     * Return the initial pixel height used to define initial arrays
+     * (buckets)
+     *
+     * @return 64 < initial pixel size < 32768 (2176 by default)
+     */
+    public static int getInitialPixelHeight() {
+        return align(
+            getInteger("sun.java2d.renderer.pixelHeight", 2176, 64, 32 * 1024),
+            64);
+    }
+
+    /**
+     * Return the log(2) corresponding to subpixel on x-axis
+     *
+     * @return 0 (1 subpixels) < initial pixel size < 8 (256 subpixels)
+     * (8 by default ie 256 subpixels)
      */
     public static int getSubPixel_Log2_X() {
-        return getInteger("sun.java2d.renderer.subPixel_log2_X", 3, 1, 8);
+        return getInteger("sun.java2d.renderer.subPixel_log2_X", 8, 0, 8);
     }
 
     /**
-     * Return the log(2) corresponding to subpixel on y-axis (
+     * Return the log(2) corresponding to subpixel on y-axis
      *
-     * @return 1 (2 subpixels) < initial pixel size < 8 (256 subpixels)
+     * @return 0 (1 subpixels) < initial pixel size < 8 (256 subpixels)
      * (3 by default ie 8 subpixels)
      */
     public static int getSubPixel_Log2_Y() {
-        return getInteger("sun.java2d.renderer.subPixel_log2_Y", 3, 1, 8);
+        return getInteger("sun.java2d.renderer.subPixel_log2_Y", 3, 0, 8);
     }
 
     /**
      * Return the log(2) corresponding to the square tile size in pixels
      *
-     * @return 3 (8x8 pixels) < tile size < 8 (256x256 pixels)
-     * (5 by default ie 32x32 pixels)
+     * @return 3 (8x8 pixels) < tile size < 10 (1024x1024 pixels)
+     * (6 by default ie 128x64 pixels)
      */
     public static int getTileSize_Log2() {
-        return getInteger("sun.java2d.renderer.tileSize_log2", 5, 3, 8);
+        return getInteger("sun.java2d.renderer.tileSize_log2", 6, 3, 10);
+    }
+
+    /**
+     * Return the log(2) corresponding to the tile width in pixels
+     *
+     * @return 3 (8 pixels) < tile width < 8 (1024 pixels)
+     * (7 by default ie 128x64 pixels)
+     */
+    public static int getTileWidth_Log2() {
+        return getInteger("sun.java2d.renderer.tileWidth_log2", 7, 3, 10);
     }
 
     /**
@@ -120,6 +156,38 @@
         return getBoolean("sun.java2d.renderer.useSimplifier", "false");
     }
 
+    public static boolean isUsePathSimplifier() {
+        return getBoolean("sun.java2d.renderer.usePathSimplifier", "false");
+    }
+
+    public static float getPathSimplifierPixelTolerance() {
+        // default: MIN_PEN_SIZE or less ?
+        return getFloat("sun.java2d.renderer.pathSimplifier.pixTol",
+                (1.0f / MarlinConst.MIN_SUBPIXELS),
+                1e-3f,
+                10.0f);
+    }
+
+    public static boolean isDoClip() {
+        return getBoolean("sun.java2d.renderer.clip", "true");
+    }
+
+    public static boolean isDoClipRuntimeFlag() {
+        return getBoolean("sun.java2d.renderer.clip.runtime.enable", "false");
+    }
+
+    public static boolean isDoClipAtRuntime() {
+        return getBoolean("sun.java2d.renderer.clip.runtime", "true");
+    }
+
+    public static boolean isDoClipSubdivider() {
+        return getBoolean("sun.java2d.renderer.clip.subdivider", "true");
+    }
+
+    public static float getSubdividerMinLength() {
+        return getFloat("sun.java2d.renderer.clip.subdivider.minLength", 100.0f, Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY);
+    }
+
     // debugging parameters
 
     public static boolean isDoStats() {
@@ -152,6 +220,24 @@
         return getBoolean("sun.java2d.renderer.logUnsafeMalloc", "false");
     }
 
+    // quality settings
+
+    public static float getCurveLengthError() {
+        return getFloat("sun.java2d.renderer.curve_len_err", 0.01f, 1e-6f, 1.0f);
+    }
+
+    public static float getCubicDecD2() {
+        return getFloat("sun.java2d.renderer.cubic_dec_d2", 1.0f, 1e-5f, 4.0f);
+    }
+
+    public static float getCubicIncD1() {
+        return getFloat("sun.java2d.renderer.cubic_inc_d1", 0.2f, 1e-6f, 1.0f);
+    }
+
+    public static float getQuadDecD2() {
+        return getFloat("sun.java2d.renderer.quad_dec_d2", 0.5f, 1e-5f, 4.0f);
+    }
+
     // system property utilities
     static boolean getBoolean(final String key, final String def) {
         return Boolean.valueOf(AccessController.doPrivileged(
@@ -182,4 +268,37 @@
         return value;
     }
 
+    static int align(final int val, final int norm) {
+        final int ceil = FloatMath.ceil_int( ((float) val) / norm);
+        return ceil * norm;
+    }
+
+    public static double getDouble(final String key, final double def,
+                                   final double min, final double max)
+    {
+        double value = def;
+        final String property = AccessController.doPrivileged(
+                                    new GetPropertyAction(key));
+
+        if (property != null) {
+            try {
+                value = Double.parseDouble(property);
+            } catch (NumberFormatException nfe) {
+                logInfo("Invalid value for " + key + " = " + property + " !");
+            }
+        }
+        // check for invalid values
+        if (value < min || value > max) {
+            logInfo("Invalid value for " + key + " = " + value
+                    + "; expect value in range[" + min + ", " + max + "] !");
+            value = def;
+        }
+        return value;
+    }
+
+    public static float getFloat(final String key, final float def,
+                                 final float min, final float max)
+    {
+        return (float)getDouble(key, def, min, max);
+    }
 }
diff --git a/src/share/classes/sun/java2d/marlin/MarlinRenderer.java b/src/share/classes/sun/java2d/marlin/MarlinRenderer.java
new file mode 100644
index 0000000..8b4e751
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/MarlinRenderer.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d.marlin;
+
+public interface MarlinRenderer extends MarlinConst {
+
+}
diff --git a/src/share/classes/sun/java2d/marlin/MarlinRenderingEngine.java b/src/share/classes/sun/java2d/marlin/MarlinRenderingEngine.java
index b7d3af4..b263689 100644
--- a/src/share/classes/sun/java2d/marlin/MarlinRenderingEngine.java
+++ b/src/share/classes/sun/java2d/marlin/MarlinRenderingEngine.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, 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
@@ -44,16 +44,58 @@
 /**
  * Marlin RendererEngine implementation (derived from Pisces)
  */
-public class MarlinRenderingEngine extends RenderingEngine
-                                   implements MarlinConst
+public final class MarlinRenderingEngine extends RenderingEngine
+                                         implements MarlinConst
 {
-    private static enum NormMode {ON_WITH_AA, ON_NO_AA, OFF}
+    // slightly slower ~2% if enabled stroker clipping (lines) but skipping cap / join handling is few percents faster in specific cases
+    static final boolean DISABLE_2ND_STROKER_CLIPPING = true;
 
-    private static final float MIN_PEN_SIZE = 1f / NORM_SUBPIXELS;
+    static final boolean DO_TRACE_PATH = false;
+
+    static final boolean TEST_CLIP = false;
+
+    static final boolean DO_CLIP = MarlinProperties.isDoClip();
+    static final boolean DO_CLIP_FILL = true;
+    static final boolean DO_CLIP_RUNTIME_ENABLE = MarlinProperties.isDoClipRuntimeFlag();
+
+    private static final float MIN_PEN_SIZE = 1.0f / MIN_SUBPIXELS;
 
     static final float UPPER_BND = Float.MAX_VALUE / 2.0f;
     static final float LOWER_BND = -UPPER_BND;
 
+    private enum NormMode {
+        ON_WITH_AA {
+            @Override
+            PathIterator getNormalizingPathIterator(final RendererContext rdrCtx,
+                                                    final PathIterator src)
+            {
+                // NormalizingPathIterator NearestPixelCenter:
+                return rdrCtx.nPCPathIterator.init(src);
+            }
+        },
+        ON_NO_AA{
+            @Override
+            PathIterator getNormalizingPathIterator(final RendererContext rdrCtx,
+                                                    final PathIterator src)
+            {
+                // NearestPixel NormalizingPathIterator:
+                return rdrCtx.nPQPathIterator.init(src);
+            }
+        },
+        OFF{
+            @Override
+            PathIterator getNormalizingPathIterator(final RendererContext rdrCtx,
+                                                    final PathIterator src)
+            {
+                // return original path iterator if normalization is disabled:
+                return src;
+            }
+        };
+
+        abstract PathIterator getNormalizingPathIterator(RendererContext rdrCtx,
+                                                         PathIterator src);
+    }
+
     /**
      * Public constructor
      */
@@ -91,13 +133,7 @@
         final RendererContext rdrCtx = getRendererContext();
         try {
             // initialize a large copyable Path2D to avoid a lot of array growing:
-            final Path2D.Float p2d =
-                    (rdrCtx.p2d == null) ?
-                    (rdrCtx.p2d = new Path2D.Float(Path2D.WIND_NON_ZERO,
-                                                   INITIAL_MEDIUM_ARRAY))
-                    : rdrCtx.p2d;
-            // reset
-            p2d.reset();
+            final Path2D.Float p2d = rdrCtx.getPath2D();
 
             strokeTo(rdrCtx,
                      src,
@@ -109,7 +145,7 @@
                      miterlimit,
                      dashes,
                      dashphase,
-                     rdrCtx.transformerPC2D.wrapPath2d(p2d)
+                     rdrCtx.transformerPC2D.wrapPath2D(p2d)
                     );
 
             // Use Path2D copy constructor (trim)
@@ -128,11 +164,11 @@
      * The specified {@code src} {@link Shape} is widened according
      * to the parameters specified by the {@link BasicStroke} object.
      * Adjustments are made to the path as appropriate for the
-     * {@link VALUE_STROKE_NORMALIZE} hint if the {@code normalize}
-     * boolean parameter is true.
+     * {@link java.awt.RenderingHints#VALUE_STROKE_NORMALIZE} hint if the
+     * {@code normalize} boolean parameter is true.
      * Adjustments are made to the path as appropriate for the
-     * {@link VALUE_ANTIALIAS_ON} hint if the {@code antialias}
-     * boolean parameter is true.
+     * {@link java.awt.RenderingHints#VALUE_ANTIALIAS_ON} hint if the
+     * {@code antialias} boolean parameter is true.
      * <p>
      * The geometry of the widened path is forwarded to the indicated
      * {@link PathConsumer2D} object as it is calculated.
@@ -170,14 +206,14 @@
         }
     }
 
-    final void strokeTo(final RendererContext rdrCtx,
-                        Shape src,
-                        AffineTransform at,
-                        BasicStroke bs,
-                        boolean thin,
-                        NormMode normalize,
-                        boolean antialias,
-                        PathConsumer2D pc2d)
+    void strokeTo(final RendererContext rdrCtx,
+                  Shape src,
+                  AffineTransform at,
+                  BasicStroke bs,
+                  boolean thin,
+                  NormMode normalize,
+                  boolean antialias,
+                  PathConsumer2D pc2d)
     {
         float lw;
         if (thin) {
@@ -202,7 +238,7 @@
                  pc2d);
     }
 
-    private final float userSpaceLineWidth(AffineTransform at, float lw) {
+    private float userSpaceLineWidth(AffineTransform at, float lw) {
 
         float widthScale;
 
@@ -234,7 +270,7 @@
              */
 
             double EA = A*A + B*B;          // x^2 coefficient
-            double EB = 2.0*(A*C + B*D);    // xy coefficient
+            double EB = 2.0d * (A*C + B*D); // xy coefficient
             double EC = C*C + D*D;          // y^2 coefficient
 
             /*
@@ -262,7 +298,7 @@
 
             double hypot = Math.sqrt(EB*EB + (EA-EC)*(EA-EC));
             // sqrt omitted, compare to squared limits below.
-            double widthsquared = ((EA + EC + hypot)/2.0);
+            double widthsquared = ((EA + EC + hypot) / 2.0d);
 
             widthScale = (float)Math.sqrt(widthsquared);
         }
@@ -270,17 +306,17 @@
         return (lw / widthScale);
     }
 
-    final void strokeTo(final RendererContext rdrCtx,
-                        Shape src,
-                        AffineTransform at,
-                        float width,
-                        NormMode normalize,
-                        int caps,
-                        int join,
-                        float miterlimit,
-                        float[] dashes,
-                        float dashphase,
-                        PathConsumer2D pc2d)
+    void strokeTo(final RendererContext rdrCtx,
+                  Shape src,
+                  AffineTransform at,
+                  float width,
+                  NormMode norm,
+                  int caps,
+                  int join,
+                  float miterlimit,
+                  float[] dashes,
+                  float dashphase,
+                  PathConsumer2D pc2d)
     {
         // We use strokerat so that in Stroker and Dasher we can work only
         // with the pre-transformation coordinates. This will repeat a lot of
@@ -299,6 +335,7 @@
 
         int dashLen = -1;
         boolean recycleDashes = false;
+        float scale = 1.0f;
 
         if (at != null && !at.isIdentity()) {
             final double a = at.getScaleX();
@@ -307,7 +344,7 @@
             final double d = at.getScaleY();
             final double det = a * d - c * b;
 
-            if (Math.abs(det) <= (2f * Float.MIN_VALUE)) {
+            if (Math.abs(det) <= (2.0f * Float.MIN_VALUE)) {
                 // this rendering engine takes one dimensional curves and turns
                 // them into 2D shapes by giving them width.
                 // However, if everything is to be passed through a singular
@@ -319,7 +356,7 @@
                 // of writing of this comment (September 16, 2010)). Actually,
                 // I am not sure if the moveTo is necessary to avoid the SIGSEGV
                 // but the pathDone is definitely needed.
-                pc2d.moveTo(0f, 0f);
+                pc2d.moveTo(0.0f, 0.0f);
                 pc2d.pathDone();
                 return;
             }
@@ -331,23 +368,12 @@
             // a*b == -c*d && a*a+c*c == b*b+d*d. In the actual check below, we
             // leave a bit of room for error.
             if (nearZero(a*b + c*d) && nearZero(a*a + c*c - (b*b + d*d))) {
-                final float scale = (float) Math.sqrt(a*a + c*c);
+                scale = (float) Math.sqrt(a*a + c*c);
 
                 if (dashes != null) {
                     recycleDashes = true;
                     dashLen = dashes.length;
-                    final float[] newDashes;
-                    if (dashLen <= INITIAL_ARRAY) {
-                        newDashes = rdrCtx.dasher.dashes_initial;
-                    } else {
-                        if (DO_STATS) {
-                            rdrCtx.stats.stat_array_dasher_dasher
-                                .add(dashLen);
-                        }
-                        newDashes = rdrCtx.getDirtyFloatArray(dashLen);
-                    }
-                    System.arraycopy(dashes, 0, newDashes, 0, dashLen);
-                    dashes = newDashes;
+                    dashes = rdrCtx.dasher.copyDashArray(dashes);
                     for (int i = 0; i < dashLen; i++) {
                         dashes[i] *= scale;
                     }
@@ -380,28 +406,62 @@
             at = null;
         }
 
+        final TransformingPathConsumer2D transformerPC2D = rdrCtx.transformerPC2D;
+
+        if (DO_TRACE_PATH) {
+            // trace Stroker:
+            pc2d = transformerPC2D.traceStroker(pc2d);
+        }
+
         if (USE_SIMPLIFIER) {
             // Use simplifier after stroker before Renderer
             // to remove collinear segments (notably due to cap square)
             pc2d = rdrCtx.simplifier.init(pc2d);
         }
 
-        final TransformingPathConsumer2D transformerPC2D = rdrCtx.transformerPC2D;
+        // deltaTransformConsumer may adjust the clip rectangle:
         pc2d = transformerPC2D.deltaTransformConsumer(pc2d, strokerat);
 
-        pc2d = rdrCtx.stroker.init(pc2d, width, caps, join, miterlimit);
+        // stroker will adjust the clip rectangle (width / miter limit):
+        pc2d = rdrCtx.stroker.init(pc2d, width, caps, join, miterlimit, scale,
+                (dashes == null));
+
+        // Curve Monotizer:
+        rdrCtx.monotonizer.init(width);
 
         if (dashes != null) {
             if (!recycleDashes) {
                 dashLen = dashes.length;
             }
+            if (DO_TRACE_PATH) {
+                pc2d = transformerPC2D.traceDasher(pc2d);
+            }
             pc2d = rdrCtx.dasher.init(pc2d, dashes, dashLen, dashphase,
                                       recycleDashes);
+
+            if (DISABLE_2ND_STROKER_CLIPPING) {
+                // disable stoker clipping
+                rdrCtx.stroker.disableClipping();
+            }
+
+        } else if (rdrCtx.doClip && (caps != Stroker.CAP_BUTT)) {
+            if (DO_TRACE_PATH) {
+                pc2d = transformerPC2D.traceClosedPathDetector(pc2d);
+            }
+
+            // If no dash and clip is enabled:
+            // detect closedPaths (polygons) for caps
+            pc2d = transformerPC2D.detectClosedPath(pc2d);
         }
         pc2d = transformerPC2D.inverseDeltaTransformConsumer(pc2d, strokerat);
 
-        final PathIterator pi = getNormalizingPathIterator(rdrCtx, normalize,
-                                    src.getPathIterator(at));
+        if (DO_TRACE_PATH) {
+            // trace Input:
+            pc2d = transformerPC2D.traceInput(pc2d);
+        }
+
+        final PathIterator pi = norm.getNormalizingPathIterator(rdrCtx,
+                                         src.getPathIterator(at));
 
         pathTo(rdrCtx, pi, pc2d);
 
@@ -421,26 +481,7 @@
     }
 
     private static boolean nearZero(final double num) {
-        return Math.abs(num) < 2.0 * Math.ulp(num);
-    }
-
-    PathIterator getNormalizingPathIterator(final RendererContext rdrCtx,
-                                            final NormMode mode,
-                                            final PathIterator src)
-    {
-        switch (mode) {
-            case ON_WITH_AA:
-                // NormalizingPathIterator NearestPixelCenter:
-                return rdrCtx.nPCPathIterator.init(src);
-            case ON_NO_AA:
-                // NearestPixel NormalizingPathIterator:
-                return rdrCtx.nPQPathIterator.init(src);
-            case OFF:
-                // return original path iterator if normalization is disabled:
-                return src;
-            default:
-                throw new InternalError("Unrecognized normalization mode");
-        }
+        return Math.abs(num) < 2.0d * Math.ulp(num);
     }
 
     abstract static class NormalizingPathIterator implements PathIterator {
@@ -519,8 +560,8 @@
                 case PathIterator.SEG_LINETO:
                     break;
                 case PathIterator.SEG_QUADTO:
-                    coords[0] += (curx_adjust + x_adjust) / 2f;
-                    coords[1] += (cury_adjust + y_adjust) / 2f;
+                    coords[0] += (curx_adjust + x_adjust) / 2.0f;
+                    coords[1] += (cury_adjust + y_adjust) / 2.0f;
                     break;
                 case PathIterator.SEG_CUBICTO:
                     coords[0] += curx_adjust;
@@ -599,14 +640,18 @@
     }
 
     private static void pathTo(final RendererContext rdrCtx, final PathIterator pi,
-                               final PathConsumer2D pc2d)
+                               PathConsumer2D pc2d)
     {
+        if (USE_PATH_SIMPLIFIER) {
+            // Use path simplifier at the first step
+            // to remove useless points
+            pc2d = rdrCtx.pathSimplifier.init(pc2d);
+        }
+
         // mark context as DIRTY:
         rdrCtx.dirty = true;
 
-        final float[] coords = rdrCtx.float6;
-
-        pathToLoop(coords, pi, pc2d);
+        pathToLoop(rdrCtx.float6, pi, pc2d);
 
         // mark context as CLEAN:
         rdrCtx.dirty = false;
@@ -784,6 +829,30 @@
 
         final RendererContext rdrCtx = getRendererContext();
         try {
+            if (DO_CLIP || (DO_CLIP_RUNTIME_ENABLE && MarlinProperties.isDoClipAtRuntime())) {
+                // Define the initial clip bounds:
+                final float[] clipRect = rdrCtx.clipRect;
+
+                if (TEST_CLIP) {
+                    float small = clip.getHeight() / 8.0f;
+                    float half = (clip.getLoY() + clip.getHeight()) / 2.0f;
+                    clipRect[0] = half - small;
+                    clipRect[1] = half + small;
+                    small = clip.getWidth() / 4.0f;
+                    half = (clip.getLoX() + clip.getWidth()) / 2.0f;
+                    clipRect[2] = half - small;
+                    clipRect[3] = half + small;
+                } else {
+                    clipRect[0] = clip.getLoY();
+                    clipRect[1] = clip.getLoY() + clip.getHeight();
+                    clipRect[2] = clip.getLoX();
+                    clipRect[3] = clip.getLoX() + clip.getWidth();
+                }
+
+                // Enable clipping:
+                rdrCtx.doClip = true;
+            }
+
             // Test if at is identity:
             final AffineTransform _at = (at != null && !at.isIdentity()) ? at
                                         : null;
@@ -792,21 +861,37 @@
 
             if (bs == null) {
                 // fill shape:
-                final PathIterator pi = getNormalizingPathIterator(rdrCtx, norm,
-                                            s.getPathIterator(_at));
+                final PathIterator pi = norm.getNormalizingPathIterator(rdrCtx,
+                                                 s.getPathIterator(_at));
 
                 // note: Winding rule may be EvenOdd ONLY for fill operations !
                 r = rdrCtx.renderer.init(clip.getLoX(), clip.getLoY(),
                                          clip.getWidth(), clip.getHeight(),
                                          pi.getWindingRule());
 
+                PathConsumer2D pc2d = r;
+
+                if (DO_CLIP_FILL && rdrCtx.doClip) {
+                    if (DO_TRACE_PATH) {
+                        // trace Filler:
+                        pc2d = rdrCtx.transformerPC2D.traceFiller(pc2d);
+                    }
+                    pc2d = rdrCtx.transformerPC2D.pathClipper(pc2d);
+                }
+
+                if (DO_TRACE_PATH) {
+                    // trace Input:
+                    pc2d = rdrCtx.transformerPC2D.traceInput(pc2d);
+                }
+
                 // TODO: subdivide quad/cubic curves into monotonic curves ?
-                pathTo(rdrCtx, pi, r);
+                pathTo(rdrCtx, pi, pc2d);
+
             } else {
                 // draw shape with given stroke:
                 r = rdrCtx.renderer.init(clip.getLoX(), clip.getLoY(),
                                          clip.getWidth(), clip.getHeight(),
-                                         PathIterator.WIND_NON_ZERO);
+                                         WIND_NON_ZERO);
 
                 strokeTo(rdrCtx, s, _at, bs, thin, norm, true, r);
             }
@@ -819,10 +904,8 @@
             }
         } finally {
             if (r != null) {
-                // dispose renderer:
+                // dispose renderer and recycle the RendererContext instance:
                 r.dispose();
-                // recycle the RendererContext instance
-                MarlinRenderingEngine.returnRendererContext(rdrCtx);
             }
         }
 
@@ -831,34 +914,34 @@
     }
 
     @Override
-    public final AATileGenerator getAATileGenerator(double x, double y,
-                                                    double dx1, double dy1,
-                                                    double dx2, double dy2,
-                                                    double lw1, double lw2,
-                                                    Region clip,
-                                                    int[] bbox)
+    public AATileGenerator getAATileGenerator(double x, double y,
+                                              double dx1, double dy1,
+                                              double dx2, double dy2,
+                                              double lw1, double lw2,
+                                              Region clip,
+                                              int[] bbox)
     {
         // REMIND: Deal with large coordinates!
         double ldx1, ldy1, ldx2, ldy2;
-        boolean innerpgram = (lw1 > 0.0 && lw2 > 0.0);
+        boolean innerpgram = (lw1 > 0.0d && lw2 > 0.0d);
 
         if (innerpgram) {
             ldx1 = dx1 * lw1;
             ldy1 = dy1 * lw1;
             ldx2 = dx2 * lw2;
             ldy2 = dy2 * lw2;
-            x -= (ldx1 + ldx2) / 2.0;
-            y -= (ldy1 + ldy2) / 2.0;
+            x -= (ldx1 + ldx2) / 2.0d;
+            y -= (ldy1 + ldy2) / 2.0d;
             dx1 += ldx1;
             dy1 += ldy1;
             dx2 += ldx2;
             dy2 += ldy2;
-            if (lw1 > 1.0 && lw2 > 1.0) {
+            if (lw1 > 1.0d && lw2 > 1.0d) {
                 // Inner parallelogram was entirely consumed by stroke...
                 innerpgram = false;
             }
         } else {
-            ldx1 = ldy1 = ldx2 = ldy2 = 0.0;
+            ldx1 = ldy1 = ldx2 = ldy2 = 0.0d;
         }
 
         MarlinTileGenerator ptg = null;
@@ -867,8 +950,8 @@
         final RendererContext rdrCtx = getRendererContext();
         try {
             r = rdrCtx.renderer.init(clip.getLoX(), clip.getLoY(),
-                                         clip.getWidth(), clip.getHeight(),
-                                         Renderer.WIND_EVEN_ODD);
+                                     clip.getWidth(), clip.getHeight(),
+                                     WIND_EVEN_ODD);
 
             r.moveTo((float) x, (float) y);
             r.lineTo((float) (x+dx1), (float) (y+dy1));
@@ -879,10 +962,10 @@
             if (innerpgram) {
                 x += ldx1 + ldx2;
                 y += ldy1 + ldy2;
-                dx1 -= 2.0 * ldx1;
-                dy1 -= 2.0 * ldy1;
-                dx2 -= 2.0 * ldx2;
-                dy2 -= 2.0 * ldy2;
+                dx1 -= 2.0d * ldx1;
+                dy1 -= 2.0d * ldy1;
+                dx2 -= 2.0d * ldx2;
+                dy2 -= 2.0d * ldy2;
                 r.moveTo((float) x, (float) y);
                 r.lineTo((float) (x+dx1), (float) (y+dy1));
                 r.lineTo((float) (x+dx1+dx2), (float) (y+dy1+dy2));
@@ -900,10 +983,8 @@
             }
         } finally {
             if (r != null) {
-                // dispose renderer:
+                // dispose renderer and recycle the RendererContext instance:
                 r.dispose();
-                // recycle the RendererContext instance
-                MarlinRenderingEngine.returnRendererContext(rdrCtx);
             }
         }
 
@@ -922,14 +1003,14 @@
     }
 
     static {
-        if (PathIterator.WIND_NON_ZERO != Renderer.WIND_NON_ZERO ||
-            PathIterator.WIND_EVEN_ODD != Renderer.WIND_EVEN_ODD ||
-            BasicStroke.JOIN_MITER != Stroker.JOIN_MITER ||
-            BasicStroke.JOIN_ROUND != Stroker.JOIN_ROUND ||
-            BasicStroke.JOIN_BEVEL != Stroker.JOIN_BEVEL ||
-            BasicStroke.CAP_BUTT != Stroker.CAP_BUTT ||
-            BasicStroke.CAP_ROUND != Stroker.CAP_ROUND ||
-            BasicStroke.CAP_SQUARE != Stroker.CAP_SQUARE)
+        if (PathIterator.WIND_NON_ZERO != WIND_NON_ZERO ||
+            PathIterator.WIND_EVEN_ODD != WIND_EVEN_ODD ||
+            BasicStroke.JOIN_MITER != JOIN_MITER ||
+            BasicStroke.JOIN_ROUND != JOIN_ROUND ||
+            BasicStroke.JOIN_BEVEL != JOIN_BEVEL ||
+            BasicStroke.CAP_BUTT != CAP_BUTT ||
+            BasicStroke.CAP_ROUND != CAP_ROUND ||
+            BasicStroke.CAP_SQUARE != CAP_SQUARE)
         {
             throw new InternalError("mismatched renderer constants");
         }
@@ -953,17 +1034,14 @@
         final String refType = AccessController.doPrivileged(
                             new GetPropertyAction("sun.java2d.renderer.useRef",
                             "soft"));
-        switch (refType) {
-            default:
-            case "soft":
-                REF_TYPE = ReentrantContextProvider.REF_SOFT;
-                break;
-            case "weak":
-                REF_TYPE = ReentrantContextProvider.REF_WEAK;
-                break;
-            case "hard":
-                REF_TYPE = ReentrantContextProvider.REF_HARD;
-                break;
+
+        // Java 1.6 does not support strings in switch:
+        if ("hard".equalsIgnoreCase(refType)) {
+            REF_TYPE = ReentrantContextProvider.REF_HARD;
+        } else if ("weak".equalsIgnoreCase(refType)) {
+            REF_TYPE = ReentrantContextProvider.REF_WEAK;
+        } else {
+            REF_TYPE = ReentrantContextProvider.REF_SOFT;
         }
 
         if (USE_THREAD_LOCAL) {
@@ -1021,18 +1099,22 @@
         logInfo("sun.java2d.renderer.useRef           = "
                 + refType);
 
-        logInfo("sun.java2d.renderer.pixelsize        = "
-                + MarlinConst.INITIAL_PIXEL_DIM);
+        logInfo("sun.java2d.renderer.edges            = "
+                + MarlinConst.INITIAL_EDGES_COUNT);
+        logInfo("sun.java2d.renderer.pixelWidth       = "
+                + MarlinConst.INITIAL_PIXEL_WIDTH);
+        logInfo("sun.java2d.renderer.pixelHeight      = "
+                + MarlinConst.INITIAL_PIXEL_HEIGHT);
+
         logInfo("sun.java2d.renderer.subPixel_log2_X  = "
                 + MarlinConst.SUBPIXEL_LG_POSITIONS_X);
         logInfo("sun.java2d.renderer.subPixel_log2_Y  = "
                 + MarlinConst.SUBPIXEL_LG_POSITIONS_Y);
+
         logInfo("sun.java2d.renderer.tileSize_log2    = "
-                + MarlinConst.TILE_SIZE_LG);
-
-        logInfo("sun.java2d.renderer.blockSize_log2   = "
-                + MarlinConst.BLOCK_SIZE_LG);
-
+                + MarlinConst.TILE_H_LG);
+        logInfo("sun.java2d.renderer.tileWidth_log2   = "
+                + MarlinConst.TILE_W_LG);
         logInfo("sun.java2d.renderer.blockSize_log2   = "
                 + MarlinConst.BLOCK_SIZE_LG);
 
@@ -1052,6 +1134,20 @@
         // optimisation parameters
         logInfo("sun.java2d.renderer.useSimplifier    = "
                 + MarlinConst.USE_SIMPLIFIER);
+        logInfo("sun.java2d.renderer.usePathSimplifier= "
+                + MarlinConst.USE_PATH_SIMPLIFIER);
+        logInfo("sun.java2d.renderer.pathSimplifier.pixTol = "
+                + MarlinProperties.getPathSimplifierPixelTolerance());
+
+        logInfo("sun.java2d.renderer.clip             = "
+                + MarlinProperties.isDoClip());
+        logInfo("sun.java2d.renderer.clip.runtime.enable = "
+                + MarlinProperties.isDoClipRuntimeFlag());
+
+        logInfo("sun.java2d.renderer.clip.subdivider  = "
+                + MarlinProperties.isDoClipSubdivider());
+        logInfo("sun.java2d.renderer.clip.subdivider.minLength = "
+                + MarlinProperties.getSubdividerMinLength());
 
         // debugging parameters
         logInfo("sun.java2d.renderer.doStats          = "
@@ -1070,12 +1166,25 @@
                 + MarlinConst.LOG_UNSAFE_MALLOC);
 
         // quality settings
+        logInfo("sun.java2d.renderer.curve_len_err    = "
+                + MarlinProperties.getCurveLengthError());
+        logInfo("sun.java2d.renderer.cubic_dec_d2     = "
+                + MarlinProperties.getCubicDecD2());
+        logInfo("sun.java2d.renderer.cubic_inc_d1     = "
+                + MarlinProperties.getCubicIncD1());
+        logInfo("sun.java2d.renderer.quad_dec_d2      = "
+                + MarlinProperties.getQuadDecD2());
+
         logInfo("Renderer settings:");
-        logInfo("CUB_COUNT_LG = " + Renderer.CUB_COUNT_LG);
         logInfo("CUB_DEC_BND  = " + Renderer.CUB_DEC_BND);
         logInfo("CUB_INC_BND  = " + Renderer.CUB_INC_BND);
         logInfo("QUAD_DEC_BND = " + Renderer.QUAD_DEC_BND);
 
+        logInfo("INITIAL_EDGES_CAPACITY               = "
+                + MarlinConst.INITIAL_EDGES_CAPACITY);
+        logInfo("INITIAL_CROSSING_COUNT               = "
+                + Renderer.INITIAL_CROSSING_COUNT);
+
         logInfo("=========================================================="
                 + "=====================");
     }
diff --git a/src/share/classes/sun/java2d/marlin/MarlinTileGenerator.java b/src/share/classes/sun/java2d/marlin/MarlinTileGenerator.java
index 824660f..2882d68 100644
--- a/src/share/classes/sun/java2d/marlin/MarlinTileGenerator.java
+++ b/src/share/classes/sun/java2d/marlin/MarlinTileGenerator.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, 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
@@ -25,25 +25,54 @@
 
 package sun.java2d.marlin;
 
+import java.util.Arrays;
 import sun.java2d.pipe.AATileGenerator;
+//import jdk.internal.misc.Unsafe;
 import sun.misc.Unsafe;
 
 final class MarlinTileGenerator implements AATileGenerator, MarlinConst {
 
-    private static final int MAX_TILE_ALPHA_SUM = TILE_SIZE * TILE_SIZE
-                                                      * MAX_AA_ALPHA;
+    private static final boolean DISABLE_BLEND = false;
 
-    private final Renderer rdr;
+    private static final int MAX_TILE_ALPHA_SUM = TILE_W * TILE_H * MAX_AA_ALPHA;
+
+    private static final int TH_AA_ALPHA_FILL_EMPTY = ((MAX_AA_ALPHA + 1) / 3); // 33%
+    private static final int TH_AA_ALPHA_FILL_FULL  = ((MAX_AA_ALPHA + 1) * 2 / 3); // 66%
+
+    private static final int FILL_TILE_W = TILE_W >> 1; // half tile width
+
+    static {
+        if (MAX_TILE_ALPHA_SUM <= 0) {
+            throw new IllegalStateException("Invalid MAX_TILE_ALPHA_SUM: " + MAX_TILE_ALPHA_SUM);
+        }
+        if (DO_TRACE) {
+            System.out.println("MAX_AA_ALPHA           : " + MAX_AA_ALPHA);
+            System.out.println("TH_AA_ALPHA_FILL_EMPTY : " + TH_AA_ALPHA_FILL_EMPTY);
+            System.out.println("TH_AA_ALPHA_FILL_FULL  : " + TH_AA_ALPHA_FILL_FULL);
+            System.out.println("FILL_TILE_W            : " + FILL_TILE_W);
+        }
+    }
+
+    private final Renderer rdrF;
+    private final DRenderer rdrD;
     private final MarlinCache cache;
     private int x, y;
 
-    // per-thread renderer context
-    final RendererContext rdrCtx;
+    // per-thread renderer stats
+    final RendererStats rdrStats;
 
-    MarlinTileGenerator(Renderer r) {
-        this.rdr = r;
-        this.cache = r.cache;
-        this.rdrCtx = r.rdrCtx;
+    MarlinTileGenerator(final RendererStats stats, final MarlinRenderer r,
+                        final MarlinCache cache)
+    {
+        this.rdrStats = stats;
+        if (r instanceof Renderer) {
+            this.rdrF = (Renderer)r;
+            this.rdrD = null;
+        } else {
+            this.rdrF = null;
+            this.rdrD = (DRenderer)r;
+        }
+        this.cache = cache;
     }
 
     MarlinTileGenerator init() {
@@ -61,14 +90,17 @@
     public void dispose() {
         if (DO_MONITORS) {
             // called from AAShapePipe.renderTiles() (render tiles end):
-            rdrCtx.stats.mon_pipe_renderTiles.stop();
+            rdrStats.mon_pipe_renderTiles.stop();
         }
         // dispose cache:
         cache.dispose();
-        // dispose renderer:
-        rdr.dispose();
-        // recycle the RendererContext instance
-        MarlinRenderingEngine.returnRendererContext(rdrCtx);
+        // dispose renderer and recycle the RendererContext instance:
+        // bimorphic call optimization:
+        if (rdrF != null) {
+            rdrF.dispose();
+        } else if (rdrD != null) {
+            rdrD.dispose();
+        }
     }
 
     void getBbox(int[] bbox) {
@@ -86,9 +118,9 @@
     public int getTileWidth() {
         if (DO_MONITORS) {
             // called from AAShapePipe.renderTiles() (render tiles start):
-            rdrCtx.stats.mon_pipe_renderTiles.start();
+            rdrStats.mon_pipe_renderTiles.start();
         }
-        return TILE_SIZE;
+        return TILE_W;
     }
 
     /**
@@ -97,7 +129,7 @@
      */
     @Override
     public int getTileHeight() {
-        return TILE_SIZE;
+        return TILE_H;
     }
 
     /**
@@ -112,6 +144,10 @@
      */
     @Override
     public int getTypicalAlpha() {
+        if (DISABLE_BLEND) {
+            // always return empty tiles to disable blending operations
+            return 0x00;
+        }
         int al = cache.alphaSumInTile(x);
         // Note: if we have a filled rectangle that doesn't end on a tile
         // border, we could still return 0xff, even though al!=maxTileAlphaSum
@@ -131,7 +167,7 @@
         final int alpha = (al == 0x00 ? 0x00
                               : (al == MAX_TILE_ALPHA_SUM ? 0xff : 0x80));
         if (DO_STATS) {
-            rdrCtx.stats.hist_tile_generator_alpha.add(alpha);
+            rdrStats.hist_tile_generator_alpha.add(alpha);
         }
         return alpha;
     }
@@ -143,14 +179,19 @@
      */
     @Override
     public void nextTile() {
-        if ((x += TILE_SIZE) >= cache.bboxX1) {
+        if ((x += TILE_W) >= cache.bboxX1) {
             x = cache.bboxX0;
-            y += TILE_SIZE;
+            y += TILE_H;
 
             if (y < cache.bboxY1) {
                 // compute for the tile line
                 // [ y; max(y + TILE_SIZE, bboxY1) ]
-                this.rdr.endRendering(y);
+                // bimorphic call optimization:
+                if (rdrF != null) {
+                    rdrF.endRendering(y);
+                } else if (rdrD != null) {
+                    rdrD.endRendering(y);
+                }
             }
         }
     }
@@ -180,7 +221,7 @@
                                final int rowstride)
     {
         if (DO_MONITORS) {
-            rdrCtx.stats.mon_ptg_getAlpha.start();
+            rdrStats.mon_ptg_getAlpha.start();
         }
 
         // local vars for performance:
@@ -190,11 +231,11 @@
         final int[] rowAAx1 = _cache.rowAAx1;
 
         final int x0 = this.x;
-        final int x1 = FloatMath.min(x0 + TILE_SIZE, _cache.bboxX1);
+        final int x1 = FloatMath.min(x0 + TILE_W, _cache.bboxX1);
 
         // note: process tile line [0 - 32[
         final int y0 = 0;
-        final int y1 = FloatMath.min(this.y + TILE_SIZE, _cache.bboxY1) - this.y;
+        final int y1 = FloatMath.min(this.y + TILE_H, _cache.bboxY1) - this.y;
 
         if (DO_LOG_BOUNDS) {
             MarlinUtils.logInfo("getAlpha = [" + x0 + " ... " + x1
@@ -237,14 +278,14 @@
                         }
                     }
 
-                    // now: cx >= x0 but cx < aax0 (x1 < aax0)
+                    // now: cx >= x0 and cx >= aax0
 
                     // Copy AA data (sum alpha data):
                     addr = addr_rowAA + rowAAChunkIndex[cy] + (cx - aax0);
 
                     for (end = (aax1 <= x1) ? aax1 : x1; cx < end; cx++) {
                         // cx inside tile[x0; x1[ :
-                        tile[idx++] = _unsafe.getByte(addr); // [0..255]
+                        tile[idx++] = _unsafe.getByte(addr); // [0-255]
                         addr += SIZE;
                     }
                 }
@@ -269,7 +310,7 @@
         nextTile();
 
         if (DO_MONITORS) {
-            rdrCtx.stats.mon_ptg_getAlpha.stop();
+            rdrStats.mon_ptg_getAlpha.stop();
         }
     }
 
@@ -282,7 +323,7 @@
                              final int rowstride)
     {
         if (DO_MONITORS) {
-            rdrCtx.stats.mon_ptg_getAlpha.start();
+            rdrStats.mon_ptg_getAlpha.start();
         }
 
         // Decode run-length encoded alpha mask data
@@ -300,24 +341,48 @@
         final long[] rowAAPos = _cache.rowAAPos;
 
         final int x0 = this.x;
-        final int x1 = FloatMath.min(x0 + TILE_SIZE, _cache.bboxX1);
+        final int x1 = FloatMath.min(x0 + TILE_W, _cache.bboxX1);
+        final int w  = x1 - x0;
 
         // note: process tile line [0 - 32[
         final int y0 = 0;
-        final int y1 = FloatMath.min(this.y + TILE_SIZE, _cache.bboxY1) - this.y;
+        final int y1 = FloatMath.min(this.y + TILE_H, _cache.bboxY1) - this.y;
 
         if (DO_LOG_BOUNDS) {
             MarlinUtils.logInfo("getAlpha = [" + x0 + " ... " + x1
                                 + "[ [" + y0 + " ... " + y1 + "[");
         }
 
+        // avoid too small area: fill is not faster !
+        final int clearTile;
+        final byte refVal;
+        final int area;
+
+        if ((w >= FILL_TILE_W) && (area = w * y1) > 64) { // 64 / 4 ie 16 words min (faster)
+            final int alphaSum = cache.alphaSumInTile(x0);
+
+            if (alphaSum < area * TH_AA_ALPHA_FILL_EMPTY) {
+                clearTile = 1;
+                refVal = 0;
+            } else if (alphaSum > area * TH_AA_ALPHA_FILL_FULL) {
+                clearTile = 2;
+                refVal = (byte)0xff;
+            } else {
+                clearTile = 0;
+                refVal = 0;
+            }
+        } else {
+            clearTile = 0;
+            refVal = 0;
+        }
+
         final Unsafe _unsafe = OffHeapArray.UNSAFE;
         final long SIZE_BYTE = 1L;
         final long SIZE_INT = 4L;
         final long addr_rowAA = _cache.rowAAChunk.address;
         long addr, addr_row, last_addr, addr_end;
 
-        final int skipRowPixels = (rowstride - (x1 - x0));
+        final int skipRowPixels = (rowstride - w);
 
         int cx, cy, cx1;
         int rx0, rx1, runLen, end;
@@ -325,137 +390,414 @@
         byte val;
         int idx = offset;
 
-        for (cy = y0; cy < y1; cy++) {
-            // empty line (default)
-            cx = x0;
+        switch (clearTile) {
+        case 1: // 0x00
+            // Clear full tile rows:
+            Arrays.fill(tile, offset, offset + (y1 * rowstride), refVal);
 
-            if (rowAAEnc[cy] == 0) {
-                // Raw encoding:
+            for (cy = y0; cy < y1; cy++) {
+                // empty line (default)
+                cx = x0;
 
-                final int aax1 = rowAAx1[cy]; // exclusive
+                if (rowAAEnc[cy] == 0) {
+                    // Raw encoding:
 
-                // quick check if there is AA data
-                // corresponding to this tile [x0; x1[
-                if (aax1 > x0) {
-                    final int aax0 = rowAAx0[cy]; // inclusive
+                    final int aax1 = rowAAx1[cy]; // exclusive
 
-                    if (aax0 < x1) {
-                        // note: cx is the cursor pointer in the tile array
-                        // (left to right)
-                        cx = aax0;
+                    // quick check if there is AA data
+                    // corresponding to this tile [x0; x1[
+                    if (aax1 > x0) {
+                        final int aax0 = rowAAx0[cy]; // inclusive
 
-                        // ensure cx >= x0
-                        if (cx <= x0) {
-                            cx = x0;
-                        } else {
-                            // fill line start until first AA pixel rowAA exclusive:
-                            for (end = x0; end < cx; end++) {
-                                tile[idx++] = 0;
+                        if (aax0 < x1) {
+                            // note: cx is the cursor pointer in the tile array
+                            // (left to right)
+                            cx = aax0;
+
+                            // ensure cx >= x0
+                            if (cx <= x0) {
+                                cx = x0;
+                            } else {
+                                // skip line start until first AA pixel rowAA exclusive:
+                                idx += (cx - x0); // > 0
+                            }
+
+                            // now: cx >= x0 and cx >= aax0
+
+                            // Copy AA data (sum alpha data):
+                            addr = addr_rowAA + rowAAChunkIndex[cy] + (cx - aax0);
+
+                            for (end = (aax1 <= x1) ? aax1 : x1; cx < end; cx++) {
+                                tile[idx++] = _unsafe.getByte(addr); // [0-255]
+                                addr += SIZE_BYTE;
+                            }
+                        }
+                    }
+                } else {
+                    // RLE encoding:
+
+                    // quick check if there is AA data
+                    // corresponding to this tile [x0; x1[
+                    if (rowAAx1[cy] > x0) { // last pixel exclusive
+
+                        cx = rowAAx0[cy]; // inclusive
+                        if (cx > x1) {
+                            cx = x1;
+                        }
+
+                        // skip line start until first AA pixel rowAA exclusive:
+                        if (cx > x0) {
+                            idx += (cx - x0); // > 0
+                        }
+
+                        // get row address:
+                        addr_row = addr_rowAA + rowAAChunkIndex[cy];
+                        // get row end address:
+                        addr_end = addr_row + rowAALen[cy]; // coded length
+
+                        // reuse previous iteration position:
+                        addr = addr_row + rowAAPos[cy];
+
+                        last_addr = 0L;
+
+                        while ((cx < x1) && (addr < addr_end)) {
+                            // keep current position:
+                            last_addr = addr;
+
+                            // packed value:
+                            packed = _unsafe.getInt(addr);
+
+                            // last exclusive pixel x-coordinate:
+                            cx1 = (packed >> 8);
+                            // as bytes:
+                            addr += SIZE_INT;
+
+                            rx0 = cx;
+                            if (rx0 < x0) {
+                                rx0 = x0;
+                            }
+                            rx1 = cx = cx1;
+                            if (rx1 > x1) {
+                                rx1 = x1;
+                                cx  = x1; // fix last x
+                            }
+                            // adjust runLen:
+                            runLen = rx1 - rx0;
+
+                            // ensure rx1 > rx0:
+                            if (runLen > 0) {
+                                packed &= 0xFF; // [0-255]
+
+                                if (packed == 0)
+                                {
+                                    idx += runLen;
+                                    continue;
+                                }
+                                val = (byte) packed; // [0-255]
+                                do {
+                                    tile[idx++] = val;
+                                } while (--runLen > 0);
                             }
                         }
 
-                        // now: cx >= x0 but cx < aax0 (x1 < aax0)
-
-                        // Copy AA data (sum alpha data):
-                        addr = addr_rowAA + rowAAChunkIndex[cy] + (cx - aax0);
-
-                        for (end = (aax1 <= x1) ? aax1 : x1; cx < end; cx++) {
-                            tile[idx++] = _unsafe.getByte(addr); // [0..255]
-                            addr += SIZE_BYTE;
+                        // Update last position in RLE entries:
+                        if (last_addr != 0L) {
+                            // Fix x0:
+                            rowAAx0[cy]  = cx; // inclusive
+                            // Fix position:
+                            rowAAPos[cy] = (last_addr - addr_row);
                         }
                     }
                 }
-            } else {
-                // RLE encoding:
 
-                // quick check if there is AA data
-                // corresponding to this tile [x0; x1[
-                if (rowAAx1[cy] > x0) { // last pixel exclusive
+                // skip line end
+                if (cx < x1) {
+                    idx += (x1 - cx); // > 0
+                }
 
-                    cx = rowAAx0[cy]; // inclusive
-                    if (cx > x1) {
-                        cx = x1;
+                if (DO_TRACE) {
+                    for (int i = idx - (x1 - x0); i < idx; i++) {
+                        System.out.print(hex(tile[i], 2));
                     }
+                    System.out.println();
+                }
 
-                    // fill line start until first AA pixel rowAA exclusive:
-                    for (int i = x0; i < cx; i++) {
-                        tile[idx++] = 0;
-                    }
+                idx += skipRowPixels;
+            }
+        break;
 
-                    // get row address:
-                    addr_row = addr_rowAA + rowAAChunkIndex[cy];
-                    // get row end address:
-                    addr_end = addr_row + rowAALen[cy]; // coded length
+        case 0:
+        default:
+            for (cy = y0; cy < y1; cy++) {
+                // empty line (default)
+                cx = x0;
 
-                    // reuse previous iteration position:
-                    addr = addr_row + rowAAPos[cy];
+                if (rowAAEnc[cy] == 0) {
+                    // Raw encoding:
 
-                    last_addr = 0L;
+                    final int aax1 = rowAAx1[cy]; // exclusive
 
-                    while ((cx < x1) && (addr < addr_end)) {
-                        // keep current position:
-                        last_addr = addr;
+                    // quick check if there is AA data
+                    // corresponding to this tile [x0; x1[
+                    if (aax1 > x0) {
+                        final int aax0 = rowAAx0[cy]; // inclusive
 
-                        // packed value:
-                        packed = _unsafe.getInt(addr);
+                        if (aax0 < x1) {
+                            // note: cx is the cursor pointer in the tile array
+                            // (left to right)
+                            cx = aax0;
 
-                        // last exclusive pixel x-coordinate:
-                        cx1 = (packed >> 8);
-                        // as bytes:
-                        addr += SIZE_INT;
+                            // ensure cx >= x0
+                            if (cx <= x0) {
+                                cx = x0;
+                            } else {
+                                for (end = x0; end < cx; end++) {
+                                    tile[idx++] = 0;
+                                }
+                            }
 
-                        rx0 = cx;
-                        if (rx0 < x0) {
-                            rx0 = x0;
-                        }
-                        rx1 = cx = cx1;
-                        if (rx1 > x1) {
-                            rx1 = x1;
-                            cx  = x1; // fix last x
-                        }
-                        // adjust runLen:
-                        runLen = rx1 - rx0;
+                            // now: cx >= x0 and cx >= aax0
 
-                        // ensure rx1 > rx0:
-                        if (runLen > 0) {
-                            val = (byte)(packed & 0xFF); // [0..255]
+                            // Copy AA data (sum alpha data):
+                            addr = addr_rowAA + rowAAChunkIndex[cy] + (cx - aax0);
 
-                            do {
-                                tile[idx++] = val;
-                            } while (--runLen > 0);
+                            for (end = (aax1 <= x1) ? aax1 : x1; cx < end; cx++) {
+                                tile[idx++] = _unsafe.getByte(addr); // [0-255]
+                                addr += SIZE_BYTE;
+                            }
                         }
                     }
+                } else {
+                    // RLE encoding:
 
-                    // Update last position in RLE entries:
-                    if (last_addr != 0L) {
-                        // Fix x0:
-                        rowAAx0[cy]  = cx; // inclusive
-                        // Fix position:
-                        rowAAPos[cy] = (last_addr - addr_row);
+                    // quick check if there is AA data
+                    // corresponding to this tile [x0; x1[
+                    if (rowAAx1[cy] > x0) { // last pixel exclusive
+
+                        cx = rowAAx0[cy]; // inclusive
+                        if (cx > x1) {
+                            cx = x1;
+                        }
+
+                        // fill line start until first AA pixel rowAA exclusive:
+                        for (end = x0; end < cx; end++) {
+                            tile[idx++] = 0;
+                        }
+
+                        // get row address:
+                        addr_row = addr_rowAA + rowAAChunkIndex[cy];
+                        // get row end address:
+                        addr_end = addr_row + rowAALen[cy]; // coded length
+
+                        // reuse previous iteration position:
+                        addr = addr_row + rowAAPos[cy];
+
+                        last_addr = 0L;
+
+                        while ((cx < x1) && (addr < addr_end)) {
+                            // keep current position:
+                            last_addr = addr;
+
+                            // packed value:
+                            packed = _unsafe.getInt(addr);
+
+                            // last exclusive pixel x-coordinate:
+                            cx1 = (packed >> 8);
+                            // as bytes:
+                            addr += SIZE_INT;
+
+                            rx0 = cx;
+                            if (rx0 < x0) {
+                                rx0 = x0;
+                            }
+                            rx1 = cx = cx1;
+                            if (rx1 > x1) {
+                                rx1 = x1;
+                                cx  = x1; // fix last x
+                            }
+                            // adjust runLen:
+                            runLen = rx1 - rx0;
+
+                            // ensure rx1 > rx0:
+                            if (runLen > 0) {
+                                packed &= 0xFF; // [0-255]
+
+                                val = (byte) packed; // [0-255]
+                                do {
+                                    tile[idx++] = val;
+                                } while (--runLen > 0);
+                            }
+                        }
+
+                        // Update last position in RLE entries:
+                        if (last_addr != 0L) {
+                            // Fix x0:
+                            rowAAx0[cy]  = cx; // inclusive
+                            // Fix position:
+                            rowAAPos[cy] = (last_addr - addr_row);
+                        }
                     }
                 }
-            }
 
-            // fill line end
-            while (cx < x1) {
-                tile[idx++] = 0;
-                cx++;
-            }
-
-            if (DO_TRACE) {
-                for (int i = idx - (x1 - x0); i < idx; i++) {
-                    System.out.print(hex(tile[i], 2));
+                // fill line end
+                while (cx < x1) {
+                    tile[idx++] = 0;
+                    cx++;
                 }
-                System.out.println();
-            }
 
-            idx += skipRowPixels;
+                if (DO_TRACE) {
+                    for (int i = idx - (x1 - x0); i < idx; i++) {
+                        System.out.print(hex(tile[i], 2));
+                    }
+                    System.out.println();
+                }
+
+                idx += skipRowPixels;
+            }
+        break;
+
+        case 2: // 0xFF
+            // Fill full tile rows:
+            Arrays.fill(tile, offset, offset + (y1 * rowstride), refVal);
+
+            for (cy = y0; cy < y1; cy++) {
+                // empty line (default)
+                cx = x0;
+
+                if (rowAAEnc[cy] == 0) {
+                    // Raw encoding:
+
+                    final int aax1 = rowAAx1[cy]; // exclusive
+
+                    // quick check if there is AA data
+                    // corresponding to this tile [x0; x1[
+                    if (aax1 > x0) {
+                        final int aax0 = rowAAx0[cy]; // inclusive
+
+                        if (aax0 < x1) {
+                            // note: cx is the cursor pointer in the tile array
+                            // (left to right)
+                            cx = aax0;
+
+                            // ensure cx >= x0
+                            if (cx <= x0) {
+                                cx = x0;
+                            } else {
+                                // fill line start until first AA pixel rowAA exclusive:
+                                for (end = x0; end < cx; end++) {
+                                    tile[idx++] = 0;
+                                }
+                            }
+
+                            // now: cx >= x0 and cx >= aax0
+
+                            // Copy AA data (sum alpha data):
+                            addr = addr_rowAA + rowAAChunkIndex[cy] + (cx - aax0);
+
+                            for (end = (aax1 <= x1) ? aax1 : x1; cx < end; cx++) {
+                                tile[idx++] = _unsafe.getByte(addr); // [0-255]
+                                addr += SIZE_BYTE;
+                            }
+                        }
+                    }
+                } else {
+                    // RLE encoding:
+
+                    // quick check if there is AA data
+                    // corresponding to this tile [x0; x1[
+                    if (rowAAx1[cy] > x0) { // last pixel exclusive
+
+                        cx = rowAAx0[cy]; // inclusive
+                        if (cx > x1) {
+                            cx = x1;
+                        }
+
+                        // fill line start until first AA pixel rowAA exclusive:
+                        for (end = x0; end < cx; end++) {
+                            tile[idx++] = 0;
+                        }
+
+                        // get row address:
+                        addr_row = addr_rowAA + rowAAChunkIndex[cy];
+                        // get row end address:
+                        addr_end = addr_row + rowAALen[cy]; // coded length
+
+                        // reuse previous iteration position:
+                        addr = addr_row + rowAAPos[cy];
+
+                        last_addr = 0L;
+
+                        while ((cx < x1) && (addr < addr_end)) {
+                            // keep current position:
+                            last_addr = addr;
+
+                            // packed value:
+                            packed = _unsafe.getInt(addr);
+
+                            // last exclusive pixel x-coordinate:
+                            cx1 = (packed >> 8);
+                            // as bytes:
+                            addr += SIZE_INT;
+
+                            rx0 = cx;
+                            if (rx0 < x0) {
+                                rx0 = x0;
+                            }
+                            rx1 = cx = cx1;
+                            if (rx1 > x1) {
+                                rx1 = x1;
+                                cx  = x1; // fix last x
+                            }
+                            // adjust runLen:
+                            runLen = rx1 - rx0;
+
+                            // ensure rx1 > rx0:
+                            if (runLen > 0) {
+                                packed &= 0xFF; // [0-255]
+
+                                if (packed == 0xFF)
+                                {
+                                    idx += runLen;
+                                    continue;
+                                }
+                                val = (byte) packed; // [0-255]
+                                do {
+                                    tile[idx++] = val;
+                                } while (--runLen > 0);
+                            }
+                        }
+
+                        // Update last position in RLE entries:
+                        if (last_addr != 0L) {
+                            // Fix x0:
+                            rowAAx0[cy]  = cx; // inclusive
+                            // Fix position:
+                            rowAAPos[cy] = (last_addr - addr_row);
+                        }
+                    }
+                }
+
+                // fill line end
+                while (cx < x1) {
+                    tile[idx++] = 0;
+                    cx++;
+                }
+
+                if (DO_TRACE) {
+                    for (int i = idx - (x1 - x0); i < idx; i++) {
+                        System.out.print(hex(tile[i], 2));
+                    }
+                    System.out.println();
+                }
+
+                idx += skipRowPixels;
+            }
         }
 
         nextTile();
 
         if (DO_MONITORS) {
-            rdrCtx.stats.mon_ptg_getAlpha.stop();
+            rdrStats.mon_ptg_getAlpha.stop();
         }
     }
 
diff --git a/src/share/classes/sun/java2d/marlin/MarlinUtils.java b/src/share/classes/sun/java2d/marlin/MarlinUtils.java
index 5645e70..50b6475 100644
--- a/src/share/classes/sun/java2d/marlin/MarlinUtils.java
+++ b/src/share/classes/sun/java2d/marlin/MarlinUtils.java
@@ -28,11 +28,13 @@
 
 public final class MarlinUtils {
     // Marlin logger
-    private static final sun.util.logging.PlatformLogger LOG;
+//    private static final sun.util.logging.PlatformLogger LOG;
+    private static final java.util.logging.Logger LOG;
 
     static {
         if (MarlinConst.USE_LOGGER) {
-            LOG = sun.util.logging.PlatformLogger.getLogger("sun.java2d.marlin");
+//            log = sun.util.logging.PlatformLogger.getLogger("sun.java2d.marlin");
+            LOG = java.util.logging.Logger.getLogger("sun.java2d.marlin");
         } else {
             LOG = null;
         }
@@ -53,11 +55,29 @@
 
     public static void logException(final String msg, final Throwable th) {
         if (MarlinConst.USE_LOGGER) {
-            LOG.warning(msg, th);
+            LOG.log(java.util.logging.Level.WARNING, msg, th);
         } else if (MarlinConst.ENABLE_LOGS) {
             System.out.print("WARNING: ");
             System.out.println(msg);
             th.printStackTrace(System.err);
         }
     }
+
+    // From sun.awt.util.ThreadGroupUtils
+
+    /**
+     * Returns a root thread group.
+     * Should be called with {@link sun.security.util.SecurityConstants#MODIFY_THREADGROUP_PERMISSION}
+     *
+     * @return a root {@code ThreadGroup}
+     */
+    public static ThreadGroup getRootThreadGroup() {
+        ThreadGroup currentTG = Thread.currentThread().getThreadGroup();
+        ThreadGroup parentTG = currentTG.getParent();
+        while (parentTG != null) {
+            currentTG = parentTG;
+            parentTG = currentTG.getParent();
+        }
+        return currentTG;
+    }
 }
diff --git a/src/share/classes/sun/java2d/marlin/OffHeapArray.java b/src/share/classes/sun/java2d/marlin/OffHeapArray.java
index 77b216b..a1531af 100644
--- a/src/share/classes/sun/java2d/marlin/OffHeapArray.java
+++ b/src/share/classes/sun/java2d/marlin/OffHeapArray.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, 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
@@ -25,20 +25,17 @@
 
 package sun.java2d.marlin;
 
-import static sun.java2d.marlin.MarlinConst.LOG_UNSAFE_MALLOC;
-
-import sun.misc.ThreadGroupUtils;
-import sun.misc.Unsafe;
-
 import java.lang.ref.PhantomReference;
 import java.lang.ref.ReferenceQueue;
+import java.lang.reflect.Field;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.Vector;
+import static sun.java2d.marlin.MarlinConst.LOG_UNSAFE_MALLOC;
+import sun.misc.Unsafe;
 
 /**
  *
- * @author bourgesl
  */
 final class OffHeapArray  {
 
@@ -47,36 +44,45 @@
     // size of int / float
     static final int SIZE_INT;
 
-    // RendererContext reference queue
-    private static final ReferenceQueue<Object> rdrQueue
-        = new ReferenceQueue<Object>();
-    // reference list
-    private static final Vector<OffHeapReference> refList
-        = new Vector<OffHeapReference>(32);
-
     static {
-        UNSAFE   = Unsafe.getUnsafe();
-        SIZE_INT = Unsafe.ARRAY_INT_INDEX_SCALE;
+        UNSAFE = AccessController.doPrivileged(new PrivilegedAction<Unsafe>() {
+            @Override
+            public Unsafe run() {
+                Unsafe ref = null;
+                try {
+                    final Field field = Unsafe.class.getDeclaredField("theUnsafe");
+                    field.setAccessible(true);
+                    ref = (Unsafe) field.get(null);
+                } catch (Exception e) {
+                    throw new InternalError("Unable to get sun.misc.Unsafe instance", e);
+                }
+                return ref;
+            }
+        });
+
+        SIZE_INT = 4; // jdk 1.6 (Unsafe.ARRAY_INT_INDEX_SCALE)
 
         // Mimics Java2D Disposer:
-        AccessController.doPrivileged(
-            (PrivilegedAction<Void>) () -> {
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+
+            @Override
+            public Void run() {
                 /*
                  * The thread must be a member of a thread group
                  * which will not get GCed before VM exit.
                  * Make its parent the top-level thread group.
                  */
                 final ThreadGroup rootTG
-                    = ThreadGroupUtils.getRootThreadGroup();
+                    = MarlinUtils.getRootThreadGroup();
                 final Thread t = new Thread(rootTG, new OffHeapDisposer(),
                     "MarlinRenderer Disposer");
                 t.setContextClassLoader(null);
                 t.setDaemon(true);
-                t.setPriority(Thread.MAX_PRIORITY);
+                t.setPriority(Thread.MAX_PRIORITY - 2);
                 t.start();
                 return null;
             }
-        );
+        });
     }
 
     /* members */
@@ -91,12 +97,12 @@
         this.used    = 0;
         if (LOG_UNSAFE_MALLOC) {
             MarlinUtils.logInfo(System.currentTimeMillis()
-                                + ": OffHeapArray.allocateMemory = "
+                                + ": OffHeapArray.allocateMemory =   "
                                 + len + " to addr = " + this.address);
         }
 
         // Create the phantom reference to ensure freeing off-heap memory:
-        refList.add(new OffHeapReference(parent, this));
+        REF_LIST.add(new OffHeapReference(parent, this));
     }
 
     /*
@@ -119,22 +125,32 @@
         UNSAFE.freeMemory(this.address);
         if (LOG_UNSAFE_MALLOC) {
             MarlinUtils.logInfo(System.currentTimeMillis()
-                                + ": OffHeapEdgeArray.free = "
+                                + ": OffHeapArray.freeMemory =       "
                                 + this.length
                                 + " at addr = " + this.address);
         }
+        this.address = 0L;
     }
 
     void fill(final byte val) {
         UNSAFE.setMemory(this.address, this.length, val);
     }
 
+    // Custom disposer (replaced by jdk9 Cleaner)
+
+    // Parent reference queue
+    private static final ReferenceQueue<Object> REF_QUEUE
+        = new ReferenceQueue<Object>();
+    // reference list
+    private static final Vector<OffHeapReference> REF_LIST
+        = new Vector<OffHeapReference>(32);
+
     static final class OffHeapReference extends PhantomReference<Object> {
 
         private final OffHeapArray array;
 
         OffHeapReference(final Object parent, final OffHeapArray edges) {
-            super(parent, rdrQueue);
+            super(parent, REF_QUEUE);
             this.array = edges;
         }
 
@@ -153,10 +169,10 @@
             // check interrupted:
             for (; !currentThread.isInterrupted();) {
                 try {
-                    ref = (OffHeapReference)rdrQueue.remove();
+                    ref = (OffHeapReference)REF_QUEUE.remove();
                     ref.dispose();
 
-                    refList.remove(ref);
+                    REF_LIST.remove(ref);
 
                 } catch (InterruptedException ie) {
                     MarlinUtils.logException("OffHeapDisposer interrupted:",
diff --git a/src/share/classes/sun/java2d/marlin/PathSimplifier.java b/src/share/classes/sun/java2d/marlin/PathSimplifier.java
new file mode 100644
index 0000000..3052725
--- /dev/null
+++ b/src/share/classes/sun/java2d/marlin/PathSimplifier.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package sun.java2d.marlin;
+
+import sun.awt.geom.PathConsumer2D;
+
+final class PathSimplifier implements PathConsumer2D {
+
+    // distance threshold in pixels (device)
+    private static final float PIX_THRESHOLD = MarlinProperties.getPathSimplifierPixelTolerance();
+
+    private static final float SQUARE_TOLERANCE = PIX_THRESHOLD * PIX_THRESHOLD;
+
+    // members:
+    private PathConsumer2D delegate;
+    private float cx, cy;
+
+    PathSimplifier() {
+    }
+
+    PathSimplifier init(final PathConsumer2D delegate) {
+        this.delegate = delegate;
+        return this; // fluent API
+    }
+
+    @Override
+    public void pathDone() {
+        delegate.pathDone();
+    }
+
+    @Override
+    public void closePath() {
+        delegate.closePath();
+    }
+
+    @Override
+    public long getNativeConsumer() {
+        return 0;
+    }
+
+    @Override
+    public void quadTo(final float x1, final float y1,
+                       final float xe, final float ye)
+    {
+        // Test if curve is too small:
+        float dx = (xe - cx);
+        float dy = (ye - cy);
+
+        if ((dx * dx + dy * dy) <= SQUARE_TOLERANCE) {
+            // check control points P1:
+            dx = (x1 - cx);
+            dy = (y1 - cy);
+
+            if ((dx * dx + dy * dy) <= SQUARE_TOLERANCE) {
+                return;
+            }
+        }
+        delegate.quadTo(x1, y1, xe, ye);
+        // final end point:
+        cx = xe;
+        cy = ye;
+    }
+
+    @Override
+    public void curveTo(final float x1, final float y1,
+                        final float x2, final float y2,
+                        final float xe, final float ye)
+    {
+        // Test if curve is too small:
+        float dx = (xe - cx);
+        float dy = (ye - cy);
+
+        if ((dx * dx + dy * dy) <= SQUARE_TOLERANCE) {
+            // check control points P1:
+            dx = (x1 - cx);
+            dy = (y1 - cy);
+
+            if ((dx * dx + dy * dy) <= SQUARE_TOLERANCE) {
+                // check control points P2:
+                dx = (x2 - cx);
+                dy = (y2 - cy);
+
+                if ((dx * dx + dy * dy) <= SQUARE_TOLERANCE) {
+                    return;
+                }
+            }
+        }
+        delegate.curveTo(x1, y1, x2, y2, xe, ye);
+        // final end point:
+        cx = xe;
+        cy = ye;
+    }
+
+    @Override
+    public void moveTo(final float xe, final float ye) {
+        delegate.moveTo(xe, ye);
+        // starting point:
+        cx = xe;
+        cy = ye;
+    }
+
+    @Override
+    public void lineTo(final float xe, final float ye) {
+        // Test if segment is too small:
+        float dx = (xe - cx);
+        float dy = (ye - cy);
+
+        if ((dx * dx + dy * dy) <= SQUARE_TOLERANCE) {
+            return;
+        }
+        delegate.lineTo(xe, ye);
+        // final end point:
+        cx = xe;
+        cy = ye;
+    }
+}
diff --git a/src/share/classes/sun/java2d/marlin/Renderer.java b/src/share/classes/sun/java2d/marlin/Renderer.java
index f8a9c71..bd7769b 100644
--- a/src/share/classes/sun/java2d/marlin/Renderer.java
+++ b/src/share/classes/sun/java2d/marlin/Renderer.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, 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
@@ -25,41 +25,42 @@
 
 package sun.java2d.marlin;
 
-import java.util.Arrays;
 import sun.awt.geom.PathConsumer2D;
 import static sun.java2d.marlin.OffHeapArray.SIZE_INT;
+//import jdk.internal.misc.Unsafe;
 import sun.misc.Unsafe;
 
-final class Renderer implements PathConsumer2D, MarlinConst {
+final class Renderer implements PathConsumer2D, MarlinRenderer {
 
     static final boolean DISABLE_RENDER = false;
 
     static final boolean ENABLE_BLOCK_FLAGS = MarlinProperties.isUseTileFlags();
     static final boolean ENABLE_BLOCK_FLAGS_HEURISTICS = MarlinProperties.isUseTileFlagsWithHeuristics();
 
-    private static final int ALL_BUT_LSB = 0xfffffffe;
-    private static final int ERR_STEP_MAX = 0x7fffffff; // = 2^31 - 1
+    private static final int ALL_BUT_LSB = 0xFFFFFFFE;
+    private static final int ERR_STEP_MAX = 0x7FFFFFFF; // = 2^31 - 1
 
-    private static final double POWER_2_TO_32 = 0x1.0p32;
+    private static final double POWER_2_TO_32 = 0x1.0p32d;
 
     // use float to make tosubpix methods faster (no int to float conversion)
-    public static final float f_SUBPIXEL_POSITIONS_X
-        = (float) SUBPIXEL_POSITIONS_X;
-    public static final float f_SUBPIXEL_POSITIONS_Y
-        = (float) SUBPIXEL_POSITIONS_Y;
-    public static final int SUBPIXEL_MASK_X = SUBPIXEL_POSITIONS_X - 1;
-    public static final int SUBPIXEL_MASK_Y = SUBPIXEL_POSITIONS_Y - 1;
+    static final float SUBPIXEL_SCALE_X = (float) SUBPIXEL_POSITIONS_X;
+    static final float SUBPIXEL_SCALE_Y = (float) SUBPIXEL_POSITIONS_Y;
+    static final int SUBPIXEL_MASK_X = SUBPIXEL_POSITIONS_X - 1;
+    static final int SUBPIXEL_MASK_Y = SUBPIXEL_POSITIONS_Y - 1;
+
+    static final float RDR_OFFSET_X = 0.5f / SUBPIXEL_SCALE_X;
+    static final float RDR_OFFSET_Y = 0.5f / SUBPIXEL_SCALE_Y;
 
     // number of subpixels corresponding to a tile line
     private static final int SUBPIXEL_TILE
-        = TILE_SIZE << SUBPIXEL_LG_POSITIONS_Y;
+        = TILE_H << SUBPIXEL_LG_POSITIONS_Y;
 
-    // 2048 (pixelSize) pixels (height) x 8 subpixels = 64K
+    // 2176 pixels (height) x 8 subpixels = 68K
     static final int INITIAL_BUCKET_ARRAY
-        = INITIAL_PIXEL_DIM * SUBPIXEL_POSITIONS_Y;
+        = INITIAL_PIXEL_HEIGHT * SUBPIXEL_POSITIONS_Y;
 
-    public static final int WIND_EVEN_ODD = 0;
-    public static final int WIND_NON_ZERO = 1;
+    // crossing capacity = edges count / 4 ~ 1024
+    static final int INITIAL_CROSSING_COUNT = INITIAL_EDGES_COUNT >> 2;
 
     // common to all types of input path segments.
     // OFFSET as bytes
@@ -77,20 +78,24 @@
     // curve break into lines
     // cubic error in subpixels to decrement step
     private static final float CUB_DEC_ERR_SUBPIX
-        = 2.5f * (NORM_SUBPIXELS / 8f); // 2.5 subpixel for typical 8x8 subpixels
+        = MarlinProperties.getCubicDecD2() * (SUBPIXEL_POSITIONS_X / 8.0f); // 1.0 / 8th pixel
     // cubic error in subpixels to increment step
     private static final float CUB_INC_ERR_SUBPIX
-        = 1f * (NORM_SUBPIXELS / 8f); // 1 subpixel for typical 8x8 subpixels
+        = MarlinProperties.getCubicIncD1() * (SUBPIXEL_POSITIONS_X / 8.0f); // 0.4 / 8th pixel
+    // scale factor for Y-axis contribution to quad / cubic errors:
+    public static final float SCALE_DY = ((float) SUBPIXEL_POSITIONS_X) / SUBPIXEL_POSITIONS_Y;
 
-    // cubic bind length to decrement step = 8 * error in subpixels
-    // pisces: 20 / 8
-    // openjfx pisces: 8 / 3.2
-    // multiply by 8 = error scale factor:
+    // TestNonAARasterization (JDK-8170879): cubics
+    // bad paths (59294/100000 == 59,29%, 94335 bad pixels (avg = 1,59), 3966 warnings (avg = 0,07)
+// 2018
+    // 1.0 / 0.2: bad paths (67194/100000 == 67,19%, 117394 bad pixels (avg = 1,75 - max =  9), 4042 warnings (avg = 0,06)
+
+    // cubic bind length to decrement step
     public static final float CUB_DEC_BND
-        = 8f * CUB_DEC_ERR_SUBPIX; // 20f means 2.5 subpixel error
-    // cubic bind length to increment step = 8 * error in subpixels
+        = 8.0f * CUB_DEC_ERR_SUBPIX;
+    // cubic bind length to increment step
     public static final float CUB_INC_BND
-        = 8f * CUB_INC_ERR_SUBPIX; // 8f means 1 subpixel error
+        = 8.0f * CUB_INC_ERR_SUBPIX;
 
     // cubic countlg
     public static final int CUB_COUNT_LG = 2;
@@ -101,21 +106,25 @@
     // cubic count^3 = 8^countlg
     private static final int CUB_COUNT_3 = 1 << (3 * CUB_COUNT_LG);
     // cubic dt = 1 / count
-    private static final float CUB_INV_COUNT = 1f / CUB_COUNT;
+    private static final float CUB_INV_COUNT = 1.0f / CUB_COUNT;
     // cubic dt^2 = 1 / count^2 = 1 / 4^countlg
-    private static final float CUB_INV_COUNT_2 = 1f / CUB_COUNT_2;
+    private static final float CUB_INV_COUNT_2 = 1.0f / CUB_COUNT_2;
     // cubic dt^3 = 1 / count^3 = 1 / 8^countlg
-    private static final float CUB_INV_COUNT_3 = 1f / CUB_COUNT_3;
+    private static final float CUB_INV_COUNT_3 = 1.0f / CUB_COUNT_3;
 
     // quad break into lines
     // quadratic error in subpixels
     private static final float QUAD_DEC_ERR_SUBPIX
-        = 1f * (NORM_SUBPIXELS / 8f); // 1 subpixel for typical 8x8 subpixels
+        = MarlinProperties.getQuadDecD2() * (SUBPIXEL_POSITIONS_X / 8.0f); // 0.5 / 8th pixel
 
-    // quadratic bind length to decrement step = 8 * error in subpixels
-    // pisces and openjfx pisces: 32
+    // TestNonAARasterization (JDK-8170879): quads
+    // bad paths (62916/100000 == 62,92%, 103818 bad pixels (avg = 1,65), 6514 warnings (avg = 0,10)
+// 2018
+    // 0.50px  = bad paths (62915/100000 == 62,92%, 103810 bad pixels (avg = 1,65), 6512 warnings (avg = 0,10)
+
+    // quadratic bind length to decrement step
     public static final float QUAD_DEC_BND
-        = 8f * QUAD_DEC_ERR_SUBPIX; // 8f means 1 subpixel error
+        = 8.0f * QUAD_DEC_ERR_SUBPIX;
 
 //////////////////////////////////////////////////////////////////////////////
 //  SCAN LINE
@@ -136,14 +145,15 @@
     // max used for both edgePtrs and crossings (stats only)
     private int activeEdgeMaxUsed;
 
-    // per-thread initial arrays (large enough to satisfy most usages) (1024)
-    private final int[] crossings_initial = new int[INITIAL_SMALL_ARRAY]; // 4K
-    // +1 to avoid recycling in Helpers.widenArray()
-    private final int[] edgePtrs_initial  = new int[INITIAL_SMALL_ARRAY + 1]; // 4K
+    // crossings ref (dirty)
+    private final IntArrayCache.Reference crossings_ref;
+    // edgePtrs ref (dirty)
+    private final IntArrayCache.Reference edgePtrs_ref;
     // merge sort initial arrays (large enough to satisfy most usages) (1024)
-    private final int[] aux_crossings_initial = new int[INITIAL_SMALL_ARRAY]; // 4K
-    // +1 to avoid recycling in Helpers.widenArray()
-    private final int[] aux_edgePtrs_initial  = new int[INITIAL_SMALL_ARRAY + 1]; // 4K
+    // aux_crossings ref (dirty)
+    private final IntArrayCache.Reference aux_crossings_ref;
+    // aux_edgePtrs ref (dirty)
+    private final IntArrayCache.Reference aux_edgePtrs_ref;
 
 //////////////////////////////////////////////////////////////////////////////
 //  EDGE LIST
@@ -153,7 +163,7 @@
     private float edgeMinX = Float.POSITIVE_INFINITY;
     private float edgeMaxX = Float.NEGATIVE_INFINITY;
 
-    // edges [floats|ints] stored in off-heap memory
+    // edges [ints] stored in off-heap memory
     private final OffHeapArray edges;
 
     private int[] edgeBuckets;
@@ -161,14 +171,11 @@
     // used range for edgeBuckets / edgeBucketCounts
     private int buckets_minY;
     private int buckets_maxY;
-    // sum of each edge delta Y (subpixels)
-    private int edgeSumDeltaY;
 
-    // +1 to avoid recycling in Helpers.widenArray()
-    private final int[] edgeBuckets_initial
-        = new int[INITIAL_BUCKET_ARRAY + 1]; // 64K
-    private final int[] edgeBucketCounts_initial
-        = new int[INITIAL_BUCKET_ARRAY + 1]; // 64K
+    // edgeBuckets ref (clean)
+    private final IntArrayCache.Reference edgeBuckets_ref;
+    // edgeBucketCounts ref (clean)
+    private final IntArrayCache.Reference edgeBucketCounts_ref;
 
     // Flattens using adaptive forward differencing. This only carries out
     // one iteration of the AFD loop. All it does is update AFD variables (i.e.
@@ -180,13 +187,13 @@
         int count = 1; // dt = 1 / count
 
         // maximum(ddX|Y) = norm(dbx, dby) * dt^2 (= 1)
-        float maxDD = FloatMath.max(Math.abs(c.dbx), Math.abs(c.dby));
+        float maxDD = Math.abs(c.dbx) + Math.abs(c.dby) * SCALE_DY;
 
         final float _DEC_BND = QUAD_DEC_BND;
 
         while (maxDD >= _DEC_BND) {
             // divide step by half:
-            maxDD /= 4f; // error divided by 2^2 = 4
+            maxDD /= 4.0f; // error divided by 2^2 = 4
 
             count <<= 1;
             if (DO_STATS) {
@@ -194,9 +201,10 @@
             }
         }
 
-        int nL = 0; // line count
+        final int nL = count; // line count
+
         if (count > 1) {
-            final float icount = 1f / count; // dt
+            final float icount = 1.0f / count; // dt
             final float icount2 = icount * icount; // dt^2
 
             final float ddx = c.dbx * icount2;
@@ -204,17 +212,12 @@
             float dx = c.bx * icount2 + c.cx * icount;
             float dy = c.by * icount2 + c.cy * icount;
 
-            float x1, y1;
-
-            while (--count > 0) {
-                x1 = x0 + dx;
-                dx += ddx;
-                y1 = y0 + dy;
-                dy += ddy;
+            // we use x0, y0 to walk the line
+            for (float x1 = x0, y1 = y0; --count > 0; dx += ddx, dy += ddy) {
+                x1 += dx;
+                y1 += dy;
 
                 addLine(x0, y0, x1, y1);
-
-                if (DO_STATS) { nL++; }
                 x0 = x1;
                 y0 = y1;
             }
@@ -222,7 +225,7 @@
         addLine(x0, y0, x2, y2);
 
         if (DO_STATS) {
-            rdrCtx.stats.stat_rdr_quadBreak.add(nL + 1);
+            rdrCtx.stats.stat_rdr_quadBreak.add(nL);
         }
     }
 
@@ -243,76 +246,77 @@
         // the dx and dy refer to forward differencing variables, not the last
         // coefficients of the "points" polynomial
         float dddx, dddy, ddx, ddy, dx, dy;
-        dddx = 2f * c.dax * icount3;
-        dddy = 2f * c.day * icount3;
+        dddx = 2.0f * c.dax * icount3;
+        dddy = 2.0f * c.day * icount3;
         ddx = dddx + c.dbx * icount2;
         ddy = dddy + c.dby * icount2;
         dx = c.ax * icount3 + c.bx * icount2 + c.cx * icount;
         dy = c.ay * icount3 + c.by * icount2 + c.cy * icount;
 
-        // we use x0, y0 to walk the line
-        float x1 = x0, y1 = y0;
         int nL = 0; // line count
 
         final float _DEC_BND = CUB_DEC_BND;
         final float _INC_BND = CUB_INC_BND;
+        final float _SCALE_DY = SCALE_DY;
 
-        while (count > 0) {
-            // divide step by half:
-            while (Math.abs(ddx) >= _DEC_BND || Math.abs(ddy) >= _DEC_BND) {
-                dddx /= 8f;
-                dddy /= 8f;
-                ddx = ddx/4f - dddx;
-                ddy = ddy/4f - dddy;
-                dx = (dx - ddx) / 2f;
-                dy = (dy - ddy) / 2f;
+        // we use x0, y0 to walk the line
+        for (float x1 = x0, y1 = y0; count > 0; ) {
+            // inc / dec => ratio ~ 5 to minimize upscale / downscale but minimize edges
 
-                count <<= 1;
-                if (DO_STATS) {
-                    rdrCtx.stats.stat_rdr_curveBreak_dec.add(count);
-                }
-            }
-
-            // double step:
-            // TODO: why use first derivative dX|Y instead of second ddX|Y ?
-            // both scale changes should use speed or acceleration to have the same metric.
-
+            // float step:
             // can only do this on even "count" values, because we must divide count by 2
-            while (count % 2 == 0
-                   && Math.abs(dx) <= _INC_BND && Math.abs(dy) <= _INC_BND)
-            {
-                dx = 2f * dx + ddx;
-                dy = 2f * dy + ddy;
-                ddx = 4f * (ddx + dddx);
-                ddy = 4f * (ddy + dddy);
-                dddx *= 8f;
-                dddy *= 8f;
+            while ((count % 2 == 0)
+                    && ((Math.abs(ddx) + Math.abs(ddy) * _SCALE_DY) <= _INC_BND
+//                     && (Math.abs(ddx + dddx) + Math.abs(ddy + dddy) * _SCALE_DY) <= _INC_BND
+                  )) {
+                dx = 2.0f * dx + ddx;
+                dy = 2.0f * dy + ddy;
+                ddx = 4.0f * (ddx + dddx);
+                ddy = 4.0f * (ddy + dddy);
+                dddx *= 8.0f;
+                dddy *= 8.0f;
 
                 count >>= 1;
                 if (DO_STATS) {
                     rdrCtx.stats.stat_rdr_curveBreak_inc.add(count);
                 }
             }
-            if (--count > 0) {
-                x1 += dx;
-                dx += ddx;
-                ddx += dddx;
-                y1 += dy;
-                dy += ddy;
-                ddy += dddy;
-            } else {
-                x1 = x3;
-                y1 = y3;
+
+            // divide step by half:
+            while ((Math.abs(ddx) + Math.abs(ddy) * _SCALE_DY) >= _DEC_BND
+//                || (Math.abs(ddx + dddx) + Math.abs(ddy + dddy) * _SCALE_DY) >= _DEC_BND
+                  ) {
+                dddx /= 8.0f;
+                dddy /= 8.0f;
+                ddx = ddx / 4.0f - dddx;
+                ddy = ddy / 4.0f - dddy;
+                dx = (dx - ddx) / 2.0f;
+                dy = (dy - ddy) / 2.0f;
+
+                count <<= 1;
+                if (DO_STATS) {
+                    rdrCtx.stats.stat_rdr_curveBreak_dec.add(count);
+                }
+            }
+            if (--count == 0) {
+                break;
             }
 
-            addLine(x0, y0, x1, y1);
+            x1 += dx;
+            y1 += dy;
+            dx += ddx;
+            dy += ddy;
+            ddx += dddx;
+            ddy += dddy;
 
-            if (DO_STATS) { nL++; }
+            addLine(x0, y0, x1, y1);
             x0 = x1;
             y0 = y1;
         }
+        addLine(x0, y0, x3, y3);
+
         if (DO_STATS) {
-            rdrCtx.stats.stat_rdr_curveBreak.add(nL);
+            rdrCtx.stats.stat_rdr_curveBreak.add(nL + 1);
         }
     }
 
@@ -334,7 +338,7 @@
             x1 = tmp;
         }
 
-        // convert subpixel coordinates (float) into pixel positions (int)
+        // convert subpixel coordinates [float] into pixel positions [int]
 
         // The index of the pixel that holds the next HPC is at ceil(trueY - 0.5)
         // Since y1 and y2 are biased by -0.5 in tosubpixy(), this is simply
@@ -358,7 +362,7 @@
             return;
         }
 
-        // edge min/max X/Y are in subpixel space (inclusive) within bounds:
+        // edge min/max X/Y are in subpixel space (half-open interval):
         // note: Use integer crossings to ensure consistent range within
         // edgeBuckets / edgeBucketCounts arrays in case of NaN values (int = 0)
         if (firstCrossing < edgeMinY) {
@@ -373,7 +377,7 @@
         final double y1d   = y1;
         final double slope = (x1d - x2) / (y1d - y2);
 
-        if (slope >= 0.0) { // <==> x1 < x2
+        if (slope >= 0.0d) { // <==> x1 < x2
             if (x1 < edgeMinX) {
                 edgeMinX = x1;
             }
@@ -402,7 +406,8 @@
             // suppose _edges.length > _SIZEOF_EDGE_BYTES
             // so doubling size is enough to add needed bytes
             // note: throw IOOB if neededSize > 2Gb:
-            final long edgeNewSize = ArrayCache.getNewLargeSize(_edges.length,
+            final long edgeNewSize = ArrayCacheConst.getNewLargeSize(
+                                        _edges.length,
                                         edgePtr + _SIZEOF_EDGE_BYTES);
 
             if (DO_STATS) {
@@ -435,13 +440,13 @@
         // long x1_fixed = x1_intercept * 2^32;  (fixed point 32.32 format)
         // curx = next VPC = fixed_floor(x1_fixed - 2^31 + 2^32 - 1)
         //                 = fixed_floor(x1_fixed + 2^31 - 1)
-        //                 = fixed_floor(x1_fixed + 0x7fffffff)
-        // and error       = fixed_fract(x1_fixed + 0x7fffffff)
+        //                 = fixed_floor(x1_fixed + 0x7FFFFFFF)
+        // and error       = fixed_fract(x1_fixed + 0x7FFFFFFF)
         final double x1_intercept = x1d + (firstCrossing - y1d) * slope;
 
         // inlined scalb(x1_intercept, 32):
         final long x1_fixed_biased = ((long) (POWER_2_TO_32 * x1_intercept))
-                                     + 0x7fffffffL;
+                                     + 0x7FFFFFFFL;
         // curx:
         // last bit corresponds to the orientation
         _unsafe.putInt(addr, (((int) (x1_fixed_biased >> 31L)) & ALL_BUT_LSB) | or);
@@ -470,7 +475,7 @@
         // pointer from bucket
         _unsafe.putInt(addr, _edgeBuckets[bucketIdx]);
         addr += SIZE_INT;
-        // y max (inclusive)
+        // y max (exclusive)
         _unsafe.putInt(addr,  lastCrossing);
 
         // Update buckets:
@@ -480,9 +485,6 @@
         // last bit means edge end
         _edgeBucketCounts[lastCrossing - _boundsMinY] |= 0x1;
 
-        // update sum of delta Y (subpixels):
-        edgeSumDeltaY += (lastCrossing - firstCrossing);
-
         // update free pointer (ie length in bytes)
         _edges.used += _SIZEOF_EDGE_BYTES;
 
@@ -514,34 +516,56 @@
     // dirty curve
     private final Curve curve;
 
+    // clean alpha array (zero filled)
+    private int[] alphaLine;
+
+    // alphaLine ref (clean)
+    private final IntArrayCache.Reference alphaLine_ref;
+
+    private boolean enableBlkFlags = false;
+    private boolean prevUseBlkFlags = false;
+
+    /* block flags (0|1) */
+    private int[] blkFlags;
+
+    // blkFlags ref (clean)
+    private final IntArrayCache.Reference blkFlags_ref;
+
     Renderer(final RendererContext rdrCtx) {
         this.rdrCtx = rdrCtx;
-
-        this.edges = new OffHeapArray(rdrCtx.cleanerObj, INITIAL_EDGES_CAPACITY); // 96K
-
         this.curve = rdrCtx.curve;
-
-        edgeBuckets = edgeBuckets_initial;
-        edgeBucketCounts = edgeBucketCounts_initial;
-
-        alphaLine  = alphaLine_initial;
-
         this.cache = rdrCtx.cache;
 
-        // ScanLine:
-        crossings     = crossings_initial;
-        aux_crossings = aux_crossings_initial;
-        edgePtrs      = edgePtrs_initial;
-        aux_edgePtrs  = aux_edgePtrs_initial;
+        this.edges = rdrCtx.newOffHeapArray(INITIAL_EDGES_CAPACITY); // 96K
 
-        edgeCount = 0;
-        activeEdgeMaxUsed = 0;
+        edgeBuckets_ref      = rdrCtx.newCleanIntArrayRef(INITIAL_BUCKET_ARRAY); // 64K
+        edgeBucketCounts_ref = rdrCtx.newCleanIntArrayRef(INITIAL_BUCKET_ARRAY); // 64K
+
+        edgeBuckets      = edgeBuckets_ref.initial;
+        edgeBucketCounts = edgeBucketCounts_ref.initial;
+
+        // 4096 pixels large
+        alphaLine_ref = rdrCtx.newCleanIntArrayRef(INITIAL_AA_ARRAY); // 16K
+        alphaLine     = alphaLine_ref.initial;
+
+        crossings_ref     = rdrCtx.newDirtyIntArrayRef(INITIAL_CROSSING_COUNT); // 2K
+        aux_crossings_ref = rdrCtx.newDirtyIntArrayRef(INITIAL_CROSSING_COUNT); // 2K
+        edgePtrs_ref      = rdrCtx.newDirtyIntArrayRef(INITIAL_CROSSING_COUNT); // 2K
+        aux_edgePtrs_ref  = rdrCtx.newDirtyIntArrayRef(INITIAL_CROSSING_COUNT); // 2K
+
+        crossings     = crossings_ref.initial;
+        aux_crossings = aux_crossings_ref.initial;
+        edgePtrs      = edgePtrs_ref.initial;
+        aux_edgePtrs  = aux_edgePtrs_ref.initial;
+
+        blkFlags_ref = rdrCtx.newCleanIntArrayRef(INITIAL_ARRAY); // 1K = 1 tile line
+        blkFlags     = blkFlags_ref.initial;
     }
 
     Renderer init(final int pix_boundsX, final int pix_boundsY,
                   final int pix_boundsWidth, final int pix_boundsHeight,
-                  final int windingRule) {
-
+                  final int windingRule)
+    {
         this.windingRule = windingRule;
 
         // bounds as half-open intervals: minX <= x < maxX and minY <= y < maxY
@@ -569,8 +593,8 @@
                 rdrCtx.stats.stat_array_renderer_edgeBucketCounts
                     .add(edgeBucketsLength);
             }
-            edgeBuckets = rdrCtx.getIntArray(edgeBucketsLength);
-            edgeBucketCounts = rdrCtx.getIntArray(edgeBucketsLength);
+            edgeBuckets = edgeBuckets_ref.getArray(edgeBucketsLength);
+            edgeBucketCounts = edgeBucketCounts_ref.getArray(edgeBucketsLength);
         }
 
         edgeMinY = Integer.MAX_VALUE;
@@ -583,8 +607,6 @@
         activeEdgeMaxUsed = 0;
         edges.used = 0;
 
-        edgeSumDeltaY = 0;
-
         return this; // fluent API
     }
 
@@ -595,41 +617,19 @@
         if (DO_STATS) {
             rdrCtx.stats.stat_rdr_activeEdges.add(activeEdgeMaxUsed);
             rdrCtx.stats.stat_rdr_edges.add(edges.used);
-            rdrCtx.stats.stat_rdr_edges_count
-                .add(edges.used / SIZEOF_EDGE_BYTES);
-        }
-        if (DO_CLEAN_DIRTY) {
-            // Force zero-fill dirty arrays:
-            Arrays.fill(crossings,     0);
-            Arrays.fill(aux_crossings, 0);
-            Arrays.fill(edgePtrs,      0);
-            Arrays.fill(aux_edgePtrs,  0);
+            rdrCtx.stats.stat_rdr_edges_count.add(edges.used / SIZEOF_EDGE_BYTES);
+            rdrCtx.stats.hist_rdr_edges_count.add(edges.used / SIZEOF_EDGE_BYTES);
+            rdrCtx.stats.totalOffHeap += edges.length;
         }
         // Return arrays:
-        if (crossings != crossings_initial) {
-            rdrCtx.putDirtyIntArray(crossings);
-            crossings = crossings_initial;
-            if (aux_crossings != aux_crossings_initial) {
-                rdrCtx.putDirtyIntArray(aux_crossings);
-                aux_crossings = aux_crossings_initial;
-            }
-        }
-        if (edgePtrs != edgePtrs_initial) {
-            rdrCtx.putDirtyIntArray(edgePtrs);
-            edgePtrs = edgePtrs_initial;
-            if (aux_edgePtrs != aux_edgePtrs_initial) {
-                rdrCtx.putDirtyIntArray(aux_edgePtrs);
-                aux_edgePtrs = aux_edgePtrs_initial;
-            }
-        }
-        if (alphaLine != alphaLine_initial) {
-            rdrCtx.putIntArray(alphaLine, 0, 0); // already zero filled
-            alphaLine = alphaLine_initial;
-        }
-        if (blkFlags != blkFlags_initial) {
-            rdrCtx.putIntArray(blkFlags, 0, 0); // already zero filled
-            blkFlags = blkFlags_initial;
-        }
+        crossings = crossings_ref.putArray(crossings);
+        aux_crossings = aux_crossings_ref.putArray(aux_crossings);
+
+        edgePtrs = edgePtrs_ref.putArray(edgePtrs);
+        aux_edgePtrs = aux_edgePtrs_ref.putArray(aux_edgePtrs);
+
+        alphaLine = alphaLine_ref.putArray(alphaLine, 0, 0); // already zero filled
+        blkFlags  = blkFlags_ref.putArray(blkFlags, 0, 0); // already zero filled
 
         if (edgeMinY != Integer.MAX_VALUE) {
             // if context is maked as DIRTY:
@@ -639,30 +639,16 @@
                 buckets_minY = 0;
                 buckets_maxY = boundsMaxY - boundsMinY;
             }
-            // clear used part
-            if (edgeBuckets == edgeBuckets_initial) {
-                // fill only used part
-                IntArrayCache.fill(edgeBuckets,      buckets_minY,
-                                                     buckets_maxY,     0);
-                IntArrayCache.fill(edgeBucketCounts, buckets_minY,
-                                                     buckets_maxY + 1, 0);
-            } else {
-                 // clear only used part
-                rdrCtx.putIntArray(edgeBuckets,      buckets_minY,
-                                                     buckets_maxY);
-                edgeBuckets = edgeBuckets_initial;
-
-                rdrCtx.putIntArray(edgeBucketCounts, buckets_minY,
-                                                     buckets_maxY + 1);
-                edgeBucketCounts = edgeBucketCounts_initial;
-            }
-        } else if (edgeBuckets != edgeBuckets_initial) {
+            // clear only used part
+            edgeBuckets = edgeBuckets_ref.putArray(edgeBuckets, buckets_minY,
+                                                                buckets_maxY);
+            edgeBucketCounts = edgeBucketCounts_ref.putArray(edgeBucketCounts,
+                                                             buckets_minY,
+                                                             buckets_maxY + 1);
+        } else {
             // unused arrays
-            rdrCtx.putIntArray(edgeBuckets, 0, 0);
-            edgeBuckets = edgeBuckets_initial;
-
-            rdrCtx.putIntArray(edgeBucketCounts, 0, 0);
-            edgeBucketCounts = edgeBucketCounts_initial;
+            edgeBuckets = edgeBuckets_ref.putArray(edgeBuckets, 0, 0);
+            edgeBucketCounts = edgeBucketCounts_ref.putArray(edgeBucketCounts, 0, 0);
         }
 
         // At last: resize back off-heap edges to initial size
@@ -677,19 +663,21 @@
         if (DO_MONITORS) {
             rdrCtx.stats.mon_rdr_endRendering.stop();
         }
+        // recycle the RendererContext instance
+        MarlinRenderingEngine.returnRendererContext(rdrCtx);
     }
 
     private static float tosubpixx(final float pix_x) {
-        return f_SUBPIXEL_POSITIONS_X * pix_x;
+        return SUBPIXEL_SCALE_X * pix_x;
     }
 
     private static float tosubpixy(final float pix_y) {
         // shift y by -0.5 for fast ceil(y - 0.5):
-        return f_SUBPIXEL_POSITIONS_Y * pix_y - 0.5f;
+        return SUBPIXEL_SCALE_Y * pix_y - 0.5f;
     }
 
     @Override
-    public void moveTo(float pix_x0, float pix_y0) {
+    public void moveTo(final float pix_x0, final float pix_y0) {
         closePath();
         final float sx = tosubpixx(pix_x0);
         final float sy = tosubpixy(pix_y0);
@@ -700,7 +688,7 @@
     }
 
     @Override
-    public void lineTo(float pix_x1, float pix_y1) {
+    public void lineTo(final float pix_x1, final float pix_y1) {
         final float x1 = tosubpixx(pix_x1);
         final float y1 = tosubpixy(pix_y1);
         addLine(x0, y0, x1, y1);
@@ -709,24 +697,30 @@
     }
 
     @Override
-    public void curveTo(float x1, float y1,
-            float x2, float y2,
-            float x3, float y3)
+    public void curveTo(final float pix_x1, final float pix_y1,
+                        final float pix_x2, final float pix_y2,
+                        final float pix_x3, final float pix_y3)
     {
-        final float xe = tosubpixx(x3);
-        final float ye = tosubpixy(y3);
-        curve.set(x0, y0, tosubpixx(x1), tosubpixy(y1),
-                          tosubpixx(x2), tosubpixy(y2), xe, ye);
+        final float xe = tosubpixx(pix_x3);
+        final float ye = tosubpixy(pix_y3);
+        curve.set(x0, y0,
+                tosubpixx(pix_x1), tosubpixy(pix_y1),
+                tosubpixx(pix_x2), tosubpixy(pix_y2),
+                xe, ye);
         curveBreakIntoLinesAndAdd(x0, y0, curve, xe, ye);
         x0 = xe;
         y0 = ye;
     }
 
     @Override
-    public void quadTo(float x1, float y1, float x2, float y2) {
-        final float xe = tosubpixx(x2);
-        final float ye = tosubpixy(y2);
-        curve.set(x0, y0, tosubpixx(x1), tosubpixy(y1), xe, ye);
+    public void quadTo(final float pix_x1, final float pix_y1,
+                       final float pix_x2, final float pix_y2)
+    {
+        final float xe = tosubpixx(pix_x2);
+        final float ye = tosubpixy(pix_y2);
+        curve.set(x0, y0,
+                tosubpixx(pix_x1), tosubpixy(pix_y1),
+                xe, ye);
         quadBreakIntoLinesAndAdd(x0, y0, curve, xe, ye);
         x0 = xe;
         y0 = ye;
@@ -734,9 +728,11 @@
 
     @Override
     public void closePath() {
-        addLine(x0, y0, sx0, sy0);
-        x0 = sx0;
-        y0 = sy0;
+        if (x0 != sx0 || y0 != sy0) {
+            addLine(x0, y0, sx0, sy0);
+            x0 = sx0;
+            y0 = sy0;
+        }
     }
 
     @Override
@@ -749,11 +745,6 @@
         throw new InternalError("Renderer does not use a native consumer.");
     }
 
-    // clean alpha array (zero filled)
-    private int[] alphaLine;
-    // 2048 (pixelsize) pixel large
-    private final int[] alphaLine_initial = new int[INITIAL_AA_ARRAY]; // 8K
-
     private void _endRendering(final int ymin, final int ymax) {
         if (DISABLE_RENDER) {
             return;
@@ -857,8 +848,7 @@
             // bucketCount indicates new edge / edge end:
             if (bucketcount != 0) {
                 if (DO_STATS) {
-                    rdrCtx.stats.stat_rdr_activeEdges_updates
-                        .add(numCrossings);
+                    rdrCtx.stats.stat_rdr_activeEdges_updates.add(numCrossings);
                 }
 
                 // last bit set to 1 means that edges ends
@@ -883,38 +873,33 @@
 
                 if (ptrLen != 0) {
                     if (DO_STATS) {
-                        rdrCtx.stats.stat_rdr_activeEdges_adds
-                            .add(ptrLen);
+                        rdrCtx.stats.stat_rdr_activeEdges_adds.add(ptrLen);
                         if (ptrLen > 10) {
-                            rdrCtx.stats.stat_rdr_activeEdges_adds_high
-                                .add(ptrLen);
+                            rdrCtx.stats.stat_rdr_activeEdges_adds_high.add(ptrLen);
                         }
                     }
                     ptrEnd = numCrossings + ptrLen;
 
                     if (edgePtrsLen < ptrEnd) {
                         if (DO_STATS) {
-                            rdrCtx.stats.stat_array_renderer_edgePtrs
-                                .add(ptrEnd);
+                            rdrCtx.stats.stat_array_renderer_edgePtrs.add(ptrEnd);
                         }
                         this.edgePtrs = _edgePtrs
-                            = rdrCtx.widenDirtyIntArray(_edgePtrs, numCrossings,
-                                                        ptrEnd);
+                            = edgePtrs_ref.widenArray(_edgePtrs, numCrossings,
+                                                      ptrEnd);
 
                         edgePtrsLen = _edgePtrs.length;
                         // Get larger auxiliary storage:
-                        if (_aux_edgePtrs != aux_edgePtrs_initial) {
-                            rdrCtx.putDirtyIntArray(_aux_edgePtrs);
-                        }
+                        aux_edgePtrs_ref.putArray(_aux_edgePtrs);
+
                         // use ArrayCache.getNewSize() to use the same growing
-                        // factor than widenDirtyIntArray():
+                        // factor than widenArray():
                         if (DO_STATS) {
-                            rdrCtx.stats.stat_array_renderer_aux_edgePtrs
-                                .add(ptrEnd);
+                            rdrCtx.stats.stat_array_renderer_aux_edgePtrs.add(ptrEnd);
                         }
                         this.aux_edgePtrs = _aux_edgePtrs
-                            = rdrCtx.getDirtyIntArray(
-                                ArrayCache.getNewSize(numCrossings, ptrEnd)
+                            = aux_edgePtrs_ref.getArray(
+                                ArrayCacheConst.getNewSize(numCrossings, ptrEnd)
                             );
                     }
 
@@ -933,26 +918,24 @@
 
                     if (crossingsLen < numCrossings) {
                         // Get larger array:
-                        if (_crossings != crossings_initial) {
-                            rdrCtx.putDirtyIntArray(_crossings);
-                        }
+                        crossings_ref.putArray(_crossings);
+
                         if (DO_STATS) {
                             rdrCtx.stats.stat_array_renderer_crossings
                                 .add(numCrossings);
                         }
                         this.crossings = _crossings
-                            = rdrCtx.getDirtyIntArray(numCrossings);
+                            = crossings_ref.getArray(numCrossings);
 
                         // Get larger auxiliary storage:
-                        if (_aux_crossings != aux_crossings_initial) {
-                            rdrCtx.putDirtyIntArray(_aux_crossings);
-                        }
+                        aux_crossings_ref.putArray(_aux_crossings);
+
                         if (DO_STATS) {
                             rdrCtx.stats.stat_array_renderer_aux_crossings
                                 .add(numCrossings);
                         }
                         this.aux_crossings = _aux_crossings
-                            = rdrCtx.getDirtyIntArray(numCrossings);
+                            = aux_crossings_ref.getArray(numCrossings);
 
                         crossingsLen = _crossings.length;
                     }
@@ -973,10 +956,8 @@
                  */
                 if ((ptrLen < 10) || (numCrossings < 40)) {
                     if (DO_STATS) {
-                        rdrCtx.stats.hist_rdr_crossings
-                            .add(numCrossings);
-                        rdrCtx.stats.hist_rdr_crossings_adds
-                            .add(ptrLen);
+                        rdrCtx.stats.hist_rdr_crossings.add(numCrossings);
+                        rdrCtx.stats.hist_rdr_crossings_adds.add(ptrLen);
                     }
 
                     /*
@@ -992,8 +973,8 @@
                         // get the pointer to the edge
                         ecur = _edgePtrs[i];
 
-                        /* convert subpixel coordinates (float) into pixel
-                            positions (int) for coming scanline */
+                        /* convert subpixel coordinates into pixel
+                            positions for coming scanline */
                         /* note: it is faster to always update edges even
                            if it is removed from AEL for coming or last scanline */
 
@@ -1019,23 +1000,20 @@
                         _unsafe.putInt(addr + _OFF_ERROR, (err & _ERR_STEP_MAX));
 
                         if (DO_STATS) {
-                            rdrCtx.stats.stat_rdr_crossings_updates
-                                .add(numCrossings);
+                            rdrCtx.stats.stat_rdr_crossings_updates.add(numCrossings);
                         }
 
                         // insertion sort of crossings:
                         if (cross < lastCross) {
                             if (DO_STATS) {
-                                rdrCtx.stats.stat_rdr_crossings_sorts
-                                    .add(i);
+                                rdrCtx.stats.stat_rdr_crossings_sorts.add(i);
                             }
 
                             /* use binary search for newly added edges
                                in crossings if arrays are large enough */
                             if (useBinarySearch && (i >= prevNumCrossings)) {
                                 if (DO_STATS) {
-                                    rdrCtx.stats.
-                                        stat_rdr_crossings_bsearch.add(i);
+                                    rdrCtx.stats.stat_rdr_crossings_bsearch.add(i);
                                 }
                                 low = 0;
                                 high = i - 1;
@@ -1078,14 +1056,11 @@
                     }
                 } else {
                     if (DO_STATS) {
-                        rdrCtx.stats.stat_rdr_crossings_msorts
-                            .add(numCrossings);
+                        rdrCtx.stats.stat_rdr_crossings_msorts.add(numCrossings);
                         rdrCtx.stats.hist_rdr_crossings_ratio
                             .add((1000 * ptrLen) / numCrossings);
-                        rdrCtx.stats.hist_rdr_crossings_msorts
-                            .add(numCrossings);
-                        rdrCtx.stats.hist_rdr_crossings_msorts_adds
-                            .add(ptrLen);
+                        rdrCtx.stats.hist_rdr_crossings_msorts.add(numCrossings);
+                        rdrCtx.stats.hist_rdr_crossings_msorts_adds.add(ptrLen);
                     }
 
                     // Copy sorted data in auxiliary arrays
@@ -1098,8 +1073,8 @@
                         // get the pointer to the edge
                         ecur = _edgePtrs[i];
 
-                        /* convert subpixel coordinates (float) into pixel
-                            positions (int) for coming scanline */
+                        /* convert subpixel coordinates into pixel
+                            positions for coming scanline */
                         /* note: it is faster to always update edges even
                            if it is removed from AEL for coming or last scanline */
 
@@ -1125,8 +1100,7 @@
                         _unsafe.putInt(addr + _OFF_ERROR, (err & _ERR_STEP_MAX));
 
                         if (DO_STATS) {
-                            rdrCtx.stats.stat_rdr_crossings_updates
-                                .add(numCrossings);
+                            rdrCtx.stats.stat_rdr_crossings_updates.add(numCrossings);
                         }
 
                         if (i >= prevNumCrossings) {
@@ -1136,8 +1110,7 @@
 
                         } else if (cross < lastCross) {
                             if (DO_STATS) {
-                                rdrCtx.stats.stat_rdr_crossings_sorts
-                                    .add(i);
+                                rdrCtx.stats.stat_rdr_crossings_sorts.add(i);
                             }
 
                             // (straight) insertion sort of crossings:
@@ -1207,7 +1180,14 @@
                             // TODO: perform line clipping on left-right sides
                             // to avoid such bound checks:
                             x0 = (prev > bboxx0) ? prev : bboxx0;
-                            x1 = (curx < bboxx1) ? curx : bboxx1;
+
+                            if (curx < bboxx1) {
+                                x1 = curx;
+                            } else {
+                                x1 = bboxx1;
+                                // skip right side (fast exit loop):
+                                i = numCrossings;
+                            }
 
                             if (x0 < x1) {
                                 x0 -= bboxx0; // turn x0, x1 from coords to indices
@@ -1224,7 +1204,8 @@
 
                                     if (useBlkFlags) {
                                         // flag used blocks:
-                                        _blkFlags[pix_x >> _BLK_SIZE_LG] = 1;
+                                        // note: block processing handles extra pixel:
+                                        _blkFlags[pix_x    >> _BLK_SIZE_LG] = 1;
                                     }
                                 } else {
                                     tmp = (x0 & _SUBPIXEL_MASK_X);
@@ -1243,6 +1224,7 @@
 
                                     if (useBlkFlags) {
                                         // flag used blocks:
+                                        // note: block processing handles extra pixel:
                                         _blkFlags[pix_x    >> _BLK_SIZE_LG] = 1;
                                         _blkFlags[pix_xmax >> _BLK_SIZE_LG] = 1;
                                     }
@@ -1268,7 +1250,14 @@
                             // TODO: perform line clipping on left-right sides
                             // to avoid such bound checks:
                             x0 = (prev > bboxx0) ? prev : bboxx0;
-                            x1 = (curx < bboxx1) ? curx : bboxx1;
+
+                            if (curx < bboxx1) {
+                                x1 = curx;
+                            } else {
+                                x1 = bboxx1;
+                                // skip right side (fast exit loop):
+                                i = numCrossings;
+                            }
 
                             if (x0 < x1) {
                                 x0 -= bboxx0; // turn x0, x1 from coords to indices
@@ -1285,7 +1274,8 @@
 
                                     if (useBlkFlags) {
                                         // flag used blocks:
-                                        _blkFlags[pix_x >> _BLK_SIZE_LG] = 1;
+                                        // note: block processing handles extra pixel:
+                                        _blkFlags[pix_x    >> _BLK_SIZE_LG] = 1;
                                     }
                                 } else {
                                     tmp = (x0 & _SUBPIXEL_MASK_X);
@@ -1304,6 +1294,7 @@
 
                                     if (useBlkFlags) {
                                         // flag used blocks:
+                                        // note: block processing handles extra pixel:
                                         _blkFlags[pix_x    >> _BLK_SIZE_LG] = 1;
                                         _blkFlags[pix_xmax >> _BLK_SIZE_LG] = 1;
                                     }
@@ -1337,9 +1328,12 @@
 
                 if (maxX >= minX) {
                     // note: alpha array will be zeroed by copyAARow()
-                    // +2 because alpha [pix_minX; pix_maxX+1]
+                    // +1 because alpha [pix_minX; pix_maxX[
                     // fix range [x0; x1[
-                    copyAARow(_alpha, lastY, minX, maxX + 2, useBlkFlags);
+                    // note: if x1=bboxx1, then alpha is written up to bboxx1+1
+                    // inclusive: alpha[bboxx1] ignored, alpha[bboxx1+1] == 0
+                    // (normally so never cleared below)
+                    copyAARow(_alpha, lastY, minX, maxX + 1, useBlkFlags);
 
                     // speculative for next pixel row (scanline coherence):
                     if (_enableBlkFlagsHeuristics) {
@@ -1381,9 +1375,12 @@
 
         if (maxX >= minX) {
             // note: alpha array will be zeroed by copyAARow()
-            // +2 because alpha [pix_minX; pix_maxX+1]
+            // +1 because alpha [pix_minX; pix_maxX[
             // fix range [x0; x1[
-            copyAARow(_alpha, y, minX, maxX + 2, useBlkFlags);
+            // note: if x1=bboxx1, then alpha is written up to bboxx1+1
+            // inclusive: alpha[bboxx1] ignored then cleared and
+            // alpha[bboxx1+1] == 0 (normally so never cleared after)
+            copyAARow(_alpha, y, minX, maxX + 1, useBlkFlags);
         } else if (y != lastY) {
             _cache.clearAARow(y);
         }
@@ -1406,36 +1403,26 @@
             return false; // undefined edges bounds
         }
 
-        final int _boundsMinY = boundsMinY;
-        final int _boundsMaxY = boundsMaxY;
-
-        // bounds as inclusive intervals
+        // bounds as half-open intervals
         final int spminX = FloatMath.max(FloatMath.ceil_int(edgeMinX - 0.5f), boundsMinX);
-        final int spmaxX = FloatMath.min(FloatMath.ceil_int(edgeMaxX - 0.5f), boundsMaxX - 1);
+        final int spmaxX = FloatMath.min(FloatMath.ceil_int(edgeMaxX - 0.5f), boundsMaxX);
 
         // edge Min/Max Y are already rounded to subpixels within bounds:
         final int spminY = edgeMinY;
-        final int spmaxY;
-        int maxY = edgeMaxY;
+        final int spmaxY = edgeMaxY;
 
-        if (maxY <= _boundsMaxY - 1) {
-            spmaxY = maxY;
-        } else {
-            spmaxY = _boundsMaxY - 1;
-            maxY   = _boundsMaxY;
-        }
-        buckets_minY = spminY - _boundsMinY;
-        buckets_maxY = maxY   - _boundsMinY;
+        buckets_minY = spminY - boundsMinY;
+        buckets_maxY = spmaxY - boundsMinY;
 
         if (DO_LOG_BOUNDS) {
             MarlinUtils.logInfo("edgesXY = [" + edgeMinX + " ... " + edgeMaxX
-                                + "][" + edgeMinY + " ... " + edgeMaxY + "]");
+                                + "[ [" + edgeMinY + " ... " + edgeMaxY + "[");
             MarlinUtils.logInfo("spXY    = [" + spminX + " ... " + spmaxX
-                                + "][" + spminY + " ... " + spmaxY + "]");
+                                + "[ [" + spminY + " ... " + spmaxY + "[");
         }
 
         // test clipping for shapes out of bounds
-        if ((spminX > spmaxX) || (spminY > spmaxY)) {
+        if ((spminX >= spmaxX) || (spminY >= spmaxY)) {
             return false;
         }
 
@@ -1450,7 +1437,7 @@
         final int pmaxY = (spmaxY + SUBPIXEL_MASK_Y) >> SUBPIXEL_LG_POSITIONS_Y;
 
         // store BBox to answer ptg.getBBox():
-        this.cache.init(pminX, pminY, pmaxX, pmaxY, edgeSumDeltaY);
+        this.cache.init(pminX, pminY, pmaxX, pmaxY);
 
         // Heuristics for using block flags:
         if (ENABLE_BLOCK_FLAGS) {
@@ -1460,9 +1447,9 @@
             if (enableBlkFlags) {
                 // ensure blockFlags array is large enough:
                 // note: +2 to ensure enough space left at end
-                final int nxTiles = ((pmaxX - pminX) >> TILE_SIZE_LG) + 2;
-                if (nxTiles > INITIAL_ARRAY) {
-                    blkFlags = rdrCtx.getIntArray(nxTiles);
+                final int blkLen = ((pmaxX - pminX) >> BLOCK_SIZE_LG) + 2;
+                if (blkLen > INITIAL_ARRAY) {
+                    blkFlags = blkFlags_ref.getArray(blkLen);
                 }
             }
         }
@@ -1477,7 +1464,7 @@
         // inclusive:
         bbox_spminY = spminY;
         // exclusive:
-        bbox_spmaxY = FloatMath.min(spmaxY + 1, pmaxY << SUBPIXEL_LG_POSITIONS_Y);
+        bbox_spmaxY = spmaxY;
 
         if (DO_LOG_BOUNDS) {
             MarlinUtils.logInfo("pXY       = [" + pminX + " ... " + pmaxX
@@ -1494,10 +1481,9 @@
         // Useful when processing tile line by tile line
         if (width > INITIAL_AA_ARRAY) {
             if (DO_STATS) {
-                rdrCtx.stats.stat_array_renderer_alphaline
-                    .add(width);
+                rdrCtx.stats.stat_array_renderer_alphaline.add(width);
             }
-            alphaLine = rdrCtx.getIntArray(width);
+            alphaLine = alphaLine_ref.getArray(width);
         }
 
         // process first tile line:
@@ -1532,17 +1518,13 @@
         }
     }
 
-    private boolean enableBlkFlags = false;
-    private boolean prevUseBlkFlags = false;
-
-    private final int[] blkFlags_initial = new int[INITIAL_ARRAY]; // 1 tile line
-    /* block flags (0|1) */
-    private int[] blkFlags = blkFlags_initial;
-
     void copyAARow(final int[] alphaRow,
                    final int pix_y, final int pix_from, final int pix_to,
                    final boolean useBlockFlags)
     {
+        if (DO_MONITORS) {
+            rdrCtx.stats.mon_rdr_copyAARow.start();
+        }
         if (useBlockFlags) {
             if (DO_STATS) {
                 rdrCtx.stats.hist_tile_generator_encoding.add(1);
@@ -1554,5 +1536,8 @@
             }
             cache.copyAARowNoRLE(alphaRow, pix_y, pix_from, pix_to);
         }
+        if (DO_MONITORS) {
+            rdrCtx.stats.mon_rdr_copyAARow.stop();
+        }
     }
 }
diff --git a/src/share/classes/sun/java2d/marlin/RendererContext.java b/src/share/classes/sun/java2d/marlin/RendererContext.java
index a11a1e8..2a63e9f 100644
--- a/src/share/classes/sun/java2d/marlin/RendererContext.java
+++ b/src/share/classes/sun/java2d/marlin/RendererContext.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, 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
@@ -29,24 +29,18 @@
 import java.lang.ref.WeakReference;
 import java.util.concurrent.atomic.AtomicInteger;
 import sun.java2d.ReentrantContext;
-import sun.java2d.ReentrantContextProvider;
-import static sun.java2d.marlin.ArrayCache.*;
+import sun.java2d.marlin.ArrayCacheConst.CacheStats;
 import sun.java2d.marlin.MarlinRenderingEngine.NormalizingPathIterator;
-import static sun.java2d.marlin.MarlinUtils.logInfo;
+import sun.java2d.marlin.TransformingPathConsumer2D.CurveBasicMonotonizer;
+import sun.java2d.marlin.TransformingPathConsumer2D.CurveClipSplitter;
 
 /**
  * This class is a renderer context dedicated to a single thread
  */
-final class RendererContext extends ReentrantContext implements MarlinConst {
+final class RendererContext extends ReentrantContext implements IRendererContext {
 
     // RendererContext creation counter
     private static final AtomicInteger CTX_COUNT = new AtomicInteger(1);
-    // RendererContext statistics
-    final RendererStats stats = (DO_STATS || DO_MONITORS)
-                                       ? RendererStats.getInstance(): null;
-
-    private static final boolean USE_CACHE_HARD_REF = DO_STATS
-        || (MarlinRenderingEngine.REF_TYPE == ReentrantContextProvider.REF_WEAK);
 
     /**
      * Create a new renderer context
@@ -54,25 +48,14 @@
      * @return new RendererContext instance
      */
     static RendererContext createContext() {
-        final RendererContext newCtx = new RendererContext("ctx"
-                    + Integer.toString(CTX_COUNT.getAndIncrement()));
-
-        if (DO_STATS || DO_MONITORS) {
-            RendererStats.ALL_CONTEXTS.add(newCtx);
-        }
-        return newCtx;
+        return new RendererContext("ctx"
+                       + Integer.toString(CTX_COUNT.getAndIncrement()));
     }
 
-    // context name (debugging purposes)
-    final String name;
     // Smallest object used as Cleaner's parent reference
-    final Object cleanerObj = new Object();
+    private final Object cleanerObj;
     // dirty flag indicating an exception occured during pipeline in pathTo()
     boolean dirty = false;
-    // dynamic array caches kept using weak reference (low memory footprint)
-    WeakReference<ArrayCachesHolder> refArrayCaches = null;
-    // hard reference to array caches (for statistics)
-    ArrayCachesHolder hardRefArrayCaches = null;
     // shared data
     final float[] float6 = new float[6];
     // shared curve (dirty) (Renderer / Stroker)
@@ -83,17 +66,42 @@
     final NormalizingPathIterator nPQPathIterator;
     // MarlinRenderingEngine.TransformingPathConsumer2D
     final TransformingPathConsumer2D transformerPC2D;
-    // recycled Path2D instance
-    Path2D.Float p2d = null;
+    // recycled Path2D instance (weak)
+    private WeakReference<Path2D.Float> refPath2D = null;
     final Renderer renderer;
     final Stroker stroker;
     // Simplifies out collinear lines
     final CollinearSimplifier simplifier = new CollinearSimplifier();
+    // Simplifies path
+    final PathSimplifier pathSimplifier = new PathSimplifier();
     final Dasher dasher;
     final MarlinTileGenerator ptg;
     final MarlinCache cache;
     // flag indicating the shape is stroked (1) or filled (0)
     int stroking = 0;
+    // flag indicating to clip the shape
+    boolean doClip = false;
+    // flag indicating if the path is closed or not (in advance) to handle properly caps
+    boolean closedPath = false;
+    // clip rectangle (ymin, ymax, xmin, xmax):
+    final float[] clipRect = new float[4];
+    // CurveBasicMonotonizer instance
+    final CurveBasicMonotonizer monotonizer;
+    // CurveClipSplitter instance
+    final CurveClipSplitter curveClipSplitter;
+
+    // Array caches:
+    /* clean int[] cache (zero-filled) = 5 refs */
+    private final IntArrayCache cleanIntCache = new IntArrayCache(true, 5);
+    /* dirty int[] cache = 5 refs */
+    private final IntArrayCache dirtyIntCache = new IntArrayCache(false, 5);
+    /* dirty float[] cache = 4 refs (2 polystack) */
+    private final FloatArrayCache dirtyFloatCache = new FloatArrayCache(false, 4);
+    /* dirty byte[] cache = 2 ref (2 polystack) */
+    private final ByteArrayCache dirtyByteCache = new ByteArrayCache(false, 2);
+
+    // RendererContext statistics
+    final RendererStats stats;
 
     /**
      * Constructor
@@ -104,20 +112,34 @@
         if (LOG_CREATE_CONTEXT) {
             MarlinUtils.logInfo("new RendererContext = " + name);
         }
+        this.cleanerObj = new Object();
 
-        this.name = name;
+        // create first stats (needed by newOffHeapArray):
+        if (DO_STATS || DO_MONITORS) {
+            stats = RendererStats.createInstance(cleanerObj, name);
+            // push cache stats:
+            stats.cacheStats = new CacheStats[] { cleanIntCache.stats,
+                dirtyIntCache.stats, dirtyFloatCache.stats, dirtyByteCache.stats
+            };
+        } else {
+            stats = null;
+        }
 
         // NormalizingPathIterator instances:
         nPCPathIterator = new NormalizingPathIterator.NearestPixelCenter(float6);
         nPQPathIterator  = new NormalizingPathIterator.NearestPixelQuarter(float6);
 
+        // curve monotonizer & clip subdivider (before transformerPC2D init)
+        monotonizer = new CurveBasicMonotonizer(this);
+        curveClipSplitter = new CurveClipSplitter(this);
+
         // MarlinRenderingEngine.TransformingPathConsumer2D
-        transformerPC2D = new TransformingPathConsumer2D();
+        transformerPC2D = new TransformingPathConsumer2D(this);
 
         // Renderer:
         cache = new MarlinCache(this);
         renderer = new Renderer(this); // needs MarlinCache from rdrCtx.cache
-        ptg = new MarlinTileGenerator(renderer);
+        ptg = new MarlinTileGenerator(stats, renderer, cache);
 
         stroker = new Stroker(this);
         dasher = new Dasher(this);
@@ -128,11 +150,16 @@
      * clean up before reusing this context
      */
     void dispose() {
-        stroking = 0;
-        // reset hard reference to array caches if needed:
-        if (!USE_CACHE_HARD_REF) {
-            hardRefArrayCaches = null;
+        if (DO_STATS) {
+            if (stats.totalOffHeap > stats.totalOffHeapMax) {
+                stats.totalOffHeapMax = stats.totalOffHeap;
+            }
+            stats.totalOffHeap = 0L;
         }
+        stroking   = 0;
+        doClip     = false;
+        closedPath = false;
+
         // if context is maked as DIRTY:
         if (dirty) {
             // may happen if an exception if thrown in the pipeline processing:
@@ -151,300 +178,49 @@
         }
     }
 
-    // Array caches
-    ArrayCachesHolder getArrayCachesHolder() {
-        // Use hard reference first (cached resolved weak reference):
-        ArrayCachesHolder holder = hardRefArrayCaches;
-        if (holder == null) {
-            // resolve reference:
-            holder = (refArrayCaches != null)
-                     ? refArrayCaches.get()
-                     : null;
-            // create a new ArrayCachesHolder if none is available
-            if (holder == null) {
-                if (LOG_CREATE_CONTEXT) {
-                    MarlinUtils.logInfo("new ArrayCachesHolder for "
-                                        + "RendererContext = " + name);
-                }
+    Path2D.Float getPath2D() {
+        // resolve reference:
+        Path2D.Float p2d = (refPath2D != null) ? refPath2D.get() : null;
 
-                holder = new ArrayCachesHolder();
+        // create a new Path2D ?
+        if (p2d == null) {
+            p2d = new Path2D.Float(WIND_NON_ZERO, INITIAL_EDGES_COUNT); // 32K
 
-                if (USE_CACHE_HARD_REF) {
-                    // update hard reference:
-                    hardRefArrayCaches = holder;
-                } else {
-                    // update weak reference:
-                    refArrayCaches = new WeakReference<ArrayCachesHolder>(holder);
-                }
-            }
+            // update weak reference:
+            refPath2D = new WeakReference<Path2D.Float>(p2d);
         }
-        return holder;
+        // reset the path anyway:
+        p2d.reset();
+        return p2d;
     }
 
-    // dirty byte array cache
-    ByteArrayCache getDirtyByteArrayCache(final int length) {
-        final int bucket = ArrayCache.getBucketDirtyBytes(length);
-        return getArrayCachesHolder().dirtyByteArrayCaches[bucket];
+    @Override
+    public RendererStats stats() {
+        return stats;
     }
 
-    byte[] getDirtyByteArray(final int length) {
-        if (length <= MAX_DIRTY_BYTE_ARRAY_SIZE) {
-            return getDirtyByteArrayCache(length).getArray();
-        }
-
+    @Override
+    public OffHeapArray newOffHeapArray(final long initialSize) {
         if (DO_STATS) {
-            incOversize();
+            stats.totalOffHeapInitial += initialSize;
         }
-
-        if (DO_LOG_OVERSIZE) {
-            logInfo("getDirtyByteArray[oversize]: length=\t" + length);
-        }
-
-        return new byte[length];
+        return new OffHeapArray(cleanerObj, initialSize);
     }
 
-    void putDirtyByteArray(final byte[] array) {
-        final int length = array.length;
-        // odd sized array are non-cached arrays (initial arrays)
-        // ensure to never store initial arrays in cache:
-        if (((length & 0x1) == 0) && (length <= MAX_DIRTY_BYTE_ARRAY_SIZE)) {
-            getDirtyByteArrayCache(length).putDirtyArray(array, length);
-        }
+    @Override
+    public IntArrayCache.Reference newCleanIntArrayRef(final int initialSize) {
+        return cleanIntCache.createRef(initialSize);
     }
 
-    byte[] widenDirtyByteArray(final byte[] in,
-                               final int usedSize, final int needSize)
-    {
-        final int length = in.length;
-        if (DO_CHECKS && length >= needSize) {
-            return in;
-        }
-        if (DO_STATS) {
-            incResizeDirtyByte();
-        }
-
-        // maybe change bucket:
-        // ensure getNewSize() > newSize:
-        final byte[] res = getDirtyByteArray(getNewSize(usedSize, needSize));
-
-        System.arraycopy(in, 0, res, 0, usedSize); // copy only used elements
-
-        // maybe return current array:
-        // NO clean-up of array data = DIRTY ARRAY
-        putDirtyByteArray(in);
-
-        if (DO_LOG_WIDEN_ARRAY) {
-            logInfo("widenDirtyByteArray[" + res.length + "]: usedSize=\t"
-                    + usedSize + "\tlength=\t" + length + "\tneeded length=\t"
-                    + needSize);
-        }
-        return res;
+    IntArrayCache.Reference newDirtyIntArrayRef(final int initialSize) {
+        return dirtyIntCache.createRef(initialSize);
     }
 
-    // int array cache
-    IntArrayCache getIntArrayCache(final int length) {
-        final int bucket = ArrayCache.getBucket(length);
-        return getArrayCachesHolder().intArrayCaches[bucket];
+    FloatArrayCache.Reference newDirtyFloatArrayRef(final int initialSize) {
+        return dirtyFloatCache.createRef(initialSize);
     }
 
-    int[] getIntArray(final int length) {
-        if (length <= MAX_ARRAY_SIZE) {
-            return getIntArrayCache(length).getArray();
-        }
-
-        if (DO_STATS) {
-            incOversize();
-        }
-
-        if (DO_LOG_OVERSIZE) {
-            logInfo("getIntArray[oversize]: length=\t" + length);
-        }
-
-        return new int[length];
-    }
-
-    // unused
-    int[] widenIntArray(final int[] in, final int usedSize,
-                        final int needSize, final int clearTo)
-    {
-        final int length = in.length;
-        if (DO_CHECKS && length >= needSize) {
-            return in;
-        }
-        if (DO_STATS) {
-            incResizeInt();
-        }
-
-        // maybe change bucket:
-        // ensure getNewSize() > newSize:
-        final int[] res = getIntArray(getNewSize(usedSize, needSize));
-
-        System.arraycopy(in, 0, res, 0, usedSize); // copy only used elements
-
-        // maybe return current array:
-        putIntArray(in, 0, clearTo); // ensure all array is cleared (grow-reduce algo)
-
-        if (DO_LOG_WIDEN_ARRAY) {
-            logInfo("widenIntArray[" + res.length + "]: usedSize=\t"
-                    + usedSize + "\tlength=\t" + length + "\tneeded length=\t"
-                    + needSize);
-        }
-        return res;
-    }
-
-    void putIntArray(final int[] array, final int fromIndex,
-                     final int toIndex)
-    {
-        final int length = array.length;
-        // odd sized array are non-cached arrays (initial arrays)
-        // ensure to never store initial arrays in cache:
-        if (((length & 0x1) == 0) && (length <= MAX_ARRAY_SIZE)) {
-            getIntArrayCache(length).putArray(array, length, fromIndex, toIndex);
-        }
-    }
-
-    // dirty int array cache
-    IntArrayCache getDirtyIntArrayCache(final int length) {
-        final int bucket = ArrayCache.getBucket(length);
-        return getArrayCachesHolder().dirtyIntArrayCaches[bucket];
-    }
-
-    int[] getDirtyIntArray(final int length) {
-        if (length <= MAX_ARRAY_SIZE) {
-            return getDirtyIntArrayCache(length).getArray();
-        }
-
-        if (DO_STATS) {
-            incOversize();
-        }
-
-        if (DO_LOG_OVERSIZE) {
-            logInfo("getDirtyIntArray[oversize]: length=\t" + length);
-        }
-
-        return new int[length];
-    }
-
-    int[] widenDirtyIntArray(final int[] in,
-                             final int usedSize, final int needSize)
-    {
-        final int length = in.length;
-        if (DO_CHECKS && length >= needSize) {
-            return in;
-        }
-        if (DO_STATS) {
-            incResizeDirtyInt();
-        }
-
-        // maybe change bucket:
-        // ensure getNewSize() > newSize:
-        final int[] res = getDirtyIntArray(getNewSize(usedSize, needSize));
-
-        System.arraycopy(in, 0, res, 0, usedSize); // copy only used elements
-
-        // maybe return current array:
-        // NO clean-up of array data = DIRTY ARRAY
-        putDirtyIntArray(in);
-
-        if (DO_LOG_WIDEN_ARRAY) {
-            logInfo("widenDirtyIntArray[" + res.length + "]: usedSize=\t"
-                    + usedSize + "\tlength=\t" + length + "\tneeded length=\t"
-                    + needSize);
-        }
-        return res;
-    }
-
-    void putDirtyIntArray(final int[] array) {
-        final int length = array.length;
-        // odd sized array are non-cached arrays (initial arrays)
-        // ensure to never store initial arrays in cache:
-        if (((length & 0x1) == 0) && (length <= MAX_ARRAY_SIZE)) {
-            getDirtyIntArrayCache(length).putDirtyArray(array, length);
-        }
-    }
-
-    // dirty float array cache
-    FloatArrayCache getDirtyFloatArrayCache(final int length) {
-        final int bucket = ArrayCache.getBucket(length);
-        return getArrayCachesHolder().dirtyFloatArrayCaches[bucket];
-    }
-
-    float[] getDirtyFloatArray(final int length) {
-        if (length <= MAX_ARRAY_SIZE) {
-            return getDirtyFloatArrayCache(length).getArray();
-        }
-
-        if (DO_STATS) {
-            incOversize();
-        }
-
-        if (DO_LOG_OVERSIZE) {
-            logInfo("getDirtyFloatArray[oversize]: length=\t" + length);
-        }
-
-        return new float[length];
-    }
-
-    float[] widenDirtyFloatArray(final float[] in,
-                                 final int usedSize, final int needSize)
-    {
-        final int length = in.length;
-        if (DO_CHECKS && length >= needSize) {
-            return in;
-        }
-        if (DO_STATS) {
-            incResizeDirtyFloat();
-        }
-
-        // maybe change bucket:
-        // ensure getNewSize() > newSize:
-        final float[] res = getDirtyFloatArray(getNewSize(usedSize, needSize));
-
-        System.arraycopy(in, 0, res, 0, usedSize); // copy only used elements
-
-        // maybe return current array:
-        // NO clean-up of array data = DIRTY ARRAY
-        putDirtyFloatArray(in);
-
-        if (DO_LOG_WIDEN_ARRAY) {
-            logInfo("widenDirtyFloatArray[" + res.length + "]: usedSize=\t"
-                    + usedSize + "\tlength=\t" + length + "\tneeded length=\t"
-                    + needSize);
-        }
-        return res;
-    }
-
-    void putDirtyFloatArray(final float[] array) {
-        final int length = array.length;
-        // odd sized array are non-cached arrays (initial arrays)
-        // ensure to never store initial arrays in cache:
-        if (((length & 0x1) == 0) && (length <= MAX_ARRAY_SIZE)) {
-            getDirtyFloatArrayCache(length).putDirtyArray(array, length);
-        }
-    }
-
-    /* class holding all array cache instances */
-    static final class ArrayCachesHolder {
-        // zero-filled int array cache:
-        final IntArrayCache[] intArrayCaches;
-        // dirty array caches:
-        final IntArrayCache[] dirtyIntArrayCaches;
-        final FloatArrayCache[] dirtyFloatArrayCaches;
-        final ByteArrayCache[] dirtyByteArrayCaches;
-
-        ArrayCachesHolder() {
-            intArrayCaches = new IntArrayCache[BUCKETS];
-            dirtyIntArrayCaches = new IntArrayCache[BUCKETS];
-            dirtyFloatArrayCaches = new FloatArrayCache[BUCKETS];
-            dirtyByteArrayCaches = new ByteArrayCache[BUCKETS];
-
-            for (int i = 0; i < BUCKETS; i++) {
-                intArrayCaches[i] = new IntArrayCache(ARRAY_SIZES[i]);
-                // dirty array caches:
-                dirtyIntArrayCaches[i] = new IntArrayCache(ARRAY_SIZES[i]);
-                dirtyFloatArrayCaches[i] = new FloatArrayCache(ARRAY_SIZES[i]);
-                dirtyByteArrayCaches[i] = new ByteArrayCache(DIRTY_BYTE_ARRAY_SIZES[i]);
-            }
-        }
+    ByteArrayCache.Reference newDirtyByteArrayRef(final int initialSize) {
+        return dirtyByteCache.createRef(initialSize);
     }
 }
diff --git a/src/share/classes/sun/java2d/marlin/RendererStats.java b/src/share/classes/sun/java2d/marlin/RendererStats.java
index 9c2fa73..66a9eb1 100644
--- a/src/share/classes/sun/java2d/marlin/RendererStats.java
+++ b/src/share/classes/sun/java2d/marlin/RendererStats.java
@@ -25,42 +25,42 @@
 
 package sun.java2d.marlin;
 
+import java.lang.ref.PhantomReference;
+import java.lang.ref.ReferenceQueue;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.Timer;
 import java.util.TimerTask;
+import java.util.Vector;
 import java.util.concurrent.ConcurrentLinkedQueue;
+import sun.java2d.marlin.ArrayCacheConst.CacheStats;
 import static sun.java2d.marlin.MarlinUtils.logInfo;
 import sun.java2d.marlin.stats.Histogram;
 import sun.java2d.marlin.stats.Monitor;
 import sun.java2d.marlin.stats.StatLong;
-import sun.misc.ThreadGroupUtils;
+//import sun.awt.util.ThreadGroupUtils;
 
 /**
  * This class gathers global rendering statistics for debugging purposes only
  */
 public final class RendererStats implements MarlinConst {
 
-    // singleton
-    private static volatile RendererStats SINGLETON = null;
+    static RendererStats createInstance(final Object parent, final String name)
+    {
+        final RendererStats stats = new RendererStats(name);
 
-    static RendererStats getInstance() {
-        if (SINGLETON == null) {
-            SINGLETON = new RendererStats();
-        }
-        return SINGLETON;
+        // Keep a strong reference to dump it later:
+        RendererStatsHolder.getInstance().add(parent, stats);
+
+        return stats;
     }
 
     public static void dumpStats() {
-        if (SINGLETON != null) {
-            SINGLETON.dump();
-        }
+        RendererStatsHolder.dumpStats();
     }
 
-    /* RendererContext collection as hard references
-       (only used for debugging purposes) */
-    static final ConcurrentLinkedQueue<RendererContext> ALL_CONTEXTS
-        = new ConcurrentLinkedQueue<RendererContext>();
+    // context name (debugging purposes)
+    final String name;
     // stats
     final StatLong stat_cache_rowAA
         = new StatLong("cache.rowAA");
@@ -68,10 +68,6 @@
         = new StatLong("cache.rowAAChunk");
     final StatLong stat_cache_tiles
         = new StatLong("cache.tiles");
-    final StatLong stat_rdr_poly_stack_curves
-        = new StatLong("renderer.poly.stack.curves");
-    final StatLong stat_rdr_poly_stack_types
-        = new StatLong("renderer.poly.stack.types");
     final StatLong stat_rdr_addLine
         = new StatLong("renderer.addLine");
     final StatLong stat_rdr_addLine_skip
@@ -108,17 +104,23 @@
         = new StatLong("renderer.crossings.bsearch");
     final StatLong stat_rdr_crossings_msorts
         = new StatLong("renderer.crossings.msorts");
+    final StatLong stat_str_polystack_curves
+        = new StatLong("stroker.polystack.curves");
+    final StatLong stat_str_polystack_types
+        = new StatLong("stroker.polystack.types");
+    final StatLong stat_cpd_polystack_curves
+        = new StatLong("closedPathDetector.polystack.curves");
+    final StatLong stat_cpd_polystack_types
+        = new StatLong("closedPathDetector.polystack.types");
+    final StatLong stat_pcf_idxstack_indices
+        = new StatLong("pathClipFilter.stack.indices");
     // growable arrays
     final StatLong stat_array_dasher_dasher
         = new StatLong("array.dasher.dasher.d_float");
     final StatLong stat_array_dasher_firstSegmentsBuffer
         = new StatLong("array.dasher.firstSegmentsBuffer.d_float");
-    final StatLong stat_array_stroker_polystack_curves
-        = new StatLong("array.stroker.polystack.curves.d_float");
-    final StatLong stat_array_stroker_polystack_curveTypes
-        = new StatLong("array.stroker.polystack.curveTypes.d_byte");
     final StatLong stat_array_marlincache_rowAAChunk
-        = new StatLong("array.marlincache.rowAAChunk.d_byte");
+        = new StatLong("array.marlincache.rowAAChunk.resize");
     final StatLong stat_array_marlincache_touchedTile
         = new StatLong("array.marlincache.touchedTile.int");
     final StatLong stat_array_renderer_alphaline
@@ -135,7 +137,19 @@
         = new StatLong("array.renderer.edgePtrs.int");
     final StatLong stat_array_renderer_aux_edgePtrs
         = new StatLong("array.renderer.aux_edgePtrs.int");
+    final StatLong stat_array_str_polystack_curves
+        = new StatLong("array.stroker.polystack.curves.d_float");
+    final StatLong stat_array_str_polystack_types
+        = new StatLong("array.stroker.polystack.curveTypes.d_byte");
+    final StatLong stat_array_cpd_polystack_curves
+        = new StatLong("array.closedPathDetector.polystack.curves.d_float");
+    final StatLong stat_array_cpd_polystack_types
+        = new StatLong("array.closedPathDetector.polystack.curveTypes.d_byte");
+    final StatLong stat_array_pcf_idxstack_indices
+        = new StatLong("array.pathClipFilter.stack.indices.d_int");
     // histograms
+    final Histogram hist_rdr_edges_count
+        = new Histogram("renderer.edges.count");
     final Histogram hist_rdr_crossings
         = new Histogram("renderer.crossings");
     final Histogram hist_rdr_crossings_ratio
@@ -146,6 +160,8 @@
         = new Histogram("renderer.crossings.msorts");
     final Histogram hist_rdr_crossings_msorts_adds
         = new Histogram("renderer.crossings.msorts.adds");
+    final Histogram hist_str_polystack_curves
+        = new Histogram("stroker.polystack.curves");
     final Histogram hist_tile_generator_alpha
         = new Histogram("tile_generator.alpha");
     final Histogram hist_tile_generator_encoding
@@ -156,13 +172,15 @@
         = new Histogram("tile_generator.encoding.ratio");
     final Histogram hist_tile_generator_encoding_runLen
         = new Histogram("tile_generator.encoding.runLen");
+    final Histogram hist_cpd_polystack_curves
+        = new Histogram("closedPathDetector.polystack.curves");
+    final Histogram hist_pcf_idxstack_indices
+        = new Histogram("pathClipFilter.stack.indices");
     // all stats
     final StatLong[] statistics = new StatLong[]{
         stat_cache_rowAA,
         stat_cache_rowAAChunk,
         stat_cache_tiles,
-        stat_rdr_poly_stack_types,
-        stat_rdr_poly_stack_curves,
         stat_rdr_addLine,
         stat_rdr_addLine_skip,
         stat_rdr_curveBreak,
@@ -181,6 +199,12 @@
         stat_rdr_crossings_sorts,
         stat_rdr_crossings_bsearch,
         stat_rdr_crossings_msorts,
+        stat_str_polystack_types,
+        stat_str_polystack_curves,
+        stat_cpd_polystack_curves,
+        stat_cpd_polystack_types,
+        stat_pcf_idxstack_indices,
+        hist_rdr_edges_count,
         hist_rdr_crossings,
         hist_rdr_crossings_ratio,
         hist_rdr_crossings_adds,
@@ -191,10 +215,11 @@
         hist_tile_generator_encoding_dist,
         hist_tile_generator_encoding_ratio,
         hist_tile_generator_encoding_runLen,
+        hist_str_polystack_curves,
+        hist_cpd_polystack_curves,
+        hist_pcf_idxstack_indices,
         stat_array_dasher_dasher,
         stat_array_dasher_firstSegmentsBuffer,
-        stat_array_stroker_polystack_curves,
-        stat_array_stroker_polystack_curveTypes,
         stat_array_marlincache_rowAAChunk,
         stat_array_marlincache_touchedTile,
         stat_array_renderer_alphaline,
@@ -203,7 +228,12 @@
         stat_array_renderer_edgeBuckets,
         stat_array_renderer_edgeBucketCounts,
         stat_array_renderer_edgePtrs,
-        stat_array_renderer_aux_edgePtrs
+        stat_array_renderer_aux_edgePtrs,
+        stat_array_str_polystack_curves,
+        stat_array_str_polystack_types,
+        stat_array_cpd_polystack_curves,
+        stat_array_cpd_polystack_types,
+        stat_array_pcf_idxstack_indices
     };
     // monitors
     final Monitor mon_pre_getAATileGenerator
@@ -233,94 +263,216 @@
         mon_ptg_getAlpha,
         mon_debug
     };
+    // offheap stats
+    long totalOffHeapInitial = 0L;
+     // live accumulator
+    long totalOffHeap = 0L;
+    long totalOffHeapMax = 0L;
+    // cache stats
+    CacheStats[] cacheStats = null;
 
-    private RendererStats() {
-        super();
-
-        AccessController.doPrivileged(
-            (PrivilegedAction<Void>) () -> {
-                final Thread hook = new Thread(
-                    ThreadGroupUtils.getRootThreadGroup(),
-                    new Runnable() {
-                        @Override
-                        public void run() {
-                            dump();
-                        }
-                    },
-                    "MarlinStatsHook"
-                );
-                hook.setContextClassLoader(null);
-                Runtime.getRuntime().addShutdownHook(hook);
-
-                if (USE_DUMP_THREAD) {
-                    final Timer statTimer = new Timer("RendererStats");
-                    statTimer.scheduleAtFixedRate(new TimerTask() {
-                        @Override
-                        public void run() {
-                            dump();
-                        }
-                    }, DUMP_INTERVAL, DUMP_INTERVAL);
-                }
-                return null;
-            }
-        );
+    private RendererStats(final String name) {
+        this.name = name;
     }
 
     void dump() {
-        if (DO_STATS) {
-            ArrayCache.dumpStats();
-        }
-        for (RendererContext rdrCtx : ALL_CONTEXTS) {
-            logInfo("RendererContext: " + rdrCtx.name);
+        logInfo("RendererContext: " + name);
 
-            if (DO_MONITORS) {
+        if (DO_MONITORS) {
+            for (Monitor monitor : monitors) {
+                if (monitor.count != 0) {
+                    logInfo(monitor.toString());
+                }
+            }
+            // As getAATileGenerator percents:
+            final long total = mon_pre_getAATileGenerator.sum;
+            if (total != 0L) {
                 for (Monitor monitor : monitors) {
-                    if (monitor.count != 0) {
-                        logInfo(monitor.toString());
-                    }
+                    logInfo(monitor.name + " : "
+                            + ((100d * monitor.sum) / total) + " %");
                 }
-                // As getAATileGenerator percents:
-                final long total = mon_pre_getAATileGenerator.sum;
-                if (total != 0L) {
-                    for (Monitor monitor : monitors) {
-                        logInfo(monitor.name + " : "
-                                + ((100d * monitor.sum) / total) + " %");
-                    }
+            }
+            if (DO_FLUSH_MONITORS) {
+                for (Monitor m : monitors) {
+                    m.reset();
                 }
-                if (DO_FLUSH_MONITORS) {
-                    for (Monitor m : monitors) {
-                        m.reset();
+            }
+        }
+
+        if (DO_STATS) {
+            for (StatLong stat : statistics) {
+                if (stat.count != 0) {
+                    logInfo(stat.toString());
+                    if (DO_FLUSH_STATS) {
+                        stat.reset();
                     }
                 }
             }
 
-            if (DO_STATS) {
-                for (StatLong stat : statistics) {
-                    if (stat.count != 0) {
-                        logInfo(stat.toString());
+            logInfo("OffHeap footprint: initial: " + totalOffHeapInitial
+                + " bytes - max: " + totalOffHeapMax + " bytes");
+            if (DO_FLUSH_STATS) {
+                totalOffHeapMax = 0L;
+            }
+
+            logInfo("Array caches for RendererContext: " + name);
+
+            long totalInitialBytes = totalOffHeapInitial;
+            long totalCacheBytes   = 0L;
+
+            if (cacheStats != null) {
+                for (CacheStats stat : cacheStats) {
+                    totalCacheBytes   += stat.dumpStats();
+                    totalInitialBytes += stat.getTotalInitialBytes();
+                    if (DO_FLUSH_STATS) {
                         stat.reset();
                     }
                 }
-                // IntArrayCaches stats:
-                final RendererContext.ArrayCachesHolder holder
-                    = rdrCtx.getArrayCachesHolder();
+            }
+            logInfo("Heap footprint: initial: " + totalInitialBytes
+                    + " bytes - cache: " + totalCacheBytes + " bytes");
+        }
+    }
 
-                logInfo("Array caches for thread: " + rdrCtx.name);
+    static final class RendererStatsHolder {
 
-                for (IntArrayCache cache : holder.intArrayCaches) {
-                    cache.dumpStats();
+        // singleton
+        private static volatile RendererStatsHolder SINGLETON = null;
+
+        static synchronized RendererStatsHolder getInstance() {
+            if (SINGLETON == null) {
+                SINGLETON = new RendererStatsHolder();
+            }
+            return SINGLETON;
+        }
+
+        static void dumpStats() {
+            if (SINGLETON != null) {
+                SINGLETON.dump();
+            }
+        }
+
+        /* RendererStats collection as hard references
+           (only used for debugging purposes) */
+        private final ConcurrentLinkedQueue<RendererStats> allStats
+            = new ConcurrentLinkedQueue<RendererStats>();
+
+        private RendererStatsHolder() {
+            AccessController.doPrivileged(new PrivilegedAction<Void>() {
+
+                @Override
+                public Void run() {
+                    final Thread hook = new Thread(
+                        MarlinUtils.getRootThreadGroup(),
+                        new Runnable() {
+                            @Override
+                            public void run() {
+                                dump();
+                            }
+                        },
+                        "MarlinStatsHook"
+                    );
+                    hook.setContextClassLoader(null);
+                    Runtime.getRuntime().addShutdownHook(hook);
+
+                    if (USE_DUMP_THREAD) {
+                        final Timer statTimer = new Timer("RendererStats");
+                        statTimer.scheduleAtFixedRate(new TimerTask() {
+                            @Override
+                            public void run() {
+                                dump();
+                            }
+                        }, DUMP_INTERVAL, DUMP_INTERVAL);
+                    }
+                    return null;
                 }
+            });
 
-                logInfo("Dirty Array caches for thread: " + rdrCtx.name);
+            // Mimics Java2D Disposer:
+            AccessController.doPrivileged(new PrivilegedAction<Void>() {
 
-                for (IntArrayCache cache : holder.dirtyIntArrayCaches) {
-                    cache.dumpStats();
+                @Override
+                public Void run() {
+                    /*
+                     * The thread must be a member of a thread group
+                     * which will not get GCed before VM exit.
+                     * Make its parent the top-level thread group.
+                     */
+                    final ThreadGroup rootTG
+//                        = ThreadGroupUtils.getRootThreadGroup();
+                        = MarlinUtils.getRootThreadGroup();
+                    final Thread t = new Thread(rootTG, new RendererStatsDisposer(),
+                        "MarlinRenderer Disposer");
+                    t.setContextClassLoader(null);
+                    t.setDaemon(true);
+                    t.setPriority(Thread.MAX_PRIORITY - 2);
+                    t.start();
+                    return null;
                 }
-                for (FloatArrayCache cache : holder.dirtyFloatArrayCaches) {
-                    cache.dumpStats();
-                }
-                for (ByteArrayCache cache : holder.dirtyByteArrayCaches) {
-                    cache.dumpStats();
+            });
+        }
+
+        void add(final Object parent, final RendererStats stats) {
+            allStats.add(stats);
+
+            // Create the phantom reference to ensure removing dead entries:
+            REF_LIST.add(new RendererStatsReference(parent, stats));
+        }
+
+        void remove(final RendererStats stats) {
+            stats.dump(); // dump anyway
+            allStats.remove(stats);
+        }
+
+        void dump() {
+            for (RendererStats stats : allStats) {
+                stats.dump();
+            }
+        }
+
+
+        // Custom disposer (replaced by jdk9 Cleaner)
+
+        // Parent reference queue
+        private static final ReferenceQueue<Object> REF_QUEUE
+            = new ReferenceQueue<Object>();
+        // reference list
+        private static final Vector<RendererStatsReference> REF_LIST
+            = new Vector<RendererStatsReference>(32);
+
+        static final class RendererStatsReference extends PhantomReference<Object> {
+
+            private final RendererStats stats;
+
+            RendererStatsReference(final Object parent, final RendererStats stats) {
+                super(parent, REF_QUEUE);
+                this.stats = stats;
+            }
+
+            void dispose() {
+                // remove stats from allRdrStats
+                RendererStatsHolder.getInstance().remove(this.stats);
+            }
+        }
+
+        static final class RendererStatsDisposer implements Runnable {
+            @Override
+            public void run() {
+                final Thread currentThread = Thread.currentThread();
+                RendererStatsReference ref;
+
+                // check interrupted:
+                for (; !currentThread.isInterrupted();) {
+                    try {
+                        ref = (RendererStatsReference)REF_QUEUE.remove();
+                        ref.dispose();
+
+                        REF_LIST.remove(ref);
+
+                    } catch (InterruptedException ie) {
+                        MarlinUtils.logException("RendererStatsDisposer interrupted:",
+                                                 ie);
+                    }
                 }
             }
         }
diff --git a/src/share/classes/sun/java2d/marlin/Stroker.java b/src/share/classes/sun/java2d/marlin/Stroker.java
index f25993b..2d67ef1 100644
--- a/src/share/classes/sun/java2d/marlin/Stroker.java
+++ b/src/share/classes/sun/java2d/marlin/Stroker.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, 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
@@ -26,12 +26,11 @@
 package sun.java2d.marlin;
 
 import java.util.Arrays;
-import static java.lang.Math.ulp;
-import static java.lang.Math.sqrt;
 
 import sun.awt.geom.PathConsumer2D;
-import sun.java2d.marlin.Curve.BreakPtrIterator;
-
+import sun.java2d.marlin.Helpers.PolyStack;
+import sun.java2d.marlin.TransformingPathConsumer2D.CurveBasicMonotonizer;
+import sun.java2d.marlin.TransformingPathConsumer2D.CurveClipSplitter;
 
 // TODO: some of the arithmetic here is too verbose and prone to hard to
 // debug typos. We should consider making a small Point/Vector class that
@@ -42,44 +41,15 @@
     private static final int DRAWING_OP_TO = 1; // ie. curve, line, or quad
     private static final int CLOSE = 2;
 
-    /**
-     * Constant value for join style.
-     */
-    public static final int JOIN_MITER = 0;
+    // round join threshold = 1 subpixel
+    private static final float ERR_JOIN = (1.0f / MIN_SUBPIXELS);
+    private static final float ROUND_JOIN_THRESHOLD = ERR_JOIN * ERR_JOIN;
 
-    /**
-     * Constant value for join style.
-     */
-    public static final int JOIN_ROUND = 1;
+    // kappa = (4/3) * (SQRT(2) - 1)
+    private static final float C = (float)(4.0d * (Math.sqrt(2.0d) - 1.0d) / 3.0d);
 
-    /**
-     * Constant value for join style.
-     */
-    public static final int JOIN_BEVEL = 2;
-
-    /**
-     * Constant value for end cap style.
-     */
-    public static final int CAP_BUTT = 0;
-
-    /**
-     * Constant value for end cap style.
-     */
-    public static final int CAP_ROUND = 1;
-
-    /**
-     * Constant value for end cap style.
-     */
-    public static final int CAP_SQUARE = 2;
-
-    // pisces used to use fixed point arithmetic with 16 decimal digits. I
-    // didn't want to change the values of the constant below when I converted
-    // it to floating point, so that's why the divisions by 2^16 are there.
-    private static final float ROUND_JOIN_THRESHOLD = 1000/65536f;
-
-    private static final float C = 0.5522847498307933f;
-
-    private static final int MAX_N_CURVES = 11;
+    // SQRT(2)
+    private static final float SQRT_2 = (float)Math.sqrt(2.0d);
 
     private PathConsumer2D out;
 
@@ -111,13 +81,8 @@
 
     private final PolyStack reverse;
 
-    // This is where the curve to be processed is put. We give it
-    // enough room to store 2 curves: one for the current subdivision, the
-    // other for the rest of the curve.
-    private final float[] middle = new float[2 * 8];
     private final float[] lp = new float[8];
     private final float[] rp = new float[8];
-    private final float[] subdivTs = new float[MAX_N_CURVES - 1];
 
     // per-thread renderer context
     final RendererContext rdrCtx;
@@ -125,6 +90,25 @@
     // dirty curve
     final Curve curve;
 
+    // Bounds of the drawing region, at pixel precision.
+    private float[] clipRect;
+
+    // the outcode of the current point
+    private int cOutCode = 0;
+
+    // the outcode of the starting point
+    private int sOutCode = 0;
+
+    // flag indicating if the path is opened (clipped)
+    private boolean opened = false;
+    // flag indicating if the starting point's cap is done
+    private boolean capStart = false;
+    // flag indicating to monotonize curves
+    private boolean monotonize;
+
+    private boolean subdivide = DO_CLIP_SUBDIVIDER;
+    private final CurveClipSplitter curveSplitter;
+
     /**
      * Constructs a <code>Stroker</code>.
      * @param rdrCtx per-thread renderer context
@@ -132,8 +116,17 @@
     Stroker(final RendererContext rdrCtx) {
         this.rdrCtx = rdrCtx;
 
-        this.reverse = new PolyStack(rdrCtx);
+        this.reverse = (rdrCtx.stats != null) ?
+            new PolyStack(rdrCtx,
+                    rdrCtx.stats.stat_str_polystack_types,
+                    rdrCtx.stats.stat_str_polystack_curves,
+                    rdrCtx.stats.hist_str_polystack_curves,
+                    rdrCtx.stats.stat_array_str_polystack_curves,
+                    rdrCtx.stats.stat_array_str_polystack_types)
+            : new PolyStack(rdrCtx);
+
         this.curve = rdrCtx.curve;
+        this.curveSplitter = rdrCtx.curveClipSplitter;
     }
 
     /**
@@ -148,31 +141,84 @@
      * <code>JOIN_MITER</code>, <code>JOIN_ROUND</code> or
      * <code>JOIN_BEVEL</code>.
      * @param miterLimit the desired miter limit
+     * @param scale scaling factor applied to clip boundaries
+     * @param subdivideCurves true to indicate to subdivide curves, false if dasher does
      * @return this instance
      */
-    Stroker init(PathConsumer2D pc2d,
-              float lineWidth,
-              int capStyle,
-              int joinStyle,
-              float miterLimit)
+    Stroker init(final PathConsumer2D pc2d,
+                 final float lineWidth,
+                 final int capStyle,
+                 final int joinStyle,
+                 final float miterLimit,
+                 final float scale,
+                 final boolean subdivideCurves)
     {
         this.out = pc2d;
 
-        this.lineWidth2 = lineWidth / 2f;
-        this.invHalfLineWidth2Sq = 1f / (2f * lineWidth2 * lineWidth2);
+        this.lineWidth2 = lineWidth / 2.0f;
+        this.invHalfLineWidth2Sq = 1.0f / (2.0f * lineWidth2 * lineWidth2);
+        this.monotonize = subdivideCurves;
+
         this.capStyle = capStyle;
         this.joinStyle = joinStyle;
 
-        float limit = miterLimit * lineWidth2;
+        final float limit = miterLimit * lineWidth2;
         this.miterLimitSq = limit * limit;
 
         this.prev = CLOSE;
 
         rdrCtx.stroking = 1;
 
+        if (rdrCtx.doClip) {
+            // Adjust the clipping rectangle with the stroker margin (miter limit, width)
+            float rdrOffX = 0.0f, rdrOffY = 0.0f;
+            float margin = lineWidth2;
+
+            if (capStyle == CAP_SQUARE) {
+                margin *= SQRT_2;
+            }
+            if ((joinStyle == JOIN_MITER) && (margin < limit)) {
+                margin = limit;
+            }
+            if (scale != 1.0f) {
+                margin *= scale;
+                rdrOffX = scale * Renderer.RDR_OFFSET_X;
+                rdrOffY = scale * Renderer.RDR_OFFSET_Y;
+            }
+            // add a small rounding error:
+            margin += 1e-3f;
+
+            // bounds as half-open intervals: minX <= x < maxX and minY <= y < maxY
+            // adjust clip rectangle (ymin, ymax, xmin, xmax):
+            final float[] _clipRect = rdrCtx.clipRect;
+            _clipRect[0] -= margin - rdrOffY;
+            _clipRect[1] += margin + rdrOffY;
+            _clipRect[2] -= margin - rdrOffX;
+            _clipRect[3] += margin + rdrOffX;
+            this.clipRect = _clipRect;
+
+            // initialize curve splitter here for stroker & dasher:
+            if (DO_CLIP_SUBDIVIDER) {
+                subdivide = subdivideCurves;
+                // adjust padded clip rectangle:
+                curveSplitter.init();
+            } else {
+                subdivide = false;
+            }
+        } else {
+            this.clipRect = null;
+            this.cOutCode = 0;
+            this.sOutCode = 0;
+        }
         return this; // fluent API
     }
 
+    void disableClipping() {
+        this.clipRect = null;
+        this.cOutCode = 0;
+        this.sOutCode = 0;
+    }
+
     /**
      * Disposes this stroker:
      * clean up before reusing this instance
@@ -180,16 +226,17 @@
     void dispose() {
         reverse.dispose();
 
+        opened   = false;
+        capStart = false;
+
         if (DO_CLEAN_DIRTY) {
             // Force zero-fill dirty arrays:
-            Arrays.fill(offset0, 0f);
-            Arrays.fill(offset1, 0f);
-            Arrays.fill(offset2, 0f);
-            Arrays.fill(miter, 0f);
-            Arrays.fill(middle, 0f);
-            Arrays.fill(lp, 0f);
-            Arrays.fill(rp, 0f);
-            Arrays.fill(subdivTs, 0f);
+            Arrays.fill(offset0, 0.0f);
+            Arrays.fill(offset1, 0.0f);
+            Arrays.fill(offset2, 0.0f);
+            Arrays.fill(miter, 0.0f);
+            Arrays.fill(lp, 0.0f);
+            Arrays.fill(rp, 0.0f);
         }
     }
 
@@ -197,11 +244,11 @@
                                       final float w, final float[] m)
     {
         float len = lx*lx + ly*ly;
-        if (len == 0f) {
-            m[0] = 0f;
-            m[1] = 0f;
+        if (len == 0.0f) {
+            m[0] = 0.0f;
+            m[1] = 0.0f;
         } else {
-            len = (float) sqrt(len);
+            len = (float) Math.sqrt(len);
             m[0] =  (ly * w) / len;
             m[1] = -(lx * w) / len;
         }
@@ -221,19 +268,20 @@
         return dx1 * dy2 <= dy1 * dx2;
     }
 
-    private void drawRoundJoin(float x, float y,
-                               float omx, float omy, float mx, float my,
-                               boolean rev,
-                               float threshold)
+    private void mayDrawRoundJoin(float cx, float cy,
+                                  float omx, float omy,
+                                  float mx, float my,
+                                  boolean rev)
     {
-        if ((omx == 0f && omy == 0f) || (mx == 0f && my == 0f)) {
+        if ((omx == 0.0f && omy == 0.0f) || (mx == 0.0f && my == 0.0f)) {
             return;
         }
 
-        float domx = omx - mx;
-        float domy = omy - my;
-        float len = domx*domx + domy*domy;
-        if (len < threshold) {
+        final float domx = omx - mx;
+        final float domy = omy - my;
+        final float lenSq = domx*domx + domy*domy;
+
+        if (lenSq < ROUND_JOIN_THRESHOLD) {
             return;
         }
 
@@ -243,7 +291,7 @@
             mx  = -mx;
             my  = -my;
         }
-        drawRoundJoin(x, y, omx, omy, mx, my, rev);
+        drawRoundJoin(cx, cy, omx, omy, mx, my, rev);
     }
 
     private void drawRoundJoin(float cx, float cy,
@@ -258,7 +306,7 @@
         // If it is >=0, we know that abs(ext) is <= 90 degrees, so we only
         // need 1 curve to approximate the circle section that joins omx,omy
         // and mx,my.
-        final int numCurves = (cosext >= 0f) ? 1 : 2;
+        final int numCurves = (cosext >= 0.0f) ? 1 : 2;
 
         switch (numCurves) {
         case 1:
@@ -280,7 +328,7 @@
             // this normal's length is at least 0.5 and at most sqrt(2)/2 (because
             // we know the angle of the arc is > 90 degrees).
             float nx = my - omy, ny = omx - mx;
-            float nlen = (float) sqrt(nx*nx + ny*ny);
+            float nlen = (float) Math.sqrt(nx*nx + ny*ny);
             float scale = lineWidth2/nlen;
             float mmx = nx * scale, mmy = ny * scale;
 
@@ -318,8 +366,8 @@
         // define the bezier curve we're computing.
         // It is computed using the constraints that P1-P0 and P3-P2 are parallel
         // to the arc tangents at the endpoints, and that |P1-P0|=|P3-P2|.
-        float cv = (float) ((4.0 / 3.0) * sqrt(0.5 - cosext2) /
-                            (1.0 + sqrt(cosext2 + 0.5)));
+        float cv = (float) ((4.0d / 3.0d) * Math.sqrt(0.5d - cosext2) /
+                            (1.0d + Math.sqrt(cosext2 + 0.5d)));
         // if clockwise, we need to negate cv.
         if (rev) { // rev is equivalent to isCW(omx, omy, mx, my)
             cv = -cv;
@@ -348,36 +396,79 @@
                     cx - mx,       cy - my);
     }
 
-    // Put the intersection point of the lines (x0, y0) -> (x1, y1)
-    // and (x0p, y0p) -> (x1p, y1p) in m[off] and m[off+1].
-    // If the lines are parallel, it will put a non finite number in m.
-    private static void computeIntersection(final float x0, final float y0,
-                                            final float x1, final float y1,
-                                            final float x0p, final float y0p,
-                                            final float x1p, final float y1p,
-                                            final float[] m, int off)
+    // Return the intersection point of the lines (x0, y0) -> (x1, y1)
+    // and (x0p, y0p) -> (x1p, y1p) in m[off] and m[off+1]
+    private static void computeMiter(final float x0, final float y0,
+                                     final float x1, final float y1,
+                                     final float x0p, final float y0p,
+                                     final float x1p, final float y1p,
+                                     final float[] m)
     {
         float x10 = x1 - x0;
         float y10 = y1 - y0;
         float x10p = x1p - x0p;
         float y10p = y1p - y0p;
 
+        // if this is 0, the lines are parallel. If they go in the
+        // same direction, there is no intersection so m[off] and
+        // m[off+1] will contain infinity, so no miter will be drawn.
+        // If they go in the same direction that means that the start of the
+        // current segment and the end of the previous segment have the same
+        // tangent, in which case this method won't even be involved in
+        // miter drawing because it won't be called by drawMiter (because
+        // (mx == omx && my == omy) will be true, and drawMiter will return
+        // immediately).
         float den = x10*y10p - x10p*y10;
         float t = x10p*(y0-y0p) - y10p*(x0-x0p);
         t /= den;
-        m[off++] = x0 + t*x10;
-        m[off]   = y0 + t*y10;
+        m[0] = x0 + t*x10;
+        m[1] = y0 + t*y10;
+    }
+
+    // Return the intersection point of the lines (x0, y0) -> (x1, y1)
+    // and (x0p, y0p) -> (x1p, y1p) in m[off] and m[off+1]
+    private static void safeComputeMiter(final float x0, final float y0,
+                                         final float x1, final float y1,
+                                         final float x0p, final float y0p,
+                                         final float x1p, final float y1p,
+                                         final float[] m)
+    {
+        float x10 = x1 - x0;
+        float y10 = y1 - y0;
+        float x10p = x1p - x0p;
+        float y10p = y1p - y0p;
+
+        // if this is 0, the lines are parallel. If they go in the
+        // same direction, there is no intersection so m[off] and
+        // m[off+1] will contain infinity, so no miter will be drawn.
+        // If they go in the same direction that means that the start of the
+        // current segment and the end of the previous segment have the same
+        // tangent, in which case this method won't even be involved in
+        // miter drawing because it won't be called by drawMiter (because
+        // (mx == omx && my == omy) will be true, and drawMiter will return
+        // immediately).
+        float den = x10*y10p - x10p*y10;
+        if (den == 0.0f) {
+            m[2] = (x0 + x0p) / 2.0f;
+            m[3] = (y0 + y0p) / 2.0f;
+        } else {
+            float t = x10p*(y0-y0p) - y10p*(x0-x0p);
+            t /= den;
+            m[2] = x0 + t*x10;
+            m[3] = y0 + t*y10;
+        }
     }
 
     private void drawMiter(final float pdx, final float pdy,
                            final float x0, final float y0,
                            final float dx, final float dy,
-                           float omx, float omy, float mx, float my,
+                           float omx, float omy,
+                           float mx, float my,
                            boolean rev)
     {
         if ((mx == omx && my == omy) ||
-            (pdx == 0f && pdy == 0f) ||
-            (dx == 0f && dy == 0f))
+            (pdx == 0.0f && pdy == 0.0f) ||
+            (dx == 0.0f && dy == 0.0f))
         {
             return;
         }
@@ -389,9 +480,8 @@
             my  = -my;
         }
 
-        computeIntersection((x0 - pdx) + omx, (y0 - pdy) + omy, x0 + omx, y0 + omy,
-                            (dx + x0) + mx, (dy + y0) + my, x0 + mx, y0 + my,
-                            miter, 0);
+        computeMiter((x0 - pdx) + omx, (y0 - pdy) + omy, x0 + omx, y0 + omy,
+                     (dx + x0) + mx, (dy + y0) + my, x0 + mx, y0 + my, miter);
 
         final float miterX = miter[0];
         final float miterY = miter[1];
@@ -408,29 +498,96 @@
     }
 
     @Override
-    public void moveTo(float x0, float y0) {
-        if (prev == DRAWING_OP_TO) {
-            finish();
+    public void moveTo(final float x0, final float y0) {
+        _moveTo(x0, y0, cOutCode);
+        // update starting point:
+        this.sx0 = x0;
+        this.sy0 = y0;
+        this.sdx = 1.0f;
+        this.sdy = 0.0f;
+        this.opened   = false;
+        this.capStart = false;
+
+        if (clipRect != null) {
+            final int outcode = Helpers.outcode(x0, y0, clipRect);
+            this.cOutCode = outcode;
+            this.sOutCode = outcode;
         }
-        this.sx0 = this.cx0 = x0;
-        this.sy0 = this.cy0 = y0;
-        this.cdx = this.sdx = 1f;
-        this.cdy = this.sdy = 0f;
-        this.prev = MOVE_TO;
+    }
+
+    private void _moveTo(final float x0, final float y0,
+                        final int outcode)
+    {
+        if (prev == MOVE_TO) {
+            this.cx0 = x0;
+            this.cy0 = y0;
+        } else {
+            if (prev == DRAWING_OP_TO) {
+                finish(outcode);
+            }
+            this.prev = MOVE_TO;
+            this.cx0 = x0;
+            this.cy0 = y0;
+            this.cdx = 1.0f;
+            this.cdy = 0.0f;
+        }
     }
 
     @Override
-    public void lineTo(float x1, float y1) {
+    public void lineTo(final float x1, final float y1) {
+        lineTo(x1, y1, false);
+    }
+
+    private void lineTo(final float x1, final float y1,
+                        final boolean force)
+    {
+        final int outcode0 = this.cOutCode;
+
+        if (!force && clipRect != null) {
+            final int outcode1 = Helpers.outcode(x1, y1, clipRect);
+
+            // Should clip
+            final int orCode = (outcode0 | outcode1);
+            if (orCode != 0) {
+                final int sideCode = outcode0 & outcode1;
+
+                // basic rejection criteria:
+                if (sideCode == 0) {
+                    // ovelap clip:
+                    if (subdivide) {
+                        // avoid reentrance
+                        subdivide = false;
+                        // subdivide curve => callback with subdivided parts:
+                        boolean ret = curveSplitter.splitLine(cx0, cy0, x1, y1,
+                                                              orCode, this);
+                        // reentrance is done:
+                        subdivide = true;
+                        if (ret) {
+                            return;
+                        }
+                    }
+                    // already subdivided so render it
+                } else {
+                    this.cOutCode = outcode1;
+                    _moveTo(x1, y1, outcode0);
+                    opened = true;
+                    return;
+                }
+            }
+
+            this.cOutCode = outcode1;
+        }
+
         float dx = x1 - cx0;
         float dy = y1 - cy0;
-        if (dx == 0f && dy == 0f) {
-            dx = 1f;
+        if (dx == 0.0f && dy == 0.0f) {
+            dx = 1.0f;
         }
         computeOffset(dx, dy, lineWidth2, offset0);
         final float mx = offset0[0];
         final float my = offset0[1];
 
-        drawJoin(cdx, cdy, cx0, cy0, dx, dy, cmx, cmy, mx, my);
+        drawJoin(cdx, cdy, cx0, cy0, dx, dy, cmx, cmy, mx, my, outcode0);
 
         emitLineTo(cx0 + mx, cy0 + my);
         emitLineTo( x1 + mx,  y1 + my);
@@ -438,43 +595,65 @@
         emitLineToRev(cx0 - mx, cy0 - my);
         emitLineToRev( x1 - mx,  y1 - my);
 
-        this.cmx = mx;
-        this.cmy = my;
-        this.cdx = dx;
-        this.cdy = dy;
+        this.prev = DRAWING_OP_TO;
         this.cx0 = x1;
         this.cy0 = y1;
-        this.prev = DRAWING_OP_TO;
+        this.cdx = dx;
+        this.cdy = dy;
+        this.cmx = mx;
+        this.cmy = my;
     }
 
     @Override
     public void closePath() {
-        if (prev != DRAWING_OP_TO) {
+        // distinguish empty path at all vs opened path ?
+        if (prev != DRAWING_OP_TO && !opened) {
             if (prev == CLOSE) {
                 return;
             }
             emitMoveTo(cx0, cy0 - lineWidth2);
-            this.cmx = this.smx = 0f;
-            this.cmy = this.smy = -lineWidth2;
-            this.cdx = this.sdx = 1f;
-            this.cdy = this.sdy = 0f;
-            finish();
+
+            this.sdx = 1.0f;
+            this.sdy = 0.0f;
+            this.cdx = 1.0f;
+            this.cdy = 0.0f;
+
+            this.smx = 0.0f;
+            this.smy = -lineWidth2;
+            this.cmx = 0.0f;
+            this.cmy = -lineWidth2;
+
+            finish(cOutCode);
             return;
         }
 
-        if (cx0 != sx0 || cy0 != sy0) {
-            lineTo(sx0, sy0);
+        // basic acceptance criteria
+        if ((sOutCode & cOutCode) == 0) {
+            if (cx0 != sx0 || cy0 != sy0) {
+                lineTo(sx0, sy0, true);
+            }
+
+            drawJoin(cdx, cdy, cx0, cy0, sdx, sdy, cmx, cmy, smx, smy, sOutCode);
+
+            emitLineTo(sx0 + smx, sy0 + smy);
+
+            if (opened) {
+                emitLineTo(sx0 - smx, sy0 - smy);
+            } else {
+                emitMoveTo(sx0 - smx, sy0 - smy);
+            }
         }
-
-        drawJoin(cdx, cdy, cx0, cy0, sdx, sdy, cmx, cmy, smx, smy);
-
-        emitLineTo(sx0 + smx, sy0 + smy);
-
-        emitMoveTo(sx0 - smx, sy0 - smy);
+        // Ignore caps like finish(false)
         emitReverse();
 
         this.prev = CLOSE;
-        emitClose();
+
+        if (opened) {
+            // do not emit close
+            opened = false;
+        } else {
+            emitClose();
+        }
     }
 
     private void emitReverse() {
@@ -484,7 +663,7 @@
     @Override
     public void pathDone() {
         if (prev == DRAWING_OP_TO) {
-            finish();
+            finish(cOutCode);
         }
 
         out.pathDone();
@@ -497,23 +676,39 @@
         dispose();
     }
 
-    private void finish() {
-        if (capStyle == CAP_ROUND) {
-            drawRoundCap(cx0, cy0, cmx, cmy);
-        } else if (capStyle == CAP_SQUARE) {
-            emitLineTo(cx0 - cmy + cmx, cy0 + cmx + cmy);
-            emitLineTo(cx0 - cmy - cmx, cy0 + cmx - cmy);
+    private void finish(final int outcode) {
+        // Problem: impossible to guess if the path will be closed in advance
+        //          i.e. if caps must be drawn or not ?
+        // Solution: use the ClosedPathDetector before Stroker to determine
+        // if the path is a closed path or not
+        if (!rdrCtx.closedPath) {
+            if (outcode == 0) {
+                // current point = end's cap:
+                if (capStyle == CAP_ROUND) {
+                    drawRoundCap(cx0, cy0, cmx, cmy);
+                } else if (capStyle == CAP_SQUARE) {
+                    emitLineTo(cx0 - cmy + cmx, cy0 + cmx + cmy);
+                    emitLineTo(cx0 - cmy - cmx, cy0 + cmx - cmy);
+                }
+            }
+            emitReverse();
+
+            if (!capStart) {
+                capStart = true;
+
+                if (sOutCode == 0) {
+                    // starting point = initial cap:
+                    if (capStyle == CAP_ROUND) {
+                        drawRoundCap(sx0, sy0, -smx, -smy);
+                    } else if (capStyle == CAP_SQUARE) {
+                        emitLineTo(sx0 + smy - smx, sy0 - smx - smy);
+                        emitLineTo(sx0 + smy + smx, sy0 - smx + smy);
+                    }
+                }
+            }
+        } else {
+            emitReverse();
         }
-
-        emitReverse();
-
-        if (capStyle == CAP_ROUND) {
-            drawRoundCap(sx0, sy0, -smx, -smy);
-        } else if (capStyle == CAP_SQUARE) {
-            emitLineTo(sx0 + smy - smx, sy0 - smx - smy);
-            emitLineTo(sx0 + smy + smx, sy0 - smx + smy);
-        }
-
         emitClose();
     }
 
@@ -585,23 +780,25 @@
                           float x0, float y0,
                           float dx, float dy,
                           float omx, float omy,
-                          float mx, float my)
+                          float mx, float my,
+                          final int outcode)
     {
         if (prev != DRAWING_OP_TO) {
             emitMoveTo(x0 + mx, y0 + my);
-            this.sdx = dx;
-            this.sdy = dy;
-            this.smx = mx;
-            this.smy = my;
+            if (!opened) {
+                this.sdx = dx;
+                this.sdy = dy;
+                this.smx = mx;
+                this.smy = my;
+            }
         } else {
-            boolean cw = isCW(pdx, pdy, dx, dy);
-            if (joinStyle == JOIN_MITER) {
-                drawMiter(pdx, pdy, x0, y0, dx, dy, omx, omy, mx, my, cw);
-            } else if (joinStyle == JOIN_ROUND) {
-                drawRoundJoin(x0, y0,
-                              omx, omy,
-                              mx, my, cw,
-                              ROUND_JOIN_THRESHOLD);
+            final boolean cw = isCW(pdx, pdy, dx, dy);
+            if (outcode == 0) {
+                if (joinStyle == JOIN_MITER) {
+                    drawMiter(pdx, pdy, x0, y0, dx, dy, omx, omy, mx, my, cw);
+                } else if (joinStyle == JOIN_ROUND) {
+                    mayDrawRoundJoin(x0, y0, omx, omy, mx, my, cw);
+                }
             }
             emitLineTo(x0, y0, !cw);
         }
@@ -610,18 +807,19 @@
 
     private static boolean within(final float x1, final float y1,
                                   final float x2, final float y2,
-                                  final float ERR)
+                                  final float err)
     {
-        assert ERR > 0 : "";
+        assert err > 0 : "";
         // compare taxicab distance. ERR will always be small, so using
         // true distance won't give much benefit
-        return (Helpers.within(x1, x2, ERR) &&  // we want to avoid calling Math.abs
-                Helpers.within(y1, y2, ERR)); // this is just as good.
+        return (Helpers.within(x1, x2, err) && // we want to avoid calling Math.abs
+                Helpers.within(y1, y2, err));  // this is just as good.
     }
 
-    private void getLineOffsets(float x1, float y1,
-                                float x2, float y2,
-                                float[] left, float[] right) {
+    private void getLineOffsets(final float x1, final float y1,
+                                final float x2, final float y2,
+                                final float[] left, final float[] right)
+    {
         computeOffset(x2 - x1, y2 - y1, lineWidth2, offset0);
         final float mx = offset0[0];
         final float my = offset0[1];
@@ -629,23 +827,25 @@
         left[1] = y1 + my;
         left[2] = x2 + mx;
         left[3] = y2 + my;
+
         right[0] = x1 - mx;
         right[1] = y1 - my;
         right[2] = x2 - mx;
         right[3] = y2 - my;
     }
 
-    private int computeOffsetCubic(float[] pts, final int off,
-                                   float[] leftOff, float[] rightOff)
+    private int computeOffsetCubic(final float[] pts, final int off,
+                                   final float[] leftOff,
+                                   final float[] rightOff)
     {
         // if p1=p2 or p3=p4 it means that the derivative at the endpoint
         // vanishes, which creates problems with computeOffset. Usually
-        // this happens when this stroker object is trying to winden
+        // this happens when this stroker object is trying to widen
         // a curve with a cusp. What happens is that curveTo splits
         // the input curve at the cusp, and passes it to this function.
         // because of inaccuracies in the splitting, we consider points
         // equal if they're very close to each other.
-        final float x1 = pts[off + 0], y1 = pts[off + 1];
+        final float x1 = pts[off    ], y1 = pts[off + 1];
         final float x2 = pts[off + 2], y2 = pts[off + 3];
         final float x3 = pts[off + 4], y3 = pts[off + 5];
         final float x4 = pts[off + 6], y4 = pts[off + 7];
@@ -657,8 +857,9 @@
 
         // if p1 == p2 && p3 == p4: draw line from p1->p4, unless p1 == p4,
         // in which case ignore if p1 == p2
-        final boolean p1eqp2 = within(x1,y1,x2,y2, 6f * ulp(y2));
-        final boolean p3eqp4 = within(x3,y3,x4,y4, 6f * ulp(y4));
+        final boolean p1eqp2 = within(x1, y1, x2, y2, 6.0f * Math.ulp(y2));
+        final boolean p3eqp4 = within(x3, y3, x4, y4, 6.0f * Math.ulp(y4));
+
         if (p1eqp2 && p3eqp4) {
             getLineOffsets(x1, y1, x4, y4, leftOff, rightOff);
             return 4;
@@ -674,7 +875,8 @@
         float dotsq = (dx1 * dx4 + dy1 * dy4);
         dotsq *= dotsq;
         float l1sq = dx1 * dx1 + dy1 * dy1, l4sq = dx4 * dx4 + dy4 * dy4;
-        if (Helpers.within(dotsq, l1sq * l4sq, 4f * ulp(dotsq))) {
+
+        if (Helpers.within(dotsq, l1sq * l4sq, 4.0f * Math.ulp(dotsq))) {
             getLineOffsets(x1, y1, x4, y4, leftOff, rightOff);
             return 4;
         }
@@ -726,8 +928,8 @@
 //      getting the inverse of the matrix above. Then we use [c1,c2] to compute
 //      p2p and p3p.
 
-        float x = (x1 + 3f * (x2 + x3) + x4) / 8f;
-        float y = (y1 + 3f * (y2 + y3) + y4) / 8f;
+        float x = (x1 + 3.0f * (x2 + x3) + x4) / 8.0f;
+        float y = (y1 + 3.0f * (y2 + y3) + y4) / 8.0f;
         // (dxm,dym) is some tangent of B at t=0.5. This means it's equal to
         // c*B'(0.5) for some constant c.
         float dxm = x3 + x4 - x1 - x2, dym = y3 + y4 - y1 - y2;
@@ -745,10 +947,10 @@
         float x4p = x4 + offset2[0]; // end
         float y4p = y4 + offset2[1]; // point
 
-        float invdet43 = 4f / (3f * (dx1 * dy4 - dy1 * dx4));
+        float invdet43 = 4.0f / (3.0f * (dx1 * dy4 - dy1 * dx4));
 
-        float two_pi_m_p1_m_p4x = 2f * xi - x1p - x4p;
-        float two_pi_m_p1_m_p4y = 2f * yi - y1p - y4p;
+        float two_pi_m_p1_m_p4x = 2.0f * xi - x1p - x4p;
+        float two_pi_m_p1_m_p4y = 2.0f * yi - y1p - y4p;
         float c1 = invdet43 * (dy4 * two_pi_m_p1_m_p4x - dx4 * two_pi_m_p1_m_p4y);
         float c2 = invdet43 * (dx1 * two_pi_m_p1_m_p4y - dy1 * two_pi_m_p1_m_p4x);
 
@@ -764,11 +966,11 @@
         leftOff[6] = x4p; leftOff[7] = y4p;
 
         x1p = x1 - offset0[0]; y1p = y1 - offset0[1];
-        xi = xi - 2f * offset1[0]; yi = yi - 2f * offset1[1];
+        xi = xi - 2.0f * offset1[0]; yi = yi - 2.0f * offset1[1];
         x4p = x4 - offset2[0]; y4p = y4 - offset2[1];
 
-        two_pi_m_p1_m_p4x = 2f * xi - x1p - x4p;
-        two_pi_m_p1_m_p4y = 2f * yi - y1p - y4p;
+        two_pi_m_p1_m_p4x = 2.0f * xi - x1p - x4p;
+        two_pi_m_p1_m_p4y = 2.0f * yi - y1p - y4p;
         c1 = invdet43 * (dy4 * two_pi_m_p1_m_p4x - dx4 * two_pi_m_p1_m_p4y);
         c2 = invdet43 * (dx1 * two_pi_m_p1_m_p4y - dy1 * two_pi_m_p1_m_p4x);
 
@@ -784,11 +986,14 @@
         return 8;
     }
 
+    // compute offset curves using bezier spline through t=0.5 (i.e.
+    // ComputedCurve(0.5) == IdealParallelCurve(0.5))
     // return the kind of curve in the right and left arrays.
-    private int computeOffsetQuad(float[] pts, final int off,
-                                  float[] leftOff, float[] rightOff)
+    private int computeOffsetQuad(final float[] pts, final int off,
+                                  final float[] leftOff,
+                                  final float[] rightOff)
     {
-        final float x1 = pts[off + 0], y1 = pts[off + 1];
+        final float x1 = pts[off    ], y1 = pts[off + 1];
         final float x2 = pts[off + 2], y2 = pts[off + 3];
         final float x3 = pts[off + 4], y3 = pts[off + 5];
 
@@ -797,301 +1002,181 @@
         final float dx1 = x2 - x1;
         final float dy1 = y2 - y1;
 
-        // this computes the offsets at t = 0, 1
+        // if p1=p2 or p3=p4 it means that the derivative at the endpoint
+        // vanishes, which creates problems with computeOffset. Usually
+        // this happens when this stroker object is trying to widen
+        // a curve with a cusp. What happens is that curveTo splits
+        // the input curve at the cusp, and passes it to this function.
+        // because of inaccuracies in the splitting, we consider points
+        // equal if they're very close to each other.
+
+        // if p1 == p2 && p3 == p4: draw line from p1->p4, unless p1 == p4,
+        // in which case ignore.
+        final boolean p1eqp2 = within(x1, y1, x2, y2, 6.0f * Math.ulp(y2));
+        final boolean p2eqp3 = within(x2, y2, x3, y3, 6.0f * Math.ulp(y3));
+
+        if (p1eqp2 || p2eqp3) {
+            getLineOffsets(x1, y1, x3, y3, leftOff, rightOff);
+            return 4;
+        }
+
+        // if p2-p1 and p4-p3 are parallel, that must mean this curve is a line
+        float dotsq = (dx1 * dx3 + dy1 * dy3);
+        dotsq *= dotsq;
+        float l1sq = dx1 * dx1 + dy1 * dy1, l3sq = dx3 * dx3 + dy3 * dy3;
+
+        if (Helpers.within(dotsq, l1sq * l3sq, 4.0f * Math.ulp(dotsq))) {
+            getLineOffsets(x1, y1, x3, y3, leftOff, rightOff);
+            return 4;
+        }
+
+        // this computes the offsets at t=0, 0.5, 1, using the property that
+        // for any bezier curve the vectors p2-p1 and p4-p3 are parallel to
+        // the (dx/dt, dy/dt) vectors at the endpoints.
         computeOffset(dx1, dy1, lineWidth2, offset0);
         computeOffset(dx3, dy3, lineWidth2, offset1);
 
-        leftOff[0]  = x1 + offset0[0]; leftOff[1]  = y1 + offset0[1];
-        leftOff[4]  = x3 + offset1[0]; leftOff[5]  = y3 + offset1[1];
-        rightOff[0] = x1 - offset0[0]; rightOff[1] = y1 - offset0[1];
-        rightOff[4] = x3 - offset1[0]; rightOff[5] = y3 - offset1[1];
+        float x1p = x1 + offset0[0]; // start
+        float y1p = y1 + offset0[1]; // point
+        float x3p = x3 + offset1[0]; // end
+        float y3p = y3 + offset1[1]; // point
+        safeComputeMiter(x1p, y1p, x1p+dx1, y1p+dy1, x3p, y3p, x3p-dx3, y3p-dy3, leftOff);
+        leftOff[0] = x1p; leftOff[1] = y1p;
+        leftOff[4] = x3p; leftOff[5] = y3p;
 
-        float x1p = leftOff[0]; // start
-        float y1p = leftOff[1]; // point
-        float x3p = leftOff[4]; // end
-        float y3p = leftOff[5]; // point
-
-        // Corner cases:
-        // 1. If the two control vectors are parallel, we'll end up with NaN's
-        //    in leftOff (and rightOff in the body of the if below), so we'll
-        //    do getLineOffsets, which is right.
-        // 2. If the first or second two points are equal, then (dx1,dy1)==(0,0)
-        //    or (dx3,dy3)==(0,0), so (x1p, y1p)==(x1p+dx1, y1p+dy1)
-        //    or (x3p, y3p)==(x3p-dx3, y3p-dy3), which means that
-        //    computeIntersection will put NaN's in leftOff and right off, and
-        //    we will do getLineOffsets, which is right.
-        computeIntersection(x1p, y1p, x1p+dx1, y1p+dy1, x3p, y3p, x3p-dx3, y3p-dy3, leftOff, 2);
-        float cx = leftOff[2];
-        float cy = leftOff[3];
-
-        if (!(isFinite(cx) && isFinite(cy))) {
-            // maybe the right path is not degenerate.
-            x1p = rightOff[0];
-            y1p = rightOff[1];
-            x3p = rightOff[4];
-            y3p = rightOff[5];
-            computeIntersection(x1p, y1p, x1p+dx1, y1p+dy1, x3p, y3p, x3p-dx3, y3p-dy3, rightOff, 2);
-            cx = rightOff[2];
-            cy = rightOff[3];
-            if (!(isFinite(cx) && isFinite(cy))) {
-                // both are degenerate. This curve is a line.
-                getLineOffsets(x1, y1, x3, y3, leftOff, rightOff);
-                return 4;
-            }
-            // {left,right}Off[0,1,4,5] are already set to the correct values.
-            leftOff[2] = 2f * x2 - cx;
-            leftOff[3] = 2f * y2 - cy;
-            return 6;
-        }
-
-        // rightOff[2,3] = (x2,y2) - ((left_x2, left_y2) - (x2, y2))
-        // == 2*(x2, y2) - (left_x2, left_y2)
-        rightOff[2] = 2f * x2 - cx;
-        rightOff[3] = 2f * y2 - cy;
+        x1p = x1 - offset0[0]; y1p = y1 - offset0[1];
+        x3p = x3 - offset1[0]; y3p = y3 - offset1[1];
+        safeComputeMiter(x1p, y1p, x1p+dx1, y1p+dy1, x3p, y3p, x3p-dx3, y3p-dy3, rightOff);
+        rightOff[0] = x1p; rightOff[1] = y1p;
+        rightOff[4] = x3p; rightOff[5] = y3p;
         return 6;
     }
 
-    private static boolean isFinite(float x) {
-        return (Float.NEGATIVE_INFINITY < x && x < Float.POSITIVE_INFINITY);
-    }
+    @Override
+    public void curveTo(final float x1, final float y1,
+                        final float x2, final float y2,
+                        final float x3, final float y3)
+    {
+        final int outcode0 = this.cOutCode;
 
-    // If this class is compiled with ecj, then Hotspot crashes when OSR
-    // compiling this function. See bugs 7004570 and 6675699
-    // TODO: until those are fixed, we should work around that by
-    // manually inlining this into curveTo and quadTo.
-/******************************* WORKAROUND **********************************
-    private void somethingTo(final int type) {
-        // need these so we can update the state at the end of this method
-        final float xf = middle[type-2], yf = middle[type-1];
-        float dxs = middle[2] - middle[0];
-        float dys = middle[3] - middle[1];
-        float dxf = middle[type - 2] - middle[type - 4];
-        float dyf = middle[type - 1] - middle[type - 3];
-        switch(type) {
-        case 6:
-            if ((dxs == 0f && dys == 0f) ||
-                (dxf == 0f && dyf == 0f)) {
-               dxs = dxf = middle[4] - middle[0];
-               dys = dyf = middle[5] - middle[1];
-            }
-            break;
-        case 8:
-            boolean p1eqp2 = (dxs == 0f && dys == 0f);
-            boolean p3eqp4 = (dxf == 0f && dyf == 0f);
-            if (p1eqp2) {
-                dxs = middle[4] - middle[0];
-                dys = middle[5] - middle[1];
-                if (dxs == 0f && dys == 0f) {
-                    dxs = middle[6] - middle[0];
-                    dys = middle[7] - middle[1];
+        if (clipRect != null) {
+            final int outcode1 = Helpers.outcode(x1, y1, clipRect);
+            final int outcode2 = Helpers.outcode(x2, y2, clipRect);
+            final int outcode3 = Helpers.outcode(x3, y3, clipRect);
+
+            // Should clip
+            final int orCode = (outcode0 | outcode1 | outcode2 | outcode3);
+            if (orCode != 0) {
+                final int sideCode = outcode0 & outcode1 & outcode2 & outcode3;
+
+                // basic rejection criteria:
+                if (sideCode == 0) {
+                    // ovelap clip:
+                    if (subdivide) {
+                        // avoid reentrance
+                        subdivide = false;
+                        // subdivide curve => callback with subdivided parts:
+                        boolean ret = curveSplitter.splitCurve(cx0, cy0, x1, y1,
+                                                               x2, y2, x3, y3,
+                                                               orCode, this);
+                        // reentrance is done:
+                        subdivide = true;
+                        if (ret) {
+                            return;
+                        }
+                    }
+                    // already subdivided so render it
+                } else {
+                    this.cOutCode = outcode3;
+                    _moveTo(x3, y3, outcode0);
+                    opened = true;
+                    return;
                 }
             }
-            if (p3eqp4) {
-                dxf = middle[6] - middle[2];
-                dyf = middle[7] - middle[3];
-                if (dxf == 0f && dyf == 0f) {
-                    dxf = middle[6] - middle[0];
-                    dyf = middle[7] - middle[1];
-                }
-            }
+
+            this.cOutCode = outcode3;
         }
-        if (dxs == 0f && dys == 0f) {
-            // this happens iff the "curve" is just a point
-            lineTo(middle[0], middle[1]);
-            return;
-        }
-        // if these vectors are too small, normalize them, to avoid future
-        // precision problems.
-        if (Math.abs(dxs) < 0.1f && Math.abs(dys) < 0.1f) {
-            float len = (float) sqrt(dxs*dxs + dys*dys);
-            dxs /= len;
-            dys /= len;
-        }
-        if (Math.abs(dxf) < 0.1f && Math.abs(dyf) < 0.1f) {
-            float len = (float) sqrt(dxf*dxf + dyf*dyf);
-            dxf /= len;
-            dyf /= len;
-        }
-
-        computeOffset(dxs, dys, lineWidth2, offset0);
-        final float mx = offset0[0];
-        final float my = offset0[1];
-        drawJoin(cdx, cdy, cx0, cy0, dxs, dys, cmx, cmy, mx, my);
-
-        int nSplits = findSubdivPoints(curve, middle, subdivTs, type, lineWidth2);
-
-        int kind = 0;
-        BreakPtrIterator it = curve.breakPtsAtTs(middle, type, subdivTs, nSplits);
-        while(it.hasNext()) {
-            int curCurveOff = it.next();
-
-            switch (type) {
-            case 8:
-                kind = computeOffsetCubic(middle, curCurveOff, lp, rp);
-                break;
-            case 6:
-                kind = computeOffsetQuad(middle, curCurveOff, lp, rp);
-                break;
-            }
-            emitLineTo(lp[0], lp[1]);
-            switch(kind) {
-            case 8:
-                emitCurveTo(lp[2], lp[3], lp[4], lp[5], lp[6], lp[7]);
-                emitCurveToRev(rp[0], rp[1], rp[2], rp[3], rp[4], rp[5]);
-                break;
-            case 6:
-                emitQuadTo(lp[2], lp[3], lp[4], lp[5]);
-                emitQuadToRev(rp[0], rp[1], rp[2], rp[3]);
-                break;
-            case 4:
-                emitLineTo(lp[2], lp[3]);
-                emitLineTo(rp[0], rp[1], true);
-                break;
-            }
-            emitLineTo(rp[kind - 2], rp[kind - 1], true);
-        }
-
-        this.cmx = (lp[kind - 2] - rp[kind - 2]) / 2;
-        this.cmy = (lp[kind - 1] - rp[kind - 1]) / 2;
-        this.cdx = dxf;
-        this.cdy = dyf;
-        this.cx0 = xf;
-        this.cy0 = yf;
-        this.prev = DRAWING_OP_TO;
-    }
-****************************** END WORKAROUND *******************************/
-
-    // finds values of t where the curve in pts should be subdivided in order
-    // to get good offset curves a distance of w away from the middle curve.
-    // Stores the points in ts, and returns how many of them there were.
-    private static int findSubdivPoints(final Curve c, float[] pts, float[] ts,
-                                        final int type, final float w)
-    {
-        final float x12 = pts[2] - pts[0];
-        final float y12 = pts[3] - pts[1];
-        // if the curve is already parallel to either axis we gain nothing
-        // from rotating it.
-        if (y12 != 0f && x12 != 0f) {
-            // we rotate it so that the first vector in the control polygon is
-            // parallel to the x-axis. This will ensure that rotated quarter
-            // circles won't be subdivided.
-            final float hypot = (float) sqrt(x12 * x12 + y12 * y12);
-            final float cos = x12 / hypot;
-            final float sin = y12 / hypot;
-            final float x1 = cos * pts[0] + sin * pts[1];
-            final float y1 = cos * pts[1] - sin * pts[0];
-            final float x2 = cos * pts[2] + sin * pts[3];
-            final float y2 = cos * pts[3] - sin * pts[2];
-            final float x3 = cos * pts[4] + sin * pts[5];
-            final float y3 = cos * pts[5] - sin * pts[4];
-
-            switch(type) {
-            case 8:
-                final float x4 = cos * pts[6] + sin * pts[7];
-                final float y4 = cos * pts[7] - sin * pts[6];
-                c.set(x1, y1, x2, y2, x3, y3, x4, y4);
-                break;
-            case 6:
-                c.set(x1, y1, x2, y2, x3, y3);
-                break;
-            default:
-            }
-        } else {
-            c.set(pts, type);
-        }
-
-        int ret = 0;
-        // we subdivide at values of t such that the remaining rotated
-        // curves are monotonic in x and y.
-        ret += c.dxRoots(ts, ret);
-        ret += c.dyRoots(ts, ret);
-        // subdivide at inflection points.
-        if (type == 8) {
-            // quadratic curves can't have inflection points
-            ret += c.infPoints(ts, ret);
-        }
-
-        // now we must subdivide at points where one of the offset curves will have
-        // a cusp. This happens at ts where the radius of curvature is equal to w.
-        ret += c.rootsOfROCMinusW(ts, ret, w, 0.0001f);
-
-        ret = Helpers.filterOutNotInAB(ts, 0, ret, 0.0001f, 0.9999f);
-        Helpers.isort(ts, 0, ret);
-        return ret;
+        _curveTo(x1, y1, x2, y2, x3, y3, outcode0);
     }
 
-    @Override public void curveTo(float x1, float y1,
-                                  float x2, float y2,
-                                  float x3, float y3)
+    private void _curveTo(final float x1, final float y1,
+                          final float x2, final float y2,
+                          final float x3, final float y3,
+                          final int outcode0)
     {
-        final float[] mid = middle;
-
-        mid[0] = cx0; mid[1] = cy0;
-        mid[2] = x1;  mid[3] = y1;
-        mid[4] = x2;  mid[5] = y2;
-        mid[6] = x3;  mid[7] = y3;
-
-        // inlined version of somethingTo(8);
-        // See the TODO on somethingTo
-
         // need these so we can update the state at the end of this method
-        final float xf = mid[6], yf = mid[7];
-        float dxs = mid[2] - mid[0];
-        float dys = mid[3] - mid[1];
-        float dxf = mid[6] - mid[4];
-        float dyf = mid[7] - mid[5];
+        float dxs = x1 - cx0;
+        float dys = y1 - cy0;
+        float dxf = x3 - x2;
+        float dyf = y3 - y2;
 
-        boolean p1eqp2 = (dxs == 0f && dys == 0f);
-        boolean p3eqp4 = (dxf == 0f && dyf == 0f);
-        if (p1eqp2) {
-            dxs = mid[4] - mid[0];
-            dys = mid[5] - mid[1];
-            if (dxs == 0f && dys == 0f) {
-                dxs = mid[6] - mid[0];
-                dys = mid[7] - mid[1];
+        if ((dxs == 0.0f) && (dys == 0.0f)) {
+            dxs = x2 - cx0;
+            dys = y2 - cy0;
+            if ((dxs == 0.0f) && (dys == 0.0f)) {
+                dxs = x3 - cx0;
+                dys = y3 - cy0;
             }
         }
-        if (p3eqp4) {
-            dxf = mid[6] - mid[2];
-            dyf = mid[7] - mid[3];
-            if (dxf == 0f && dyf == 0f) {
-                dxf = mid[6] - mid[0];
-                dyf = mid[7] - mid[1];
+        if ((dxf == 0.0f) && (dyf == 0.0f)) {
+            dxf = x3 - x1;
+            dyf = y3 - y1;
+            if ((dxf == 0.0f) && (dyf == 0.0f)) {
+                dxf = x3 - cx0;
+                dyf = y3 - cy0;
             }
         }
-        if (dxs == 0f && dys == 0f) {
+        if ((dxs == 0.0f) && (dys == 0.0f)) {
             // this happens if the "curve" is just a point
-            lineTo(mid[0], mid[1]);
+            // fix outcode0 for lineTo() call:
+            if (clipRect != null) {
+                this.cOutCode = outcode0;
+            }
+            lineTo(cx0, cy0);
             return;
         }
 
         // if these vectors are too small, normalize them, to avoid future
         // precision problems.
         if (Math.abs(dxs) < 0.1f && Math.abs(dys) < 0.1f) {
-            float len = (float) sqrt(dxs*dxs + dys*dys);
+            final float len = (float)Math.sqrt(dxs * dxs + dys * dys);
             dxs /= len;
             dys /= len;
         }
         if (Math.abs(dxf) < 0.1f && Math.abs(dyf) < 0.1f) {
-            float len = (float) sqrt(dxf*dxf + dyf*dyf);
+            final float len = (float)Math.sqrt(dxf * dxf + dyf * dyf);
             dxf /= len;
             dyf /= len;
         }
 
         computeOffset(dxs, dys, lineWidth2, offset0);
-        drawJoin(cdx, cdy, cx0, cy0, dxs, dys, cmx, cmy, offset0[0], offset0[1]);
+        drawJoin(cdx, cdy, cx0, cy0, dxs, dys, cmx, cmy, offset0[0], offset0[1], outcode0);
 
-        int nSplits = findSubdivPoints(curve, mid, subdivTs, 8, lineWidth2);
-
+        int nSplits = 0;
+        final float[] mid;
         final float[] l = lp;
+
+        if (monotonize) {
+            // monotonize curve:
+            final CurveBasicMonotonizer monotonizer
+                = rdrCtx.monotonizer.curve(cx0, cy0, x1, y1, x2, y2, x3, y3);
+
+            nSplits = monotonizer.nbSplits;
+            mid = monotonizer.middle;
+        } else {
+            // use left instead:
+            mid = l;
+            mid[0] = cx0; mid[1] = cy0;
+            mid[2] = x1;  mid[3] = y1;
+            mid[4] = x2;  mid[5] = y2;
+            mid[6] = x3;  mid[7] = y3;
+        }
         final float[] r = rp;
 
         int kind = 0;
-        BreakPtrIterator it = curve.breakPtsAtTs(mid, 8, subdivTs, nSplits);
-        while(it.hasNext()) {
-            int curCurveOff = it.next();
+        for (int i = 0, off = 0; i <= nSplits; i++, off += 6) {
+            kind = computeOffsetCubic(mid, off, l, r);
 
-            kind = computeOffsetCubic(mid, curCurveOff, l, r);
             emitLineTo(l[0], l[1]);
 
             switch(kind) {
@@ -1108,67 +1193,121 @@
             emitLineToRev(r[kind - 2], r[kind - 1]);
         }
 
-        this.cmx = (l[kind - 2] - r[kind - 2]) / 2f;
-        this.cmy = (l[kind - 1] - r[kind - 1]) / 2f;
+        this.prev = DRAWING_OP_TO;
+        this.cx0 = x3;
+        this.cy0 = y3;
         this.cdx = dxf;
         this.cdy = dyf;
-        this.cx0 = xf;
-        this.cy0 = yf;
-        this.prev = DRAWING_OP_TO;
+        this.cmx = (l[kind - 2] - r[kind - 2]) / 2.0f;
+        this.cmy = (l[kind - 1] - r[kind - 1]) / 2.0f;
     }
 
-    @Override public void quadTo(float x1, float y1, float x2, float y2) {
-        final float[] mid = middle;
+    @Override
+    public void quadTo(final float x1, final float y1,
+                       final float x2, final float y2)
+    {
+        final int outcode0 = this.cOutCode;
 
-        mid[0] = cx0; mid[1] = cy0;
-        mid[2] = x1;  mid[3] = y1;
-        mid[4] = x2;  mid[5] = y2;
+        if (clipRect != null) {
+            final int outcode1 = Helpers.outcode(x1, y1, clipRect);
+            final int outcode2 = Helpers.outcode(x2, y2, clipRect);
 
-        // inlined version of somethingTo(8);
-        // See the TODO on somethingTo
+            // Should clip
+            final int orCode = (outcode0 | outcode1 | outcode2);
+            if (orCode != 0) {
+                final int sideCode = outcode0 & outcode1 & outcode2;
 
-        // need these so we can update the state at the end of this method
-        final float xf = mid[4], yf = mid[5];
-        float dxs = mid[2] - mid[0];
-        float dys = mid[3] - mid[1];
-        float dxf = mid[4] - mid[2];
-        float dyf = mid[5] - mid[3];
-        if ((dxs == 0f && dys == 0f) || (dxf == 0f && dyf == 0f)) {
-            dxs = dxf = mid[4] - mid[0];
-            dys = dyf = mid[5] - mid[1];
+                // basic rejection criteria:
+                if (sideCode == 0) {
+                    // ovelap clip:
+                    if (subdivide) {
+                        // avoid reentrance
+                        subdivide = false;
+                        // subdivide curve => call lineTo() with subdivided curves:
+                        boolean ret = curveSplitter.splitQuad(cx0, cy0, x1, y1,
+                                                              x2, y2, orCode, this);
+                        // reentrance is done:
+                        subdivide = true;
+                        if (ret) {
+                            return;
+                        }
+                    }
+                    // already subdivided so render it
+                } else {
+                    this.cOutCode = outcode2;
+                    _moveTo(x2, y2, outcode0);
+                    opened = true;
+                    return;
+                }
+            }
+
+            this.cOutCode = outcode2;
         }
-        if (dxs == 0f && dys == 0f) {
+        _quadTo(x1, y1, x2, y2, outcode0);
+    }
+
+    private void _quadTo(final float x1, final float y1,
+                          final float x2, final float y2,
+                          final int outcode0)
+    {
+        // need these so we can update the state at the end of this method
+        float dxs = x1 - cx0;
+        float dys = y1 - cy0;
+        float dxf = x2 - x1;
+        float dyf = y2 - y1;
+
+        if (((dxs == 0.0f) && (dys == 0.0f)) || ((dxf == 0.0f) && (dyf == 0.0f))) {
+            dxs = dxf = x2 - cx0;
+            dys = dyf = y2 - cy0;
+        }
+        if ((dxs == 0.0f) && (dys == 0.0f)) {
             // this happens if the "curve" is just a point
-            lineTo(mid[0], mid[1]);
+            // fix outcode0 for lineTo() call:
+            if (clipRect != null) {
+                this.cOutCode = outcode0;
+            }
+            lineTo(cx0, cy0);
             return;
         }
         // if these vectors are too small, normalize them, to avoid future
         // precision problems.
         if (Math.abs(dxs) < 0.1f && Math.abs(dys) < 0.1f) {
-            float len = (float) sqrt(dxs*dxs + dys*dys);
+            final float len = (float)Math.sqrt(dxs * dxs + dys * dys);
             dxs /= len;
             dys /= len;
         }
         if (Math.abs(dxf) < 0.1f && Math.abs(dyf) < 0.1f) {
-            float len = (float) sqrt(dxf*dxf + dyf*dyf);
+            final float len = (float)Math.sqrt(dxf * dxf + dyf * dyf);
             dxf /= len;
             dyf /= len;
         }
-
         computeOffset(dxs, dys, lineWidth2, offset0);
-        drawJoin(cdx, cdy, cx0, cy0, dxs, dys, cmx, cmy, offset0[0], offset0[1]);
+        drawJoin(cdx, cdy, cx0, cy0, dxs, dys, cmx, cmy, offset0[0], offset0[1], outcode0);
 
-        int nSplits = findSubdivPoints(curve, mid, subdivTs, 6, lineWidth2);
-
+        int nSplits = 0;
+        final float[] mid;
         final float[] l = lp;
+
+        if (monotonize) {
+            // monotonize quad:
+            final CurveBasicMonotonizer monotonizer
+                = rdrCtx.monotonizer.quad(cx0, cy0, x1, y1, x2, y2);
+
+            nSplits = monotonizer.nbSplits;
+            mid = monotonizer.middle;
+        } else {
+            // use left instead:
+            mid = l;
+            mid[0] = cx0; mid[1] = cy0;
+            mid[2] = x1;  mid[3] = y1;
+            mid[4] = x2;  mid[5] = y2;
+        }
         final float[] r = rp;
 
         int kind = 0;
-        BreakPtrIterator it = curve.breakPtsAtTs(mid, 6, subdivTs, nSplits);
-        while(it.hasNext()) {
-            int curCurveOff = it.next();
+        for (int i = 0, off = 0; i <= nSplits; i++, off += 4) {
+            kind = computeOffsetQuad(mid, off, l, r);
 
-            kind = computeOffsetQuad(mid, curCurveOff, l, r);
             emitLineTo(l[0], l[1]);
 
             switch(kind) {
@@ -1185,212 +1324,16 @@
             emitLineToRev(r[kind - 2], r[kind - 1]);
         }
 
-        this.cmx = (l[kind - 2] - r[kind - 2]) / 2f;
-        this.cmy = (l[kind - 1] - r[kind - 1]) / 2f;
+        this.prev = DRAWING_OP_TO;
+        this.cx0 = x2;
+        this.cy0 = y2;
         this.cdx = dxf;
         this.cdy = dyf;
-        this.cx0 = xf;
-        this.cy0 = yf;
-        this.prev = DRAWING_OP_TO;
+        this.cmx = (l[kind - 2] - r[kind - 2]) / 2.0f;
+        this.cmy = (l[kind - 1] - r[kind - 1]) / 2.0f;
     }
 
     @Override public long getNativeConsumer() {
         throw new InternalError("Stroker doesn't use a native consumer");
     }
-
-    // a stack of polynomial curves where each curve shares endpoints with
-    // adjacent ones.
-    static final class PolyStack {
-        private static final byte TYPE_LINETO  = (byte) 0;
-        private static final byte TYPE_QUADTO  = (byte) 1;
-        private static final byte TYPE_CUBICTO = (byte) 2;
-
-        float[] curves;
-        int end;
-        byte[] curveTypes;
-        int numCurves;
-
-        // per-thread renderer context
-        final RendererContext rdrCtx;
-
-        // per-thread initial arrays (large enough to satisfy most usages: 8192)
-        // +1 to avoid recycling in Helpers.widenArray()
-        private final float[] curves_initial = new float[INITIAL_LARGE_ARRAY + 1]; // 32K
-        private final byte[] curveTypes_initial = new byte[INITIAL_LARGE_ARRAY + 1]; // 8K
-
-        // used marks (stats only)
-        int curveTypesUseMark;
-        int curvesUseMark;
-
-        /**
-         * Constructor
-         * @param rdrCtx per-thread renderer context
-         */
-        PolyStack(final RendererContext rdrCtx) {
-            this.rdrCtx = rdrCtx;
-
-            curves = curves_initial;
-            curveTypes = curveTypes_initial;
-            end = 0;
-            numCurves = 0;
-
-            if (DO_STATS) {
-                curveTypesUseMark = 0;
-                curvesUseMark = 0;
-            }
-        }
-
-        /**
-         * Disposes this PolyStack:
-         * clean up before reusing this instance
-         */
-        void dispose() {
-            end = 0;
-            numCurves = 0;
-
-            if (DO_STATS) {
-                rdrCtx.stats.stat_rdr_poly_stack_types
-                    .add(curveTypesUseMark);
-                rdrCtx.stats.stat_rdr_poly_stack_curves
-                    .add(curvesUseMark);
-                // reset marks
-                curveTypesUseMark = 0;
-                curvesUseMark = 0;
-            }
-
-            // Return arrays:
-            // curves and curveTypes are kept dirty
-            if (curves != curves_initial) {
-                rdrCtx.putDirtyFloatArray(curves);
-                curves = curves_initial;
-            }
-
-            if (curveTypes != curveTypes_initial) {
-                rdrCtx.putDirtyByteArray(curveTypes);
-                curveTypes = curveTypes_initial;
-            }
-        }
-
-        private void ensureSpace(final int n) {
-            // use substraction to avoid integer overflow:
-            if (curves.length - end < n) {
-                if (DO_STATS) {
-                    rdrCtx.stats.stat_array_stroker_polystack_curves
-                        .add(end + n);
-                }
-                curves = rdrCtx.widenDirtyFloatArray(curves, end, end + n);
-            }
-            if (curveTypes.length <= numCurves) {
-                if (DO_STATS) {
-                    rdrCtx.stats.stat_array_stroker_polystack_curveTypes
-                        .add(numCurves + 1);
-                }
-                curveTypes = rdrCtx.widenDirtyByteArray(curveTypes,
-                                                        numCurves,
-                                                        numCurves + 1);
-            }
-        }
-
-        void pushCubic(float x0, float y0,
-                       float x1, float y1,
-                       float x2, float y2)
-        {
-            ensureSpace(6);
-            curveTypes[numCurves++] = TYPE_CUBICTO;
-            // we reverse the coordinate order to make popping easier
-            final float[] _curves = curves;
-            int e = end;
-            _curves[e++] = x2;    _curves[e++] = y2;
-            _curves[e++] = x1;    _curves[e++] = y1;
-            _curves[e++] = x0;    _curves[e++] = y0;
-            end = e;
-        }
-
-        void pushQuad(float x0, float y0,
-                      float x1, float y1)
-        {
-            ensureSpace(4);
-            curveTypes[numCurves++] = TYPE_QUADTO;
-            final float[] _curves = curves;
-            int e = end;
-            _curves[e++] = x1;    _curves[e++] = y1;
-            _curves[e++] = x0;    _curves[e++] = y0;
-            end = e;
-        }
-
-        void pushLine(float x, float y) {
-            ensureSpace(2);
-            curveTypes[numCurves++] = TYPE_LINETO;
-            curves[end++] = x;    curves[end++] = y;
-        }
-
-        void popAll(PathConsumer2D io) {
-            if (DO_STATS) {
-                // update used marks:
-                if (numCurves > curveTypesUseMark) {
-                    curveTypesUseMark = numCurves;
-                }
-                if (end > curvesUseMark) {
-                    curvesUseMark = end;
-                }
-            }
-            final byte[]  _curveTypes = curveTypes;
-            final float[] _curves = curves;
-            int nc = numCurves;
-            int e  = end;
-
-            while (nc != 0) {
-                switch(_curveTypes[--nc]) {
-                case TYPE_LINETO:
-                    e -= 2;
-                    io.lineTo(_curves[e], _curves[e+1]);
-                    continue;
-                case TYPE_QUADTO:
-                    e -= 4;
-                    io.quadTo(_curves[e+0], _curves[e+1],
-                              _curves[e+2], _curves[e+3]);
-                    continue;
-                case TYPE_CUBICTO:
-                    e -= 6;
-                    io.curveTo(_curves[e+0], _curves[e+1],
-                               _curves[e+2], _curves[e+3],
-                               _curves[e+4], _curves[e+5]);
-                    continue;
-                default:
-                }
-            }
-            numCurves = 0;
-            end = 0;
-        }
-
-        @Override
-        public String toString() {
-            String ret = "";
-            int nc = numCurves;
-            int e  = end;
-            int len;
-            while (nc != 0) {
-                switch(curveTypes[--nc]) {
-                case TYPE_LINETO:
-                    len = 2;
-                    ret += "line: ";
-                    break;
-                case TYPE_QUADTO:
-                    len = 4;
-                    ret += "quad: ";
-                    break;
-                case TYPE_CUBICTO:
-                    len = 6;
-                    ret += "cubic: ";
-                    break;
-                default:
-                    len = 0;
-                }
-                e -= len;
-                ret += Arrays.toString(Arrays.copyOfRange(curves, e, e+len))
-                                       + "\n";
-            }
-            return ret;
-        }
-    }
 }
diff --git a/src/share/classes/sun/java2d/marlin/TransformingPathConsumer2D.java b/src/share/classes/sun/java2d/marlin/TransformingPathConsumer2D.java
index db8f8dd..06500f8 100644
--- a/src/share/classes/sun/java2d/marlin/TransformingPathConsumer2D.java
+++ b/src/share/classes/sun/java2d/marlin/TransformingPathConsumer2D.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, 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,50 +28,178 @@
 import sun.awt.geom.PathConsumer2D;
 import java.awt.geom.AffineTransform;
 import java.awt.geom.Path2D;
+import java.util.Arrays;
+import sun.java2d.marlin.Helpers.IndexStack;
+import sun.java2d.marlin.Helpers.PolyStack;
 
 final class TransformingPathConsumer2D {
 
-    TransformingPathConsumer2D() {
-        // used by RendererContext
-    }
+    // higher uncertainty in float variant for huge shapes > 10^7
+    static final float CLIP_RECT_PADDING = 1.0f;
 
-    // recycled PathConsumer2D instance from wrapPath2d()
+    private final RendererContext rdrCtx;
+
+    // recycled ClosedPathDetector instance from detectClosedPath()
+    private final ClosedPathDetector   cpDetector;
+
+    // recycled PathClipFilter instance from pathClipper()
+    private final PathClipFilter       pathClipper;
+
+    // recycled PathConsumer2D instance from wrapPath2D()
     private final Path2DWrapper        wp_Path2DWrapper        = new Path2DWrapper();
 
-    PathConsumer2D wrapPath2d(Path2D.Float p2d)
-    {
-        return wp_Path2DWrapper.init(p2d);
-    }
-
     // recycled PathConsumer2D instances from deltaTransformConsumer()
     private final DeltaScaleFilter     dt_DeltaScaleFilter     = new DeltaScaleFilter();
     private final DeltaTransformFilter dt_DeltaTransformFilter = new DeltaTransformFilter();
 
+    // recycled PathConsumer2D instances from inverseDeltaTransformConsumer()
+    private final DeltaScaleFilter     iv_DeltaScaleFilter     = new DeltaScaleFilter();
+    private final DeltaTransformFilter iv_DeltaTransformFilter = new DeltaTransformFilter();
+
+    // recycled PathTracer instances from tracer...() methods
+    private final PathTracer tracerInput      = new PathTracer("[Input]");
+    private final PathTracer tracerCPDetector = new PathTracer("ClosedPathDetector");
+    private final PathTracer tracerFiller     = new PathTracer("Filler");
+    private final PathTracer tracerStroker    = new PathTracer("Stroker");
+    private final PathTracer tracerDasher     = new PathTracer("Dasher");
+
+    TransformingPathConsumer2D(final RendererContext rdrCtx) {
+        // used by RendererContext
+        this.rdrCtx = rdrCtx;
+        this.cpDetector = new ClosedPathDetector(rdrCtx);
+        this.pathClipper = new PathClipFilter(rdrCtx);
+    }
+
+    PathConsumer2D wrapPath2D(Path2D.Float p2d) {
+        return wp_Path2DWrapper.init(p2d);
+    }
+
+    PathConsumer2D traceInput(PathConsumer2D out) {
+        return tracerInput.init(out);
+    }
+
+    PathConsumer2D traceClosedPathDetector(PathConsumer2D out) {
+        return tracerCPDetector.init(out);
+    }
+
+    PathConsumer2D traceFiller(PathConsumer2D out) {
+        return tracerFiller.init(out);
+    }
+
+    PathConsumer2D traceStroker(PathConsumer2D out) {
+        return tracerStroker.init(out);
+    }
+
+    PathConsumer2D traceDasher(PathConsumer2D out) {
+        return tracerDasher.init(out);
+    }
+
+    PathConsumer2D detectClosedPath(PathConsumer2D out) {
+        return cpDetector.init(out);
+    }
+
+    PathConsumer2D pathClipper(PathConsumer2D out) {
+        return pathClipper.init(out);
+    }
+
     PathConsumer2D deltaTransformConsumer(PathConsumer2D out,
                                           AffineTransform at)
     {
         if (at == null) {
             return out;
         }
-        float mxx = (float) at.getScaleX();
-        float mxy = (float) at.getShearX();
-        float myx = (float) at.getShearY();
-        float myy = (float) at.getScaleY();
+        final float mxx = (float) at.getScaleX();
+        final float mxy = (float) at.getShearX();
+        final float myx = (float) at.getShearY();
+        final float myy = (float) at.getScaleY();
 
-        if (mxy == 0f && myx == 0f) {
-            if (mxx == 1f && myy == 1f) {
+        if (mxy == 0.0f && myx == 0.0f) {
+            if (mxx == 1.0f && myy == 1.0f) {
                 return out;
             } else {
+                // Scale only
+                if (rdrCtx.doClip) {
+                    // adjust clip rectangle (ymin, ymax, xmin, xmax):
+                    adjustClipScale(rdrCtx.clipRect, mxx, myy);
+                }
                 return dt_DeltaScaleFilter.init(out, mxx, myy);
             }
         } else {
+            if (rdrCtx.doClip) {
+                // adjust clip rectangle (ymin, ymax, xmin, xmax):
+                adjustClipInverseDelta(rdrCtx.clipRect, mxx, mxy, myx, myy);
+            }
             return dt_DeltaTransformFilter.init(out, mxx, mxy, myx, myy);
         }
     }
 
-    // recycled PathConsumer2D instances from inverseDeltaTransformConsumer()
-    private final DeltaScaleFilter     iv_DeltaScaleFilter     = new DeltaScaleFilter();
-    private final DeltaTransformFilter iv_DeltaTransformFilter = new DeltaTransformFilter();
+    private static void adjustClipOffset(final float[] clipRect) {
+        clipRect[0] += Renderer.RDR_OFFSET_Y;
+        clipRect[1] += Renderer.RDR_OFFSET_Y;
+        clipRect[2] += Renderer.RDR_OFFSET_X;
+        clipRect[3] += Renderer.RDR_OFFSET_X;
+    }
+
+    private static void adjustClipScale(final float[] clipRect,
+                                        final float mxx, final float myy)
+    {
+        adjustClipOffset(clipRect);
+
+        // Adjust the clipping rectangle (iv_DeltaScaleFilter):
+        clipRect[0] /= myy;
+        clipRect[1] /= myy;
+        clipRect[2] /= mxx;
+        clipRect[3] /= mxx;
+    }
+
+    private static void adjustClipInverseDelta(final float[] clipRect,
+                                               final float mxx, final float mxy,
+                                               final float myx, final float myy)
+    {
+        adjustClipOffset(clipRect);
+
+        // Adjust the clipping rectangle (iv_DeltaTransformFilter):
+        final float det = mxx * myy - mxy * myx;
+        final float imxx =  myy / det;
+        final float imxy = -mxy / det;
+        final float imyx = -myx / det;
+        final float imyy =  mxx / det;
+
+        float xmin, xmax, ymin, ymax;
+        float x, y;
+        // xmin, ymin:
+        x = clipRect[2] * imxx + clipRect[0] * imxy;
+        y = clipRect[2] * imyx + clipRect[0] * imyy;
+
+        xmin = xmax = x;
+        ymin = ymax = y;
+
+        // xmax, ymin:
+        x = clipRect[3] * imxx + clipRect[0] * imxy;
+        y = clipRect[3] * imyx + clipRect[0] * imyy;
+
+        if (x < xmin) { xmin = x; } else if (x > xmax) { xmax = x; }
+        if (y < ymin) { ymin = y; } else if (y > ymax) { ymax = y; }
+
+        // xmin, ymax:
+        x = clipRect[2] * imxx + clipRect[1] * imxy;
+        y = clipRect[2] * imyx + clipRect[1] * imyy;
+
+        if (x < xmin) { xmin = x; } else if (x > xmax) { xmax = x; }
+        if (y < ymin) { ymin = y; } else if (y > ymax) { ymax = y; }
+
+        // xmax, ymax:
+        x = clipRect[3] * imxx + clipRect[1] * imxy;
+        y = clipRect[3] * imyx + clipRect[1] * imyy;
+
+        if (x < xmin) { xmin = x; } else if (x > xmax) { xmax = x; }
+        if (y < ymin) { ymin = y; } else if (y > ymax) { ymax = y; }
+
+        clipRect[0] = ymin;
+        clipRect[1] = ymax;
+        clipRect[2] = xmin;
+        clipRect[3] = xmax;
+    }
 
     PathConsumer2D inverseDeltaTransformConsumer(PathConsumer2D out,
                                                  AffineTransform at)
@@ -84,14 +212,14 @@
         float myx = (float) at.getShearY();
         float myy = (float) at.getScaleY();
 
-        if (mxy == 0f && myx == 0f) {
-            if (mxx == 1f && myy == 1f) {
+        if (mxy == 0.0f && myx == 0.0f) {
+            if (mxx == 1.0f && myy == 1.0f) {
                 return out;
             } else {
                 return iv_DeltaScaleFilter.init(out, 1.0f/mxx, 1.0f/myy);
             }
         } else {
-            float det = mxx * myy - mxy * myx;
+            final float det = mxx * myy - mxy * myx;
             return iv_DeltaTransformFilter.init(out,
                                                 myy / det,
                                                -mxy / det,
@@ -100,7 +228,6 @@
         }
     }
 
-
     static final class DeltaScaleFilter implements PathConsumer2D {
         private PathConsumer2D out;
         private float sx, sy;
@@ -275,4 +402,777 @@
             throw new InternalError("Not using a native peer");
         }
     }
+
+    static final class ClosedPathDetector implements PathConsumer2D {
+
+        private final RendererContext rdrCtx;
+        private final PolyStack stack;
+
+        private PathConsumer2D out;
+
+        ClosedPathDetector(final RendererContext rdrCtx) {
+            this.rdrCtx = rdrCtx;
+            this.stack = (rdrCtx.stats != null) ?
+                new PolyStack(rdrCtx,
+                        rdrCtx.stats.stat_cpd_polystack_types,
+                        rdrCtx.stats.stat_cpd_polystack_curves,
+                        rdrCtx.stats.hist_cpd_polystack_curves,
+                        rdrCtx.stats.stat_array_cpd_polystack_curves,
+                        rdrCtx.stats.stat_array_cpd_polystack_types)
+                : new PolyStack(rdrCtx);
+        }
+
+        ClosedPathDetector init(PathConsumer2D out) {
+            this.out = out;
+            return this; // fluent API
+        }
+
+        /**
+         * Disposes this instance:
+         * clean up before reusing this instance
+         */
+        void dispose() {
+            stack.dispose();
+        }
+
+        @Override
+        public void pathDone() {
+            // previous path is not closed:
+            finish(false);
+            out.pathDone();
+
+            // TODO: fix possible leak if exception happened
+            // Dispose this instance:
+            dispose();
+        }
+
+        @Override
+        public void closePath() {
+            // path is closed
+            finish(true);
+            out.closePath();
+        }
+
+        @Override
+        public void moveTo(float x0, float y0) {
+            // previous path is not closed:
+            finish(false);
+            out.moveTo(x0, y0);
+        }
+
+        private void finish(final boolean closed) {
+            rdrCtx.closedPath = closed;
+            stack.pullAll(out);
+        }
+
+        @Override
+        public void lineTo(float x1, float y1) {
+            stack.pushLine(x1, y1);
+        }
+
+        @Override
+        public void curveTo(float x3, float y3,
+                            float x2, float y2,
+                            float x1, float y1)
+        {
+            stack.pushCubic(x1, y1, x2, y2, x3, y3);
+        }
+
+        @Override
+        public void quadTo(float x2, float y2, float x1, float y1) {
+            stack.pushQuad(x1, y1, x2, y2);
+        }
+
+        @Override
+        public long getNativeConsumer() {
+            throw new InternalError("Not using a native peer");
+        }
+    }
+
+    static final class PathClipFilter implements PathConsumer2D {
+
+        private PathConsumer2D out;
+
+        // Bounds of the drawing region, at pixel precision.
+        private final float[] clipRect;
+
+        private final float[] corners = new float[8];
+        private boolean init_corners = false;
+
+        private final IndexStack stack;
+
+        // the current outcode of the current sub path
+        private int cOutCode = 0;
+
+        // the cumulated (and) outcode of the complete path
+        private int gOutCode = MarlinConst.OUTCODE_MASK_T_B_L_R;
+
+        private boolean outside = false;
+
+        // The current point (TODO stupid repeated info)
+        private float cx0, cy0;
+
+        // The current point OUTSIDE
+        private float cox0, coy0;
+
+        private boolean subdivide = MarlinConst.DO_CLIP_SUBDIVIDER;
+        private final CurveClipSplitter curveSplitter;
+
+        PathClipFilter(final RendererContext rdrCtx) {
+            this.clipRect = rdrCtx.clipRect;
+            this.curveSplitter = rdrCtx.curveClipSplitter;
+
+            this.stack = (rdrCtx.stats != null) ?
+                new IndexStack(rdrCtx,
+                        rdrCtx.stats.stat_pcf_idxstack_indices,
+                        rdrCtx.stats.hist_pcf_idxstack_indices,
+                        rdrCtx.stats.stat_array_pcf_idxstack_indices)
+                : new IndexStack(rdrCtx);
+        }
+
+        PathClipFilter init(final PathConsumer2D out) {
+            this.out = out;
+
+            // Adjust the clipping rectangle with the renderer offsets
+            final float rdrOffX = Renderer.RDR_OFFSET_X;
+            final float rdrOffY = Renderer.RDR_OFFSET_Y;
+
+            // add a small rounding error:
+            final float margin = 1e-3f;
+
+            final float[] _clipRect = this.clipRect;
+            _clipRect[0] -= margin - rdrOffY;
+            _clipRect[1] += margin + rdrOffY;
+            _clipRect[2] -= margin - rdrOffX;
+            _clipRect[3] += margin + rdrOffX;
+
+            if (MarlinConst.DO_CLIP_SUBDIVIDER) {
+                // adjust padded clip rectangle:
+                curveSplitter.init();
+            }
+
+            this.init_corners = true;
+            this.gOutCode = MarlinConst.OUTCODE_MASK_T_B_L_R;
+
+            return this; // fluent API
+        }
+
+        /**
+         * Disposes this instance:
+         * clean up before reusing this instance
+         */
+        void dispose() {
+            stack.dispose();
+        }
+
+        private void finishPath() {
+            if (outside) {
+                // criteria: inside or totally outside ?
+                if (gOutCode == 0) {
+                    finish();
+                } else {
+                    this.outside = false;
+                    stack.reset();
+                }
+            }
+        }
+
+        private void finish() {
+            this.outside = false;
+
+            if (!stack.isEmpty()) {
+                if (init_corners) {
+                    init_corners = false;
+
+                    final float[] _corners = corners;
+                    final float[] _clipRect = clipRect;
+                    // Top Left (0):
+                    _corners[0] = _clipRect[2];
+                    _corners[1] = _clipRect[0];
+                    // Bottom Left (1):
+                    _corners[2] = _clipRect[2];
+                    _corners[3] = _clipRect[1];
+                    // Top right (2):
+                    _corners[4] = _clipRect[3];
+                    _corners[5] = _clipRect[0];
+                    // Bottom Right (3):
+                    _corners[6] = _clipRect[3];
+                    _corners[7] = _clipRect[1];
+                }
+                stack.pullAll(corners, out);
+            }
+            out.lineTo(cox0, coy0);
+            this.cx0 = cox0;
+            this.cy0 = coy0;
+        }
+
+        @Override
+        public void pathDone() {
+            finishPath();
+
+            out.pathDone();
+
+            // TODO: fix possible leak if exception happened
+            // Dispose this instance:
+            dispose();
+        }
+
+        @Override
+        public void closePath() {
+            finishPath();
+
+            out.closePath();
+        }
+
+        @Override
+        public void moveTo(final float x0, final float y0) {
+            finishPath();
+
+            this.cOutCode = Helpers.outcode(x0, y0, clipRect);
+            this.outside = false;
+            out.moveTo(x0, y0);
+            this.cx0 = x0;
+            this.cy0 = y0;
+        }
+
+        @Override
+        public void lineTo(final float xe, final float ye) {
+            final int outcode0 = this.cOutCode;
+            final int outcode1 = Helpers.outcode(xe, ye, clipRect);
+
+            // Should clip
+            final int orCode = (outcode0 | outcode1);
+            if (orCode != 0) {
+                final int sideCode = (outcode0 & outcode1);
+
+                // basic rejection criteria:
+                if (sideCode == 0) {
+                    // ovelap clip:
+                    if (subdivide) {
+                        // avoid reentrance
+                        subdivide = false;
+                        boolean ret;
+                        // subdivide curve => callback with subdivided parts:
+                        if (outside) {
+                            ret = curveSplitter.splitLine(cox0, coy0, xe, ye,
+                                                          orCode, this);
+                        } else {
+                            ret = curveSplitter.splitLine(cx0, cy0, xe, ye,
+                                                          orCode, this);
+                        }
+                        // reentrance is done:
+                        subdivide = true;
+                        if (ret) {
+                            return;
+                        }
+                    }
+                    // already subdivided so render it
+                } else {
+                    this.cOutCode = outcode1;
+                    this.gOutCode &= sideCode;
+                    // keep last point coordinate before entering the clip again:
+                    this.outside = true;
+                    this.cox0 = xe;
+                    this.coy0 = ye;
+
+                    clip(sideCode, outcode0, outcode1);
+                    return;
+                }
+            }
+
+            this.cOutCode = outcode1;
+            this.gOutCode = 0;
+
+            if (outside) {
+                finish();
+            }
+            // clipping disabled:
+            out.lineTo(xe, ye);
+            this.cx0 = xe;
+            this.cy0 = ye;
+        }
+
+        private void clip(final int sideCode,
+                          final int outcode0,
+                          final int outcode1)
+        {
+            // corner or cross-boundary on left or right side:
+            if ((outcode0 != outcode1)
+                    && ((sideCode & MarlinConst.OUTCODE_MASK_L_R) != 0))
+            {
+                // combine outcodes:
+                final int mergeCode = (outcode0 | outcode1);
+                final int tbCode = mergeCode & MarlinConst.OUTCODE_MASK_T_B;
+                final int lrCode = mergeCode & MarlinConst.OUTCODE_MASK_L_R;
+                final int off = (lrCode == MarlinConst.OUTCODE_LEFT) ? 0 : 2;
+
+                // add corners to outside stack:
+                switch (tbCode) {
+                    case MarlinConst.OUTCODE_TOP:
+                        stack.push(off); // top
+                        return;
+                    case MarlinConst.OUTCODE_BOTTOM:
+                        stack.push(off + 1); // bottom
+                        return;
+                    default:
+                        // both TOP / BOTTOM:
+                        if ((outcode0 & MarlinConst.OUTCODE_TOP) != 0) {
+                            // top to bottom
+                            stack.push(off); // top
+                            stack.push(off + 1); // bottom
+                        } else {
+                            // bottom to top
+                            stack.push(off + 1); // bottom
+                            stack.push(off); // top
+                        }
+                }
+            }
+        }
+
+        @Override
+        public void curveTo(final float x1, final float y1,
+                            final float x2, final float y2,
+                            final float xe, final float ye)
+        {
+            final int outcode0 = this.cOutCode;
+            final int outcode1 = Helpers.outcode(x1, y1, clipRect);
+            final int outcode2 = Helpers.outcode(x2, y2, clipRect);
+            final int outcode3 = Helpers.outcode(xe, ye, clipRect);
+
+            // Should clip
+            final int orCode = (outcode0 | outcode1 | outcode2 | outcode3);
+            if (orCode != 0) {
+                final int sideCode = outcode0 & outcode1 & outcode2 & outcode3;
+
+                // basic rejection criteria:
+                if (sideCode == 0) {
+                    // ovelap clip:
+                    if (subdivide) {
+                        // avoid reentrance
+                        subdivide = false;
+                        // subdivide curve => callback with subdivided parts:
+                        boolean ret;
+                        if (outside) {
+                            ret = curveSplitter.splitCurve(cox0, coy0, x1, y1,
+                                                           x2, y2, xe, ye,
+                                                           orCode, this);
+                        } else {
+                            ret = curveSplitter.splitCurve(cx0, cy0, x1, y1,
+                                                           x2, y2, xe, ye,
+                                                           orCode, this);
+                        }
+                        // reentrance is done:
+                        subdivide = true;
+                        if (ret) {
+                            return;
+                        }
+                    }
+                    // already subdivided so render it
+                } else {
+                    this.cOutCode = outcode3;
+                    this.gOutCode &= sideCode;
+                    // keep last point coordinate before entering the clip again:
+                    this.outside = true;
+                    this.cox0 = xe;
+                    this.coy0 = ye;
+
+                    clip(sideCode, outcode0, outcode3);
+                    return;
+                }
+            }
+
+            this.cOutCode = outcode3;
+            this.gOutCode = 0;
+
+            if (outside) {
+                finish();
+            }
+            // clipping disabled:
+            out.curveTo(x1, y1, x2, y2, xe, ye);
+            this.cx0 = xe;
+            this.cy0 = ye;
+        }
+
+        @Override
+        public void quadTo(final float x1, final float y1,
+                           final float xe, final float ye)
+        {
+            final int outcode0 = this.cOutCode;
+            final int outcode1 = Helpers.outcode(x1, y1, clipRect);
+            final int outcode2 = Helpers.outcode(xe, ye, clipRect);
+
+            // Should clip
+            final int orCode = (outcode0 | outcode1 | outcode2);
+            if (orCode != 0) {
+                final int sideCode = outcode0 & outcode1 & outcode2;
+
+                // basic rejection criteria:
+                if (sideCode == 0) {
+                    // ovelap clip:
+                    if (subdivide) {
+                        // avoid reentrance
+                        subdivide = false;
+                        // subdivide curve => callback with subdivided parts:
+                        boolean ret;
+                        if (outside) {
+                            ret = curveSplitter.splitQuad(cox0, coy0, x1, y1,
+                                                          xe, ye, orCode, this);
+                        } else {
+                            ret = curveSplitter.splitQuad(cx0, cy0, x1, y1,
+                                                          xe, ye, orCode, this);
+                        }
+                        // reentrance is done:
+                        subdivide = true;
+                        if (ret) {
+                            return;
+                        }
+                    }
+                    // already subdivided so render it
+                } else {
+                    this.cOutCode = outcode2;
+                    this.gOutCode &= sideCode;
+                    // keep last point coordinate before entering the clip again:
+                    this.outside = true;
+                    this.cox0 = xe;
+                    this.coy0 = ye;
+
+                    clip(sideCode, outcode0, outcode2);
+                    return;
+                }
+            }
+
+            this.cOutCode = outcode2;
+            this.gOutCode = 0;
+
+            if (outside) {
+                finish();
+            }
+            // clipping disabled:
+            out.quadTo(x1, y1, xe, ye);
+            this.cx0 = xe;
+            this.cy0 = ye;
+        }
+
+        @Override
+        public long getNativeConsumer() {
+            throw new InternalError("Not using a native peer");
+        }
+    }
+
+    static final class CurveClipSplitter {
+
+        static final float LEN_TH = MarlinProperties.getSubdividerMinLength();
+        static final boolean DO_CHECK_LENGTH = (LEN_TH > 0.0f);
+
+        private static final boolean TRACE = false;
+
+        private static final int MAX_N_CURVES = 3 * 4;
+
+        // clip rectangle (ymin, ymax, xmin, xmax):
+        final float[] clipRect;
+
+        // clip rectangle (ymin, ymax, xmin, xmax) including padding:
+        final float[] clipRectPad = new float[4];
+        private boolean init_clipRectPad = false;
+
+        // This is where the curve to be processed is put. We give it
+        // enough room to store all curves.
+        final float[] middle = new float[MAX_N_CURVES * 8 + 2];
+        // t values at subdivision points
+        private final float[] subdivTs = new float[MAX_N_CURVES];
+
+        // dirty curve
+        private final Curve curve;
+
+        CurveClipSplitter(final RendererContext rdrCtx) {
+            this.clipRect = rdrCtx.clipRect;
+            this.curve = rdrCtx.curve;
+        }
+
+        void init() {
+            this.init_clipRectPad = true;
+        }
+
+        private void initPaddedClip() {
+            // bounds as half-open intervals: minX <= x < maxX and minY <= y < maxY
+            // adjust padded clip rectangle (ymin, ymax, xmin, xmax):
+            // add a rounding error (curve subdivision ~ 0.1px):
+            final float[] _clipRect = clipRect;
+            final float[] _clipRectPad = clipRectPad;
+
+            _clipRectPad[0] = _clipRect[0] - CLIP_RECT_PADDING;
+            _clipRectPad[1] = _clipRect[1] + CLIP_RECT_PADDING;
+            _clipRectPad[2] = _clipRect[2] - CLIP_RECT_PADDING;
+            _clipRectPad[3] = _clipRect[3] + CLIP_RECT_PADDING;
+
+            if (TRACE) {
+                System.out.println("clip: X [" + _clipRectPad[2] + " .. " + _clipRectPad[3] +"] "
+                                        + "Y ["+ _clipRectPad[0] + " .. " + _clipRectPad[1] +"]");
+            }
+        }
+
+        boolean splitLine(final float x0, final float y0,
+                          final float x1, final float y1,
+                          final int outCodeOR,
+                          final PathConsumer2D out)
+        {
+            if (TRACE) {
+                System.out.println("divLine P0(" + x0 + ", " + y0 + ") P1(" + x1 + ", " + y1 + ")");
+            }
+
+            if (DO_CHECK_LENGTH && Helpers.fastLineLen(x0, y0, x1, y1) <= LEN_TH) {
+                return false;
+            }
+
+            final float[] mid = middle;
+            mid[0] = x0;  mid[1] = y0;
+            mid[2] = x1;  mid[3] = y1;
+
+            return subdivideAtIntersections(4, outCodeOR, out);
+        }
+
+        boolean splitQuad(final float x0, final float y0,
+                          final float x1, final float y1,
+                          final float x2, final float y2,
+                          final int outCodeOR,
+                          final PathConsumer2D out)
+        {
+            if (TRACE) {
+                System.out.println("divQuad P0(" + x0 + ", " + y0 + ") P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2 + ")");
+            }
+
+            if (DO_CHECK_LENGTH && Helpers.fastQuadLen(x0, y0, x1, y1, x2, y2) <= LEN_TH) {
+                return false;
+            }
+
+            final float[] mid = middle;
+            mid[0] = x0;  mid[1] = y0;
+            mid[2] = x1;  mid[3] = y1;
+            mid[4] = x2;  mid[5] = y2;
+
+            return subdivideAtIntersections(6, outCodeOR, out);
+        }
+
+        boolean splitCurve(final float x0, final float y0,
+                           final float x1, final float y1,
+                           final float x2, final float y2,
+                           final float x3, final float y3,
+                           final int outCodeOR,
+                           final PathConsumer2D out)
+        {
+            if (TRACE) {
+                System.out.println("divCurve P0(" + x0 + ", " + y0 + ") P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2 + ") P3(" + x3 + ", " + y3 + ")");
+            }
+
+            if (DO_CHECK_LENGTH && Helpers.fastCurvelen(x0, y0, x1, y1, x2, y2, x3, y3) <= LEN_TH) {
+                return false;
+            }
+
+            final float[] mid = middle;
+            mid[0] = x0;  mid[1] = y0;
+            mid[2] = x1;  mid[3] = y1;
+            mid[4] = x2;  mid[5] = y2;
+            mid[6] = x3;  mid[7] = y3;
+
+            return subdivideAtIntersections(8, outCodeOR, out);
+        }
+
+        private boolean subdivideAtIntersections(final int type, final int outCodeOR,
+                                                 final PathConsumer2D out)
+        {
+            final float[] mid = middle;
+            final float[] subTs = subdivTs;
+
+            if (init_clipRectPad) {
+                init_clipRectPad = false;
+                initPaddedClip();
+            }
+
+            final int nSplits = Helpers.findClipPoints(curve, mid, subTs, type,
+                                                        outCodeOR, clipRectPad);
+
+            if (TRACE) {
+                System.out.println("nSplits: "+ nSplits);
+                System.out.println("subTs: "+Arrays.toString(Arrays.copyOfRange(subTs, 0, nSplits)));
+            }
+            if (nSplits == 0) {
+                // only curve support shortcut
+                return false;
+            }
+            float prevT = 0.0f;
+
+            for (int i = 0, off = 0; i < nSplits; i++, off += type) {
+                final float t = subTs[i];
+
+                Helpers.subdivideAt((t - prevT) / (1.0f - prevT),
+                                     mid, off, mid, off, type);
+                prevT = t;
+            }
+
+            for (int i = 0, off = 0; i <= nSplits; i++, off += type) {
+                if (TRACE) {
+                    System.out.println("Part Curve "+Arrays.toString(Arrays.copyOfRange(mid, off, off + type)));
+                }
+                emitCurrent(type, mid, off, out);
+            }
+            return true;
+        }
+
+        static void emitCurrent(final int type, final float[] pts,
+                                final int off, final PathConsumer2D out)
+        {
+            // if instead of switch (perf + most probable cases first)
+            if (type == 8) {
+                out.curveTo(pts[off + 2], pts[off + 3],
+                            pts[off + 4], pts[off + 5],
+                            pts[off + 6], pts[off + 7]);
+            } else if (type == 4) {
+                out.lineTo(pts[off + 2], pts[off + 3]);
+            } else {
+                out.quadTo(pts[off + 2], pts[off + 3],
+                           pts[off + 4], pts[off + 5]);
+            }
+        }
+    }
+
+    static final class CurveBasicMonotonizer {
+
+        private static final int MAX_N_CURVES = 11;
+
+        // squared half line width (for stroker)
+        private float lw2;
+
+        // number of splitted curves
+        int nbSplits;
+
+        // This is where the curve to be processed is put. We give it
+        // enough room to store all curves.
+        final float[] middle = new float[MAX_N_CURVES * 6 + 2];
+        // t values at subdivision points
+        private final float[] subdivTs = new float[MAX_N_CURVES - 1];
+
+        // dirty curve
+        private final Curve curve;
+
+        CurveBasicMonotonizer(final RendererContext rdrCtx) {
+            this.curve = rdrCtx.curve;
+        }
+
+        void init(final float lineWidth) {
+            this.lw2 = (lineWidth * lineWidth) / 4.0f;
+        }
+
+        CurveBasicMonotonizer curve(final float x0, final float y0,
+                                    final float x1, final float y1,
+                                    final float x2, final float y2,
+                                    final float x3, final float y3)
+        {
+            final float[] mid = middle;
+            mid[0] = x0;  mid[1] = y0;
+            mid[2] = x1;  mid[3] = y1;
+            mid[4] = x2;  mid[5] = y2;
+            mid[6] = x3;  mid[7] = y3;
+
+            final float[] subTs = subdivTs;
+            final int nSplits = Helpers.findSubdivPoints(curve, mid, subTs, 8, lw2);
+
+            float prevT = 0.0f;
+            for (int i = 0, off = 0; i < nSplits; i++, off += 6) {
+                final float t = subTs[i];
+
+                Helpers.subdivideCubicAt((t - prevT) / (1.0f - prevT),
+                                          mid, off, mid, off, off + 6);
+                prevT = t;
+            }
+
+            this.nbSplits = nSplits;
+            return this;
+        }
+
+        CurveBasicMonotonizer quad(final float x0, final float y0,
+                                   final float x1, final float y1,
+                                   final float x2, final float y2)
+        {
+            final float[] mid = middle;
+            mid[0] = x0;  mid[1] = y0;
+            mid[2] = x1;  mid[3] = y1;
+            mid[4] = x2;  mid[5] = y2;
+
+            final float[] subTs = subdivTs;
+            final int nSplits = Helpers.findSubdivPoints(curve, mid, subTs, 6, lw2);
+
+            float prevt = 0.0f;
+            for (int i = 0, off = 0; i < nSplits; i++, off += 4) {
+                final float t = subTs[i];
+                Helpers.subdivideQuadAt((t - prevt) / (1.0f - prevt),
+                                         mid, off, mid, off, off + 4);
+                prevt = t;
+            }
+
+            this.nbSplits = nSplits;
+            return this;
+        }
+    }
+
+    static final class PathTracer implements PathConsumer2D {
+        private final String prefix;
+        private PathConsumer2D out;
+
+        PathTracer(String name) {
+            this.prefix = name + ": ";
+        }
+
+        PathTracer init(PathConsumer2D out) {
+            this.out = out;
+            return this; // fluent API
+        }
+
+        @Override
+        public void moveTo(float x0, float y0) {
+            log("moveTo (" + x0 + ", " + y0 + ')');
+            out.moveTo(x0, y0);
+        }
+
+        @Override
+        public void lineTo(float x1, float y1) {
+            log("lineTo (" + x1 + ", " + y1 + ')');
+            out.lineTo(x1, y1);
+        }
+
+        @Override
+        public void curveTo(float x1, float y1,
+                            float x2, float y2,
+                            float x3, float y3)
+        {
+            log("curveTo P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2  + ") P3(" + x3 + ", " + y3 + ')');
+            out.curveTo(x1, y1, x2, y2, x3, y3);
+        }
+
+        @Override
+        public void quadTo(float x1, float y1, float x2, float y2) {
+            log("quadTo P1(" + x1 + ", " + y1 + ") P2(" + x2 + ", " + y2  + ')');
+            out.quadTo(x1, y1, x2, y2);
+        }
+
+        @Override
+        public void closePath() {
+            log("closePath");
+            out.closePath();
+        }
+
+        @Override
+        public void pathDone() {
+            log("pathDone");
+            out.pathDone();
+        }
+
+        private void log(final String message) {
+            System.out.println(prefix + message);
+        }
+
+        @Override
+        public long getNativeConsumer() {
+            throw new InternalError("Not using a native peer");
+        }
+    }
 }
diff --git a/src/share/classes/sun/java2d/marlin/Version.java b/src/share/classes/sun/java2d/marlin/Version.java
index dc0a925..b2b43be 100644
--- a/src/share/classes/sun/java2d/marlin/Version.java
+++ b/src/share/classes/sun/java2d/marlin/Version.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, 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
@@ -27,7 +27,7 @@
 
 public final class Version {
 
-    private static final String VERSION = "marlin-0.7.3.4-Unsafe-OpenJDK";
+    private static final String VERSION = "marlin-0.9.1-Unsafe-OpenJDK";
 
     public static String getVersion() {
         return VERSION;
diff --git a/src/share/classes/sun/java2d/marlin/stats/Monitor.java b/src/share/classes/sun/java2d/marlin/stats/Monitor.java
index dcb3c8b..7688602 100644
--- a/src/share/classes/sun/java2d/marlin/stats/Monitor.java
+++ b/src/share/classes/sun/java2d/marlin/stats/Monitor.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
diff --git a/src/share/classes/sun/java2d/marlin/stats/StatLong.java b/src/share/classes/sun/java2d/marlin/stats/StatLong.java
index 50f906f..9aca2a4 100644
--- a/src/share/classes/sun/java2d/marlin/stats/StatLong.java
+++ b/src/share/classes/sun/java2d/marlin/stats/StatLong.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -71,9 +71,7 @@
 
     @Override
     public String toString() {
-        final StringBuilder sb = new StringBuilder(128);
-        toString(sb);
-        return sb.toString();
+        return toString(new StringBuilder(128)).toString();
     }
 
     public final StringBuilder toString(final StringBuilder sb) {
diff --git a/src/share/classes/sun/java2d/opengl/OGLTextRenderer.java b/src/share/classes/sun/java2d/opengl/OGLTextRenderer.java
index 546246c..612e0c0 100644
--- a/src/share/classes/sun/java2d/opengl/OGLTextRenderer.java
+++ b/src/share/classes/sun/java2d/opengl/OGLTextRenderer.java
@@ -71,12 +71,13 @@
             super(ogltr.rq);
         }
         protected void drawGlyphList(SunGraphics2D sg2d, GlyphList gl) {
+            final String prim = "OGLDrawGlyphs" + (gl.isRGBOrder() ? "LCD" : "Gray");
             if ((GraphicsPrimitive.traceflags & GraphicsPrimitive.TRACEPTIME) == 0) {
-                GraphicsPrimitive.tracePrimitive("OGLDrawGlyphs");
+                GraphicsPrimitive.tracePrimitive(prim);
             }
             long time = System.nanoTime();
             super.drawGlyphList(sg2d, gl);
-            GraphicsPrimitive.tracePrimitiveTime("OGLDrawGlyphs", System.nanoTime() - time);
+            GraphicsPrimitive.tracePrimitiveTime(prim, System.nanoTime() - time);
         }
     }
 }
diff --git a/src/share/classes/sun/java2d/pipe/AAShapePipe.java b/src/share/classes/sun/java2d/pipe/AAShapePipe.java
index 239d134..2a796b9 100644
--- a/src/share/classes/sun/java2d/pipe/AAShapePipe.java
+++ b/src/share/classes/sun/java2d/pipe/AAShapePipe.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,15 +22,16 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-
 package sun.java2d.pipe;
 
 import java.awt.BasicStroke;
 import java.awt.Rectangle;
 import java.awt.Shape;
 import java.awt.geom.Rectangle2D;
-import java.awt.geom.PathIterator;
 import sun.awt.SunHints;
+import sun.java2d.ReentrantContext;
+import sun.java2d.ReentrantContextProvider;
+import sun.java2d.ReentrantContextProviderTL;
 import sun.java2d.SunGraphics2D;
 
 /**
@@ -40,19 +41,31 @@
  * This class sets up the Generator and computes the alpha tiles
  * and then passes them on to a CompositePipe object for painting.
  */
-public class AAShapePipe
+public final class AAShapePipe
     implements ShapeDrawPipe, ParallelogramPipe
 {
-    static RenderingEngine renderengine = RenderingEngine.getInstance();
+    static final RenderingEngine RDR_ENGINE = RenderingEngine.getInstance();
 
-    CompositePipe outpipe;
+    // Per-thread TileState (~1K very small so do not use any Weak Reference)
+    private static final ReentrantContextProvider<TileState> TILE_STATE_PROVIDER =
+            new ReentrantContextProviderTL<TileState>(
+                    ReentrantContextProvider.REF_HARD)
+            {
+                @Override
+                protected TileState newContext() {
+                    return new TileState();
+                }
+            };
+
+    final CompositePipe outpipe;
 
     public AAShapePipe(CompositePipe pipe) {
         outpipe = pipe;
     }
 
+    @Override
     public void draw(SunGraphics2D sg, Shape s) {
-        BasicStroke bs;
+        final BasicStroke bs;
 
         if (sg.stroke instanceof BasicStroke) {
             bs = (BasicStroke) sg.stroke;
@@ -64,24 +77,12 @@
         renderPath(sg, s, bs);
     }
 
+    @Override
     public void fill(SunGraphics2D sg, Shape s) {
         renderPath(sg, s, null);
     }
 
-    private static Rectangle2D computeBBox(double ux1, double uy1,
-                                           double ux2, double uy2)
-    {
-        if ((ux2 -= ux1) < 0) {
-            ux1 += ux2;
-            ux2 = -ux2;
-        }
-        if ((uy2 -= uy1) < 0) {
-            uy1 += uy2;
-            uy2 = -uy2;
-        }
-        return new Rectangle2D.Double(ux1, uy1, ux2, uy2);
-    }
-
+    @Override
     public void fillParallelogram(SunGraphics2D sg,
                                   double ux1, double uy1,
                                   double ux2, double uy2,
@@ -89,19 +90,23 @@
                                   double dx1, double dy1,
                                   double dx2, double dy2)
     {
-        Region clip = sg.getCompClip();
-        int abox[] = new int[4];
-        AATileGenerator aatg =
-            renderengine.getAATileGenerator(x, y, dx1, dy1, dx2, dy2, 0, 0,
-                                            clip, abox);
-        if (aatg == null) {
-            // Nothing to render
-            return;
-        }
+        final TileState ts = TILE_STATE_PROVIDER.acquire();
+        try {
+            final int[] abox = ts.abox;
 
-        renderTiles(sg, computeBBox(ux1, uy1, ux2, uy2), aatg, abox);
+            final AATileGenerator aatg =
+                RDR_ENGINE.getAATileGenerator(x, y, dx1, dy1, dx2, dy2, 0, 0,
+                                                sg.getCompClip(), abox);
+            if (aatg != null) {
+                renderTiles(sg, ts.computeBBox(ux1, uy1, ux2, uy2),
+                            aatg, abox, ts);
+            }
+        } finally {
+            TILE_STATE_PROVIDER.release(ts);
+        }
     }
 
+    @Override
     public void drawParallelogram(SunGraphics2D sg,
                                   double ux1, double uy1,
                                   double ux2, double uy2,
@@ -110,82 +115,77 @@
                                   double dx2, double dy2,
                                   double lw1, double lw2)
     {
-        Region clip = sg.getCompClip();
-        int abox[] = new int[4];
-        AATileGenerator aatg =
-            renderengine.getAATileGenerator(x, y, dx1, dy1, dx2, dy2, lw1, lw2,
-                                            clip, abox);
-        if (aatg == null) {
-            // Nothing to render
-            return;
+        final TileState ts = TILE_STATE_PROVIDER.acquire();
+        try {
+            final int[] abox = ts.abox;
+
+            final AATileGenerator aatg =
+                RDR_ENGINE.getAATileGenerator(x, y, dx1, dy1, dx2, dy2, lw1,
+                                                lw2, sg.getCompClip(), abox);
+            if (aatg != null) {
+                // Note that bbox is of the original shape, not the wide path.
+                // This is appropriate for handing to Paint methods...
+                renderTiles(sg, ts.computeBBox(ux1, uy1, ux2, uy2),
+                            aatg, abox, ts);
+            }
+        } finally {
+            TILE_STATE_PROVIDER.release(ts);
         }
-
-        // Note that bbox is of the original shape, not the wide path.
-        // This is appropriate for handing to Paint methods...
-        renderTiles(sg, computeBBox(ux1, uy1, ux2, uy2), aatg, abox);
-    }
-
-    private static byte[] theTile;
-
-    private synchronized static byte[] getAlphaTile(int len) {
-        byte[] t = theTile;
-        if (t == null || t.length < len) {
-            t = new byte[len];
-        } else {
-            theTile = null;
-        }
-        return t;
-    }
-
-    private synchronized static void dropAlphaTile(byte[] t) {
-        theTile = t;
     }
 
     public void renderPath(SunGraphics2D sg, Shape s, BasicStroke bs) {
-        boolean adjust = (bs != null &&
+        final boolean adjust = (bs != null &&
                           sg.strokeHint != SunHints.INTVAL_STROKE_PURE);
-        boolean thin = (sg.strokeState <= SunGraphics2D.STROKE_THINDASHED);
+        final boolean thin = (sg.strokeState <= SunGraphics2D.STROKE_THINDASHED);
 
-        Region clip = sg.getCompClip();
-        int abox[] = new int[4];
-        AATileGenerator aatg =
-            renderengine.getAATileGenerator(s, sg.transform, clip,
-                                            bs, thin, adjust, abox);
-        if (aatg == null) {
-            // Nothing to render
-            return;
+        final TileState ts = TILE_STATE_PROVIDER.acquire();
+        try {
+            final int[] abox = ts.abox;
+
+            final AATileGenerator aatg =
+                RDR_ENGINE.getAATileGenerator(s, sg.transform, sg.getCompClip(),
+                                                bs, thin, adjust, abox);
+            if (aatg != null) {
+                renderTiles(sg, s, aatg, abox, ts);
+            }
+        } finally {
+            TILE_STATE_PROVIDER.release(ts);
         }
-
-        renderTiles(sg, s, aatg, abox);
     }
 
     public void renderTiles(SunGraphics2D sg, Shape s,
-                            AATileGenerator aatg, int abox[])
+                            final AATileGenerator aatg,
+                            final int[] abox, final TileState ts)
     {
         Object context = null;
-        byte alpha[] = null;
         try {
+            // reentrance: outpipe may also use AAShapePipe:
             context = outpipe.startSequence(sg, s,
-                                            new Rectangle(abox[0], abox[1],
-                                                          abox[2] - abox[0],
-                                                          abox[3] - abox[1]),
+                                            ts.computeDevBox(abox),
                                             abox);
 
-            int tw = aatg.getTileWidth();
-            int th = aatg.getTileHeight();
-            alpha = getAlphaTile(tw * th);
+            // copy of int[] abox as local variables for performance:
+            final int x0 = abox[0];
+            final int y0 = abox[1];
+            final int x1 = abox[2];
+            final int y1 = abox[3];
 
+            final int tw = aatg.getTileWidth();
+            final int th = aatg.getTileHeight();
+
+            // get tile from thread local storage:
+            final byte[] alpha = ts.getAlphaTile(tw * th);
             byte[] atile;
 
-            for (int y = abox[1]; y < abox[3]; y += th) {
-                for (int x = abox[0]; x < abox[2]; x += tw) {
-                    int w = Math.min(tw, abox[2] - x);
-                    int h = Math.min(th, abox[3] - y);
+            for (int y = y0; y < y1; y += th) {
+                final int h = Math.min(th, y1 - y);
 
-                    int a = aatg.getTypicalAlpha();
-                    if (a == 0x00 ||
-                        outpipe.needTile(context, x, y, w, h) == false)
-                    {
+                for (int x = x0; x < x1; x += tw) {
+                    final int w = Math.min(tw, x1 - x);
+
+                    final int a = aatg.getTypicalAlpha();
+
+                    if (a == 0x00 || !outpipe.needTile(context, x, y, w, h)) {
                         aatg.nextTile();
                         outpipe.skipTile(context, x, y);
                         continue;
@@ -198,8 +198,7 @@
                         aatg.getAlpha(alpha, 0, tw);
                     }
 
-                    outpipe.renderPathTile(context, atile, 0, tw,
-                                           x, y, w, h);
+                    outpipe.renderPathTile(context, atile, 0, tw, x, y, w, h);
                 }
             }
         } finally {
@@ -207,9 +206,55 @@
             if (context != null) {
                 outpipe.endSequence(context);
             }
-            if (alpha != null) {
-                dropAlphaTile(alpha);
+        }
+    }
+
+    // Tile state used by AAShapePipe
+    static final class TileState extends ReentrantContext {
+        // cached tile (32 x 32 tile by default)
+        private byte[] theTile = new byte[32 * 32];
+        // dirty aabox array
+        final int[] abox = new int[4];
+        // dirty bbox rectangle
+        private final Rectangle dev = new Rectangle();
+        // dirty bbox rectangle2D.Double
+        private final Rectangle2D.Double bbox2D = new Rectangle2D.Double();
+
+        byte[] getAlphaTile(int len) {
+            byte[] t = theTile;
+            if (t.length < len) {
+                // create a larger tile and may free current theTile (too small)
+                theTile = t = new byte[len];
             }
+            return t;
+        }
+
+        Rectangle computeDevBox(final int[] abox) {
+            final Rectangle box = this.dev;
+            box.x = abox[0];
+            box.y = abox[1];
+            box.width = abox[2] - abox[0];
+            box.height = abox[3] - abox[1];
+            return box;
+        }
+
+        Rectangle2D computeBBox(double ux1, double uy1,
+                                double ux2, double uy2)
+        {
+            if ((ux2 -= ux1) < 0.0) {
+                ux1 += ux2;
+                ux2 = -ux2;
+            }
+            if ((uy2 -= uy1) < 0.0) {
+                uy1 += uy2;
+                uy2 = -uy2;
+            }
+            final Rectangle2D.Double box = this.bbox2D;
+            box.x = ux1;
+            box.y = uy1;
+            box.width = ux2;
+            box.height = uy2;
+            return box;
         }
     }
 }
diff --git a/src/share/classes/sun/swing/SwingUtilities2.java b/src/share/classes/sun/swing/SwingUtilities2.java
index 4abaebb..baa8b8f 100644
--- a/src/share/classes/sun/swing/SwingUtilities2.java
+++ b/src/share/classes/sun/swing/SwingUtilities2.java
@@ -140,9 +140,7 @@
             Object aaHint   = hints.get(KEY_TEXT_ANTIALIASING);
             Object contHint = hints.get(KEY_TEXT_LCD_CONTRAST);
 
-            if (aaHint == null ||
-                aaHint == VALUE_TEXT_ANTIALIAS_OFF ||
-                aaHint == VALUE_TEXT_ANTIALIAS_DEFAULT) {
+            if (aaHint == null) {
                 return null;
             } else {
                 return new AATextInfo(aaHint, (Integer)contHint);
@@ -173,10 +171,6 @@
             if (aaHint == null) {
                 throw new InternalError("null not allowed here");
             }
-            if (aaHint == VALUE_TEXT_ANTIALIAS_OFF ||
-                aaHint == VALUE_TEXT_ANTIALIAS_DEFAULT) {
-                throw new InternalError("AA must be on");
-            }
             this.aaHint = aaHint;
             this.lcdContrastHint = lcdContrastHint;
         }
diff --git a/src/share/demo/java2d/J2DBench/src/j2dbench/report/TCChartReporter.java b/src/share/demo/java2d/J2DBench/src/j2dbench/report/TCChartReporter.java
index f34dd6c..36c8760 100644
--- a/src/share/demo/java2d/J2DBench/src/j2dbench/report/TCChartReporter.java
+++ b/src/share/demo/java2d/J2DBench/src/j2dbench/report/TCChartReporter.java
@@ -141,7 +141,7 @@
                             System.err.println("\treferenceValue=" + refValue);
                             System.err.println("\t   actualValue=" + value);
                             System.err.println("\t          diff:" + ((value / refValue - 1) * 100));
-                            testFailed = true;
+                            testFailed = (value < refValue);
                         }
                     }
                 }
diff --git a/src/share/native/sun/java2d/Trace.h b/src/share/native/sun/java2d/Trace.h
index 16414ef..a8a4a75 100644
--- a/src/share/native/sun/java2d/Trace.h
+++ b/src/share/native/sun/java2d/Trace.h
@@ -28,10 +28,15 @@
 
 #include <jni.h>
 #include "debug_trace.h"
+#ifdef __MACH__
+#include <mach/mach_time.h>
+#endif
 
 #ifdef __cplusplus
 extern "C" {
 #endif /* __cplusplus */
+extern JavaVM *jvm;
+extern jint graphicsPrimitive_traceflags;
 
 /**
  * J2dTrace
@@ -50,6 +55,8 @@
 #define J2D_TRACE_VERBOSE2      5
 #define J2D_TRACE_MAX           (J2D_TRACE_VERBOSE2+1)
 
+#define J2D_PTRACE_TIME         8
+
 JNIEXPORT void JNICALL
 J2dTraceImpl(int level, jboolean cr, const char *string, ...);
 JNIEXPORT void JNICALL
@@ -175,6 +182,45 @@
             J2dTraceImpl(level, JNI_TRUE, string, arg1, arg2, arg3, arg4, arg5); \
         }
 
+#define J2dTracePrimitive(string) { \
+        if (graphicsPrimitive_traceflags && jvm) { \
+            JNIEnv *env; \
+            jstring jstr; \
+            (*jvm)->AttachCurrentThreadAsDaemon(jvm, (void**)&env, NULL); \
+            jstr = (*env)->NewStringUTF(env, string); \
+            JNU_CallStaticMethodByName( \
+                    env, NULL, "sun/java2d/loops/GraphicsPrimitive", \
+                    "tracePrimitive", "(Ljava/lang/Object;)V", jstr); \
+            (*env)->DeleteLocalRef(env, jstr); \
+        } \
+    }
+
+#ifdef __MACH__
+#define J2dTraceNanoTime() (mach_absolute_time())
+
+#define J2dTracePrimitiveTime(string,t0) { \
+        if ((graphicsPrimitive_traceflags & J2D_PTRACE_TIME) && jvm) { \
+            JNIEnv *env; \
+            jstring jstr; \
+            static mach_timebase_info_data_t ti; \
+            jlong t1; \
+            t1 = mach_absolute_time(); \
+            if (ti.denom == 0) { \
+                (void) mach_timebase_info(&ti); \
+            } \
+            (*jvm)->AttachCurrentThreadAsDaemon(jvm, &env, NULL); \
+            jstr = (*env)->NewStringUTF(env, string); \
+            JNU_CallStaticMethodByName(env, NULL, "sun/java2d/loops/GraphicsPrimitive", \
+                                       "tracePrimitiveTime", "(Ljava/lang/Object;J)V", jstr,\
+                                       (((t1-t0)*ti.numer)/ti.denom)); \
+            (*env)->DeleteLocalRef(env, jstr); \
+        } \
+    }
+#else
+#define J2dTracePrimitiveTime(string,t)
+#define J2dTraceNanoTime() (0)
+#endif
+
 #ifdef __cplusplus
 };
 #endif /* __cplusplus */
diff --git a/src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.c b/src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.c
index 6a70d40..cbd0ee8 100644
--- a/src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.c
+++ b/src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.c
@@ -75,6 +75,7 @@
 jfieldID path2DFloatCoordsID;
 jfieldID sg2dStrokeHintID;
 jint sunHints_INTVAL_STROKE_PURE;
+jint graphicsPrimitive_traceflags = 0;
 
 /*
  * Class:     sun_java2d_loops_GraphicsPrimitiveMgr
@@ -148,6 +149,13 @@
     sunHints_INTVAL_STROKE_PURE = (*env)->GetStaticIntField(env, SHints, fid);
 }
 
+JNIEXPORT void JNICALL
+Java_sun_java2d_loops_GraphicsPrimitiveMgr_setTraceFlags
+    (JNIEnv *env, jclass GPMgr, jint traceflags)
+{
+    graphicsPrimitive_traceflags = traceflags;
+}
+
 void GrPrim_RefineBounds(SurfaceDataBounds *bounds, jint transX, jint transY,
                          jfloat *coords,  jint maxCoords)
 {
diff --git a/src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.h b/src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.h
index 6c67461..0249dae 100644
--- a/src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.h
+++ b/src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.h
@@ -557,6 +557,7 @@
 extern jfieldID path2DFloatCoordsID;
 extern jfieldID sg2dStrokeHintID;
 extern jint sunHints_INTVAL_STROKE_PURE;
+extern jint graphicsPrimitive_traceflags;
 
 /*
  * Macros for using jlong variables as 32bits.32bits fractional values
diff --git a/src/share/native/sun/java2d/opengl/OGLFuncs.h b/src/share/native/sun/java2d/opengl/OGLFuncs.h
index 427c91d..51fdf28 100644
--- a/src/share/native/sun/java2d/opengl/OGLFuncs.h
+++ b/src/share/native/sun/java2d/opengl/OGLFuncs.h
@@ -131,6 +131,7 @@
  * extensions, which is why they are called out separately here)
  */
 typedef void (GLAPIENTRY *glActiveTextureARBType)(GLenum texture);
+typedef void (GLAPIENTRY *glClientActiveTextureType)(GLenum texture);
 typedef void (GLAPIENTRY *glMultiTexCoord2fARBType)(GLenum texture, GLfloat s, GLfloat t);
 typedef void (GLAPIENTRY *glTexImage3DType)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
 
@@ -290,6 +291,7 @@
 
 #define OGL_EXPRESS_EXT_FUNCS(action) \
     OGL_##action##_EXT_FUNC(glActiveTextureARB); \
+    OGL_##action##_EXT_FUNC(glClientActiveTexture); \
     OGL_##action##_EXT_FUNC(glMultiTexCoord2fARB); \
     OGL_##action##_EXT_FUNC(glTexImage3D); \
     OGL_##action##_EXT_FUNC(glBindRenderbufferEXT); \
diff --git a/src/share/native/sun/java2d/opengl/OGLTextRenderer.c b/src/share/native/sun/java2d/opengl/OGLTextRenderer.c
index 186bab8..75681fe 100644
--- a/src/share/native/sun/java2d/opengl/OGLTextRenderer.c
+++ b/src/share/native/sun/java2d/opengl/OGLTextRenderer.c
@@ -38,13 +38,14 @@
 #include "OGLTextRenderer.h"
 #include "OGLVertexCache.h"
 #include "AccelGlyphCache.h"
+#include "jni_util.h"
 
 /**
  * The following constants define the inner and outer bounds of the
  * accelerated glyph cache.
  */
-#define OGLTR_CACHE_WIDTH       1024
-#define OGLTR_CACHE_HEIGHT      1024
+#define OGLTR_CACHE_WIDTH       2048
+#define OGLTR_CACHE_HEIGHT      2048
 #define OGLTR_CACHE_CELL_WIDTH  64
 #define OGLTR_CACHE_CELL_HEIGHT 64
 
@@ -225,8 +226,10 @@
     J2dTraceLn(J2D_TRACE_INFO, "OGLTR_AddToGlyphCache");
 
     if (pixelFormat == GL_LUMINANCE) {
+        J2dTracePrimitive("OGLTR_AddToGlyphCacheGray");
         gcinfo = glyphCacheAA;
     } else {
+        J2dTracePrimitive("OGLTR_AddToGlyphCacheLCD");
         gcinfo = glyphCacheLCD;
     }
 
@@ -710,21 +713,14 @@
 }
 
 static jboolean
-OGLTR_DrawLCDGlyphViaCache(OGLContext *oglc, OGLSDOps *dstOps,
-                           GlyphInfo *ginfo, jint x, jint y,
-                           jint glyphIndex, jint totalGlyphs,
-                           jboolean rgbOrder, jint contrast,
-                           GLuint dstTextureID, jboolean * opened)
+OGLTR_DrawLCDGlyphViaCache(OGLContext *oglc, OGLSDOps *dstOps, GlyphInfo *ginfo, jint x, jint y, jint glyphIndex,
+                           jint totalGlyphs, jboolean rgbOrder, jint contrast, GLuint dstTextureID)
 {
     CacheCellInfo *cell;
     jint dx1, dy1, dx2, dy2;
     jfloat dtx1, dty1, dtx2, dty2;
 
     if (glyphMode != MODE_USE_CACHE_LCD) {
-        if (*opened) {
-            *opened = JNI_FALSE;
-            j2d_glEnd();
-        }
         OGLTR_DisableGlyphModeState();
         CHECK_PREVIOUS_OP(GL_TEXTURE_2D);
         j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
@@ -756,10 +752,6 @@
     }
 
     if (ginfo->cellInfo == NULL) {
-        if (*opened) {
-            *opened = JNI_FALSE;
-            j2d_glEnd();
-        }
         // rowBytes will always be a multiple of 3, so the following is safe
         j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, ginfo->rowBytes / 3);
 
@@ -785,10 +777,6 @@
     dy2 = dy1 + ginfo->height;
 
     if (dstTextureID == 0) {
-        if (*opened) {
-            *opened = JNI_FALSE;
-            j2d_glEnd();
-        }
         // copy destination into second cached texture, if necessary
         OGLTR_UpdateCachedDestination(dstOps, ginfo,
                                       dx1, dy1, dx2, dy2,
@@ -816,23 +804,12 @@
     }
 
     // render composed texture to the destination surface
-    if (!*opened)  {
-        j2d_glBegin(GL_QUADS);
-        *opened = JNI_TRUE;
+    if (!OGLMTVertexCache_enable(oglc, dstTextureID != 0)) {
+        J2dTracePrimitive("OGLMTVertexCache_enable_failed");
+        return JNI_FALSE;
     }
-
-    j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, cell->tx1, cell->ty1);
-    j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx1, dty1);
-    j2d_glVertex2i(dx1, dy1);
-    j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, cell->tx2, cell->ty1);
-    j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx2, dty1);
-    j2d_glVertex2i(dx2, dy1);
-    j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, cell->tx2, cell->ty2);
-    j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx2, dty2);
-    j2d_glVertex2i(dx2, dy2);
-    j2d_glMultiTexCoord2fARB(GL_TEXTURE0_ARB, cell->tx1, cell->ty2);
-    j2d_glMultiTexCoord2fARB(GL_TEXTURE1_ARB, dtx1, dty2);
-    j2d_glVertex2i(dx1, dy2);
+    OGLMTVertexCache_addGlyphQuad(dx1, dy1, dx2, dy2, cell->tx1, cell->ty1,
+                                  cell->tx2, cell->ty2, dtx1, dty1, dtx2, dty2);
 
     return JNI_TRUE;
 }
@@ -1064,11 +1041,13 @@
 {
     int glyphCounter;
     GLuint dstTextureID = 0;
-    jboolean hasLCDGlyphs = JNI_FALSE;
-    jboolean lcdOpened = JNI_FALSE;
-    jint ox1 = INT_MIN;
+    jlong time;
 
     J2dTraceLn(J2D_TRACE_INFO, "OGLTR_DrawGlyphList");
+    if (graphicsPrimitive_traceflags & J2D_PTRACE_TIME) {
+        J2dTracePrimitive("OGLTR_DrawGlyphList");
+        time = J2dTraceNanoTime();
+    }
 
     RETURN_IF_NULL(oglc);
     RETURN_IF_NULL(dstOps);
@@ -1136,10 +1115,7 @@
         }
 
         if (ginfo->rowBytes == ginfo->width) {
-            if (lcdOpened) {
-                lcdOpened = JNI_FALSE;
-                j2d_glEnd();
-            }
+            OGLMTVertexCache_disable();
             // grayscale or monochrome glyph data
             if (ginfo->width <= OGLTR_CACHE_CELL_WIDTH &&
                 ginfo->height <= OGLTR_CACHE_CELL_HEIGHT)
@@ -1149,22 +1125,12 @@
                 ok = OGLTR_DrawGrayscaleGlyphNoCache(oglc, ginfo, x, y);
             }
         } else if (ginfo->rowBytes == ginfo->width * 4) {
-            if (lcdOpened) {
-                lcdOpened = JNI_FALSE;
-                j2d_glEnd();
-            }
+            OGLMTVertexCache_disable();
             // color glyph data
             ok = OGLTR_DrawColorGlyphNoCache(oglc, ginfo, x, y);
         } else {
             // LCD-optimized glyph data
             jint rowBytesOffset = 0;
-            if (!hasLCDGlyphs) {
-                // Flush GPU buffers before processing first LCD glyph
-                hasLCDGlyphs = JNI_TRUE;
-                if (dstTextureID != 0) {
-                    j2d_glTextureBarrierNV();
-                }
-            }
 
             if (subPixPos) {
                 jint frac = (jint)((glyphx - x) * 3);
@@ -1174,29 +1140,16 @@
                 }
             }
 
-            // Flush GPU buffers before processing overlapping LCD glyphs on OSX
-            if (dstTextureID != 0 && ox1 > x) {
-                if (lcdOpened) {
-                    lcdOpened = JNI_FALSE;
-                    j2d_glEnd();
-                }
-                j2d_glTextureBarrierNV();
-            }
-
             if (rowBytesOffset == 0 &&
                 ginfo->width <= OGLTR_CACHE_CELL_WIDTH &&
                 ginfo->height <= OGLTR_CACHE_CELL_HEIGHT)
             {
-                ok = OGLTR_DrawLCDGlyphViaCache(oglc, dstOps,
-                                                ginfo, x, y,
+                ok = OGLTR_DrawLCDGlyphViaCache(oglc, dstOps, ginfo, x, y,
                                                 glyphCounter, totalGlyphs,
                                                 rgbOrder, lcdContrast,
-                                                dstTextureID, &lcdOpened);
+                                                dstTextureID);
             } else {
-                if (lcdOpened) {
-                    lcdOpened = JNI_FALSE;
-                    j2d_glEnd();
-                }
+                OGLMTVertexCache_disable();
                 ok = OGLTR_DrawLCDGlyphNoCache(oglc, dstOps,
                                                ginfo, x, y,
                                                rowBytesOffset,
@@ -1204,15 +1157,12 @@
                                                dstTextureID);
             }
         }
-
-        ox1 = x + ginfo->width;
         if (!ok) {
             break;
         }
     }
-    if (lcdOpened) {
-        j2d_glEnd();
-    }
+    OGLMTVertexCache_disable();
+    J2dTracePrimitiveTime("OGLTR_DrawGlyphList", time);
 }
 
 JNIEXPORT void JNICALL
diff --git a/src/share/native/sun/java2d/opengl/OGLVertexCache.c b/src/share/native/sun/java2d/opengl/OGLVertexCache.c
index cd2d60c..53c9a8a 100644
--- a/src/share/native/sun/java2d/opengl/OGLVertexCache.c
+++ b/src/share/native/sun/java2d/opengl/OGLVertexCache.c
@@ -27,9 +27,11 @@
 
 #include <stdlib.h>
 #include <string.h>
+#include <float.h>
 
 #include "sun_java2d_SunGraphics2D.h"
 
+#include "jni_util.h"
 #include "OGLPaints.h"
 #include "OGLVertexCache.h"
 
@@ -39,11 +41,28 @@
     jfloat dx, dy;
 } J2DVertex;
 
+// Multitexture vertex
+typedef struct _J2DMTVertex {
+    jfloat dx, dy;
+    jfloat tx0, ty0;
+    jfloat tx1, ty1;
+} J2DMTVertex;
+
 static J2DVertex *vertexCache = NULL;
 static jint vertexCacheIndex = 0;
 
+static J2DMTVertex *mtVertexCache = NULL;
+static jboolean mtVertexCacheEnabled = JNI_FALSE;
+static jboolean mtUseTxtBarrier = JNI_FALSE;
+static jint evenLCDGlyphInd = 0;
+static jint oddLCDGlyphInd = ODD_LCD_GLYPHS_OFFSET;
+static jint lcdGlyphInd = 0;
+static jfloat evenOx2 = FLT_MIN;
+static jfloat oddOx2 = FLT_MIN;
+
 static GLuint maskCacheTexID = 0;
 static jint maskCacheIndex = 0;
+static void OGLMTVertexCache_flush(jint mask);
 
 #define OGLVC_ADD_VERTEX(TX, TY, R, G, B, A, DX, DY) \
     do { \
@@ -66,6 +85,25 @@
         OGLVC_ADD_VERTEX(TX1, TY2, R, G, B, A, DX1, DY2); \
     } while (0)
 
+#define OGLMTVC_ADD_VERTEX(IND, DX, DY, TX0, TY0, TX1, TY1) \
+    do { \
+        J2DMTVertex *v = &mtVertexCache[IND++]; \
+        v->dx = DX; \
+        v->dy = DY; \
+        v->tx0 = TX0; \
+        v->ty0 = TY0; \
+        v->tx1 = TX1; \
+        v->ty1 = TY1; \
+    } while (0)
+
+#define OGLMTVC_ADD_QUAD(IND, DX1, DY1, DX2, DY2, TX1, TY1, TX2, TY2, DTX1, DTY1, DTX2, DTY2) \
+    do { \
+        OGLMTVC_ADD_VERTEX((IND), DX1, DY1, TX1, TY1, DTX1, DTY1); \
+        OGLMTVC_ADD_VERTEX((IND), DX2, DY1, TX2, TY1, DTX2, DTY1); \
+        OGLMTVC_ADD_VERTEX((IND), DX2, DY2, TX2, TY2, DTX2, DTY2); \
+        OGLMTVC_ADD_VERTEX((IND), DX1, DY2, TX1, TY2, DTX1, DTY2); \
+    } while (0)
+
 jboolean
 OGLVertexCache_InitVertexCache(OGLContext *oglc)
 {
@@ -287,4 +325,97 @@
                    oglc->r, oglc->g, oglc->b, oglc->a);
 }
 
+jboolean OGLMTVertexCache_enable(OGLContext *oglc, jboolean useTxtBarrier) {
+     mtUseTxtBarrier = useTxtBarrier;
+    if (mtVertexCache == NULL) {
+        mtVertexCache = (J2DMTVertex *)malloc(OGLMTVC_MAX_INDEX * sizeof(J2DMTVertex));
+        if (mtVertexCache == NULL) {
+            return JNI_FALSE;
+        }
+    }
+
+    if (!mtVertexCacheEnabled) {
+        oglc->vertexCacheEnabled = JNI_FALSE;
+
+        j2d_glVertexPointer(2, GL_FLOAT, sizeof(J2DMTVertex), &mtVertexCache[0].dx);
+        j2d_glEnableClientState(GL_VERTEX_ARRAY);
+        j2d_glClientActiveTexture(GL_TEXTURE1_ARB);
+        j2d_glTexCoordPointer(2, GL_FLOAT, sizeof(J2DMTVertex), &mtVertexCache[0].tx1);
+        j2d_glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+        j2d_glClientActiveTexture(GL_TEXTURE0_ARB);
+        j2d_glTexCoordPointer(2, GL_FLOAT, sizeof(J2DMTVertex), &mtVertexCache[0].tx0);
+        j2d_glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+        mtVertexCacheEnabled = JNI_TRUE;
+        evenLCDGlyphInd = 0;
+        oddLCDGlyphInd = ODD_LCD_GLYPHS_OFFSET;
+        lcdGlyphInd = 0;
+    }
+
+    return JNI_TRUE;
+}
+void OGLMTVertexCache_disable() {
+    if (mtVertexCacheEnabled) {
+        OGLMTVertexCache_flush(OGLMTVC_FLUSH_ALL);
+        mtVertexCacheEnabled = JNI_FALSE;
+    }
+}
+
+void OGLMTVertexCache_flush(jint mask) {
+    if (mtVertexCacheEnabled) {
+        if ((mask & OGLMTVC_FLUSH_EVEN) && evenLCDGlyphInd > 0) {
+            if (mtUseTxtBarrier) {
+                // TextureBarrierNV() will guarantee that writes have completed
+                // and caches have been invalidated before subsequent Draws are
+                // executed
+                j2d_glTextureBarrierNV();
+                evenOx2 = FLT_MIN;
+            }
+            j2d_glDrawArrays(GL_QUADS, 0, evenLCDGlyphInd);
+            evenLCDGlyphInd = 0;
+        }
+
+        if ((mask & OGLMTVC_FLUSH_ODD) && oddLCDGlyphInd > ODD_LCD_GLYPHS_OFFSET) {
+            if (mtUseTxtBarrier) {
+                // See the comment above
+                j2d_glTextureBarrierNV();
+                oddOx2 = FLT_MIN;
+            }
+            j2d_glDrawArrays(GL_QUADS, ODD_LCD_GLYPHS_OFFSET,
+                             oddLCDGlyphInd - ODD_LCD_GLYPHS_OFFSET);
+            oddLCDGlyphInd = ODD_LCD_GLYPHS_OFFSET;
+        }
+    }
+}
+
+void OGLMTVertexCache_addGlyphQuad(jfloat dx1, jfloat dy1,
+                                   jfloat dx2, jfloat dy2,
+                                   jfloat tx1, jfloat ty1,
+                                   jfloat tx2, jfloat ty2,
+                                   jfloat dtx1, jfloat dty1,
+                                   jfloat dtx2, jfloat dty2)
+{
+    jint* ind;
+    if (lcdGlyphInd & 0x1) {
+        if (oddLCDGlyphInd >= OGLMTVC_MAX_INDEX ||
+            (mtUseTxtBarrier && oddOx2 >= dx1))
+        {
+            OGLMTVertexCache_flush(OGLMTVC_FLUSH_ODD);
+        } else if (mtUseTxtBarrier) {
+            oddOx2 = dx2;
+        }
+        ind = &oddLCDGlyphInd;
+    } else {
+        if (evenLCDGlyphInd >= ODD_LCD_GLYPHS_OFFSET ||
+            (mtUseTxtBarrier && evenOx2 >= dx1))
+        {
+            OGLMTVertexCache_flush(OGLMTVC_FLUSH_EVEN);
+        } else if (mtUseTxtBarrier) {
+            evenOx2 = dx2;
+        }
+        ind = &evenLCDGlyphInd;
+    }
+    lcdGlyphInd++;
+    OGLMTVC_ADD_QUAD(*ind, dx1, dy1, dx2, dy2, tx1, ty1, tx2, ty2, dtx1, dty1, dtx2, dty2);
+}
+
 #endif /* !HEADLESS */
diff --git a/src/share/native/sun/java2d/opengl/OGLVertexCache.h b/src/share/native/sun/java2d/opengl/OGLVertexCache.h
index ef41893..5572daa 100644
--- a/src/share/native/sun/java2d/opengl/OGLVertexCache.h
+++ b/src/share/native/sun/java2d/opengl/OGLVertexCache.h
@@ -30,9 +30,14 @@
 #include "OGLContext.h"
 
 /**
- * Constants that control the size of the vertex cache.
+ * Constants that control the size of the vertex caches.
  */
 #define OGLVC_MAX_INDEX         1024
+#define OGLMTVC_MAX_INDEX       2048
+#define ODD_LCD_GLYPHS_OFFSET   (OGLMTVC_MAX_INDEX >> 1)
+#define OGLMTVC_FLUSH_EVEN      1
+#define OGLMTVC_FLUSH_ODD       2
+#define OGLMTVC_FLUSH_ALL       3
 
 /**
  * Constants that control the size of the texture tile cache used for
@@ -83,4 +88,14 @@
                                  jfloat dx1, jfloat dy1,
                                  jfloat dx2, jfloat dy2);
 
+jboolean OGLMTVertexCache_enable(OGLContext *oglc, jboolean useTxtBarrier);
+void OGLMTVertexCache_addGlyphQuad(jfloat dx1, jfloat dy1,
+                                   jfloat dx2, jfloat dy2,
+                                   jfloat tx1, jfloat ty1,
+                                   jfloat tx2, jfloat ty2,
+                                   jfloat dtx1, jfloat dty1,
+                                   jfloat dtx2, jfloat dty2);
+void OGLMTVertexCache_disable();
+
+
 #endif /* OGLVertexCache_h_Included */
diff --git a/src/solaris/classes/sun/awt/X11/XBaseWindow.java b/src/solaris/classes/sun/awt/X11/XBaseWindow.java
index 1cea1ee..2648f1a 100644
--- a/src/solaris/classes/sun/awt/X11/XBaseWindow.java
+++ b/src/solaris/classes/sun/awt/X11/XBaseWindow.java
@@ -586,7 +586,11 @@
     public void toFront() {
         XToolkit.awtLock();
         try {
-            XlibWrapper.XRaiseWindow(XToolkit.getDisplay(), getWindow());
+            if (Boolean.parseBoolean(System.getProperty("com.jetbrains.suppressWindowRaise", "false"))) {
+                XlibWrapper.XLowerWindow(XToolkit.getDisplay(), getWindow());
+            } else {
+                XlibWrapper.XRaiseWindow(XToolkit.getDisplay(), getWindow());
+            }
         } finally {
             XToolkit.awtUnlock();
         }
diff --git a/src/solaris/classes/sun/awt/X11/XWindowPeer.java b/src/solaris/classes/sun/awt/X11/XWindowPeer.java
index d85781b..12fad95 100644
--- a/src/solaris/classes/sun/awt/X11/XWindowPeer.java
+++ b/src/solaris/classes/sun/awt/X11/XWindowPeer.java
@@ -1398,7 +1398,11 @@
              */
             XToolkit.awtLock();
             try {
-                XlibWrapper.XRaiseWindow(XToolkit.getDisplay(), getWindow());
+                if (Boolean.parseBoolean(System.getProperty("com.jetbrains.suppressWindowRaise", "false"))) {
+                    XlibWrapper.XLowerWindow(XToolkit.getDisplay(), getWindow());
+                } else {
+                    XlibWrapper.XRaiseWindow(XToolkit.getDisplay(), getWindow());
+                }
             } finally {
                 XToolkit.awtUnlock();
             }
@@ -2013,7 +2017,11 @@
             this.visible = visible;
             if (visible) {
                 applyWindowType();
-                XlibWrapper.XMapRaised(XToolkit.getDisplay(), getWindow());
+                if (Boolean.parseBoolean(System.getProperty("com.jetbrains.suppressWindowRaise", "false"))) {
+                    XlibWrapper.XMapWindow(XToolkit.getDisplay(), getWindow());
+                } else {
+                    XlibWrapper.XMapRaised(XToolkit.getDisplay(), getWindow());
+                }
             } else {
                 XlibWrapper.XUnmapWindow(XToolkit.getDisplay(), getWindow());
             }
diff --git a/src/windows/native/sun/windows/awt.h b/src/windows/native/sun/windows/awt.h
index 1b8bd52..74fae22 100644
--- a/src/windows/native/sun/windows/awt.h
+++ b/src/windows/native/sun/windows/awt.h
@@ -44,14 +44,18 @@
 
 extern COLORREF DesktopColor2RGB(int colorIndex);
 
-#ifndef _WIN32_WINNT_WINBLUE
+
+//#ifndef _WIN32_WINNT_WINBLUE
+// TODO: What is about ShellScalingAPI.h
 typedef enum _PROCESS_DPI_AWARENESS {
     PROCESS_DPI_UNAWARE            = 0,
     PROCESS_SYSTEM_DPI_AWARE       = 1,
     PROCESS_PER_MONITOR_DPI_AWARE  = 2
 } PROCESS_DPI_AWARENESS;
-#endif
+//#endif
 
+
+/*
 #ifndef _WIN32_WINNT_WIN10
 typedef enum _DPI_AWARENESS {
     DPI_AWARENESS_INVALID            = -1,
@@ -59,12 +63,14 @@
     DPI_AWARENESS_SYSTEM_AWARE       = 1,
     DPI_AWARENESS_PER_MONITOR_AWARE  = 2
 } DPI_AWARENESS;
-
+*/
 typedef BOOL(EnableNonClientDpiScalingFunc)(HWND);
-#endif
+//#endif
 
 // val >= 0 todo [tav] until switch to VS'12
+#if (_MSC_VER < 1700)
 #define round(val) floor(val + 0.5)
+#endif
 
 class AwtObject;
 typedef AwtObject* PDATA;
@@ -198,7 +204,7 @@
 #define LO_INT(l)           ((int)(short)(l))
 #define HI_INT(l)           ((int)(short)(((DWORD)(l) >> 16) & 0xFFFF))
 
-extern JavaVM *jvm;
+extern "C" JavaVM *jvm;
 
 // Platform encoding is Unicode (UTF-16), re-define JNU_ functions
 // to proper JNI functions.
diff --git a/src/windows/native/sun/windows/awt_Component.cpp b/src/windows/native/sun/windows/awt_Component.cpp
index f8dc397..0c0592b 100644
--- a/src/windows/native/sun/windows/awt_Component.cpp
+++ b/src/windows/native/sun/windows/awt_Component.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, 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
@@ -3878,29 +3878,44 @@
     ::ClientToScreen(hTop, &p);
     int sx = ScaleUpDX(x) - p.x;
     int sy = ScaleUpDY(y) - p.y;
+    if (!m_bitsCandType) {
+        SetCandidateWindow(m_bitsCandType, sx, sy);
+        return;
+    }
     for (int iCandType=0; iCandType<32; iCandType++, bits<<=1) {
         if ( m_bitsCandType & bits )
             SetCandidateWindow(iCandType, sx, sy);
     }
-    if (m_bitsCandType != 0) {
-        // REMIND: is there any chance GetProxyFocusOwner() returns NULL here?
-        ::DefWindowProc(ImmGetHWnd(),
-                        WM_IME_NOTIFY, IMN_OPENCANDIDATE, m_bitsCandType);
-    }
 }
 
 void AwtComponent::SetCandidateWindow(int iCandType, int x, int y)
 {
     HWND hwnd = ImmGetHWnd();
     HIMC hIMC = ImmGetContext(hwnd);
-    CANDIDATEFORM cf;
-    cf.dwIndex = iCandType;
-    cf.dwStyle = CFS_CANDIDATEPOS;
-    cf.ptCurrentPos.x = x;
-    cf.ptCurrentPos.y = y;
-
-    ImmSetCandidateWindow(hIMC, &cf);
-    ImmReleaseContext(hwnd, hIMC);
+    if (hIMC) {
+        CANDIDATEFORM cf;
+        cf.dwStyle = CFS_POINT;
+        ImmGetCandidateWindow(hIMC, 0, &cf);
+        if (x != cf.ptCurrentPos.x || y != cf.ptCurrentPos.y) {
+            cf.dwIndex = iCandType;
+            cf.dwStyle = CFS_POINT;
+            cf.ptCurrentPos.x = x;
+            cf.ptCurrentPos.y = y;
+            cf.rcArea.left = cf.rcArea.top = cf.rcArea.right = cf.rcArea.bottom = 0;
+            ImmSetCandidateWindow(hIMC, &cf);
+        }
+        COMPOSITIONFORM cfr;
+        cfr.dwStyle = CFS_POINT;
+        ImmGetCompositionWindow(hIMC, &cfr);
+        if (x != cfr.ptCurrentPos.x || y != cfr.ptCurrentPos.y) {
+            cfr.dwStyle = CFS_POINT;
+            cfr.ptCurrentPos.x = x;
+            cfr.ptCurrentPos.y = y;
+            cfr.rcArea.left = cfr.rcArea.top = cfr.rcArea.right = cfr.rcArea.bottom = 0;
+            ImmSetCompositionWindow(hIMC, &cfr);
+        }
+        ImmReleaseContext(hwnd, hIMC);
+    }
 }
 
 MsgRouting AwtComponent::WmImeSetContext(BOOL fSet, LPARAM *lplParam)
@@ -3927,10 +3942,15 @@
 
 MsgRouting AwtComponent::WmImeNotify(WPARAM subMsg, LPARAM bitsCandType)
 {
-    if (!m_useNativeCompWindow && subMsg == IMN_OPENCANDIDATE) {
-        m_bitsCandType = bitsCandType;
-        InquireCandidatePosition();
-        return mrConsume;
+    if (!m_useNativeCompWindow) {
+        if (subMsg == IMN_OPENCANDIDATE || subMsg == IMN_CHANGECANDIDATE) {
+            m_bitsCandType = bitsCandType;
+            InquireCandidatePosition();
+        } else if (subMsg == IMN_OPENSTATUSWINDOW ||
+                   subMsg == WM_IME_STARTCOMPOSITION ||
+                   subMsg == IMN_SETCANDIDATEPOS) {
+            InquireCandidatePosition();
+        }
     }
     return mrDoDefault;
 }
@@ -4189,14 +4209,14 @@
     return (HWND)NULL;
 }
 
-/* Call DefWindowProc for the focus proxy, if any */
+/* Redirects message to the focus proxy, if any */
 void AwtComponent::CallProxyDefWindowProc(UINT message, WPARAM wParam,
     LPARAM lParam, LRESULT &retVal, MsgRouting &mr)
 {
     if (mr != mrConsume)  {
         HWND proxy = GetProxyFocusOwner();
         if (proxy != NULL && ::IsWindowEnabled(proxy)) {
-            retVal = ComCtl32Util::GetInstance().DefWindowProc(NULL, proxy, message, wParam, lParam);
+            retVal = ::DefWindowProc(proxy, message, wParam, lParam);
             mr = mrConsume;
         }
     }
diff --git a/test/java/awt/hidpi/ClientAreaOriginWindowsTest.java b/test/java/awt/hidpi/ClientAreaOriginWindowsTest.java
index 5dd1bcc..bf539dc 100644
--- a/test/java/awt/hidpi/ClientAreaOriginWindowsTest.java
+++ b/test/java/awt/hidpi/ClientAreaOriginWindowsTest.java
@@ -43,16 +43,15 @@
  *                    ClientAreaOriginWindowsTest
  */
 //
-// Note, -Dsun.java2d.d3d=false is the current IDEA (ver. 181) mode.
+// Notes:
+// 1) -Dsun.java2d.d3d=false is the current IDEA (ver. 181) mode.
+// 2) The JDK build should contain the fix for JRE-573 for the test to pass.
 //
 public class ClientAreaOriginWindowsTest {
     static final int F_WIDTH = 300;
     static final int F_HEIGHT = 200;
 
     static final Color COLOR_BG = Color.green;
-    // WIth older JBSDK (not containing the fix for JRE-573) the frame's background isn't set correctly.
-    // To let the test work correctly with it, use WHITE bg as well.
-    static final Color COLOR_BG_FALLBACK = Color.white;
     static final Color COLOR_OUTLINE = Color.red;
     static final Color COLOR_FG = Color.blue;
 
@@ -104,7 +103,7 @@
                     Color c = new Color(capture.getRGB(x, y));
                     hasOutline = c.equals(COLOR_OUTLINE) || hasOutline;
                     // assuming the frame's border system color is not COLOR_BG/COLOR_BG_FALLBACK.
-                    hasBg = c.equals(COLOR_BG) || c.equals(COLOR_BG_FALLBACK) || hasBg;
+                    hasBg = c.equals(COLOR_BG) || hasBg;
                     hasFg = c.equals(COLOR_FG) || hasFg;
                 }
                 String axis = isXaxis ? "X-axis" : "Y-axis";
diff --git a/test/javax/swing/RepaintManager/8197499/RepaintManagerDoubleBufferMaximumSize.java b/test/javax/swing/RepaintManager/8197499/RepaintManagerDoubleBufferMaximumSize.java
new file mode 100644
index 0000000..1949ec2
--- /dev/null
+++ b/test/javax/swing/RepaintManager/8197499/RepaintManagerDoubleBufferMaximumSize.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2000-2018 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JTextArea;
+import javax.swing.RepaintManager;
+import javax.swing.SwingUtilities;
+import javax.swing.WindowConstants;
+
+/*
+ * @test
+ * @bug 8197499
+ * @summary RepaintManager does not increase double buffer after attaching a display with higher resolution
+ * @run main/manual RepaintManagerDoubleBufferMaximumSize
+ */
+
+public class RepaintManagerDoubleBufferMaximumSize {
+
+    private static JFrame frame = new JFrame();
+    private static JTextArea textArea = new JTextArea();
+
+    private static void createAndShowGUI() {
+        textArea = new JTextArea(5, 20);
+        textArea.setEditable(false);
+
+        JButton button = new JButton("Attach 4K display and click here to watch DoubleBufferMaximumSize");
+        button.addActionListener(e -> doTest());
+
+        frame = new JFrame("DoubleBufferMaximumSize  test");
+        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+        frame.setSize(600, 300);
+        frame.add("Center", textArea);
+        frame.add("South", button);
+
+        frame.setVisible(true);
+    }
+
+    private static void doTest() {
+        RepaintManager repaintManager = RepaintManager.currentManager(frame);
+        textArea.append("DoubleBufferMaximumSize: " + repaintManager.getDoubleBufferMaximumSize() + "\n");
+    }
+
+    public static void main(String[] args) throws Exception {
+        SwingUtilities.invokeAndWait(RepaintManagerDoubleBufferMaximumSize::createAndShowGUI);
+        doTest();
+    }
+}
diff --git a/test/jb/javax/crypto/Cipher/GetMaxAllowed638.java b/test/jb/javax/crypto/Cipher/GetMaxAllowed638.java
new file mode 100644
index 0000000..bf2721c
--- /dev/null
+++ b/test/jb/javax/crypto/Cipher/GetMaxAllowed638.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2000-2018 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import javax.crypto.Cipher;
+
+/*
+ * @test
+ * @summary JRE-638 It checks unlimited cryptographic policy was enabled for JBRE by default
+ * @run main/othervm GetMaxAllowed638
+ */
+
+public class GetMaxAllowed638 {
+
+    public static void main(String[] args) throws Exception {
+
+        int maxKey = Cipher.getMaxAllowedKeyLength("RC5");
+        if ( maxKey < Integer.MAX_VALUE) {
+            System.out.println("Cipher.getMaxAllowedKeyLength(\"RC5\"): " + maxKey);
+            throw new RuntimeException("unlimited policy is set by default, "
+                    + Integer.MAX_VALUE + "(Integer.MAX_VALUE) is expected");
+        }
+    }
+}
diff --git a/test/jb/javax/swing/JDialog/JDialog392.java b/test/jb/javax/swing/JDialog/JDialog392.java
index 2ef3224..a640306 100644
--- a/test/jb/javax/swing/JDialog/JDialog392.java
+++ b/test/jb/javax/swing/JDialog/JDialog392.java
@@ -156,7 +156,7 @@
                 int expectedRGB = screenImage.getRGB((int) (shotSize.getWidth() / 2), (int) (shotSize.getHeight() / 2)) & 0x00FFFFFF;
 
                 for (int col = 1; col < shotSize.getWidth(); col++) {
-                    for (int row = 1; row < shotSize.getHeight(); row++) {
+                    for (int row = 1; row < shotSize.getHeight()/2; row++) {
                         try {
                             // remove transparance
                             rgb = screenImage.getRGB(col, row) & 0x00FFFFFF;
diff --git a/test/jb/javax/swing/JDialog/JDialog705.java b/test/jb/javax/swing/JDialog/JDialog705.java
new file mode 100644
index 0000000..9a606ea
--- /dev/null
+++ b/test/jb/javax/swing/JDialog/JDialog705.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2000-2018 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import javax.imageio.ImageIO;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.Popup;
+import javax.swing.PopupFactory;
+import javax.swing.RootPaneContainer;
+import javax.swing.SwingUtilities;
+import java.awt.AWTException;
+import java.awt.Color;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Rectangle;
+import java.awt.Robot;
+import java.awt.Window;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+
+/* @test
+ * @summary regression test on JRE-705 Z-order of child windows is broken on Mac OS
+ * @run main/othervm JDialog705
+ */
+
+public class JDialog705 {
+
+    private static Robot robot;
+    static {
+        try {
+            robot = new Robot();
+        } catch (AWTException e1) {
+            e1.printStackTrace();
+        }
+    }
+
+    private static JFrame jFrame;
+    private static Window windowAncestor;
+    private static JDialog modalBlocker;
+
+    public static void main(String[] args) throws Exception {
+
+        SwingUtilities.invokeAndWait(() -> {
+            jFrame = new JFrame("Wrong popup z-order");
+            jFrame.setSize(200, 200);
+
+            JPanel jPanel = new JPanel();
+            jPanel.setPreferredSize(new Dimension(200, 200));
+            jPanel.setBackground(Color.BLACK);
+
+            Popup popup = PopupFactory.getSharedInstance().getPopup(jFrame, jPanel, 100, 100);
+            windowAncestor = SwingUtilities.getWindowAncestor(jPanel);
+            ((RootPaneContainer) windowAncestor).getRootPane().putClientProperty("SIMPLE_WINDOW", true);
+            windowAncestor.setFocusable(true);
+            windowAncestor.setFocusableWindowState(true);
+            windowAncestor.setAutoRequestFocus(true);
+
+            jFrame.setVisible(true);
+            popup.show();
+
+
+            modalBlocker = new JDialog(windowAncestor, "Modal Blocker");
+            modalBlocker.setModal(true);
+            modalBlocker.setSize(new Dimension(200, 200));
+            modalBlocker.setLocation(200, 200);
+            modalBlocker.addWindowListener(new DialogListener());
+
+            modalBlocker.setVisible(true);
+        });
+    }
+
+    private static boolean checkImage(Container window, Dimension shotSize, int x, int y, int maxWidth, int maxHeight) {
+
+        boolean result = true;
+
+        System.out.println("checking for expectedX: " + x + "; expectedY: " + y);
+        System.out.println("              maxWidth: " + maxWidth + ";  maxHeight: " + maxHeight);
+
+        Rectangle captureRect = new Rectangle(window.getLocationOnScreen(), shotSize);
+        BufferedImage screenImage = robot.createScreenCapture(captureRect);
+
+        int rgb;
+        int expectedRGB = screenImage.getRGB(x, y) & 0x00FFFFFF;
+
+        System.out.println("  expected rgb value: " + Integer.toHexString(expectedRGB));
+        for (int col = 1; col < maxWidth; col++) {
+            for (int row = 1; row < maxHeight; row++) {
+                // remove transparance
+                rgb = screenImage.getRGB(col, row) & 0x00FFFFFF;
+
+                result = (expectedRGB == rgb);
+                if (expectedRGB != rgb) {
+                    System.out.println("at row: " + row + "; col: " + col);
+                    System.out.println("  expected rgb value: " + Integer.toHexString(expectedRGB));
+                    System.out.println("    actual rgb value: " + Integer.toHexString(rgb));
+                    break;
+                }
+            }
+            if (!result) break;
+        }
+
+        try {
+            ImageIO.write(screenImage, "bmp", new File("test705" + window.getName() + ".bmp"));
+        } catch (IOException e1) {
+            e1.printStackTrace();
+        }
+
+        return result;
+    }
+
+    static class DialogListener implements WindowListener {
+
+        @Override
+        public void windowClosing(WindowEvent e) {
+
+        }
+
+        @Override
+        public void windowClosed(WindowEvent e) {
+
+        }
+
+        @Override
+        public void windowIconified(WindowEvent e) {
+
+        }
+
+        @Override
+        public void windowDeiconified(WindowEvent e) {
+
+        }
+
+        @Override
+        public void windowActivated(WindowEvent e) {
+
+        }
+
+        @Override
+        public void windowDeactivated(WindowEvent e) {
+
+        }
+
+        @Override
+        public void windowOpened(WindowEvent windowEvent) {
+
+            try {
+                Thread.sleep(1000);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+
+            Dimension shotSize;
+
+            shotSize = windowAncestor.getSize();
+            int expectedX = (int) (shotSize.getWidth() / 4);
+            int expectedY = (int) (shotSize.getHeight() / 4);
+            int maxWidth = (int) (shotSize.getWidth() / 2);
+            int maxHeight = (int) (shotSize.getHeight() / 2);
+            boolean popupRes = checkImage(windowAncestor, shotSize, expectedX, expectedY, maxWidth, maxHeight);
+
+            shotSize = modalBlocker.getContentPane().getSize();
+            expectedX = (int) (shotSize.getWidth() / 2 + shotSize.getWidth() / 4);
+            expectedY = (int) (shotSize.getHeight() / 2 + shotSize.getHeight() / 4);
+            maxWidth = (int) (shotSize.getWidth());
+            maxHeight = (int) (shotSize.getHeight());
+            boolean modalBlockerRes = checkImage(modalBlocker.getContentPane(), shotSize, expectedX,
+                    expectedY, maxWidth, maxHeight);
+
+            String msg = "";
+
+            if (!popupRes) msg = "The popup must be above the frame.";
+            if (!modalBlockerRes) msg += "The modal blocker must be above the popup.";
+
+            if (!popupRes || !modalBlockerRes)
+                throw new RuntimeException(msg);
+
+            modalBlocker.dispose();
+            jFrame.dispose();
+        }
+    }
+}
diff --git a/test/jb/javax/swing/JDialog/JDialog741/JDialog741.html b/test/jb/javax/swing/JDialog/JDialog741/JDialog741.html
new file mode 100644
index 0000000..f17d8be
--- /dev/null
+++ b/test/jb/javax/swing/JDialog/JDialog741/JDialog741.html
@@ -0,0 +1,33 @@
+<!--
+ Copyright 2000-2018 JetBrains s.r.o.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<html>
+<!--
+  @test
+  @summary regression test on JRE-741  Modal dialog stays above other process windows.
+  @run applet JDialog741.html
+  -->
+<head>
+    <title>  </title>
+</head>
+<body>
+
+<h1>Modal dialog stays above other process windows<br>Bug ID: JRE-741</h1>
+
+<p> This is an AUTOMATIC test, simply wait for completion </p>
+
+<APPLET CODE="JDialog741.class" WIDTH=200 HEIGHT=200></APPLET>
+</body>
+</html>
diff --git a/test/jb/javax/swing/JDialog/JDialog741/JDialog741.java b/test/jb/javax/swing/JDialog/JDialog741/JDialog741.java
new file mode 100644
index 0000000..a053ed5
--- /dev/null
+++ b/test/jb/javax/swing/JDialog/JDialog741/JDialog741.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright 2000-2018 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import javax.imageio.ImageIO;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.Popup;
+import javax.swing.PopupFactory;
+import javax.swing.RootPaneContainer;
+import javax.swing.SwingUtilities;
+import javax.swing.WindowConstants;
+import java.applet.Applet;
+import java.awt.AWTException;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Rectangle;
+import java.awt.Robot;
+import java.awt.Window;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class JDialog741 extends Applet {
+
+    private static JFrame jFrame;
+    private static Window windowAncestor;
+    private static JDialog modalBlocker;
+
+    public void start() {
+
+        System.setProperty("jbre.popupwindow.settype", "true");
+
+        jFrame = new JFrame("Wrong popup z-order");
+        jFrame.setSize(200, 200);
+        jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+
+        JPanel jPanel = new JPanel();
+        jPanel.setPreferredSize(new Dimension(200, 200));
+
+        Popup popup = PopupFactory.getSharedInstance().getPopup(jFrame, jPanel, 100, 100);
+        windowAncestor = SwingUtilities.getWindowAncestor(jPanel);
+        ((RootPaneContainer) windowAncestor).getRootPane().putClientProperty("SIMPLE_WINDOW", true);
+        windowAncestor.setFocusable(true);
+        windowAncestor.setFocusableWindowState(true);
+        windowAncestor.setAutoRequestFocus(true);
+
+        jFrame.setVisible(true);
+        popup.show();
+
+
+        modalBlocker = new JDialog(windowAncestor, "Modal Blocker");
+        modalBlocker.setModal(true);
+        modalBlocker.setSize(new Dimension(200, 200));
+        modalBlocker.setLocation(200, 200);
+        modalBlocker.addWindowListener(new JDialog741Listener());
+        modalBlocker.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
+
+        modalBlocker.setVisible(true);
+    }
+
+    static class JDialog741Listener extends DialogListener {
+
+        private static String printStream(String msg, InputStream stream) throws IOException {
+
+            String result = "";
+            int count = stream.available();
+            if (count > 0) {
+                byte[] b = new byte[count];
+                stream.read(b);
+                System.out.println("========= " + msg + " ========");
+                result = new String(b);
+                System.out.print(result);
+                System.out.println("======================================");
+            }
+            return result;
+        }
+
+        @Override
+        public void windowOpened(WindowEvent windowEvent) {
+
+            try {
+                Thread.sleep(1000);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+
+            String anotherAppMsg = "";
+            boolean appFailed = false;
+
+            try {
+                String javaPath = System.getProperty("java.home", "");
+                String command = javaPath + File.separator + "bin" +
+                        File.separator + "java -cp " + System.getProperty("test.classes", ".") +
+                        " AnotherApp";
+
+                Process process = Runtime.getRuntime().exec(command);
+                int returnCode = process.waitFor();
+
+                printStream("AnotherApp System.out", process.getInputStream());
+
+                String serr = printStream("AnotherApp System.err", process.getErrorStream());
+
+                if (!serr.isEmpty()) {
+                    String[] lines = serr.split("\\n");
+                    for (String s : lines) {
+                        if (s.contains("RuntimeException")) {
+                            anotherAppMsg = s.split(":")[1];
+                        }
+                    }
+                    appFailed = true;
+                }
+
+                System.out.println("return code: " + returnCode);
+
+                jFrame.dispose();
+                windowAncestor.dispose();
+                modalBlocker.dispose();
+
+            } catch (IOException | InterruptedException e) {
+                e.printStackTrace();
+                throw new RuntimeException(e);
+            }
+
+            if (appFailed && !anotherAppMsg.isEmpty())
+                throw new RuntimeException(anotherAppMsg);
+            else
+                throw new RuntimeException("AnotherApp failed");
+
+        }
+    }
+
+}
+
+class AnotherApp {
+
+    private static Robot robot;
+
+    static {
+        try {
+            robot = new Robot();
+        } catch (AWTException e1) {
+            e1.printStackTrace();
+        }
+    }
+
+    private static JFrame jFrame = new JFrame("Another application");
+
+    public static void main(String[] args) throws Exception {
+
+        SwingUtilities.invokeAndWait(() -> {
+            jFrame.setSize(500, 500);
+            jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+            jFrame.addWindowListener(new AnotherAppListener());
+            jFrame.setVisible(true);
+        });
+    }
+
+    private static boolean checkImage(Container window, Dimension shotSize, int x, int y, int maxWidth, int maxHeight) {
+
+        boolean result = true;
+
+        System.out.println("checking for expectedX: " + x + "; expectedY: " + y);
+        System.out.println("              maxWidth: " + maxWidth + ";  maxHeight: " + maxHeight);
+
+        Rectangle captureRect = new Rectangle(window.getLocationOnScreen(), shotSize);
+        BufferedImage screenImage = robot.createScreenCapture(captureRect);
+
+        try {
+            ImageIO.write(screenImage, "bmp", new File("test741" + window.getName() + ".bmp"));
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
+        int rgb;
+        int expectedRGB = screenImage.getRGB(x, y) & 0x00FFFFFF;
+
+        System.out.println("  expected rgb value: " + Integer.toHexString(expectedRGB));
+        for (int col = 1; col < maxWidth; col++) {
+            for (int row = 1; row < maxHeight; row++) {
+                // remove transparance
+                rgb = screenImage.getRGB(col, row) & 0x00FFFFFF;
+
+                result = (expectedRGB == rgb);
+                if (expectedRGB != rgb) {
+                    System.out.println("at row: " + row + "; col: " + col);
+                    System.out.println("  expected rgb value: " + Integer.toHexString(expectedRGB));
+                    System.out.println("    actual rgb value: " + Integer.toHexString(rgb));
+                    break;
+                }
+            }
+            if (!result) break;
+        }
+
+        return result;
+    }
+
+    static class AnotherAppListener extends DialogListener {
+
+        @Override
+        public void windowOpened(WindowEvent windowEvent) {
+            try {
+                Thread.sleep(1000);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+
+            Dimension shotSize;
+
+            Container contentPane = jFrame.getContentPane();
+            shotSize = contentPane.getSize();
+            int expectedX = (int) (shotSize.getWidth() * 3 / 4);
+            int expectedY = (int) (shotSize.getHeight() / 4);
+            int maxWidth = (int) (shotSize.getWidth());
+            int maxHeight = (int) (shotSize.getHeight());
+
+            boolean failed = !checkImage(contentPane, shotSize, expectedX, expectedY, maxWidth, maxHeight);
+
+            jFrame.dispose();
+            if (failed) throw new RuntimeException("AnotherApp must be above all windows");
+        }
+    }
+}
+
+abstract class DialogListener implements WindowListener {
+
+    @Override
+    public void windowClosing(WindowEvent e) {
+
+    }
+
+    @Override
+    public void windowClosed(WindowEvent e) {
+
+    }
+
+    @Override
+    public void windowIconified(WindowEvent e) {
+
+    }
+
+    @Override
+    public void windowDeiconified(WindowEvent e) {
+
+    }
+
+    @Override
+    public void windowActivated(WindowEvent e) {
+
+    }
+
+    @Override
+    public void windowDeactivated(WindowEvent e) {
+
+    }
+}
diff --git a/test/jb/sun/lwawt/macosx/LWCToolkit/lwctoolkit.sh b/test/jb/sun/lwawt/macosx/LWCToolkit/lwctoolkit.sh
index 43447f1..aa088ac 100755
--- a/test/jb/sun/lwawt/macosx/LWCToolkit/lwctoolkit.sh
+++ b/test/jb/sun/lwawt/macosx/LWCToolkit/lwctoolkit.sh
@@ -66,10 +66,19 @@
 ${TESTJAVA}/bin/java -XX:+ExtendedDTraceProbes -cp ${TESTCLASSES} LWCToolkit ${ITERATIONS} &
 TEST_PID=$!
 
-DTRACE_OUTPUT=$(echo ${BUPWD} | sudo -S ${DTRACE} -q -p${TEST_PID} -s ${TESTSRC}/lwctoolkit.d | grep "LWCToolkit" | grep " invokeAndWait")
+DTRACE_OUTPUT=$(echo ${BUPWD} | sudo -S ${DTRACE} -p${TEST_PID} -s ${TESTSRC}/lwctoolkit.d)
+echo "=dtrace output==========================="
 echo $DTRACE_OUTPUT
+echo "========================================="
 
-count=$(echo ${DTRACE_OUTPUT} | awk {'print $3'})
+METHOD_LINE=$(echo ${DTRACE_OUTPUT} | grep "LWCToolkit" | grep " invokeAndWait")
+
+if [ -z "${METHOD_LINE}" ]; then
+  echo "LWCToolkit.invokeAndWait is not contained in dtrace's output"
+  count=0
+else
+  count=$(echo ${METHOD_LINE} | awk {'print $3'})
+fi
 
 if [ "${count}" -lt "100" ]; then
     echo "Test PASSED"
diff --git a/test/jbProblemsList.txt b/test/jbProblemsList.txt
index 0451e79..d4d83d3 100644
--- a/test/jbProblemsList.txt
+++ b/test/jbProblemsList.txt
@@ -89,574 +89,212 @@
 
 # jdk_awt
 
-# https://bugs.openjdk.java.net/browse/JDK-8169106
-java/awt/Choice/ChoiceKeyEventReaction/ChoiceKeyEventReaction.html       generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-7100044
-java/awt/Choice/ChoiceMouseWheelTest/ChoiceMouseWheelTest.java           generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169108
-java/awt/Choice/ItemStateChangeTest/ItemStateChangeTest.java             windows-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8047703
-java/awt/Choice/RemoveAllShrinkTest/RemoveAllShrinkTest.java             generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-7105576
-java/awt/Component/F10TopToplevel/F10TopToplevel.html                    windows-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169104
-java/awt/Component/PaintAll/PaintAll.java                                windows-all
-
-https://bugs.openjdk.java.net/browse/JDK-6857809
-java/awt/Component/PrintAllXcheckJNI/PrintAllXcheckJNI.java              linux-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8165863
-java/awt/Component/SetEnabledPerformance/SetEnabledPerformance.java      macosx-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8170261
-java/awt/Component/TreeLockDeadlock/TreeLockDeadlock.java                generic-all
-
-## https://bugs.openjdk.java.net/browse/JDK-8017456
-# the fix was integrated
-#java/awt/DataFlavor/MissedHtmlAndRtfBug/MissedHtmlAndRtfBug.html         generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8171909
-# https://bugs.openjdk.java.net/browse/JDK-8169589
-java/awt/Dialog/DialogAboveFrame/DialogAboveFrameTest.java               generic-all
-
-## https://bugs.openjdk.java.net/browse/JDK-8081469
-# https://bugs.openjdk.java.net/browse/JDK-7054586
-java/awt/Dialog/MakeWindowAlwaysOnTop/MakeWindowAlwaysOnTop.java         generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-6990210
-java/awt/EventDispatchThread/HandleExceptionOnEDT/HandleExceptionOnEDT.java generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8073636
-java/awt/EventDispatchThread/LoopRobustness/LoopRobustness.html          generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8168390
-java/awt/EventDispatchThread/PreserveDispathThread/PreserveDispatchThread.java generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8131670
-java/awt/EventQueue/6980209/bug6980209.java                              generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-7149081
-java/awt/FileDialog/FilenameFilterTest/FilenameFilterTest.html           generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8029675
-java/awt/Focus/6981400/Test1.java                                        generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8173264
-java/awt/Focus/6981400/Test3.java                                        generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8196186
-java/awt/FullScreen/BufferStrategyExceptionTest/BufferStrategyExceptionTest.java generic-all
-
-## https://bugs.openjdk.java.net/browse/JDK-8013611
-# https://bugs.openjdk.java.net/browse/JDK-8175366
-java/awt/Focus/8013611/JDK8013611.java                                   generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8136517
-java/awt/Focus/8073453/AWTFocusTransitionTest.java                       generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8081301
-java/awt/Focus/8073453/SwingFocusTransitionTest.java                     generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8168408
-java/awt/Focus/ActualFocusedWindowTest/ActualFocusedWindowBlockingTest.java generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-6862004
-java/awt/Focus/AppletInitialFocusTest/AppletInitialFocusTest.html        generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-6849367
-java/awt/Focus/AppletInitialFocusTest/AppletInitialFocusTest1.html       generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-6848407
-java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusSetVisibleTest.java  generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-6848406
-java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusToFrontTest.java     generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-6829264
-java/awt/Focus/ActualFocusedWindowTest/ActualFocusedWindowRetaining.java generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169103
-java/awt/Focus/ChoiceFocus/ChoiceFocus.java                              generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8078413
-java/awt/Focus/ClearLwQueueBreakTest/ClearLwQueueBreakTest.java          generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-7124555
-java/awt/Focus/CloseDialogActivateOwnerTest/CloseDialogActivateOwnerTest.java generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-6986252
-java/awt/Focus/ConsumeNextKeyTypedOnModalShowTest/ConsumeNextKeyTypedOnModalShowTest.java generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8015886
-java/awt/Focus/DeiconifiedFrameLoosesFocus/DeiconifiedFrameLoosesFocus.html generic-all
-
-## https://bugs.openjdk.java.net/browse/JDK-8169101
-# java/awt/Focus/FocusEmbeddedFrameTest/FocusEmbeddedFrameTest.java        windows-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8081489
-java/awt/Focus/FocusOwnerFrameOnClick/FocusOwnerFrameOnClick.java        generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-6849364
-java/awt/Focus/IconifiedFrameFocusChangeTest/IconifiedFrameFocusChangeTest.java generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8053932
-java/awt/Focus/KeyEventForBadFocusOwnerTest/KeyEventForBadFocusOwnerTest.java generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-7152980
-java/awt/Focus/NoAutotransferToDisabledCompTest/NoAutotransferToDisabledCompTest.java generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8151979
-java/awt/Focus/NonFocusableWindowTest/NonfocusableOwnerTest.java         generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169110
-java/awt/Focus/OwnedWindowFocusIMECrashTest/OwnedWindowFocusIMECrashTest.java  generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8168294
-java/awt/Focus/ResetMostRecentFocusOwnerTest/ResetMostRecentFocusOwnerTest.java generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8028701
-java/awt/Focus/ShowFrameCheckForegroundTest/ShowFrameCheckForegroundTest.java generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8159599
-java/awt/Focus/SimpleWindowActivationTest/SimpleWindowActivationTest.java generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-7156130
-java/awt/Focus/ToFrontFocusTest/ToFrontFocus.html                        generic-all
-
-# http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6848810
-# https://bugs.openjdk.java.net/browse/JDK-7035459
-java/awt/Focus/TranserFocusToWindow/TranserFocusToWindow.java        generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-6986253
-java/awt/Focus/TypeAhead/TestFocusFreeze.java                        generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169100
-java/awt/Focus/WindowInitialFocusTest/WindowInitialFocusTest.html    windows-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169099
-java/awt/Focus/WindowIsFocusableAccessByThreadsTest/WindowIsFocusableAccessByThreadsTest.java generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169096
-java/awt/Focus/WrongKeyTypedConsumedTest/WrongKeyTypedConsumedTest.java generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-6868690
-java/awt/FontClass/CreateFont/bigfont.html                           generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8076151
-java/awt/FontClass/CreateFont/fileaccess/FontFile.java               generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169111
-java/awt/Frame/InvisibleOwner/InvisibleOwner.java                    generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169472
-java/awt/Frame/LayoutOnMaximizeTest/LayoutOnMaximizeTest.java        windows-all
-
-# excluded from regular runs since the test was not run
-# see http://download.java.net/openjdk/testresults/8/
-java/awt/Frame/UnfocusableMaximizedFrameResizablity/UnfocusableMaximizedFrameResizablity.java generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169470
-java/awt/Frame/WindowDragTest/WindowDragTest.java                    generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169471
-java/awt/FullScreen/8013581/bug8013581.java                          generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8047218
-java/awt/FullScreen/AltTabCrashTest/AltTabCrashTest.java             generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169469
-java/awt/FullScreen/DisplayChangeVITest/DisplayChangeVITest.java     windows-all
-
-# https://bugs.openjdk.java.net/browse/JDK-7019055
-java/awt/FullScreen/FullScreenInsets/FullScreenInsets.java           windows-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169468
-java/awt/FullScreen/NoResizeEventOnDMChangeTest/NoResizeEventOnDMChangeTest.java windows-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8012224
-java/awt/Frame/MaximizedToIconified/MaximizedToIconified.java        generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8144030
-java/awt/Frame/ShapeNotSetSometimes/ShapeNotSetSometimes.java        generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-7019055
-java/awt/FullScreen/FullScreenInsets/FullScreenInsets.java           generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8016241
-java/awt/FullScreen/SetFSWindow/FSFrame.java                         generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8153299
-java/awt/Graphics/CopyScaledArea/CopyScaledAreaTest.java             generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8080084
-java/awt/Graphics2D/DrawString/DrawStringCrash.java                  generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-7043153
-java/awt/Graphics2D/DrawString/RotTransText.java                     generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169464
-java/awt/Graphics2D/DrawString/TextRenderingTest.java                windows-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169463
-java/awt/Graphics2D/FillTexturePaint/FillTexturePaint.java           windows-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169462
-java/awt/Graphics2D/FlipDrawImage/FlipDrawImage.java                 windows-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8145808
-java/awt/Graphics2D/MTGraphicsAccessTest/MTGraphicsAccessTest.java   generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8054638
-java/awt/Graphics2D/WhiteTextColorTest.java                          generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8000171
-java/awt/GridLayout/LayoutExtraGaps/LayoutExtraGaps.java             windows-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8170729
-java/awt/JAWT/JAWT.sh                                                windows-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8158380
-java/awt/KeyboardFocusmanager/TypeAhead/SubMenuShowTest/SubMenuShowTest.html generic-all
-
-## https://bugs.openjdk.java.net/browse/JDK-8073639
-# https://bugs.openjdk.java.net/browse/JDK-8074807
-java/awt/KeyboardFocusmanager/TypeAhead/TestDialogTypeAhead.html     generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8163261
-java/awt/LightweightDispatcher/LWDispatcherMemoryLeakTest.java       generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169461
-java/awt/List/FirstItemRemoveTest/FirstItemRemoveTest.html           windows-all
-
-## https://bugs.openjdk.java.net/browse/JDK-6561487
-# https://bugs.openjdk.java.net/browse/JDK-7125471
-java/awt/List/NofocusListDblClickTest/NofocusListDblClickTest.java   generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-7037728
-java/awt/Menu/OpensWithNoGrab/OpensWithNoGrab.java                   linux-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8068305
-java/awt/Mixing/HWDisappear.java                                     generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8143295
-java/awt/Mixing/LWPopupMenu.java                                     generic-all
-
-## https://bugs.openjdk.java.net/browse/JDK-6885735
-#java/awt/Mixing/MixingInHwPanel.java                                 generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-4049668
-java/awt/Mixing/MixingOnDialog.java                                  generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169460
-java/awt/Mixing/MixingOnShrinkingHWButton.java                       generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-7124549
-java/awt/Mixing/NonOpaqueInternalFrame.java                          macosx-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169457
-# https://bugs.openjdk.java.net/browse/JDK-7124549
-java/awt/Mixing/OpaqueTest.java                                      generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-7124549
-java/awt/Mixing/OverlappingButtons.java                              generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8165619
-java/awt/Mixing/ValidBounds.java                                     generic-all
-java/awt/Mixing/Validating.java                                      generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8177323
-java/awt/Modal/LWModalTest/LWModalTest.java                          macosx-all
-
-## https://bugs.openjdk.java.net/browse/JDK-8029024
-# https://bugs.openjdk.java.net/browse/JDK-8066259
-java/awt/Modal/ModalDialogOrderingTest/ModalDialogOrderingTest.java  generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8159599
-java/awt/Modal/ModalInternalFrameTest/ModalInternalFrameTest.java    generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8052166
-java/awt/Mouse/MouseComboBoxTest/MouseComboBoxTest.java              generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8023562
-java/awt/Mouse/EnterExitEvents/DragWindowOutOfFrameTest.java         generic-all
-java/awt/Mouse/EnterExitEvents/DragWindowTest.java                   generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8165619
-java/awt/Mouse/EnterExitEvents/ModalDialogEnterExitEventsTest.java   generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169534
-java/awt/Mouse/ExtraMouseClick/ExtraMouseClick.html                  generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8051455
-java/awt/Mouse/EnterExitEvents/FullscreenEnterEventTest.java         macosx-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8144042
-java/awt/Mouse/EnterExitEvents/ResizingFrameTest.java                generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8168388
-java/awt/Mouse/GetMousePositionTest/GetMousePositionWithOverlay.java generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8027154
-java/awt/Mouse/GetMousePositionTest/GetMousePositionWithPopup.java   generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8132766
-java/awt/Mouse/MaximizedFrameTest/MaximizedFrameTest.html            macosx-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8129775
-java/awt/Mouse/MouseDragEvent/MouseDraggedTest.java                  generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8013428
-java/awt/Mouse/MouseModifiersUnitTest/ExtraButtonDrag.java           generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8130471
-java/awt/Mouse/MouseModifiersUnitTest/MouseModifiersUnitTest_Extra.java linux-all
-
-# https://bugs.openjdk.java.net/browse/JDK-7124407
-java/awt/Mouse/MouseModifiersUnitTest/MouseModifiersUnitTest_Standard.java macosx-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8157170
-java/awt/Mouse/RemovedComponentMouseListener/RemovedComponentMouseListener.java generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8148041
-java/awt/Mouse/TitleBarDoubleClick/TitleBarDoubleClick.html          generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8012577
-java/awt/MouseAdapter/MouseAdapterUnitTest/MouseAdapterUnitTest.java generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8130741
-# https://bugs.openjdk.java.net/browse/JDK-8158798
-java/awt/MouseInfo/GetPointerInfoTest.java                           generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8028484
-java/awt/MouseInfo/JContainerMousePositionTest.java                  generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-7124230
-java/awt/Multiscreen/LocationRelativeToTest/LocationRelativeToTest.java macosx-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8077686
-java/awt/Multiscreen/LocationRelativeToTest/LocationRelativeToTest.java   linux-all
-java/awt/event/TextEvent/TextEventSequenceTest/TextEventSequenceTest.java linux-all
-javax/swing/JComboBox/8015300/Test8015300.java                            linux-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8139581
-java/awt/Paint/ComponentIsNotDrawnAfterRemoveAddTest/ComponentIsNotDrawnAfterRemoveAddTest.java generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169104
-java/awt/Paint/ExposeOnEDT.java                                      windows-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8028000
-java/awt/Paint/PaintNativeOnUpdate.java                              generic-all
+java/awt/Choice/ChoiceKeyEventReaction/ChoiceKeyEventReaction.html                  8169106 windows-all,macosx-all
+java/awt/Choice/ChoiceMouseWheelTest/ChoiceMouseWheelTest.java                      7100044 windows-all,macosx-all
+java/awt/Choice/ItemStateChangeTest/ItemStateChangeTest.java                        8169108 windows-all
+java/awt/Choice/RemoveAllShrinkTest/RemoveAllShrinkTest.java                        8047703 generic-all
+java/awt/Component/F10TopToplevel/F10TopToplevel.html                               7105576 windows-all
+java/awt/Component/PaintAll/PaintAll.java                                           8169104 windows-all
+java/awt/Component/PrintAllXcheckJNI/PrintAllXcheckJNI.java                         6857809 linux-all
+java/awt/Component/SetEnabledPerformance/SetEnabledPerformance.java                 8165863 macosx-all
+java/awt/Component/TreeLockDeadlock/TreeLockDeadlock.java                           8170261 generic-all
+java/awt/Dialog/DialogAboveFrame/DialogAboveFrameTest.java                          8169589,8171909 generic-all
+java/awt/Dialog/MakeWindowAlwaysOnTop/MakeWindowAlwaysOnTop.java                    7054586 generic-all
+java/awt/EventDispatchThread/HandleExceptionOnEDT/HandleExceptionOnEDT.java         6990210 generic-all
+java/awt/EventDispatchThread/LoopRobustness/LoopRobustness.html                     8168390 generic-all
+java/awt/EventDispatchThread/PreserveDispathThread/PreserveDispatchThread.java      8168390 generic-all
+java/awt/EventQueue/6980209/bug6980209.java                                         8198615 windows-all,macosx-all
+java/awt/FileDialog/FilenameFilterTest/FilenameFilterTest.html                      7149081 generic-all
+java/awt/Focus/6981400/Test1.java                                                   8029675 windows-all,macosx-all
+java/awt/Focus/6981400/Test3.java                                                   8173264 generic-all
+java/awt/FullScreen/BufferStrategyExceptionTest/BufferStrategyExceptionTest.java    8196186 generic-all
+java/awt/Focus/8013611/JDK8013611.java                                              8175366 windows-all,macosx-all
+java/awt/Focus/8073453/AWTFocusTransitionTest.java                                  8136517 windows-all,macosx-all
+java/awt/Focus/8073453/SwingFocusTransitionTest.java                                8081301 generic-all
+java/awt/Focus/ActualFocusedWindowTest/ActualFocusedWindowBlockingTest.java         8168408 windows-all,macosx-all
+java/awt/Focus/AppletInitialFocusTest/AppletInitialFocusTest.html                   6862004 generic-all
+java/awt/Focus/AppletInitialFocusTest/AppletInitialFocusTest1.html                  6849367 generic-all
+java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusSetVisibleTest.java             6848407 generic-all
+java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusToFrontTest.java                6848406 generic-all
+java/awt/Focus/ActualFocusedWindowTest/ActualFocusedWindowRetaining.java            6829264 generic-all
+java/awt/Focus/ChoiceFocus/ChoiceFocus.java                                         8169103 windows-all,macosx-all
+java/awt/Focus/ClearLwQueueBreakTest/ClearLwQueueBreakTest.java                     8198618 macosx-all
+java/awt/Focus/CloseDialogActivateOwnerTest/CloseDialogActivateOwnerTest.java       7124555 generic-all
+java/awt/Focus/ConsumeNextKeyTypedOnModalShowTest/ConsumeNextKeyTypedOnModalShowTest.java 6986252 macosx-all
+java/awt/Focus/DeiconifiedFrameLoosesFocus/DeiconifiedFrameLoosesFocus.html         8015886 generic-all
+java/awt/Focus/FocusOwnerFrameOnClick/FocusOwnerFrameOnClick.java                   8081489 generic-all
+java/awt/Focus/IconifiedFrameFocusChangeTest/IconifiedFrameFocusChangeTest.java     6849364 generic-all
+java/awt/Focus/KeyEventForBadFocusOwnerTest/KeyEventForBadFocusOwnerTest.java       8198621 macosx-all,windows-all
+java/awt/Focus/NoAutotransferToDisabledCompTest/NoAutotransferToDisabledCompTest.java 7152980 macosx-all,windows-all
+java/awt/Focus/NonFocusableWindowTest/NonfocusableOwnerTest.java                    8151979 generic-all
+java/awt/Focus/OwnedWindowFocusIMECrashTest/OwnedWindowFocusIMECrashTest.java       8169110 generic-all
+java/awt/Focus/ResetMostRecentFocusOwnerTest/ResetMostRecentFocusOwnerTest.java     8168294 generic-all
+java/awt/Focus/ShowFrameCheckForegroundTest/ShowFrameCheckForegroundTest.java       8028701 macosx-all,windows-all,linux-all
+java/awt/Focus/SimpleWindowActivationTest/SimpleWindowActivationTest.java           8159599 macosx-all,windows-all
+java/awt/Focus/ToFrontFocusTest/ToFrontFocus.html                                   7156130 generic-all
+java/awt/Focus/TranserFocusToWindow/TranserFocusToWindow.java                       7035459,6848810 generic-all
+java/awt/Focus/TypeAhead/TestFocusFreeze.java                                       8198622 macosx-all,windows-all,linux-all
+java/awt/Focus/WindowInitialFocusTest/WindowInitialFocusTest.html                   8169100 windows-all
+java/awt/Focus/WindowIsFocusableAccessByThreadsTest/WindowIsFocusableAccessByThreadsTest.java 8169099 generic-all
+java/awt/Focus/WrongKeyTypedConsumedTest/WrongKeyTypedConsumedTest.java             8169096 macosx-all,windows-all
+java/awt/FontClass/CreateFont/bigfont.html                                          6868690 generic-all
+java/awt/FontClass/CreateFont/fileaccess/FontFile.java                              8076151 generic-all
+java/awt/Frame/InvisibleOwner/InvisibleOwner.java                                   8169111 generic-all
+java/awt/Frame/LayoutOnMaximizeTest/LayoutOnMaximizeTest.java                       8169472 windows-all
+java/awt/Frame/UnfocusableMaximizedFrameResizablity/UnfocusableMaximizedFrameResizablity.java 7158623 macosx-all
+java/awt/Frame/WindowDragTest/WindowDragTest.java                                   8169470 generic-all
+java/awt/FullScreen/8013581/bug8013581.java                                         8169471 generic-all
+java/awt/FullScreen/AltTabCrashTest/AltTabCrashTest.java                            8047218 generic-all
+java/awt/FullScreen/DisplayChangeVITest/DisplayChangeVITest.java                    7179818,8169469 windows-all,linux-all,macosx-all
+java/awt/FullScreen/FullScreenInsets/FullScreenInsets.java                          7019055 windows-all
+java/awt/FullScreen/NoResizeEventOnDMChangeTest/NoResizeEventOnDMChangeTest.java    8169468 windows-all
+java/awt/Frame/MaximizedToIconified/MaximizedToIconified.java                       8012224 generic-all
+java/awt/Frame/ShapeNotSetSometimes/ShapeNotSetSometimes.java                       8144030 macosx-all,windows-all,linux-all
+java/awt/FullScreen/FullScreenInsets/FullScreenInsets.java                          7019055 generic-all
+java/awt/FullScreen/SetFSWindow/FSFrame.java                                        8016241 generic-all
+java/awt/Graphics/CopyScaledArea/CopyScaledAreaTest.java                            8153299 generic-all
+java/awt/Graphics2D/DrawString/DrawStringCrash.java                                 8080084 generic-all
+java/awt/Graphics2D/DrawString/RotTransText.java                                    8197797 generic-all
+java/awt/Graphics2D/DrawString/TextRenderingTest.java                               8169464 windows-all
+java/awt/Graphics2D/FillTexturePaint/FillTexturePaint.java                          8169463 windows-all
+java/awt/Graphics2D/FlipDrawImage/FlipDrawImage.java                                8169462 windows-all
+java/awt/Graphics2D/MTGraphicsAccessTest/MTGraphicsAccessTest.java                  8145808 generic-all
+java/awt/Graphics2D/WhiteTextColorTest.java                                         8054638 generic-all
+java/awt/GridLayout/LayoutExtraGaps/LayoutExtraGaps.java                            8000171 windows-all
+java/awt/JAWT/JAWT.sh                                                               8197798 windows-all
+java/awt/KeyboardFocusmanager/TypeAhead/SubMenuShowTest/SubMenuShowTest.html        8158380,8198624 generic-all
+java/awt/KeyboardFocusmanager/TypeAhead/TestDialogTypeAhead.html                    8198626,8074807 generic-all
+java/awt/LightweightDispatcher/LWDispatcherMemoryLeakTest.java                      8163261 generic-all
+java/awt/List/FirstItemRemoveTest/FirstItemRemoveTest.html                          8169461 windows-all
+java/awt/List/NofocusListDblClickTest/NofocusListDblClickTest.java                  7125471 generic-all
+java/awt/Menu/OpensWithNoGrab/OpensWithNoGrab.java                                  7037728 linux-all
+java/awt/Mixing/HWDisappear.java                                                    8068305 generic-all
+java/awt/Mixing/LWPopupMenu.java                                                    8143295 generic-all
+java/awt/Mixing/MixingOnDialog.java                                                 4049668 generic-all
+java/awt/Mixing/MixingOnShrinkingHWButton.java                                      8169460 linux-all,windows-all,macosx-all
+java/awt/Mixing/NonOpaqueInternalFrame.java                                         7124549,JRE-720 macosx-all,windows-all
+java/awt/Mixing/OpaqueTest.java                                                     7124549,8169457 generic-all
+java/awt/Mixing/OverlappingButtons.java                                             7124549 generic-all
+java/awt/Mixing/ValidBounds.java                                                    8165619 generic-all
+java/awt/Mixing/Validating.java                                                     8165619 generic-all
+java/awt/Modal/LWModalTest/LWModalTest.java                                         8177323 macosx-all
+java/awt/Modal/ModalDialogOrderingTest/ModalDialogOrderingTest.java                 8066259 generic-all
+java/awt/Modal/ModalInternalFrameTest/ModalInternalFrameTest.java                   8159599 generic-all
+java/awt/Mouse/MouseComboBoxTest/MouseComboBoxTest.java                             8052166 generic-all
+java/awt/Mouse/EnterExitEvents/DragWindowOutOfFrameTest.java                        8023562 macosx-all,windows-all
+java/awt/Mouse/EnterExitEvents/DragWindowTest.java                                  8023562 macosx-all,windows-all
+java/awt/Mouse/EnterExitEvents/ModalDialogEnterExitEventsTest.java                  8165619 generic-all
+java/awt/Mouse/ExtraMouseClick/ExtraMouseClick.html                                 8169534 generic-all
+java/awt/Mouse/EnterExitEvents/FullscreenEnterEventTest.java                        8051455 macosx-all
+java/awt/Mouse/EnterExitEvents/ResizingFrameTest.java                               8144042 generic-all
+java/awt/Mouse/GetMousePositionTest/GetMousePositionWithOverlay.java                8168388 generic-all
+java/awt/Mouse/GetMousePositionTest/GetMousePositionWithPopup.java                  8027154 linux-all,windows-all,macosx-all
+java/awt/Mouse/MaximizedFrameTest/MaximizedFrameTest.html                           8132766 macosx-all
+java/awt/Mouse/MouseDragEvent/MouseDraggedTest.java                                 8129775 generic-all
+java/awt/Mouse/MouseModifiersUnitTest/ExtraButtonDrag.java                          8013428 generic-all
+java/awt/Mouse/MouseModifiersUnitTest/MouseModifiersUnitTest_Extra.java             8130471 linux-all
+java/awt/Mouse/MouseModifiersUnitTest/MouseModifiersUnitTest_Standard.java          7124407 macosx-all
+java/awt/Mouse/RemovedComponentMouseListener/RemovedComponentMouseListener.java     8157170 macosx-all,windows-all
+java/awt/Mouse/TitleBarDoubleClick/TitleBarDoubleClick.html                         8148041 generic-all
+java/awt/MouseAdapter/MouseAdapterUnitTest/MouseAdapterUnitTest.java                8012577 generic-all
+java/awt/MouseInfo/GetPointerInfoTest.java                                          8130741,8158798 generic-all
+java/awt/MouseInfo/JContainerMousePositionTest.java                                 8028484 generic-all
+java/awt/Multiscreen/LocationRelativeToTest/LocationRelativeToTest.java             7124230 macosx-all
+java/awt/Multiscreen/MultiScreenInsetsTest/MultiScreenInsetsTest.java               8134669 linux-all
+java/awt/Multiscreen/MultiScreenLocationTest/MultiScreenLocationTest.java           8155744 linux-all
+java/awt/event/TextEvent/TextEventSequenceTest/TextEventSequenceTest.java           8077686 linux-all
+javax/swing/JComboBox/8015300/Test8015300.java                                      8077686 linux-all
+java/awt/Paint/ComponentIsNotDrawnAfterRemoveAddTest/ComponentIsNotDrawnAfterRemoveAddTest.java 8139581 generic-all
+java/awt/Paint/ExposeOnEDT.java                                                     8169104 windows-all
+java/awt/Paint/PaintNativeOnUpdate.java                                             8028000 generic-all
 
 # https://bugs.openjdk.java.net/browse/JDK-8031422
 #the test fails with the applied fix
-java/awt/Paint/bug8024864.java                                       generic-all
+#java/awt/Paint/bug8024864.java                                       generic-all
 
 # excluded from regular runs since the test was not run
 # see http://download.java.net/openjdk/testresults/8/
-java/awt/ScrollPane/ScrollPanePreferredSize/ScrollPanePreferredSize.java  generic-all
-java/awt/ScrollPane/bug8077409Test.java                              generic-all
+#java/awt/ScrollPane/ScrollPanePreferredSize/ScrollPanePreferredSize.java  generic-all
+#java/awt/ScrollPane/bug8077409Test.java                              generic-all
 
-# https://bugs.openjdk.java.net/browse/JDK-8140329
-java/awt/SplashScreen/FullscreenAfterSplash/FullScreenAfterSplash.java generic-all
+java/awt/SplashScreen/FullscreenAfterSplash/FullScreenAfterSplash.java              8140329 generic-all
+java/awt/SplashScreen/MultiResolutionSplash/MultiResolutionSplashTest.java          8159592,8061235 macosx-all,windows-all,linux-all
+java/awt/TextField/SelectionInvisibleTest/SelectionInvisibleTest.java               8169533 generic-all
+java/awt/TextArea/Mixing/TextAreaMixing.java                                        8198234 generic-all
+java/awt/TextArea/UsingWithMouse/SelectionAutoscrollTest.html                       6734341 generic-all
+java/awt/Toolkit/ScreenInsetsTest/ScreenInsetsTest.java                             6829250 windows-all,macosx-all
+java/awt/Toolkit/ToolkitPropertyTest/ToolkitPropertyTest_Enable.java                6847163 generic-all
+java/awt/TrayIcon/PopupMenuLeakTest/PopupMenuLeakTest.java                          8039081 generic-all
+java/awt/Robot/AcceptExtraMouseButtons/AcceptExtraMouseButtons.java                 7107528 generic-all
 
-# https://bugs.openjdk.java.net/browse/JDK-8159592
-java/awt/SplashScreen/MultiResolutionSplash/MultiResolutionSplashTest.java generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169533
-java/awt/TextField/SelectionInvisibleTest/SelectionInvisibleTest.java generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8198234
-java/awt/TextArea/Mixing/TextAreaMixing.java                         generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-6734341
-java/awt/TextArea/UsingWithMouse/SelectionAutoscrollTest.html        generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-6829250
-java/awt/Toolkit/ScreenInsetsTest/ScreenInsetsTest.java              generic-all
-
-## https://bugs.openjdk.java.net/browse/JDK-6829267
-# https://bugs.openjdk.java.net/browse/JDK-6847163
-java/awt/Toolkit/ToolkitPropertyTest/ToolkitPropertyTest_Enable.java generic-all
-
-# http://bugs.java.com/view_bug.do?bug_id=8039081
-java/awt/TrayIcon/PopupMenuLeakTest/PopupMenuLeakTest.java           generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-7107528
-java/awt/Robot/AcceptExtraMouseButtons/AcceptExtraMouseButtons.java  generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-7081594
 # fixed in 8_112
-java/awt/Window/AlwaysOnTop/AlwaysOnTopFieldTest.java                macosx-all
+java/awt/Window/AlwaysOnTop/AlwaysOnTopFieldTest.java                               7081594 macosx-all
 
-# https://bugs.openjdk.java.net/browse/JDK-8198739
-ava/awt/Window/AlwaysOnTop/SyncAlwaysOnTopFieldTest.java             windows-all
+java/awt/Window/AlwaysOnTop/SyncAlwaysOnTopFieldTest.java                           8198739 windows-all
+java/awt/Window/AlwaysOnTop/TestAlwaysOnTopBeforeShow.java                          8032450,8169530 generic-all
+java/awt/Window/BackgroundIsNotUpdated/BackgroundIsNotUpdated.java                  8142536 generic-all
+java/awt/Window/Grab/GrabTest.java                                                  8047703 generic-all
+java/awt/Window/GrabSequence/GrabSequence.java                                      6848409 macosx-all,windows-all,linux-all
+java/awt/Window/WindowsLeak/WindowsLeak.java                                        8028486 macosx-all
+java/awt/Window/WindowType/WindowType.java                                          8051857 linux-all
+java/awt/Focus/RequestFocusAndHideTest/RequestFocusAndHideTest.java                 8051857 generic-all
+java/awt/List/SetBackgroundTest/SetBackgroundTest.java                              8051857 linux-all
+java/awt/List/SingleModeDeselect/SingleModeDeselect.java                            8196367 linux-all
+java/awt/datatransfer/DragImage/MultiResolutionDragImageTest.java                   8080982 generic-all
 
-# https://bugs.openjdk.java.net/browse/JDK-8169530
-# https://bugs.openjdk.java.net/browse/JDK-8032450
-java/awt/Window/AlwaysOnTop/TestAlwaysOnTopBeforeShow.java           generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8142536
-java/awt/Window/BackgroundIsNotUpdated/BackgroundIsNotUpdated.java   generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8047703
-java/awt/Window/Grab/GrabTest.java                                   generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-6848409
-java/awt/Window/GrabSequence/GrabSequence.java                       generic-all
-
-#
-java/awt/Window/OwnedWindowsLeak/OwnedWindowsLeak.java
-
-https://bugs.openjdk.java.net/browse/JDK-8028486
-java/awt/Window/WindowsLeak/WindowsLeak.java                         macosx-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8051857
-java/awt/Window/WindowType/WindowType.java                           linux-all
-java/awt/Focus/RequestFocusAndHideTest/RequestFocusAndHideTest.java  generic-all
-java/awt/List/SetBackgroundTest/SetBackgroundTest.java               linux-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8196367
-java/awt/List/SingleModeDeselect/SingleModeDeselect.java             linux-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8080982
-java/awt/datatransfer/DragImage/MultiResolutionDragImageTest.java    generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8017457
-java/awt/datatransfer/DragUnicodeBetweenJVMTest/DragUnicodeBetweenJVMTest.html windows-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8039082
-java/awt/dnd/BadSerializaionTest/BadSerializationTest.java           generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8144056
-java/awt/dnd/Button2DragTest/Button2DragTest.html                    generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8066096
-java/awt/dnd/DragInterceptorAppletTest/DragInterceptorAppletTest.html generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8029680
-java/awt/dnd/DropTargetEnterExitTest/ExtraDragEnterTest.java         generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8029680
-java/awt/dnd/DropTargetEnterExitTest/MissedDragExitTest.java         generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-7098447
-java/awt/dnd/ImageTransferTest/ImageTransferTest.java                generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-7124379
-java/awt/dnd/FileListBetweenJVMsTest/FileListBetweenJVMsTest.html    generic-all
-java/awt/dnd/URIListBetweenJVMsTest/URIListBetweenJVMsTest.html      generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8030121
-java/awt/dnd/MissingDragExitEventTest/MissingDragExitEventTest.java  generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8164464
-java/awt/dnd/MissingEventsOnModalDialog/MissingEventsOnModalDialogTest.java generic-all
-
-## https://bugs.openjdk.java.net/browse/JDK-7109239
-#java/awt/dnd/NoFormatsCrashTest/NoFormatsCrashTest.html              generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8072088
-java/awt/dnd/ImageDecoratedDnDNegative/ImageDecoratedDnDNegative.html generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8011614
-java/awt/dnd/InterJVMGetDropSuccessTest/InterJVMGetDropSuccessTest.html generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8041431
-java/awt/dnd/URIListToFileListBetweenJVMsTest/URIListToFileListBetweenJVMsTest.html generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-6618538
-java/awt/event/HierarchyEvent/AncestorResized/AncestorResized.java   generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8168646
-java/awt/event/InputEvent/EventWhenTest/EventWhenTest.java           generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8158362
-java/awt/event/KeyEvent/AltCharAcceleratorTest/AltCharAcceleratorTest.java generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8145652
-java/awt/event/KeyEvent/DeadKey/DeadKeySystemAssertionDialog.java    generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-6626492
-java/awt/event/KeyEvent/CorrectTime/CorrectTime.java                 generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169476
-java/awt/event/KeyEvent/ExtendedKeyCode/ExtendedKeyCodeTest.java     generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169474
-java/awt/event/KeyEvent/KeyChar/KeyCharTest.java                     windows-all
-
-# https://bugs.openjdk.java.net/browse/JDK-7156316
-# https://bugs.openjdk.java.net/browse/JDK-8160623
-java/awt/event/KeyEvent/KeyTyped/CtrlASCII.html                      generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8032254
-java/awt/event/MouseEvent/EventTimeInFuture/EventTimeInFuture.java   linux-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8168389
-java/awt/event/MouseEvent/MouseClickTest/MouseClickTest.html         generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-6854300
-java/awt/event/MouseEvent/SpuriousExitEnter/SpuriousExitEnter_3.java generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8060176
-java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion.java   generic-all
-java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_1.java generic-all
-java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_2.html generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-6956646
-java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_4.java generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-6956646
-java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_3.html generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169475
-java/awt/event/MouseWheelEvent/WheelModifier/WheelModifier.java       generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-7043170
-java/awt/font/TextLayout/CombiningPerf.java                          generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-7162125
-java/awt/font/TextLayout/OSXLigatureTest.java                        macosx-all
+java/awt/datatransfer/DragUnicodeBetweenJVMTest/DragUnicodeBetweenJVMTest.html      8017457 windows-all
+java/awt/dnd/BadSerializaionTest/BadSerializationTest.java                          8039082 generic-all
+java/awt/dnd/Button2DragTest/Button2DragTest.html                                   8144056 generic-all
+java/awt/dnd/DragInterceptorAppletTest/DragInterceptorAppletTest.html               8066096 generic-all
+java/awt/dnd/DropTargetEnterExitTest/ExtraDragEnterTest.java                        8029680 generic-all
+java/awt/dnd/DropTargetEnterExitTest/MissedDragExitTest.java                        8029680 generic-all
+java/awt/dnd/ImageTransferTest/ImageTransferTest.java                               8176556 generic-all
+java/awt/dnd/FileListBetweenJVMsTest/FileListBetweenJVMsTest.html                   7124379 generic-all
+java/awt/dnd/URIListBetweenJVMsTest/URIListBetweenJVMsTest.html                     7124379,8171510,8201284 macosx-all,linux-all linux:7124379,8201284-macosx:7124379,8171510
+java/awt/dnd/MissingDragExitEventTest/MissingDragExitEventTest.java                 8030121 generic-all
+java/awt/dnd/MissingEventsOnModalDialog/MissingEventsOnModalDialogTest.java         8164464 linux-all,macosx-all,windows-all
+java/awt/dnd/ImageDecoratedDnDNegative/ImageDecoratedDnDNegative.html               8072088 generic-all
+java/awt/dnd/InterJVMGetDropSuccessTest/InterJVMGetDropSuccessTest.html             8011614 generic-all
+java/awt/dnd/URIListToFileListBetweenJVMsTest/URIListToFileListBetweenJVMsTest.html 8041431 generic-all
+java/awt/event/HierarchyEvent/AncestorResized/AncestorResized.java                  6618538 generic-all
+java/awt/event/InputEvent/EventWhenTest/EventWhenTest.java                          8168646 generic-all
+java/awt/event/KeyEvent/AltCharAcceleratorTest/AltCharAcceleratorTest.java          8158362 generic-all
+java/awt/event/KeyEvent/DeadKey/DeadKeySystemAssertionDialog.java                   8145652 generic-all
+java/awt/event/KeyEvent/CorrectTime/CorrectTime.java                                6626492 generic-all
+java/awt/event/KeyEvent/ExtendedKeyCode/ExtendedKeyCodeTest.java                    8169476 windows-all,macosx-all
+java/awt/event/KeyEvent/KeyChar/KeyCharTest.java                                    8169474 windows-all
+java/awt/event/KeyEvent/KeyTyped/CtrlASCII.html                                     7156316,8160623 generic-all
+java/awt/event/MouseEvent/EventTimeInFuture/EventTimeInFuture.java                  8032254 linux-all
+java/awt/event/MouseEvent/MouseClickTest/MouseClickTest.html                        8168389 windows-all,macosx-all
+java/awt/event/MouseEvent/SpuriousExitEnter/SpuriousExitEnter_3.java                6854300 generic-all
+java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion.java             8060176 windows-all,macosx-all
+java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_1.java           8060176 windows-all,macosx-all
+java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_2.html           8060176 windows-all,macosx-all,linux-all
+java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_4.java           6956646 generic-all
+java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_3.html           6956646 generic-all
+java/awt/event/MouseWheelEvent/WheelModifier/WheelModifier.java                     8169475 generic-all
+java/awt/font/TextLayout/CombiningPerf.java                                         8192931,7043170 generic-all
+java/awt/font/TextLayout/OSXLigatureTest.java                                       7162125 macosx-all
 
 # Test ignored: Requires a special font installed
 java/awt/font/TextLayout/TestOldHangul.java                          generic-all
 java/awt/font/TextLayout/TestTibetan.java                            generic-all
 
-# https://bugs.openjdk.java.net/browse/JDK-8164818
-java/awt/font/TextLayout/VisibleAdvance.java                         generic-all
+java/awt/font/TextLayout/VisibleAdvance.java                                        8164818 generic-all
 
-# https://bugs.openjdk.java.net/browse/JDK-8158356
 #affects runs (on OSX, causes the reopen dialog)
-java/awt/geom/AffineTransform/InvalidTransformParameterTest.java     generic-all
+java/awt/geom/AffineTransform/InvalidTransformParameterTest.java                   8158356 generic-all
 
-# https://bugs.openjdk.java.net/browse/JDK-7080150
-java/awt/grab/EmbeddedFrameTest1/EmbeddedFrameTest1.java             generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169109
-java/awt/grab/GrabOnUnfocusableToplevel/GrabOnUnfocusableToplevel.java generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8028000
-java/awt/image/DrawImage/EABlitTest.java                             generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8056077
-java/awt/image/DrawImage/IncorrectAlphaSurface2SW.java               linux-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169473
-java/awt/image/DrawImage/IncorrectBounds.java                        windows-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8130400
-java/awt/image/DrawImage/IncorrectClipXorModeSW2Surface.java         linux-all
-java/awt/image/DrawImage/IncorrectClipXorModeSurface2Surface.java    linux-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169951
-java/awt/image/DrawImage/IncorrectOffset.java                        windows-all
-java/awt/image/DrawImage/IncorrectDestinationOffset.java             windows-all
-java/awt/image/DrawImage/IncorrectSourceOffset.java                  windows-all
+java/awt/grab/EmbeddedFrameTest1/EmbeddedFrameTest1.java                           7080150,8203918 macosx-all,linux-all,windows-all
+java/awt/grab/GrabOnUnfocusableToplevel/GrabOnUnfocusableToplevel.java             8169109 generic-all
+java/awt/image/DrawImage/EABlitTest.java                                           8028000 generic-all
+java/awt/image/DrawImage/IncorrectAlphaSurface2SW.java                             8056077 generic-all
+java/awt/image/DrawImage/IncorrectBounds.java                                      8169473 windows-all
+java/awt/image/DrawImage/IncorrectClipXorModeSW2Surface.java                       8196025,8130400 linux-all,windows-all
+java/awt/image/DrawImage/IncorrectClipXorModeSurface2Surface.java                  8196025,8130400 linux-all,windows-all
+java/awt/image/DrawImage/IncorrectOffset.java                                      8169951 windows-all
+java/awt/image/DrawImage/IncorrectDestinationOffset.java                           8169951 windows-all
+java/awt/image/DrawImage/IncorrectSourceOffset.java                                8196086 windows-all
 
 # no printer found
 java/awt/print/PrinterJob/ExceptionTest.java                         generic-all
@@ -664,159 +302,116 @@
 java/awt/print/PrinterJob/PrtException.java                          generic-all
 java/awt/print/PrinterJob/PrintCrashTest.java                        generic-all
 
-# https://bugs.openjdk.java.net/browse/JDK-8152944
-https://bugs.openjdk.java.net/browse/JDK-8152944
-excluded from regular runs
-java/time/tck/java/time/TCKDayOfWeek.java                            generic-all
-java/time/tck/java/time/TCKDuration.java                             generic-all
-java/time/tck/java/time/TCKInstant.java                              generic-all
-java/time/tck/java/time/TCKLocalDate.java                            generic-all
-java/time/tck/java/time/TCKLocalDateTime.java                        generic-all
-java/time/tck/java/time/TCKLocalTime.java                            generic-all
-java/time/tck/java/time/TCKMonth.java                                generic-all
-java/time/tck/java/time/TCKOffsetDateTime.java                       generic-all
-java/time/tck/java/time/TCKOffsetTime.java                           generic-all
-java/time/tck/java/time/TCKPeriod.java                               generic-all
-java/time/tck/java/time/TCKYear.java                                 generic-all
-java/time/tck/java/time/TCKYearMonth.java                            generic-all
-java/time/tck/java/time/TCKZonedDateTime.java                        generic-all
-java/time/tck/java/time/format/TCKDateTimeFormatters.java            generic-all
-java/time/tck/java/time/format/TCKDateTimeParseResolver.java         generic-all
-java/time/tck/java/time/format/TCKInstantPrinterParser.java          generic-all
-java/time/tck/java/time/format/TCKLocalizedFieldParser.java          generic-all
-java/time/tck/java/time/temporal/TCKChronoField.java                 generic-all
-java/time/tck/java/time/temporal/TCKChronoUnit.java                  generic-all
-java/time/tck/java/time/temporal/TCKIsoFields.java                   generic-all
-java/time/tck/java/time/temporal/TCKJulianFields.java                generic-all
-java/time/test/java/time/chrono/TestUmmAlQuraChronology.java         generic-all
-java/time/test/java/time/format/TestNumberParser.java                generic-all
-java/time/test/java/time/format/TestNumberPrinter.java               generic-all
-java/time/test/java/time/format/TestZoneOffsetParser.java            generic-all
-java/time/test/java/time/temporal/TestChronoUnit.java                generic-all
-java/time/test/java/time/temporal/TestDateTimeValueRange.java        generic-all
-
-
-# https://bugs.openjdk.java.net/browse/JDK-8144247
-java/awt/xembed/server/RunTestXEmbed.java                            generic-all
+java/time/tck/java/time/TCKDayOfWeek.java                                          8152944 generic-all
+java/time/tck/java/time/TCKDuration.java                                           8152944 generic-all
+java/time/tck/java/time/TCKInstant.java                                            8152944 generic-all
+java/time/tck/java/time/TCKLocalDate.java                                          8152944 generic-all
+java/time/tck/java/time/TCKLocalDateTime.java                                      8152944 generic-all
+java/time/tck/java/time/TCKLocalTime.java                                          8152944 generic-all
+java/time/tck/java/time/TCKMonth.java                                              8152944 generic-all
+java/time/tck/java/time/TCKOffsetDateTime.java                                     8152944 generic-all
+java/time/tck/java/time/TCKOffsetTime.java                                         8152944 generic-all
+java/time/tck/java/time/TCKPeriod.java                                             8152944 generic-all
+java/time/tck/java/time/TCKYear.java                                               8152944 generic-all
+java/time/tck/java/time/TCKYearMonth.java                                          8152944 generic-all
+java/time/tck/java/time/TCKZonedDateTime.java                                      8152944 generic-all
+java/time/tck/java/time/format/TCKDateTimeFormatters.java                          8152944 generic-all
+java/time/tck/java/time/format/TCKDateTimeParseResolver.java                       8152944 generic-all
+java/time/tck/java/time/format/TCKInstantPrinterParser.java                        8152944 generic-all
+java/time/tck/java/time/format/TCKLocalizedFieldParser.java                        8152944 generic-all
+java/time/tck/java/time/temporal/TCKChronoField.java                               8152944 generic-all
+java/time/tck/java/time/temporal/TCKChronoUnit.java                                8152944 generic-all
+java/time/tck/java/time/temporal/TCKIsoFields.java                                 8152944 generic-all
+java/time/tck/java/time/temporal/TCKJulianFields.java                              8152944 generic-all
+java/time/test/java/time/chrono/TestUmmAlQuraChronology.java                       8152944 generic-all
+java/time/test/java/time/format/TestNumberParser.java                              8152944 generic-all
+java/time/test/java/time/format/TestNumberPrinter.java                             8152944 generic-all
+java/time/test/java/time/format/TestZoneOffsetParser.java                          8152944 generic-all
+java/time/test/java/time/temporal/TestChronoUnit.java                              8152944 generic-all
+java/time/test/java/time/temporal/TestDateTimeValueRange.java                      8152944 generic-all
+java/awt/xembed/server/RunTestXEmbed.java                                          8144247 generic-all
 
 ############################################################################
 
 # jdk_sound
 
-## https://bugs.openjdk.java.net/browse/JDK-8134632 (fixed in jdk9)
-# MidiSystem not available
-javax/sound/midi/Devices/InitializationHang.java                     generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8148915
-javax/sound/sampled/DirectAudio/bug6400879.java                      generic-all
+javax/sound/midi/Devices/InitializationHang.java                                   8134632 generic-all
+javax/sound/sampled/DirectAudio/bug6400879.java                                    8148915 generic-all
 
 ############################################################################
 
 # jdk_beans
 
-# https://bugs.openjdk.java.net/browse/JDK-8015593
-java/beans/XMLEncoder/Test6570354.java                               macosx-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8030123
-java/beans/Introspector/Test8027648.java                             linux-all
+java/beans/XMLEncoder/Test6570354.java                                             8015593 macosx-all
+java/beans/Introspector/Test8027648.java                                           8030123 linux-all
 
 ############################################################################
 
 # jdk_io
 
 # Test ignored: This test has huge memory requirements
-java/io/ByteArrayOutputStream/MaxCapacity.java                       generic-all
+java/io/ByteArrayOutputStream/MaxCapacity.java                                     generic-all
 
 # Test ignored: This test has huge memory requirements
-java/io/CharArrayReader/OverflowInRead.java                          generic-all
+java/io/CharArrayReader/OverflowInRead.java                                        generic-all
 
 # Test ignored: until 6492634 and 6501010 is fixed
 # http://bugs.java.com/view_bug.do?bug_id=6492634
 # https://bugs.openjdk.java.net/browse/JDK-6492634
 # http://bugs.java.com/view_bug.do?bug_id=6501010
 # https://bugs.openjdk.java.net/browse/JDK-6501010
-java/io/File/GetXSpace.java                                          generic-all
+java/io/File/GetXSpace.java                                                        generic-all
 
 # Test ignored: Test truncates system files when run as root, see 7042603
-# http://bugs.java.com/view_bug.do?bug_id=7042603
-java/io/IOException/LastErrorString.java                             generic-all
+java/io/IOException/LastErrorString.java                                           7042603 generic-all
 
-# https://bugs.openjdk.java.net/browse/JDK-8169055
-java/io/Serializable/serialFilter/CheckInputOrderTest.java           generic-all
-java/io/Serializable/serialFilter/FilterWithSecurityManagerTest.java generic-all
-java/io/Serializable/serialFilter/GlobalFilterTest.java              generic-all
-java/io/Serializable/serialFilter/MixedFiltersTest.java              generic-all
-java/io/Serializable/serialFilter/SerialFilterTest.java              generic-all
+java/io/Serializable/serialFilter/CheckInputOrderTest.java                         8169055 generic-all
+java/io/Serializable/serialFilter/FilterWithSecurityManagerTest.java               8169055 generic-all
+java/io/Serializable/serialFilter/GlobalFilterTest.java                            8169055 generic-all
+java/io/Serializable/serialFilter/MixedFiltersTest.java                            8169055 generic-all
+java/io/Serializable/serialFilter/SerialFilterTest.java                            8169055 generic-all
 
 # Test ignored: This test has huge memory requirements
-java/io/StringBufferInputStream/OverflowInRead.java                  generic-all
+java/io/StringBufferInputStream/OverflowInRead.java                                generic-all
 
 # Test ignored: This test requires console (/dev/tty) input, which is not supported by the current harness
-java/io/SystemInAvailable.java                                       generic-all
+java/io/SystemInAvailable.java                                                     generic-all
 
 ############################################################################
 
 # jdk_lang
 
-# https://bugs.openjdk.java.net/browse/JDK-8029891
-java/lang/ClassLoader/deadlock/GetResource.java                      generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8168517
-java/lang/ProcessBuilder/Basic.java                                  generic-all
+java/lang/ClassLoader/deadlock/GetResource.java                                     8029891 generic-all
+java/lang/ProcessBuilder/Basic.java                                                 8168517 generic-all
 
 # Test ignored: This test has huge memory requirements
-java/lang/StringBuilder/HugeCapacity.java                            generic-all
+java/lang/StringBuilder/HugeCapacity.java                                           generic-all
 
-# https://bugs.openjdk.java.net/browse/JDK-8072130
-java/lang/instrument/BootClassPath/BootClassPathTest.sh              macosx-all
-
-## Test ignored: until bug 6835233 dealt with
-## http://bugs.java.com/view_bug.do?bug_id=6835233
-# https://bugs.openjdk.java.net/browse/JDK-8166026
-java/lang/instrument/ParallelTransformerLoader.sh                    generic-all
-
-## Test ignored: 8078602
-## http://bugs.java.com/view_bug.do?bug_id=8078602
-# https://bugs.openjdk.java.net/browse/JDK-8078602
-java/lang/invoke/LFCaching/LFGarbageCollectedTest.java               generic-all
+java/lang/instrument/BootClassPath/BootClassPathTest.sh                             8072130 macosx-all
+java/lang/instrument/ParallelTransformerLoader.sh                                   8166026 generic-all
+java/lang/invoke/LFCaching/LFGarbageCollectedTest.java                              8078602 generic-all
 
 ############################################################################
 
 # jdk_management
 
-# https://bugs.openjdk.java.net/browse/JDK-8038822
-java/lang/management/MemoryMXBean/LowMemoryTest2.sh                  generic-all
-
-## https://bugs.openjdk.java.net/browse/JDK-8170303
-# java/lang/management/ThreadMXBean/ThreadInfoArray.java               generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8029098
-javax/management/remote/mandatory/notif/ListenerScaleTest.java       generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8160913
-javax/management/security/SecurityTest.java                          generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8030616
-sun/management/jmxremote/bootstrap/RmiBootstrapTest.sh               generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8028150
-sun/management/jmxremote/bootstrap/RmiSslBootstrapTest.sh	         generic-all
+java/lang/management/MemoryMXBean/LowMemoryTest2.sh                                 8038822 generic-all
+javax/management/remote/mandatory/notif/ListenerScaleTest.java                      8029098 generic-all
+javax/management/security/SecurityTest.java                                         8160913 generic-all
+sun/management/jmxremote/bootstrap/RmiBootstrapTest.sh                              8030616 generic-all
+sun/management/jmxremote/bootstrap/RmiSslBootstrapTest.sh	                        8028150 generic-all
 
 ############################################################################
 
 # jdk_jmx
 
-# https://bugs.openjdk.java.net/browse/JDK-8047295
-# https://bugs.openjdk.java.net/browse/JDK-8031036
-com/sun/management/OperatingSystemMXBean/GetCommittedVirtualMemorySize.java macosx-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8030957
-com/sun/management/OperatingSystemMXBean/GetProcessCpuLoad.java aix-all
-com/sun/management/OperatingSystemMXBean/GetSystemCpuLoad.java  aix-all
-javax/management/MBeanServer/OldMBeanServerTest.java            aix-all
+com/sun/management/OperatingSystemMXBean/GetCommittedVirtualMemorySize.java         8047295,8031036 macosx-all
+com/sun/management/OperatingSystemMXBean/GetProcessCpuLoad.java                     8030957 aix-all
+com/sun/management/OperatingSystemMXBean/GetSystemCpuLoad.java                      8030957 aix-all
+javax/management/MBeanServer/OldMBeanServerTest.java                                8030957 aix-all
 
 # https://bugs.openjdk.java.net/browse/CODETOOLS-7901859
-com/sun/management/DiagnosticCommandMBean/DcmdMBeanPermissionsTest.java generic-all
+com/sun/management/DiagnosticCommandMBean/DcmdMBeanPermissionsTest.java             generic-all
 
 
 ############################################################################
@@ -827,539 +422,255 @@
 
 # jdk_other
 
-# https://bugs.openjdk.java.net/browse/JDK-6988950
-demo/jvmti/compiledMethodLoad/CompiledMethodLoadTest.java	generic-all
-
-# 7027502
-demo/jvmti/hprof/MonitorTest.java                               generic-all
+demo/jvmti/compiledMethodLoad/CompiledMethodLoadTest.java	                        6988950 generic-all
+demo/jvmti/hprof/MonitorTest.java                                                   7027502 generic-all
 
 # The demos are a separate bundle, they require a build which has jdk/demo
-demo/jvmti/gctest/Gctest.java                                        generic-all
-demo/jvmti/heapTracker/HeapTrackerTest.java                          generic-all
-demo/jvmti/heapViewer/HeapViewerTest.java                            generic-all
-demo/jvmti/minst/MinstTest.java                                      generic-all
-demo/jvmti/mtrace/TraceJFrame.java                                   generic-all
-demo/jvmti/versionCheck/FailsWhenJvmtiVersionDiffers.java            generic-all
-demo/jvmti/waiters/WaitersTest.java                                  generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8151352
-sample/chatserver/ChatTest.java                                      generic-all
-sample/mergesort/MergeSortTest.java                                  generic-all
-
-# 8027973
-javax/xml/jaxp/transform/jdk8004476/XSLTExFuncTest.java		windows-all
+demo/jvmti/gctest/Gctest.java                                                       generic-all
+demo/jvmti/heapTracker/HeapTrackerTest.java                                         generic-all
+demo/jvmti/heapViewer/HeapViewerTest.java                                           generic-all
+demo/jvmti/minst/MinstTest.java                                                     generic-all
+demo/jvmti/mtrace/TraceJFrame.java                                                  generic-all
+demo/jvmti/versionCheck/FailsWhenJvmtiVersionDiffers.java                           generic-all
+demo/jvmti/waiters/WaitersTest.java                                                 generic-all
+sample/chatserver/ChatTest.java                                                     8151352 generic-all
+sample/mergesort/MergeSortTest.java                                                 8151352 generic-all
+javax/xml/jaxp/transform/jdk8004476/XSLTExFuncTest.java		                        8027973 windows-all
 
 # no printer found
-javax/print/CheckDupFlavor.java                                      generic-all
-javax/print/PrintServiceLookup/CountPrintServices.java               generic-all
-javax/print/attribute/AttributeTest.java                             generic-all
-javax/print/attribute/GetCopiesSupported.java                        generic-all
-javax/print/attribute/SidesPageRangesTest.java                       generic-all
-javax/print/attribute/SupportedPrintableAreas.java                   generic-all
+javax/print/CheckDupFlavor.java                                                     generic-all
+javax/print/PrintServiceLookup/CountPrintServices.java                              generic-all
+javax/print/attribute/AttributeTest.java                                            generic-all
+javax/print/attribute/GetCopiesSupported.java                                       generic-all
+javax/print/attribute/SidesPageRangesTest.java                                      generic-all
+javax/print/attribute/SupportedPrintableAreas.java                                  generic-all
 
 # it looks like the tests spend a lot of time on Windows
-javax/print/attribute/Chroma.java                                    generic-all
-javax/print/attribute/ChromaticityValues.java                        generic-all
-javax/print/attribute/CollateAttr.java                               generic-all
-javax/print/attribute/MediaMappingsTest.java                         generic-all
-javax/print/attribute/PSCopiesFlavorTest.java                        generic-all
-javax/print/attribute/autosense/PrintAutoSenseData.java              generic-all
+javax/print/attribute/Chroma.java                                                   generic-all
+javax/print/attribute/ChromaticityValues.java                                       generic-all
+javax/print/attribute/CollateAttr.java                                              generic-all
+javax/print/attribute/MediaMappingsTest.java                                        generic-all
+javax/print/attribute/PSCopiesFlavorTest.java                                       generic-all
+javax/print/attribute/autosense/PrintAutoSenseData.java                             generic-all
 
 # hangs on Windows
-javax/print/PrintSE/PrintSE.sh                                  windows-all
+javax/print/PrintSE/PrintSE.sh                                                      windows-all
 
 ############################################################################
 
 # jdk_net
 
-# Filed 7052625
-com/sun/net/httpserver/bugs/6725892/Test.java                   generic-all
-
-# failing on vista 32/64 on nightly
-# 7102702
-java/net/PortUnreachableException/OneExceptionOnly.java         windows-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8181645
-java/net/Socket/GetLocalAddress.java                            windows-all
-
-# 7148829
-sun/net/InetAddress/nameservice/simple/CacheTest.java		generic-all
-sun/net/InetAddress/nameservice/simple/DefaultCaching.java	generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8146257
-sun/net/www/protocol/jar/B4957695.java                          generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-6602831
-java/net/Inet6Address/B6206527.java                             generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8177536
-java/net/Inet6Address/B6558853.java                              macosx-all
-java/net/InetAddress/CheckJNI.java                               macosx-all
-java/net/Socket/LinkLocal.java                                   macosx-all
-java/net/ipv6tests/B6521014.java                                 macosx-all
-java/net/ipv6tests/TcpTest.java                                  macosx-all
-java/net/ipv6tests/UdpTest.java                                  macosx-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8065419
-java/net/Inet4Address/textToNumericFormat.java                  generic-all
-
-# 7122846
-java/net/MulticastSocket/NoLoopbackPackets.java                  macosx-all
-java/net/MulticastSocket/SetLoopbackMode.java                    macosx-all
-
-# 7145658
-java/net/MulticastSocket/Test.java                               macosx-all
-
-# 7143960
-java/net/DatagramSocket/SendDatagramToBadAddress.java            macosx-all
+com/sun/net/httpserver/bugs/6725892/Test.java                                       7052625 generic-all
+java/net/PortUnreachableException/OneExceptionOnly.java                             7102702 windows-all
+java/net/Socket/GetLocalAddress.java                                                8181645 windows-all
+sun/net/InetAddress/nameservice/simple/CacheTest.java		                        7148829 generic-all
+sun/net/InetAddress/nameservice/simple/DefaultCaching.java	                        7148829 generic-all
+sun/net/www/protocol/jar/B4957695.java                                              8146257 generic-all
+java/net/Inet6Address/B6206527.java                                                 6602831 generic-all
+java/net/Inet6Address/B6558853.java                                                 8177536 macosx-all
+java/net/InetAddress/CheckJNI.java                                                  8177536 macosx-all
+java/net/Socket/LinkLocal.java                                                      8177536 macosx-all
+java/net/ipv6tests/B6521014.java                                                    8177536 macosx-all
+java/net/ipv6tests/TcpTest.java                                                     8177536 macosx-all
+java/net/ipv6tests/UdpTest.java                                                     8177536 macosx-all
+java/net/Inet4Address/textToNumericFormat.java                                      8065419 generic-all
+java/net/MulticastSocket/NoLoopbackPackets.java                                     7122846 macosx-all
+java/net/MulticastSocket/SetLoopbackMode.java                                       7122846 macosx-all
+java/net/MulticastSocket/Test.java                                                  7145658 macosx-all
+java/net/DatagramSocket/SendDatagramToBadAddress.java                               7143960 macosx-all
 
 ############################################################################
 
 # jdk_nio
 
-# https://bugs.openjdk.java.net/browse/JDK-8068693
-java/nio/channels/AsyncCloseAndInterrupt.java                   generic-all
-
-# 6963118
-java/nio/channels/Selector/Wakeup.java                          windows-all
-
-# 7141822
-java/nio/channels/DatagramChannel/ChangingAddress.java          macosx-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8137230
-java/nio/channels/FileChannel/LoopingTruncate.java              generic-all
+java/nio/channels/AsyncCloseAndInterrupt.java                                        8068693 generic-all
+java/nio/channels/Selector/Wakeup.java                                               6963118 windows-all
+java/nio/channels/DatagramChannel/ChangingAddress.java                               7141822 macosx-all
+java/nio/channels/FileChannel/LoopingTruncate.java                                   8137230 generic-all
 
 ## the test requires ~4Gb diskspace
 ## it often fails by java.io.IOException: No space left on device
 ## and affect other tests
-java/nio/channels/FileChannel/Size.java                         generic-all
+java/nio/channels/FileChannel/Size.java                                               generic-all
 
-# https://bugs.openjdk.java.net/browse/JDK-8140263
-java/nio/channels/FileChannel/Transfer.java                     macosx-all
-
-# 7132677
-java/nio/channels/Selector/OutOfBand.java                       macosx-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8030795
-java/nio/file/Files/probeContentType/ParallelProbes.java
-
-# 7158947, Solaris 11
-java/nio/file/WatchService/Basic.java				solaris-all
-java/nio/file/WatchService/LotsOfEvents.java			solaris-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8156511
-java/nio/file/WatchService/DeleteInterference.java              generic-all
+java/nio/channels/FileChannel/Transfer.java                                           8140263 macosx-all
+java/nio/channels/Selector/OutOfBand.java                                             7132677 macosx-all
+java/nio/file/Files/probeContentType/ParallelProbes.java                              8030795 generic-all
+java/nio/file/WatchService/Basic.java				                                  7158947 solaris-all Solaris 11
+java/nio/file/WatchService/LotsOfEvents.java			                              7158947 solaris-all Solaris 11
+java/nio/file/WatchService/DeleteInterference.java                                    8156511 generic-all
 
 ############################################################################
 
 # jdk_rmi
 
-# https://bugs.openjdk.java.net/browse/JDK-8085192
-java/rmi/activation/Activatable/checkRegisterInLog/CheckRegisterInLog.java generic-all
-java/rmi/activation/Activatable/forceLogSnapshot/ForceLogSnapshot.java     generic-all
-java/rmi/activation/Activatable/inactiveGroup/InactiveGroup.java           generic-all
-java/rmi/activation/Activatable/lookupActivationSystem/LookupActivationSystem.java generic-all
-java/rmi/activation/Activatable/restartService/RestartService.java         generic-all
-java/rmi/activation/CommandEnvironment/SetChildEnv.java                    generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8085192
-java/rmi/activation/Activatable/restartCrashedService/RestartCrashedService.java generic-all
-
-https://bugs.openjdk.java.net/browse/JDK-8019538
-java/rmi/activation/rmidViaInheritedChannel/RmidViaInheritedChannel.java         generic-all
-java/rmi/activation/rmidViaInheritedChannel/InheritedChannelNotServerSocket.java generic-all
-
-# 7140992
-java/rmi/server/Unreferenced/finiteGCLatency/FiniteGCLatency.java  generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8029360
-java/rmi/transport/dgcDeadLock/DGCDeadLock.java                 generic-all
-
-# 7146541
-java/rmi/transport/rapidExportUnexport/RapidExportUnexport.java	linux-all
-
-# 7191877
-java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java       generic-all
-
-# 7195095
-sun/rmi/transport/proxy/EagerHttpFallback.java                  generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8073080
-sun/rmi/transport/tcp/DeadCachedConnection.java                 windows-all
+java/rmi/activation/Activatable/checkRegisterInLog/CheckRegisterInLog.java            8085192 generic-all
+java/rmi/activation/Activatable/forceLogSnapshot/ForceLogSnapshot.java                8085192 generic-all
+java/rmi/activation/Activatable/inactiveGroup/InactiveGroup.java                      8085192 generic-all
+java/rmi/activation/Activatable/lookupActivationSystem/LookupActivationSystem.java    8085192 generic-all
+java/rmi/activation/Activatable/restartService/RestartService.java                    8085192 generic-all
+java/rmi/activation/CommandEnvironment/SetChildEnv.java                               8085192 generic-all
+java/rmi/activation/Activatable/restartCrashedService/RestartCrashedService.java      8085192 generic-all
+java/rmi/activation/rmidViaInheritedChannel/RmidViaInheritedChannel.java              8019538 generic-all
+java/rmi/activation/rmidViaInheritedChannel/InheritedChannelNotServerSocket.java      8170562 generic-all
+java/rmi/server/Unreferenced/finiteGCLatency/FiniteGCLatency.java                     7140992 generic-all
+java/rmi/registry/readTest/readTest.sh                                                8139407 windows-all
+java/rmi/transport/dgcDeadLock/DGCDeadLock.java                                       8029360 generic-all
+java/rmi/transport/rapidExportUnexport/RapidExportUnexport.java	                      7146541 linux-all
+java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java                             7191877 generic-all
+sun/rmi/transport/proxy/EagerHttpFallback.java                                        7195095 generic-all
+sun/rmi/transport/tcp/DeadCachedConnection.java                                       8073080 windows-all
 
 ############################################################################
 
 # jdk_security
 
-## https://bugs.openjdk.java.net/browse/JDK-7054428
-#java/security/SecureClassLoader/DefineClassByteBuffer.java      generic-all
-
 # Test ignored: Must set up KDC and setup Kerberos configuration file
-javax/security/auth/kerberos/KerberosHashEqualsTest.java             generic-all
-javax/security/auth/kerberos/KerberosTixDateTest.java                generic-all
+javax/security/auth/kerberos/KerberosHashEqualsTest.java                              generic-all
+javax/security/auth/kerberos/KerberosTixDateTest.java                                 generic-all
 
 # Test ignored: run these by hand
-com/sun/security/auth/callback/TextCallbackHandler/Password.java     generic-all
-com/sun/security/auth/callback/TextCallbackHandler/Default.java      generic-all
+com/sun/security/auth/callback/TextCallbackHandler/Password.java                      generic-all
+com/sun/security/auth/callback/TextCallbackHandler/Default.java                       generic-all
+
+sun/security/rsa/SpecTest.java                                                        8075565 macosx-all
 
 # Test ignored: see runwjaas.csh for instructions for how to run this test
-com/sun/security/sasl/gsskerb/NoSecurityLayer.java              generic-all
-com/sun/security/sasl/gsskerb/ConfSecurityLayer.java            generic-all
-com/sun/security/sasl/gsskerb/AuthOnly.java                     generic-all
+com/sun/security/sasl/gsskerb/NoSecurityLayer.java                                    generic-all
+com/sun/security/sasl/gsskerb/ConfSecurityLayer.java                                  generic-all
+com/sun/security/sasl/gsskerb/AuthOnly.java                                           generic-all
 
-# 7157786
-sun/security/pkcs11/ec/TestKeyFactory.java                      generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8171496
-sun/security/krb5/auto/SSL.java                                 generic-all
-
-# 7164518: no PortUnreachableException on Mac
-sun/security/krb5/auto/Unreachable.java                         macosx-all
-
-# 7147060
-com/sun/org/apache/xml/internal/security/transforms/ClassLoaderTest.java	generic-all
-
-# 6988842: 4 tests failing on Solaris 5.10
-sun/security/pkcs11/Secmod/AddPrivateKey.java                   solaris-all
-sun/security/pkcs11/ec/ReadCertificates.java                    solaris-all
-sun/security/pkcs11/ec/ReadPKCS12.java                          solaris-all
-sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java            solaris-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8074580
-sun/security/pkcs11/Secmod/AddTrustedCert.java                  linux-all
-sun/security/pkcs11/tls/TestKeyMaterial.java                    linux-all
-sun/security/pkcs11/rsa/TestKeyPairGenerator.java               generic-all
-
-# 7041639, Solaris DSA keypair generation bug
-java/security/KeyPairGenerator/SolarisShortDSA.java             solaris-all
-sun/security/tools/keytool/standard.sh                          solaris-all
-
-# 8026393
-sun/security/tools/jarsigner/warnings/BadKeyUsageTest.java      generic-all
-
-# 8158827
-sun/security/krb5/auto/tools/KinitConfPlusProps.java                       windows-all
+sun/security/pkcs11/ec/TestKeyFactory.java                                            8026976 generic-all
+sun/security/krb5/auto/SSL.java                                                       8171496 generic-all
+sun/security/krb5/auto/Unreachable.java                                               7164518 macosx-all
+com/sun/org/apache/xml/internal/security/transforms/ClassLoaderTest.java	          7147060 generic-all
+sun/security/pkcs11/Secmod/AddPrivateKey.java                                         6988842 solaris-all
+sun/security/pkcs11/ec/ReadCertificates.java                                          6988842 solaris-all
+sun/security/pkcs11/ec/ReadPKCS12.java                                                6988842 solaris-all
+sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java                                  6988842 solaris-all
+sun/security/pkcs11/Secmod/AddTrustedCert.java                                        8180837,8074580  generic-all
+sun/security/pkcs11/tls/TestKeyMaterial.java                                          8180837,8074580 generic-all
+sun/security/pkcs11/rsa/TestKeyPairGenerator.java                                     generic-all
+java/security/KeyPairGenerator/SolarisShortDSA.java                                   7041639 solaris-all
+sun/security/tools/keytool/standard.sh                                                7041639 solaris-all
+sun/security/tools/jarsigner/warnings/BadKeyUsageTest.java                            8026393 generic-all
+sun/security/krb5/auto/tools/KinitConfPlusProps.java                                  8158827 windows-all
 
 ############################################################################
 
 # jdk_swing
 
-# https://bugs.openjdk.java.net/browse/JDK-8060765
-javax/swing/AbstractButton/6711682/bug6711682.java                   generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8143021
-javax/swing/JColorChooser/Test6541987.java                           generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8076178
-javax/swing/JColorChooser/Test7194184.java                           generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8171302
-javax/swing/JComboBox/4743225/bug4743225.java                        generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8028707
-javax/swing/JComboBox/6236162/bug6236162.java                        generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8040797
-javax/swing/JComboBox/8032878/bug8032878.java                        generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8033069
-javax/swing/JComboBox/8033069/bug8033069NoScrollBar.java             generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8163367
-javax/swing/JComboBox/8033069/bug8033069ScrollBar.java               generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169953
-javax/swing/JComboBox/8057893/bug8057893.java                        generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8136998
-javax/swing/JComboBox/8136998/bug8136998.java                        generic-all
-
-# http://bugs.java.com/view_bug.do?bug_id=8067986
-javax/swing/JComboBox/ConsumedKeyTest/ConsumedKeyTest.java           generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8172337
-javax/swing/JComponent/6683775/bug6683775.java                       generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-7190978
-javax/swing/JComponent/7154030/bug7154030.java                       generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8194767
-javax/swing/JEditorPane/6917744/bug6917744.java                      generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8042380
-javax/swing/JFileChooser/4524490/bug4524490.java                     generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8058231
-javax/swing/JFileChooser/6396844/TwentyThousandTest.java             generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8198735
-javax/swing/JFileChooser/6489130/bug6489130.java                     macosx-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8087110
-javax/swing/JFileChooser/8002077/bug8002077.java                     generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169954
-javax/swing/JFileChooser/8021253/bug8021253.java                     generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8064715
-javax/swing/JFileChooser/8062561/bug8062561.java                     generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8170721
-javax/swing/JFrame/4962534/bug4962534.html                           generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169955
-javax/swing/JFrame/8016356/bug8016356.java                           windows-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8007719
-javax/swing/JInternalFrame/5066752/bug5066752.java                   generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8032568
-javax/swing/JInternalFrame/8020708/bug8020708.java                   generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8160880
-javax/swing/JInternalFrame/Test6325652.java                          generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8172535
-javax/swing/JInternalFrame/Test6505027.java                          generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8040914
-javax/swing/JLabel/6596966/bug6596966.java                           generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8003972
-javax/swing/JList/6462008/bug6462008.java                            generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8040915
-javax/swing/JMenu/4515762/bug4515762.java                            generic-all
+javax/swing/AbstractButton/6711682/bug6711682.java                                    8060765 windows-all,macosx-all
+javax/swing/JColorChooser/Test6541987.java                                            8143021 windows-all,linux-all,macosx-all
+javax/swing/JColorChooser/Test7194184.java                                            8076178 generic-all
+javax/swing/JComboBox/4743225/bug4743225.java                                         8171302 generic-all
+javax/swing/JComboBox/6236162/bug6236162.java                                         8028707 windows-all,macosx-all
+javax/swing/JComboBox/8032878/bug8032878.java                                         8040797 generic-all
+javax/swing/JComboBox/8033069/bug8033069NoScrollBar.java                              8033069 generic-all
+javax/swing/JComboBox/8033069/bug8033069ScrollBar.java                                8163367 generic-all
+javax/swing/JComboBox/8057893/bug8057893.java                                         8169953 windows-all,macosx-all
+javax/swing/JComboBox/8136998/bug8136998.java                                         8136998 generic-all
+javax/swing/JComboBox/ConsumedKeyTest/ConsumedKeyTest.java                            8067986 generic-all
+javax/swing/JComponent/6683775/bug6683775.java                                        8172337 generic-all
+javax/swing/JComponent/7154030/bug7154030.java                                        7190978 generic-all
+javax/swing/JEditorPane/6917744/bug6917744.java                                       8194767 generic-all
+javax/swing/JFileChooser/4524490/bug4524490.java                                      8042380 generic-all
+javax/swing/JFileChooser/6396844/TwentyThousandTest.java                              8058231 windows-all,linux-all,macosx-all
+javax/swing/JFileChooser/6489130/bug6489130.java                                      8198735 macosx-all
+javax/swing/JFileChooser/6868611/bug6868611.java                                      7059834 windows-all
+javax/swing/JFileChooser/8002077/bug8002077.java                                      8087110 generic-all
+javax/swing/JFileChooser/8021253/bug8021253.java                                      8169954 windows-all,linux-all,macosx-all
+javax/swing/JFileChooser/8062561/bug8062561.java                                      8196466 linux-all,macosx-all
+javax/swing/JFrame/4962534/bug4962534.html                                            8170721 generic-all
+javax/swing/JFrame/8016356/bug8016356.java                                            8169955 windows-all
+javax/swing/JInternalFrame/5066752/bug5066752.java                                    8007719 generic-all
+javax/swing/JInternalFrame/8020708/bug8020708.java                                    8032568 generic-all
+javax/swing/JInternalFrame/Test6325652.java                                           8196467,8160880 linux-all,macosx-all,windows-all
+javax/swing/JInternalFrame/Test6505027.java                                           8172535 generic-all
+javax/swing/JLabel/6596966/bug6596966.java                                            8040914 linux-all,macosx-all,windows-all
+javax/swing/JList/6462008/bug6462008.java                                             7156347 generic-all
+javax/swing/JMenu/4515762/bug4515762.java                                             8040915 generic-all
 
 # https://bugs.openjdk.java.net/browse/JDK-8171998
 # according recommendations from Oracle ForegroundLockTimeout = 0
 # in order to check it, the test is being enabled for regular runs
 # moreover it should not be executed on virtual machines
 
-# https://bugs.openjdk.java.net/browse/JDK-8076178
-javax/swing/JMenu/4692443/bug4692443.java                            generic-all
+javax/swing/JMenu/4692443/bug4692443.java                                             8076178 generic-all
+javax/swing/JMenu/8072900/WrongSelectionOnMouseOver.java                              8142534 generic-all
+javax/swing/JMenuBar/4750590/bug4750590.java                                          8158496 windows-all
+javax/swing/JMenuBar/4750590/bug4750590.java                                          8076178 macosx-all
+javax/swing/JMenuItem/4171437/bug4171437.java                                         8040916 generic-all
+javax/swing/JMenuItem/4654927/bug4654927.java                                         8172536 generic-all
+javax/swing/JMenuItem/6209975/bug6209975.java                                         8025083 generic-all
+javax/swing/JMenuItem/ActionListenerCalledTwice/ActionListenerCalledTwiceTest.java    8139169 macosx-all
+javax/swing/JOptionPane/6464022/bug6464022.java                                       7124548 macosx-all
+javax/swing/JPopupMenu/4458079/bug4458079.java                                        8040917 generic-all
+javax/swing/JPopupMenu/4966112/bug4966112.java                                        8064915,8074385 generic-all
+javax/swing/JPopupMenu/6800513/bug6800513.java                                        8080868 macosx-all,windows-all
+javax/swing/JPopupMenu/6827786/bug6827786.java                                        8042378,8042378 generic-all
+javax/swing/JPopupMenu/6987844/bug6987844.java                                        8169956 generic-all
+javax/swing/JPopupMenu/7156657/bug7156657.java                                        7185563 generic-all
+javax/swing/JRadioButton/8033699/bug8033699.java                                      8064920 generic-all
+javax/swing/JRadioButton/8075609/bug8075609.java                                      8136371 generic-all
+javax/swing/JRootPane/4670486/bug4670486.java                                         8042381 generic-all
+javax/swing/JScrollBar/4708809/bug4708809.java                                        8145647 generic-all
 
-# https://bugs.openjdk.java.net/browse/JDK-8142534
-javax/swing/JMenu/8072900/WrongSelectionOnMouseOver.java             generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8158496
-javax/swing/JMenuBar/4750590/bug4750590.java                         windows-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8076178
-javax/swing/JMenuBar/4750590/bug4750590.java                         macosx-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8040916
-javax/swing/JMenuItem/4171437/bug4171437.java                        generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8172536
-javax/swing/JMenuItem/4654927/bug4654927.java                        generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8025083
-javax/swing/JMenuItem/6209975/bug6209975.java                        generic-all
-
-https://bugs.openjdk.java.net/browse/JDK-8139169
-javax/swing/JMenuItem/ActionListenerCalledTwice/ActionListenerCalledTwiceTest.java macosx-all
-
-# https://bugs.openjdk.java.net/browse/JDK-7124548
-javax/swing/JOptionPane/6464022/bug6464022.java                      macosx-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8040917
-javax/swing/JPopupMenu/4458079/bug4458079.java                       generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8064915
-# https://bugs.openjdk.java.net/browse/JDK-8074385
-javax/swing/JPopupMenu/4966112/bug4966112.java                       generic-all
-
-# https://bugs. openjdk.java.net/browse/JDK-7184956
-javax/swing/JPopupMenu/6800513/bug6800513.java                       generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8042378
-# https://bugs.openjdk.java.net/browse/JDK-8156460
-javax/swing/JPopupMenu/6827786/bug6827786.java                       generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169956
-javax/swing/JPopupMenu/6987844/bug6987844.java                       generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-7185563
-# https://bugs.openjdk.java.net/browse/JDK-8171381
-javax/swing/JPopupMenu/7156657/bug7156657.java                       generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8064920
-javax/swing/JRadioButton/8033699/bug8033699.java                     generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8136371
-javax/swing/JRadioButton/8075609/bug8075609.java                     generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8042381
-javax/swing/JRootPane/4670486/bug4670486.java                        generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8145647                   linux
-# https://bugs.openjdk.java.net/browse/JDK-8169957
-javax/swing/JScrollBar/4708809/bug4708809.java                       generic-all
-
-## https://bugs.openjdk.java.net/browse/JDK-8024407
-#javax/swing/JScrollBar/7163696/Test7163696.java                      macosx-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8028618
-javax/swing/JScrollBar/bug4202954/bug4202954.java                    generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169960
-javax/swing/JScrollPane/HorizontalMouseWheelOnShiftPressed/HorizontalMouseWheelOnShiftPressed.java generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8172539
-javax/swing/JSlider/6348946/bug6348946.java                          generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8172408
-javax/swing/JSpinner/4973721/bug4973721.java                         generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169958
-# https://bugs.openjdk.java.net/browse/JDK-8159902
-javax/swing/JSpinner/5012888/bug5012888.java                         generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8019935
-javax/swing/JSplitPane/4885629/bug4885629.java                       generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-7033533
-javax/swing/JComboBox/4199622/bug4199622.java                        linux-all
-javax/swing/JInternalFrame/Test6802868.java                          linux-all
-javax/swing/JOptionPane/7138665/bug7138665.java                      linux-all
-javax/swing/JPopupMenu/6495920/bug6495920.java                       linux-all
-javax/swing/JTable/4220171/bug4220171.java                           linux-all
-javax/swing/Security/6657138/ComponentTest.java                      linux-all
-
-# https://bugs.openjdk.java.net/browse/JDK-7033533
-# https://bugs.openjdk.java.net/browse/JDK-8194941
-javax/swing/text/html/CSS/4530474/bug4530474.java                    generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169959
-javax/swing/JTable/6263446/bug6263446.java                           generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8169952
-javax/swing/JTableHeader/6884066/bug6884066.java                     generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-7179842
-javax/swing/JTableHeader/6889007/bug6889007.java                     generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8170260
-javax/swing/JTabbedPane/4361477/bug4361477.java                      generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8064922
-# https://bugs.openjdk.java.net/browse/JDK-8171997
-javax/swing/JTabbedPane/4624207/bug4624207.java                      generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8028281
-javax/swing/JTabbedPane/7024235/Test7024235.java                     macosx-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8051591
-javax/swing/JTabbedPane/8007563/Test8007563.java                     generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8145645
-javax/swing/JTextField/8036819/bug8036819.java                       generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8172407
-javax/swing/JToolTip/4846413/bug4846413.java                         generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8029682
-javax/swing/JTree/4330357/bug4330357.java                            generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8172065
-javax/swing/JTree/4908142/bug4908142.java                            generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8172063
-javax/swing/JTree/4927934/bug4927934.java                            generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8003839
-javax/swing/JTree/6263446/bug6263446.java                            generic-all
-
-# http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8011259
-javax/swing/JTree/8003400/Test8003400.java                           generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-7105119
-javax/swing/MultiUIDefaults/4300666/bug4300666.java                  macosx-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8165854
-javax/swing/Popup/TaskbarPositionTest.java                           macosx-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8065099
-javax/swing/PopupFactory/6276087/NonOpaquePopupMenuTest.java         macosx-all
-
-# http://bugs.java.com/view_bug.do?bug_id=8008119
-javax/swing/RepaintManager/IconifyTest/IconifyTest.java              generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8015602
-javax/swing/SpringLayout/4726194/bug4726194.java                     macosx-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8172064
-javax/swing/SwingUtilities/4917669/bug4917669.java                   generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8072110
-javax/swing/SwingUtilities/7088744/bug7088744.java                   generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8079253
-javax/swing/SwingUtilities/TestBadBreak/TestBadBreak.java            linux-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8167009
-javax/swing/ToolTipManager/Test6256140.java                          generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8042383
-javax/swing/plaf/basic/BasicMenuUI/4983388/bug4983388.java           generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8137101
-javax/swing/plaf/basic/BasicHTML/4251579/bug4251579.java             generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8140237
-javax/swing/plaf/nimbus/8041642/bug8041642.java                      generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8160438
-javax/swing/plaf/nimbus/8057791/bug8057791.java                      macosx-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8170722
-javax/swing/plaf/synth/7158712/bug7158712.java                       generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8081478
-javax/swing/plaf/synth/SynthButtonUI/6276188/bug6276188.java         generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8172071
-javax/swing/plaf/windows/WindowsRootPaneUI/WrongAltProcessing/WrongAltProcessing.java windows-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8130895
-javax/swing/system/6799345/TestShutdown.java                         linux-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8144188
-javax/swing/text/AbstractDocument/6968363/Test6968363.java           generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8003533
-javax/swing/text/CSSBorder/6796710/bug6796710.java                   generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8063107
-javax/swing/text/DefaultEditorKit/4278839/bug4278839.java            generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8050988
-javax/swing/text/GlyphPainter2/6427244/bug6427244.java               generic-all
-
-## https://bugs.openjdk.java.net/browse/JDK-7147408
-#javax/swing/text/StyledEditorKit/4506788/bug4506788.java             generic-all
-
-https://bugs.openjdk.java.net/browse/JDK-8145644
-javax/swing/text/View/8048110/bug8048110.java                        generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8041944
-javax/swing/text/View/8014863/bug8014863.java                        generic-all
-
-# http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8076178
-javax/swing/text/html/HTMLEditorKit/5043626/bug5043626.java          generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8022535
-javax/swing/text/html/parser/Test8017492.java                        generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-6962725
-javax/swing/JFileChooser/6738668/bug6738668.java                     generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8049313
-javax/swing/JTable/7068740/bug7068740.java                           generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8032895
-javax/swing/JTextArea/4697612/bug4697612.java                        linux-all
+javax/swing/JScrollBar/bug4202954/bug4202954.java                                     8028618 generic-all
+javax/swing/JScrollPane/HorizontalMouseWheelOnShiftPressed/HorizontalMouseWheelOnShiftPressed.java 8169960 generic-all
+javax/swing/JSlider/6348946/bug6348946.java                                           8172539 generic-all
+javax/swing/JSpinner/4973721/bug4973721.java                                          8172408 generic-all
+javax/swing/JSpinner/5012888/bug5012888.java                                          8169958,8159902 generic-all
+javax/swing/JSplitPane/4885629/bug4885629.java                                        8019935 generic-all
+javax/swing/JComboBox/4199622/bug4199622.java                                         7033533 linux-all
+javax/swing/JInternalFrame/Test6802868.java                                           7033533 linux-all
+javax/swing/JOptionPane/7138665/bug7138665.java                                       7033533 linux-all
+javax/swing/JPopupMenu/6495920/bug6495920.java                                        7033533 linux-all
+javax/swing/JTable/4220171/bug4220171.java                                            7033533 linux-all
+javax/swing/Security/6657138/ComponentTest.java                                       7033533 linux-all
+javax/swing/text/html/CSS/4530474/bug4530474.java                                     7033533,8194941 generic-all
+javax/swing/JTable/6263446/bug6263446.java                                            8169959 generic-all
+javax/swing/JTableHeader/6884066/bug6884066.java                                      8169952 generic-all
+javax/swing/JTableHeader/6889007/bug6889007.java                                      7179842 generic-all
+javax/swing/JTabbedPane/4361477/bug4361477.java                                       8170260 generic-all
+javax/swing/JTabbedPane/4624207/bug4624207.java                                       8064922,8171997 generic-all
+javax/swing/JTabbedPane/7024235/Test7024235.java                                      8028281 macosx-all
+javax/swing/JTabbedPane/8007563/Test8007563.java                                      8051591 generic-all
+javax/swing/JTextField/8036819/bug8036819.java                                        8145645 generic-all
+javax/swing/JToolTip/4846413/bug4846413.java                                          8172407 generic-all
+javax/swing/JTree/4330357/bug4330357.java                                             8029682 generic-all
+javax/swing/JTree/4908142/bug4908142.java                                             8172065 generic-all
+javax/swing/JTree/4927934/bug4927934.java                                             8172063 generic-all
+javax/swing/JTree/6263446/bug6263446.java                                             8003839 generic-all
+javax/swing/JTree/8003400/Test8003400.java                                            8011259 generic-all
+javax/swing/MultiUIDefaults/4300666/bug4300666.java                                   7105119 macosx-all
+javax/swing/Popup/TaskbarPositionTest.java                                            8165854 macosx-all
+javax/swing/PopupFactory/6276087/NonOpaquePopupMenuTest.java                          8065099 macosx-all
+javax/swing/RepaintManager/IconifyTest/IconifyTest.java                               8008119 generic-all
+javax/swing/SpringLayout/4726194/bug4726194.java                                      8198399 generic-all
+javax/swing/SwingUtilities/4917669/bug4917669.java                                    8172064 generic-all
+javax/swing/SwingUtilities/7088744/bug7088744.java                                    8072110 generic-all
+javax/swing/SwingUtilities/TestBadBreak/TestBadBreak.java                             8079253 linux-all
+javax/swing/ToolTipManager/Test6256140.java                                           8167009 generic-all
+javax/swing/plaf/basic/BasicMenuUI/4983388/bug4983388.java                            8042383 macosx-all,linux-all,windows-all
+javax/swing/plaf/basic/BasicHTML/4251579/bug4251579.java                              8137101 generic-all
+javax/swing/plaf/nimbus/8041642/bug8041642.java                                       8140237 generic-all
+javax/swing/plaf/nimbus/8057791/bug8057791.java                                       8160438 macosx-all
+javax/swing/plaf/synth/7158712/bug7158712.java                                        8170722 generic-all
+javax/swing/plaf/synth/SynthButtonUI/6276188/bug6276188.java                          8081478 generic-all
+javax/swing/plaf/windows/WindowsRootPaneUI/WrongAltProcessing/WrongAltProcessing.java 8172071 windows-all
+javax/swing/system/6799345/TestShutdown.java                                          8130895 linux-all
+javax/swing/text/AbstractDocument/6968363/Test6968363.java                            8144188 generic-all
+javax/swing/text/CSSBorder/6796710/bug6796710.java                                    8003533 generic-all
+javax/swing/text/DefaultEditorKit/4278839/bug4278839.java                             8063107 generic-all
+javax/swing/text/GlyphPainter2/6427244/bug6427244.java                                8050988 generic-all
+javax/swing/text/View/8048110/bug8048110.java                                         8145644 generic-all
+javax/swing/text/View/8014863/bug8014863.java                                         8041944 generic-all
+javax/swing/text/html/HTMLEditorKit/5043626/bug5043626.java                           8076178 generic-all
+javax/swing/text/html/parser/Test8017492.java                                         8022535 generic-all
+javax/swing/JFileChooser/6738668/bug6738668.java                                      8194946,6962725 generic-all
+javax/swing/JTable/7068740/bug7068740.java                                            8049313 generic-all
+javax/swing/JTextArea/4697612/bug4697612.java                                         8032895 linux-all
 
 ############################################################################
 
@@ -1373,18 +684,11 @@
 
 # jdk_tools
 
-# Tests take too long, on sparcs see 7143279
-tools/pack200/CommandLineTests.java                             solaris-all, macosx-all
-tools/pack200/Pack200Test.java                                  solaris-all, macosx-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8140611
-tools/pack200/UnpackerMemoryTest.java                           linux-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8130392
-tools/launcher/FXLauncherTest.java                              generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8180478
-tools/launcher/MultipleJRE.sh                                   windows_all
+tools/pack200/CommandLineTests.java                                                     8059906 generic-all
+tools/pack200/Pack200Test.java                                                                  solaris-all, macosx-all
+tools/pack200/UnpackerMemoryTest.java                                                   8140611 linux-all
+tools/launcher/FXLauncherTest.java                                                      8068049 linux-all,macosx-all
+tools/launcher/MultipleJRE.sh                                                           8180478 windows-all
 
 ############################################################################
 
@@ -1394,41 +698,24 @@
 
 # jdk_util
 
-# Filed 6772009
-java/util/concurrent/locks/ReentrantLock/CancelledLockLoops.java generic-all
+java/util/concurrent/locks/ReentrantLock/CancelledLockLoops.java 6772009 generic-all
 
 # Test ignored: Bug fix temporarily removed as it uncovered other bugs (4992226)
-java/util/AbstractList/CheckForComodification.java                   generic-all
+java/util/AbstractList/CheckForComodification.java                       generic-all
 
-## https://bugs.openjdk.java.net/browse/JDK-8060093
-# java/util/Currency/CurrencyTest.java                                 generic-all
-# java/util/Currency/ValidateISO4217.java                              generic-all
-
-# Test ignored: until 6842022 is resolved
-java/util/ResourceBundle/RestrictedBundleTest.java                   generic-all
-
-#Test ignored: 6876961
-java/util/ResourceBundle/Test4300693.java                            generic-all
-
-#Test ignored: until 6842353 is resolved
-# https://bugs.openjdk.java.net/browse/JDK-6842353
-java/util/WeakHashMap/GCDuringIteration.java                         generic-all
+java/util/Locale/LocaleProviders.sh                              8150432 windows-all
+java/util/WeakHashMap/GCDuringIteration.java                     6842353 generic-all
 
 # Test ignored: runs for hours and eats up 7 Gigabytes of disk space
-java/util/zip/3GBZipFiles.sh                                         generic-all
+java/util/zip/3GBZipFiles.sh                                             generic-all
 
 ############################################################################
 
 # svc_tools
 
-# 8031482
-sun/tools/jcmd/TestJcmdSanity.java				windows-all
-
-# 6456333
-sun/tools/jps/TestJpsJarRelative.java				generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8165727
-sun/tools/jstatd/TestJstatdExternalRegistry.java                     generic-all
+sun/tools/jcmd/TestJcmdSanity.java				                 8031482 windows-all
+sun/tools/jps/TestJpsJarRelative.java			                 6456333 generic-all
+sun/tools/jstatd/TestJstatdExternalRegistry.java                 8165727 generic-all
 
 ############################################################################
 
@@ -1438,230 +725,159 @@
 # 3.
 javax/imageio/stream/StreamCloserLeak/run_test.sh                    generic-all
 
-# https://bugs.openjdk.java.net/browse/JDK-8011371
-sun/awt/datatransfer/SuplementaryCharactersTransferTest.java         generic-all
+sun/awt/datatransfer/SuplementaryCharactersTransferTest.java                      8011371 generic-all
+sun/awt/dnd/8024061/bug8024061.java                                               8142540 linux-all
+sun/java2d/AcceleratedXORModeTest.java                                            8042098 windows-all
+sun/java2d/DirectX/InfiniteValidationLoopTest/InfiniteValidationLoopTest.java     8172888 windows-all
+sun/java2d/DirectX/OnScreenRenderingResizeTest/OnScreenRenderingResizeTest.java   8022403 generic-all
+sun/java2d/DirectX/OverriddenInsetsTest/OverriddenInsetsTest.java                 7148533,8196102 generic-all
+sun/java2d/OpenGL/GradientPaints.java                                             8031433 generic-all
+sun/java2d/DirectX/RenderingToCachedGraphicsTest/RenderingToCachedGraphicsTest.java 8144033 generic-all
+sun/java2d/GdiRendering/InsetClipping.java                                        7124403 generic-all
+sun/java2d/SunGraphics2D/DrawImageBilinear.java                                   8191506,8047703 generic-all
+sun/java2d/SunGraphics2D/PolyVertTest.java                                        6986565,6258137 generic-all
+sun/java2d/SunGraphics2D/SimplePrimQuality.java                                   6992007,7124403 generic-all
+sun/java2d/SunGraphics2D/SourceClippingBlitTest/SourceClippingBlitTest.java       8196191,8159142 windows-all,macosx-all,linux-all
 
-# https://bugs.openjdk.java.net/browse/JDK-8142540
-sun/awt/dnd/8024061/bug8024061.java                                  linux-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8042098
-sun/java2d/AcceleratedXORModeTest.java                               windows-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8172888
-sun/java2d/DirectX/InfiniteValidationLoopTest/InfiniteValidationLoopTest.java windows-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8022403
-sun/java2d/DirectX/OnScreenRenderingResizeTest/OnScreenRenderingResizeTest.java macosx-all
-
-# https://bugs.openjdk.java.net/browse/JDK-7148533
-sun/java2d/DirectX/OverriddenInsetsTest/OverriddenInsetsTest.java    generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8031433
-sun/java2d/OpenGL/GradientPaints.java                                generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8144033
-sun/java2d/DirectX/RenderingToCachedGraphicsTest/RenderingToCachedGraphicsTest.java generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-7124403
-sun/java2d/GdiRendering/InsetClipping.java                           generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8047703
-sun/java2d/SunGraphics2D/DrawImageBilinear.java                      generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-6258137
-# https://bugs.openjdk.java.net/browse/JDK-6986565
-sun/java2d/SunGraphics2D/PolyVertTest.java                           generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-7124403
-# https://bugs.openjdk.java.net/browse/JDK-6992007
-sun/java2d/SunGraphics2D/SimplePrimQuality.java                      generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8159142
-sun/java2d/SunGraphics2D/SourceClippingBlitTest/SourceClippingBlitTest.java generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-7184899
 # it blocks jtreg on Windows
-sun/java2d/X11SurfaceData/SharedMemoryPixmapsTest/SharedMemoryPixmapsTest.sh generic-all
+sun/java2d/X11SurfaceData/SharedMemoryPixmapsTest/SharedMemoryPixmapsTest.sh      7184899 generic-all
 
-# https://bugs.openjdk.java.net/browse/JDK-8171303
-sun/java2d/pipe/InterpolationQualityTest.java                        generic-all
+sun/java2d/pipe/InterpolationQualityTest.java                                     8171303 windows-all,linux-all,macosx-all
 
-# https://bugs.openjdk.java.net/browse/JDK-8058767
-sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java         windows-all
+sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java                      8058767,8057732 generic-all
+sun/security/pkcs11/Signature/TestDSAKeyLength.java                               8046046 generic-all
+sun/security/pkcs11/ec/TestECDH.java                                              8142541 linux-all
+sun/security/pkcs11/ec/TestECDSA.java                                             8142541 linux-all
+sun/security/pkcs11/ec/TestECGenSpec.java                                         8142541 linux-all
+sun/security/pkcs11/fips/ClientJSSEServerJSSE.java                                7057022 generic-all
+sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java                              8160071 generic-all
+sun/security/provider/PolicyFile/GrantAllPermToExtWhenNoPolicy.java               8039280 generic-all
+sun/security/provider/PolicyParser/ExtDirs.java                                   8033271 generic-all
+sun/security/provider/PolicyParser/ExtDirsChange.java                             8033271 generic-all
+sun/security/provider/PolicyParser/ExtDirsDefaultPolicy.java                      8033271 generic-all
+sun/security/provider/PolicyParser/PrincipalExpansionError.java                   8033271 generic-all
+sun/security/tools/keytool/i18n.sh                                                8033271 generic-all
 
-# https://bugs.openjdk.java.net/browse/JDK-8046046
-sun/security/pkcs11/Signature/TestDSAKeyLength.java                  generic-all
+sun/security/provider/SecureRandom/StrongSecureRandom.java                        8130151,8157344 generic-all
+sun/security/ssl/com/sun/net/ssl/internal/ssl/X509TrustManagerImpl/ClientServer.java 8011134 generic-all
+sun/security/ssl/javax/net/ssl/NewAPIs/CheckMyTrustedKeystore.java                8039130 generic-all
+sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/Basics.java                      8039130 generic-all
+sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/TestAllSuites.java               8039130 generic-all
+sun/security/ssl/sanity/ciphersuites/CheckCipherSuites.java                       8039130 generic-all
+sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/CloseKeepAliveCached.java 8039130 generic-all
 
-# https://bugs.openjdk.java.net/browse/JDK-8142541
-sun/security/pkcs11/ec/TestECDH.java                                 linux-all
-sun/security/pkcs11/ec/TestECDSA.java                                linux-all
-sun/security/pkcs11/ec/TestECGenSpec.java                            linux-all
-
-# https://bugs.openjdk.java.net/browse/JDK-7057022
-sun/security/pkcs11/fips/ClientJSSEServerJSSE.java                   generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8160071
-sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java                 generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8039280
-sun/security/provider/PolicyFile/GrantAllPermToExtWhenNoPolicy.java  generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8033271
-sun/security/provider/PolicyParser/ExtDirs.java                      generic-all
-sun/security/provider/PolicyParser/ExtDirsChange.java                generic-all
-sun/security/provider/PolicyParser/ExtDirsDefaultPolicy.java         generic-all
-sun/security/provider/PolicyParser/PrincipalExpansionError.java      generic-all
-sun/security/tools/keytool/i18n.sh                                   generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8130151
-# https://bugs.openjdk.java.net/browse/JDK-8157344
-sun/security/provider/SecureRandom/StrongSecureRandom.java           generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8011134
-sun/security/ssl/com/sun/net/ssl/internal/ssl/X509TrustManagerImpl/ClientServer.java generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8039130
-sun/security/ssl/javax/net/ssl/NewAPIs/CheckMyTrustedKeystore.java   generic-all
-sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/Basics.java         generic-all
-sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/TestAllSuites.java  generic-all
-sun/security/ssl/sanity/ciphersuites/CheckCipherSuites.java          generic-all
-sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/CloseKeepAliveCached.java generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8171489
-sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/B6216082.java linux-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8160023
-sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxyWithAuth.sh         generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8160624
-sun/security/tools/keytool/printssl.sh                               windows-all
+sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/B6216082.java      8171489 linux-all
+sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxyWithAuth.sh 8160023 generic-all
+sun/security/tools/keytool/printssl.sh                                            8160624 windows-all
 
 # expected failure on JBRE
-sun/misc/Version/Version.java                                        generic-all
+sun/misc/Version/Version.java                                                             generic-all
 
 # https://youtrack.jetbrains.com/issue/JRE-128
-java/awt/image/multiresolution/MultiDisplayTest/MultiDisplayTest.java                           generic-all
-java/awt/image/multiresolution/MultiResolutionIcon/IconTest.java                                generic-all
-java/awt/image/multiresolution/MultiResolutionTrayIconTest/MultiResolutionTrayIconTest.java     generic-all
-java/awt/image/multiresolution/BaseMultiResolutionImageTest.java                                generic-all
-java/awt/image/multiresolution/Corrupted2XImageTest.java                                        generic-all
-java/awt/image/multiresolution/MenuMultiresolutionIconTest.java                                 generic-all
-java/awt/image/multiresolution/MultiResolutionIcon/MultiResIconTest.java                        generic-all
-java/awt/image/multiresolution/MultiResolutionCachedImageTest.java                              generic-all
-java/awt/image/multiresolution/MultiresolutionIconTest.java                                     generic-all
-java/awt/image/multiresolution/MultiResolutionImagePropertiesTest.java                          generic-all
-java/awt/image/multiresolution/MultiResolutionJOptionPaneIconTest.java                          generic-all
-java/awt/image/multiresolution/MultiResolutionRenderingHintsTest.java                           generic-all
-java/awt/image/multiresolution/MultiresolutionSourceTest.java                                   generic-all
-java/awt/image/multiresolution/MultiResolutionToolkitImageTest.java                             generic-all
-java/awt/image/multiresolution/MultiResolutionImageObserverTest.java                            gereric-all
-java/awt/image/multiresolution/MultiResolutionDrawImageWithTransformTest.java                   gereric-all
-java/awt/image/MultiResolutionImage/MultiResolutionDisabledImageTest.java                       generic-all
-java/awt/image/MultiResolutionImage/MultiResolutionDrawImageWithTransformTest.java              generic-all
-java/awt/image/MultiResolutionImage/NSImageToMultiResolutionImageTest.java                      generic-all
-java/awt/image/MultiResolutionImageCommonTest.java                                              generic-all
-java/awt/image/MultiResolutionImageTest.java                                                    generic-all
+java/awt/image/multiresolution/MultiDisplayTest/MultiDisplayTest.java             JRE-128 generic-all
+java/awt/image/multiresolution/MultiResolutionIcon/IconTest.java                  JRE-128 generic-all
+java/awt/image/multiresolution/MultiResolutionTrayIconTest/MultiResolutionTrayIconTest.java JRE-128 generic-all
+java/awt/image/multiresolution/BaseMultiResolutionImageTest.java                  JRE-128 generic-all
+java/awt/image/multiresolution/Corrupted2XImageTest.java                          JRE-128 generic-all
+java/awt/image/multiresolution/MenuMultiresolutionIconTest.java                   8169187,JRE-128 generic-all
+java/awt/image/multiresolution/MultiResolutionIcon/MultiResIconTest.java          JRE-128 generic-all
+java/awt/image/multiresolution/MultiResolutionCachedImageTest.java                JRE-128 generic-all
+java/awt/image/multiresolution/MultiresolutionIconTest.java                       JRE-128 generic-all
+java/awt/image/multiresolution/MultiResolutionImagePropertiesTest.java            JRE-128 generic-all
+java/awt/image/multiresolution/MultiResolutionJOptionPaneIconTest.java            JRE-128 generic-all
+java/awt/image/multiresolution/MultiResolutionRenderingHintsTest.java             JRE-128 generic-all
+java/awt/image/multiresolution/MultiresolutionSourceTest.java                     JRE-128 generic-all
+java/awt/image/multiresolution/MultiResolutionToolkitImageTest.java               JRE-128 generic-all
+java/awt/image/multiresolution/MultiResolutionImageObserverTest.java              JRE-128 gereric-all
+java/awt/image/multiresolution/MultiResolutionDrawImageWithTransformTest.java     JRE-128,8198390 generic-all
+java/awt/image/MultiResolutionImage/MultiResolutionDisabledImageTest.java         JRE-128 generic-all
+java/awt/image/MultiResolutionImage/MultiResolutionDrawImageWithTransformTest.java JRE-128 generic-all
+java/awt/image/MultiResolutionImage/NSImageToMultiResolutionImageTest.java        JRE-128 generic-all
+java/awt/image/MultiResolutionImageCommonTest.java                                JRE-128 generic-all
+java/awt/image/MultiResolutionImageTest.java                                      JRE-128 generic-all
 
-# https://bugs.openjdk.java.net/browse/JDK-8173145
-com/sun/java/swing/plaf/windows/Test8173145.java                                                windows-all
+com/sun/java/swing/plaf/windows/Test8173145.java                                  8173145,8198334 windows-all
 
 # ignored
-com/sun/crypto/provider/Cipher/DES/PerformanceTest.java                                         generic-all
-com/sun/jdi/PopAndInvokeTest.java                                                               generic-all
-com/sun/security/auth/callback/DialogCallbackHandler/Default.java                               generic-all
-com/sun/security/auth/callback/TextCallbackHandler/Default.java                                 generic-all
-com/sun/tracing/BasicFunctionality.java                                                         generic-all
+com/sun/crypto/provider/Cipher/DES/PerformanceTest.java                                   generic-all
+com/sun/jdi/PopAndInvokeTest.java                                                         generic-all
+com/sun/security/auth/callback/DialogCallbackHandler/Default.java                         generic-all
+com/sun/security/auth/callback/TextCallbackHandler/Default.java                           generic-all
+com/sun/tracing/BasicFunctionality.java                                                   generic-all
+
 # Uses certutil.exe that isn't guaranteed to be installed
-sun/security/mscapi/nonUniqueAliases/NonUniqueAliases.sh                                        generic-all
+sun/security/mscapi/nonUniqueAliases/NonUniqueAliases.sh                                  generic-all
 
-# https://bugs.openjdk.java.net/browse/JDK-8146858
-sun/security/mscapi/PublicKeyInterop.sh                                                         windows-all
+sun/security/mscapi/PublicKeyInterop.sh                                           8146858 windows-all
+sun/security/mscapi/ShortRSAKey1024.sh                                            8023546 windows-all
+sun/security/mscapi/SignUsingNONEwithRSA.sh                                       8144559 windows-all
+sun/security/mscapi/SignUsingSHA2withRSA.sh                                       8144559 windows-all
 
-# https://bugs.openjdk.java.net/browse/JDK-8023546
-sun/security/mscapi/ShortRSAKey1024.sh                                                          windows-all
+com/sun/jdi/ArrayLengthDumpTest.sh                                                8145552 windows-all
+com/sun/jdi/BreakpointWithFullGC.sh                                               8145552 windows-all
+com/sun/jdi/CatchCaughtTest.sh                                                    8145552 windows-all
+com/sun/jdi/CatchCaughtTest.sh                                                    8145552 windows-all
+com/sun/jdi/CatchPatternTest.sh                                                   8145552 windows-all
+com/sun/jdi/GetLocalVariables3Test.sh                                             8145552 windows-all
+com/sun/jdi/GetLocalVariables4Test.sh                                             8145552,8067354 windows-all
+com/sun/jdi/JdbMethodExitTest.sh                                                  8145552,8171483 generic-all
+com/sun/jdi/JdbMissStep.sh                                                        8145552 windows-all
+com/sun/jdi/JdbVarargsTest.sh                                                     8145552 windows-all
+com/sun/jdi/NotAField.sh                                                          8145552 windows-all
+com/sun/jdi/Redefine-g.sh                                                         8145552 windows-all
+com/sun/jdi/RedefineAbstractClass.sh                                              8145552 windows-all
+com/sun/jdi/RedefineImplementor.sh                                                8145552,8004127 generic-all
+com/sun/jdi/RedefineMulti.sh                                                      8145552 windows-all
 
-# https://bugs.openjdk.java.net/browse/JDK-8144559
-sun/security/mscapi/SignUsingNONEwithRSA.sh                                                     windows-all
-sun/security/mscapi/SignUsingSHA2withRSA.sh                                                     windows-all
+com/sun/jdi/ConstantPoolInfoGC.java                                               6822627 generic-all
+com/sun/jdi/DoubleAgentTest.java                                                  8054066 generic-all
+com/sun/jdi/InvokeHangTest.java                                                   6648858 generic-all
+com/sun/jdi/RedefineClearBreakpoint.sh                                            8151887 generic-all
+com/sun/nio/sctp/SctpChannel/SocketOptionTests.java                               8141694,8075066 linux-all
+com/sun/nio/sctp/SctpMultiChannel/SocketOptionTests.java                          8141694 linux-all
+sun/nio/cs/FindDecoderBugs.java                                                   8022224 linux-all
 
-## https://bugs.openjdk.java.net/browse/JDK-8150070
-# https://bugs.openjdk.java.net/browse/JDK-8145552
-com/sun/jdi/ArrayLengthDumpTest.sh                                                              windows-all
-com/sun/jdi/BreakpointWithFullGC.sh                                                             windows-all
-com/sun/jdi/CatchCaughtTest.sh                                                                  windows-all
-com/sun/jdi/CatchCaughtTest.sh                                                                  windows-all
-com/sun/jdi/CatchPatternTest.sh                                                                 windows-all
-com/sun/jdi/GetLocalVariables3Test.sh                                                           windows-all
-com/sun/jdi/GetLocalVariables4Test.sh                                                           windows-all
-com/sun/jdi/JdbMethodExitTest.sh                                                                windows-all
-com/sun/jdi/JdbMissStep.sh                                                                      windows-all
-com/sun/jdi/JdbVarargsTest.sh                                                                   windows-all
-com/sun/jdi/NotAField.sh                                                                        windows-all
-com/sun/jdi/Redefine-g.sh                                                                       windows-all
-com/sun/jdi/RedefineAbstractClass.sh                                                            windows-all
-com/sun/jdi/RedefineImplementor.sh                                                              windows-all
-com/sun/jdi/RedefineMulti.sh                                                                    windows-all
+com/sun/awt/Translucency/WindowOpacity.java                                       8172887 windows-all
+java/awt/DataFlavor/MissedHtmlAndRtfBug/MissedHtmlAndRtfBug.html                  8172887 generic-all
+java/awt/Focus/FocusEmbeddedFrameTest/FocusEmbeddedFrameTest.java                 8172887 windows-all
+java/awt/Frame/NormalToIconified/NormalToIconifiedTest.java                       8172887 generic-all
+java/awt/Frame/ObscuredFrame/ObscuredFrameTest.java                               8172887 linux-all
+java/awt/FullScreen/TranslucentWindow/TranslucentWindow.java                      8172887 windows-all
+java/awt/Mixing/MixingInHwPanel.java                                              8172887 generic-all
+java/awt/event/MouseEvent/EnterAsGrabbedEvent/EnterAsGrabbedEvent.java            8172887 generic-all
+java/awt/event/MouseEvent/RobotLWTest/RobotLWTest.html                            8172887 windows-all
+java/awt/dnd/NoFormatsCrashTest/NoFormatsCrashTest.html                           8172887 windows-all
+java/io/File/SetLastModified.java                                                 8172887 generic-all
+javax/swing/JScrollBar/7163696/Test7163696.java                                   8172887 generic-all
+javax/swing/PopupFactory/6276087/NonOpaquePopupMenuTest.java                      8172887,8065099 windows-all,macosx-all
+javax/swing/dnd/7171812/bug7171812.java                                           8172887 windows-all
+javax/swing/plaf/basic/BasicTreeUI/8023474/bug8023474.java                        8172887 windows-all
+javax/swing/plaf/basic/Test6984643.java                                           8172887,8198340 windows-all
+javax/swing/plaf/nimbus/8041642/ScrollBarThumbVisibleTest.java                    8172887 generic-all
+javax/swing/text/JTextComponent/5074573/bug5074573.java                           8155740 generic-all
+javax/swing/text/StyledEditorKit/4506788/bug4506788.java                          8155740 windows-all
+sun/java2d/DirectX/OpaqueImageToSurfaceBlitTest/OpaqueImageToSurfaceBlitTest.java 8155740 windows-all
+sun/java2d/DrawXORModeTest.java                                                   8155740 generic-all
+sun/java2d/OpenGL/CustomCompositeTest.java                                        8155740 windows-all
+sun/java2d/OpenGL/DrawBufImgOp.java                                               8155740 windows-all
+sun/java2d/OpenGL/DrawHugeImageTest.java                                          8155740 windows-all
+sun/java2d/XRenderBlitsTest.java                                                  8155740 windows-all
+java/awt/Robot/HiDPIMouseClick/HiDPIRobotMouseClick.java                          8155740 windows-all
+java/awt/hidpi/properties/HiDPIPropertiesWindowsTest.java                         8155740 windows-all
+java/awt/Graphics2D/ScaledTransform/ScaledTransform.java                          8155740 generic-all
+javax/swing/text/Utilities/8142966/SwingFontMetricsTest.java                      8155740 windows-all
+com/apple/eawt/DefaultMenuBar/DefaultMenuBarTest.java                             8160536 macosx-all
+com/apple/laf/ScreenMenu/ScreenMenuMemoryLeakTest.java                            8180821 macosx-all
 
-# https://bugs.openjdk.java.net/browse/JDK-6822627
-com/sun/jdi/ConstantPoolInfoGC.java                                                             generic-all
+java/awt/security/Permissions.java	                                              JRE-720 linux-all, macosx-all
+javax/swing/JScrollPane/Test6526631.java                                          JRE-720 macosx-all
+java/awt/Robot/RobotExtraButton/RobotExtraButton.java                             JRE-720 linux-all, windows-all
+javax/swing/JComboBox/6607130/bug6607130.java                                     JRE-720 windows-all
+java/awt/Frame/MaximizedNormalBoundsUndecoratedTest/MaximizedNormalBoundsUndecoratedTest.java JRE-720 macosx-all
+javax/swing/ToolTipManager/7123767/bug7123767.java                                JRE-720 linux-all
+java/security/KeyPairGenerator/FinalizeHalf.java                                  JRE-720 windows-all
+sun/security/mscapi/CastError.java                 	                              JRE-720 windows-all
+sun/security/mscapi/SignatureOffsets.java          	                              JRE-720 windows-all
+sun/security/mscapi/SmallPrimeExponentP.java       	                              JRE-720 windows-all
 
-# https://bugs.openjdk.java.net/browse/JDK-8054066
-com/sun/jdi/DoubleAgentTest.java                                                                generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-6648858
-com/sun/jdi/InvokeHangTest.java                                                                 generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8151887
-com/sun/jdi/RedefineClearBreakpoint.sh                                                          generic-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8141694
-# https://bugs.openjdk.java.net/browse/JDK-8075066
-com/sun/nio/sctp/SctpChannel/SocketOptionTests.java                                             linux-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8141694
-com/sun/nio/sctp/SctpMultiChannel/SocketOptionTests.java                                        linux-all
-
-https://bugs.openjdk.java.net/browse/JDK-8022224
-sun/nio/cs/FindDecoderBugs.java                                                                 linux-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8172887
-com/sun/awt/Translucency/WindowOpacity.java                                                     windows-all
-java/awt/DataFlavor/MissedHtmlAndRtfBug/MissedHtmlAndRtfBug.html                                generic-all
-java/awt/Focus/FocusEmbeddedFrameTest/FocusEmbeddedFrameTest.java                               windows-all
-java/awt/Frame/NormalToIconified/NormalToIconifiedTest.java                                     generic-all
-java/awt/Frame/ObscuredFrame/ObscuredFrameTest.java                                             linux-all
-java/awt/FullScreen/TranslucentWindow/TranslucentWindow.java                                    windows-all
-java/awt/Mixing/MixingInHwPanel.java                                                            generic-all
-java/awt/event/MouseEvent/EnterAsGrabbedEvent/EnterAsGrabbedEvent.java                          generic-all
-java/awt/event/MouseEvent/RobotLWTest/RobotLWTest.html                                          windows-all
-#java/awt/TextArea/Mixing/TextAreaMixing.java                                                    windows-all
-java/awt/dnd/NoFormatsCrashTest/NoFormatsCrashTest.html                                         windows-all
-java/io/File/SetLastModified.java                                                               generic-all
-javax/swing/JScrollBar/7163696/Test7163696.java                                                 generic-all
-#javax/swing/text/html/CSS/4530474/bug4530474.java                                               windows-all
-# https://bugs.openjdk.java.net/browse/JDK-8065099
-javax/swing/PopupFactory/6276087/NonOpaquePopupMenuTest.java                                    generic-all
-javax/swing/dnd/7171812/bug7171812.java                                                         windows-all
-javax/swing/plaf/basic/BasicTreeUI/8023474/bug8023474.java                                      windows-all
-javax/swing/plaf/basic/Test6984643.java                                                         windows-all
-javax/swing/plaf/basic/Test6984643.java                                                         windows-all
-javax/swing/plaf/nimbus/8041642/ScrollBarThumbVisibleTest.java                                  generic-all
-# https://bugs.openjdk.java.net/browse/JDK-8155740
-javax/swing/text/JTextComponent/5074573/bug5074573.java                                         generic-all
-javax/swing/text/StyledEditorKit/4506788/bug4506788.java                                        windows-all
-sun/java2d/DirectX/OpaqueImageToSurfaceBlitTest/OpaqueImageToSurfaceBlitTest.java               windows-all
-sun/java2d/DrawXORModeTest.java                                                                 generic-all
-sun/java2d/OpenGL/CustomCompositeTest.java                                                      windows-all
-sun/java2d/OpenGL/DrawBufImgOp.java                                                             windows-all
-sun/java2d/OpenGL/DrawHugeImageTest.java                                                        windows-all
-sun/java2d/XRenderBlitsTest.java                                                                windows-all
-java/awt/Robot/HiDPIMouseClick/HiDPIRobotMouseClick.java                                        windows-all
-java/awt/hidpi/properties/HiDPIPropertiesWindowsTest.java                                       windows-all
-java/awt/Graphics2D/ScaledTransform/ScaledTransform.java                                        generic-all
-javax/swing/text/Utilities/8142966/SwingFontMetricsTest.java                                    windows-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8160536
-com/apple/eawt/DefaultMenuBar/DefaultMenuBarTest.java                                           macosx-all
-
-# https://bugs.openjdk.java.net/browse/JDK-8180821
-com/apple/laf/ScreenMenu/ScreenMenuMemoryLeakTest.java                                          macosx-all
+sun/tools/native2ascii/Native2AsciiTests.sh                                       JRE-738 windows-all
\ No newline at end of file