diff options
author | Dana Dahlstrom <dahlstrom@google.com> | 2018-08-15 16:21:23 -0700 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2018-08-15 16:21:23 -0700 |
commit | 1e89bbc549ed0017052017442eb5929a8415fef0 (patch) | |
tree | 20a862d7b2cd1e9811aafb7692ef1b9ea18df4a3 | |
parent | 3d846476d5c795a9e3b5f574027acf6567abb183 (diff) | |
parent | 9729bb43f849817fefb5642d1d771a4a013a96d9 (diff) | |
download | jdk8u_jdk-1e89bbc549ed0017052017442eb5929a8415fef0.tar.gz |
Merge tag jb8u152-b1248.8
am: 9729bb43f8
Change-Id: I44f022325d4bbdfcfb9bd8a93cff226f3c281823
82 files changed, 16476 insertions, 6741 deletions
diff --git a/.gitignore b/.gitignore index 814f17068f..3a0136438d 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 35eb1ddfbb..0000000000 --- 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 79ee123c2b..0000000000 --- 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 271743250c..0000000000 --- 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 e79edb7153..0000000000 --- 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 c1a07693d2..e8b042b529 100644 --- a/make/CreateJars.gmk +++ b/make/CreateJars.gmk @@ -265,7 +265,7 @@ $(IMAGES_OUTPUTDIR)/lib$(PROFILE)/_the.jars.contents: $(BUILD_TOOLS) $(IMAGES_OU $(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 b51cbefbd9..26370559ea 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 a3268bb9f8..dcf61776dc 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 1f4af01608..eefaf534bd 100644 --- a/src/macosx/bundle/JavaAppLauncher/src/JVMArgs.m +++ b/src/macosx/bundle/JavaAppLauncher/src/JVMArgs.m @@ -97,9 +97,9 @@ NSString *GetJavaRoot(NSDictionary *jvmInfoDict) { 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 @@ NSString *GetJavaRoot(NSDictionary *jvmInfoDict) { // 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 e4abc5fe1a..228989920b 100644 --- a/src/macosx/classes/sun/lwawt/macosx/CCursorManager.java +++ b/src/macosx/classes/sun/lwawt/macosx/CCursorManager.java @@ -29,11 +29,10 @@ import sun.lwawt.LWCursorManager; 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 @@ final class CCursorManager extends LWCursorManager { @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 543ed20d4c..eaeb8f66a8 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 @@ JNF_COCOA_ENTER(env); } 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 9581b932ad..732f7ed06d 100644 --- a/src/macosx/native/sun/awt/CCursorManager.m +++ b/src/macosx/native/sun/awt/CCursorManager.m @@ -110,23 +110,23 @@ JNF_COCOA_ENTER(env); 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 05ef198764..905c730d77 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 b854d5b072..86d2c0bf0a 100644 --- a/src/macosx/native/sun/font/AWTStrike.m +++ b/src/macosx/native/sun/font/AWTStrike.m @@ -45,13 +45,15 @@ static CGAffineTransform sInverseTX = { 1, 0, 0, -1, 0, 0 }; 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 @@ static CGAffineTransform sInverseTX = { 1, 0, 0, -1, 0, 0 }; 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 @@ JNF_COCOA_ENTER(env); 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 48027c498b..2268bc52a9 100644 --- a/src/macosx/native/sun/font/CGGlyphImages.m +++ b/src/macosx/native/sun/font/CGGlyphImages.m @@ -583,14 +583,17 @@ CGGI_CreateNewGlyphInfoFrom(CGSize advance, CGRect bbox, } 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 @@ CGGI_CreateNewGlyphInfoFrom(CGSize advance, CGRect bbox, 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 4fd122f9cb..d656880966 100644 --- a/src/share/classes/javax/swing/RepaintManager.java +++ b/src/share/classes/javax/swing/RepaintManager.java @@ -112,6 +112,8 @@ public class RepaintManager 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 @@ public class RepaintManager } 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 @@ public class RepaintManager 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 class RepaintManager 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 93d8e05996..24f1bedbbb 100644 --- a/src/share/classes/sun/java2d/loops/GraphicsPrimitive.java +++ b/src/share/classes/sun/java2d/loops/GraphicsPrimitive.java @@ -320,6 +320,7 @@ public abstract class GraphicsPrimitive { 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 abstract class GraphicsPrimitive { 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 @@ public abstract class GraphicsPrimitive { 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 @@ public abstract class GraphicsPrimitive { showTraceUsage(); } } + + GraphicsPrimitiveMgr.setTraceFlags(traceflags); + if (verbose) { System.err.print("GraphicsPrimitive logging "); if ((traceflags & GraphicsPrimitive.TRACELOG) != 0) { @@ -467,6 +475,10 @@ public abstract class GraphicsPrimitive { } 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 abstract class GraphicsPrimitive { } 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 6f76f544be..faa9383b65 100644 --- a/src/share/classes/sun/java2d/loops/GraphicsPrimitiveMgr.java +++ b/src/share/classes/sun/java2d/loops/GraphicsPrimitiveMgr.java @@ -51,6 +51,7 @@ public final class GraphicsPrimitiveMgr { 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/ArrayCacheConst.java index 5f36e0d7ce..2c0cfe2460 100644 --- a/src/share/classes/sun/java2d/marlin/ArrayCache.java +++ b/src/share/classes/sun/java2d/marlin/ArrayCacheConst.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 @@ -28,60 +28,45 @@ package sun.java2d.marlin; import java.util.Arrays; import static sun.java2d.marlin.MarlinUtils.logInfo; -public final class ArrayCache implements MarlinConst { +public final class ArrayCacheConst implements MarlinConst { - static final int BUCKETS = 4; + static final int BUCKETS = 8; static final int MIN_ARRAY_SIZE = 4096; + // maximum array size static final int MAX_ARRAY_SIZE; - static final int MASK_CLR_1 = ~1; + // 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; - 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; + // threshold to grow arrays only by (5/4) instead of (3/2) 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 final int[] ARRAY_SIZES = new int[BUCKETS]; static { // initialize buckets for int/float arrays int arraySize = MIN_ARRAY_SIZE; - for (int i = 0; i < BUCKETS; i++, arraySize <<= 2) { + 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); } - } - 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); + if (arraySize >= THRESHOLD_SMALL_ARRAY_SIZE) { + inc_lg = 1; // x2 } } - MAX_DIRTY_BYTE_ARRAY_SIZE = arraySize >> 1; + MAX_ARRAY_SIZE = arraySize >> inc_lg; - // threshold to grow arrays only by (3/2) instead of 2 - THRESHOLD_ARRAY_SIZE = Math.max(2 * 1024 * 1024, MAX_ARRAY_SIZE); // 2M + if (MAX_ARRAY_SIZE <= 0) { + throw new IllegalStateException("Invalid max array size !"); + } - THRESHOLD_LARGE_ARRAY_SIZE = 8L * THRESHOLD_ARRAY_SIZE; // 16M - THRESHOLD_HUGE_ARRAY_SIZE = 8L * THRESHOLD_LARGE_ARRAY_SIZE; // 128M + THRESHOLD_ARRAY_SIZE = 16 * 1024 * 1024; // >16M + THRESHOLD_HUGE_ARRAY_SIZE = 48L * 1024 * 1024; // >48M if (DO_STATS || DO_MONITORS) { logInfo("ArrayCache.BUCKETS = " + BUCKETS); @@ -89,56 +74,17 @@ public final class ArrayCache implements MarlinConst { 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() { + private ArrayCacheConst() { // 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) { @@ -150,15 +96,6 @@ public final class ArrayCache implements MarlinConst { 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 @@ -174,7 +111,7 @@ public final class ArrayCache implements MarlinConst { "array exceeds maximum capacity !"); } assert curSize >= 0; - final int initial = (curSize & MASK_CLR_1); + final int initial = curSize; int size; if (initial > THRESHOLD_ARRAY_SIZE) { size = initial + (initial >> 1); // x(3/2) @@ -212,10 +149,12 @@ public final class ArrayCache implements MarlinConst { long size; if (curSize > THRESHOLD_HUGE_ARRAY_SIZE) { size = curSize + (curSize >> 2L); // x(5/4) - } else if (curSize > THRESHOLD_LARGE_ARRAY_SIZE) { + } else if (curSize > THRESHOLD_ARRAY_SIZE) { size = curSize + (curSize >> 1L); // x(3/2) - } else { + } 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) { @@ -229,4 +168,108 @@ public final class ArrayCache implements MarlinConst { } 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 7854795dfd..0b7e3701c3 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; - - void dumpStats() { - if (getOp > 0) { - logInfo("ByteArrayCache[" + arraySize + "]: get: " + getOp - + " created: " + createOp + " - returned: " + returnOp - + " :: cache size: " + byteArrays.size()); - } + final boolean clean; + private final int bucketCapacity; + private WeakReference<Bucket[]> refBuckets = null; + final CacheStats stats; + + 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++; + 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; + } - return new byte[arraySize]; + Reference createRef(final int initialSize) { + return new Reference(this, initialSize); } - void putDirtyArray(final byte[] array, final int length) { - if (length != arraySize) { - if (DO_CHECKS) { - MarlinUtils.logInfo("ArrayCache: bad length = " + length); + 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++; + + 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); } - // NO clean-up of array data = DIRTY 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_CLEAN_DIRTY) { - // Force zero-fill dirty arrays: - Arrays.fill(array, 0, array.length, BYTE_0); + if (DO_LOG_WIDEN_ARRAY) { + logInfo(getLogPrefix(clean) + "ByteArrayCache: " + + "widenArray[" + res.length + + "]: usedSize=\t" + usedSize + "\tlength=\t" + length + + "\tneeded length=\t" + needSize); + } + return res; } - // fill cache: - byteArrays.addLast(array); - } + byte[] putArray(final byte[] array) + { + // dirty array helper: + return putArray(array, 0, array.length); + } - 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); + 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; + return initial; } - if (DO_STATS) { - returnOp++; + } + + 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); } - // clean-up array of dirty part[fromIndex; toIndex[ - fill(array, fromIndex, toIndex, BYTE_0); + 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; - // fill cache: - byteArrays.addLast(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 @@ final class ByteArrayCache implements MarlinConst { } } } + + 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 dbe9c2cc8a..4da33afba6 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 @@ import sun.awt.geom.PathConsumer2D; 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 @@ final class CollinearSimplifier implements PathConsumer2D { @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 @@ final class CollinearSimplifier implements PathConsumer2D { } @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; - - 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; - } + 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); + + // 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 092a38ef1c..ad73572936 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 @@ final class Curve { 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; - } - - float xat(float t) { - return t * (t * (t * ax + bx) + cx) + dx; - } - float yat(float t) { - return t * (t * (t * ay + by) + cy) + dy; - } - - float dxat(float t) { - return t * (t * dax + dbx) + cx; + dax = 0.0f; + day = 0.0f; + dbx = 2.0f * bx; + dby = 2.0f * by; } - float dyat(float t) { - return t * (t * day + dby) + cy; + 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; + } } - 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 @@ final class Curve { // 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 @@ final class Curve { 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 @@ final class Curve { // 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 @@ final class Curve { } 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 @@ final class Curve { 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 0000000000..ee85b3e59f --- /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 0000000000..2aaa55147a --- /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 0000000000..6ccc31ec8a --- /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 0000000000..7bcb0065d9 --- /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> + 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 0000000000..063584eb39 --- /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 0000000000..9cb3f1c9b3 --- /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 0000000000..8bbe5b7c71 --- /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 0000000000..27f479ae54 --- /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 0000000000..e2d6234d77 --- /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 0000000000..628850f06e --- /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 0000000000..ae60c03b6c --- /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 890bbf5dd4..561347e55d 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 @@ package sun.java2d.marlin; 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 @@ import sun.awt.geom.PathConsumer2D; * 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 @@ final class Dasher implements sun.awt.geom.PathConsumer2D, MarlinConst { 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 @@ final class Dasher implements sun.awt.geom.PathConsumer2D, MarlinConst { // 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 @@ final class Dasher implements sun.awt.geom.PathConsumer2D, MarlinConst { 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 @@ final class Dasher implements sun.awt.geom.PathConsumer2D, MarlinConst { 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 @@ final class Dasher implements sun.awt.geom.PathConsumer2D, MarlinConst { 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 @@ final class Dasher implements sun.awt.geom.PathConsumer2D, MarlinConst { 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; + + 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 == 0f) { + float len = dx * dx + dy * dy; + if (len == 0.0f) { return; } len = (float) Math.sqrt(len); @@ -263,96 +418,212 @@ final class Dasher implements sun.awt.geom.PathConsumer2D, MarlinConst { final float[] _curCurvepts = curCurvepts; final float[] _dash = dash; + final int _dashLen = this.dashLen; + + int _idx = idx; + boolean _dashOn = dashOn; + float _phase = phase; - float leftInThisDashSegment; - float dashdx, dashdy, p; + 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; - - 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); + float leftInThisDashSegment = _dash[_idx] - _phase; + + 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]; - } - goTo(curCurvepts, curCurveoff+2, type); - phase += li.lastSegLen(); - if (phase >= dash[idx]) { - phase = 0f; - idx = (idx + 1) % dashLen; - dashOn = !dashOn; + _idx = (_idx + 1) % _dashLen; + _dashOn = !_dashOn; + _phase = 0.0f; + leftInThisDashSegment = _dash[_idx]; + } + + 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 @@ final class Dasher implements sun.awt.geom.PathConsumer2D, MarlinConst { // 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 @@ final class Dasher implements sun.awt.geom.PathConsumer2D, MarlinConst { // 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 @@ final class Dasher implements sun.awt.geom.PathConsumer2D, MarlinConst { 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 @@ final class Dasher implements sun.awt.geom.PathConsumer2D, MarlinConst { // 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 @@ final class Dasher implements sun.awt.geom.PathConsumer2D, MarlinConst { while (lenAtNextT < targetLength) { if (done) { lastSegLen = lenAtNextT - lenAtLastSplit; - return 1f; + return 1.0f; } goToNextLeaf(); } @@ -524,19 +794,19 @@ final class Dasher implements sun.awt.geom.PathConsumer2D, MarlinConst { // 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 @@ final class Dasher implements sun.awt.geom.PathConsumer2D, MarlinConst { // 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 @@ final class Dasher implements sun.awt.geom.PathConsumer2D, MarlinConst { // 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 @@ final class Dasher implements sun.awt.geom.PathConsumer2D, MarlinConst { return t; } + float totalLength() { + while (!done) { + goToNextLeaf(); + } + // reset LengthIterator: + reset(); + + return lenAtNextT; + } + float lastSegLen() { return lastSegLen; } @@ -578,11 +859,11 @@ final class Dasher implements sun.awt.geom.PathConsumer2D, MarlinConst { 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 @@ final class Dasher implements sun.awt.geom.PathConsumer2D, MarlinConst { _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 @@ final class Dasher implements sun.awt.geom.PathConsumer2D, MarlinConst { // 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 0000000000..bbd6853cbe --- /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 87876b8c3e..ff84aa69c3 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; - - void dumpStats() { - if (getOp > 0) { - logInfo("FloatArrayCache[" + arraySize + "]: get: " + getOp - + " created: " + createOp + " - returned: " + returnOp - + " :: cache size: " + floatArrays.size()); - } + final boolean clean; + private final int bucketCapacity; + private WeakReference<Bucket[]> refBuckets = null; + final CacheStats stats; + + 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; - } + for (int i = 0; i < BUCKETS; i++) { + buckets[i] = new Bucket(clean, ARRAY_SIZES[i], bucketCapacity, + (DO_STATS) ? stats.bucketStats[i] : null); + } - if (DO_STATS) { - createOp++; + // update weak reference: + refBuckets = new WeakReference<Bucket[]>(buckets); } + return buckets; + } - return new float[arraySize]; + Reference createRef(final int initialSize) { + return new Reference(this, initialSize); } - void putDirtyArray(final float[] array, final int length) { - if (length != arraySize) { - if (DO_CHECKS) { - MarlinUtils.logInfo("ArrayCache: bad length = " + length); + 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++; + + 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); } - // NO clean-up of array data = DIRTY 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_CLEAN_DIRTY) { - // Force zero-fill dirty arrays: - Arrays.fill(array, 0, array.length, 0f); + if (DO_LOG_WIDEN_ARRAY) { + logInfo(getLogPrefix(clean) + "FloatArrayCache: " + + "widenArray[" + res.length + + "]: usedSize=\t" + usedSize + "\tlength=\t" + length + + "\tneeded length=\t" + needSize); + } + return res; } - // fill cache: - floatArrays.addLast(array); - } + float[] putArray(final float[] array) + { + // dirty array helper: + return putArray(array, 0, array.length); + } - 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); + 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; + return initial; } - if (DO_STATS) { - returnOp++; + } + + 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); } - // clean-up array of dirty part[fromIndex; toIndex[ - fill(array, fromIndex, toIndex, 0f); + 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; - // fill cache: - floatArrays.addLast(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 @@ final class FloatArrayCache implements MarlinConst { } } } + + 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 81dc6f7595..56e4488f8e 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 @@ public final class FloatMath implements MarlinConst { // 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 @@ public final class FloatMath implements MarlinConst { // 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 @@ public final class FloatMath implements MarlinConst { * 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 @@ public final class FloatMath implements MarlinConst { 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 @@ public final class FloatMath implements MarlinConst { // 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 @@ public final class FloatMath implements MarlinConst { * 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 @@ public final class FloatMath implements MarlinConst { 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 @@ public final class FloatMath implements MarlinConst { } /** + * 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 @@ public final class FloatMath implements MarlinConst { } 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 0b0277dc24..0aa55f7ca1 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 @@ final class Helpers implements MarlinConst { 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 (b != 0f) { - t = (-c) / b; - zeroes[ret++] = t; + } else if (dis == 0.0f) { + zeroes[ret++] = -b / (2.0f * a); } + } 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 @@ final class Helpers implements MarlinConst { // 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 @@ final class Helpers implements MarlinConst { 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); + } + + 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); } - return acc; + + // 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 @@ final class Helpers implements MarlinConst { * 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; - static void subdivideCubicAt(float t, float[] src, int srcoff, - float[] left, int leftoff, - float[] right, int rightoff) + right[0] = cx; + right[1] = cy; + } + + static void subdivideQuad(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 + 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; - } - 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 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 subdivideQuad(float[] src, int srcoff, - float[] left, int leftoff, - float[] right, int rightoff) + static void subdivideQuadAt(final float t, + final float[] src, final int offS, + final float[] pts, final int offL, final int offR) { - 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; - } + 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 subdivideQuadAt(float t, float[] src, int srcoff, - float[] left, int leftoff, - float[] right, int rightoff) + static void subdivideLineAt(final float t, + final float[] src, final int offS, + final float[] pts, final int offL, final int offR) { - 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; + 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); } } - static void subdivideAt(float t, float[] src, int srcoff, - float[] left, int leftoff, - float[] right, int rightoff, int size) + // From sun.java2d.loops.GeneralRenderer: + + static int outcode(final float x, final float y, + final float[] clipRect) { - switch(size) { - case 8: - subdivideCubicAt(t, src, srcoff, left, leftoff, right, rightoff); - return; - case 6: - subdivideQuadAt(t, src, srcoff, left, leftoff, right, rightoff); - return; + 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; + + 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); + } + + 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; + } + } + + // 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 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 0000000000..ceecc9a970 --- /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 917e992813..a23f39acac 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; - - void dumpStats() { - if (getOp > 0) { - logInfo("IntArrayCache[" + arraySize + "]: get: " + getOp - + " created: " + createOp + " - returned: " + returnOp - + " :: cache size: " + intArrays.size()); - } + final boolean clean; + private final int bucketCapacity; + private WeakReference<Bucket[]> refBuckets = null; + final CacheStats stats; + + 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++; + 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; + } - return new int[arraySize]; + Reference createRef(final int initialSize) { + return new Reference(this, initialSize); } - void putDirtyArray(final int[] array, final int length) { - if (length != arraySize) { - if (DO_CHECKS) { - MarlinUtils.logInfo("ArrayCache: bad length = " + length); + 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++; + + 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); } - // NO clean-up of array data = DIRTY 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_CLEAN_DIRTY) { - // Force zero-fill dirty arrays: - Arrays.fill(array, 0, array.length, 0); + if (DO_LOG_WIDEN_ARRAY) { + logInfo(getLogPrefix(clean) + "IntArrayCache: " + + "widenArray[" + res.length + + "]: usedSize=\t" + usedSize + "\tlength=\t" + length + + "\tneeded length=\t" + needSize); + } + return res; } - // fill cache: - intArrays.addLast(array); - } + int[] putArray(final int[] array) + { + // dirty array helper: + return putArray(array, 0, array.length); + } - 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); + 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; + return initial; } - if (DO_STATS) { - returnOp++; + } + + 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); } - // clean-up array of dirty part[fromIndex; toIndex[ - fill(array, fromIndex, toIndex, 0); + 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; - // fill cache: - intArrays.addLast(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 @@ final class IntArrayCache implements MarlinConst { } } } + + 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 0000000000..e760a02e01 --- /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 54877a2ed2..3f5e8e1674 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 @@ public final class MarlinCache implements MarlinConst { // 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 @@ public final class MarlinCache implements MarlinConst { // 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 @@ public final class MarlinCache implements MarlinConst { // 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 @@ public final class MarlinCache implements MarlinConst { // 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 @@ public final class MarlinCache implements MarlinConst { // 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 @@ public final class MarlinCache implements MarlinConst { // 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 @@ public final class MarlinCache implements MarlinConst { 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 @@ public final class MarlinCache implements MarlinConst { 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 @@ public final class MarlinCache implements MarlinConst { // 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 @@ public final class MarlinCache implements MarlinConst { } // 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 @@ public final class MarlinCache implements MarlinConst { 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 @@ public final class MarlinCache implements MarlinConst { } 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 @@ public final class MarlinCache implements MarlinConst { 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 @@ public final class MarlinCache implements MarlinConst { } 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 @@ public final class MarlinCache implements MarlinConst { 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 @@ public final class MarlinCache implements MarlinConst { 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 @@ public final class MarlinCache implements MarlinConst { } // 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 @@ public final class MarlinCache implements MarlinConst { 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 @@ public final class MarlinCache implements MarlinConst { { // 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 @@ public final class MarlinCache implements MarlinConst { } 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 22bf86d66c..baf4c2d14f 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 @@ interface MarlinConst { // 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 @@ interface MarlinConst { // 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; + static final int INITIAL_AA_ARRAY = INITIAL_PIXEL_WIDTH; - // initial edges (24 bytes) = 24K [ints] = 96K - static final int INITIAL_EDGES_CAPACITY = 4096 * 24; // 6 ints per edges + // 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 @@ interface MarlinConst { 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 bbee15a13f..3099b7c268 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 @@ public final class MarlinProperties { } /** - * 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 @@ public final class MarlinProperties { 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 @@ public final class MarlinProperties { 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 @@ public final class MarlinProperties { 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 0000000000..8b4e7518a3 --- /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 b7d3af4159..b263689587 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 @@ import sun.security.action.GetPropertyAction; /** * 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 @@ public class MarlinRenderingEngine extends RenderingEngine 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 @@ public class MarlinRenderingEngine extends RenderingEngine miterlimit, dashes, dashphase, - rdrCtx.transformerPC2D.wrapPath2d(p2d) + rdrCtx.transformerPC2D.wrapPath2D(p2d) ); // Use Path2D copy constructor (trim) @@ -128,11 +164,11 @@ public class MarlinRenderingEngine extends RenderingEngine * 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 @@ public class MarlinRenderingEngine extends RenderingEngine } } - 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 @@ public class MarlinRenderingEngine extends RenderingEngine pc2d); } - private final float userSpaceLineWidth(AffineTransform at, float lw) { + private float userSpaceLineWidth(AffineTransform at, float lw) { float widthScale; @@ -234,7 +270,7 @@ public class MarlinRenderingEngine extends RenderingEngine */ 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 @@ public class MarlinRenderingEngine extends RenderingEngine 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 @@ public class MarlinRenderingEngine extends RenderingEngine 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 @@ public class MarlinRenderingEngine extends RenderingEngine int dashLen = -1; boolean recycleDashes = false; + float scale = 1.0f; if (at != null && !at.isIdentity()) { final double a = at.getScaleX(); @@ -307,7 +344,7 @@ public class MarlinRenderingEngine extends RenderingEngine 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 @@ public class MarlinRenderingEngine extends RenderingEngine // 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 @@ public class MarlinRenderingEngine extends RenderingEngine // 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 @@ public class MarlinRenderingEngine extends RenderingEngine 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 @@ public class MarlinRenderingEngine extends RenderingEngine } 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 @@ public class MarlinRenderingEngine extends RenderingEngine 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 @@ public class MarlinRenderingEngine extends RenderingEngine } 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 @@ public class MarlinRenderingEngine extends RenderingEngine 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 @@ public class MarlinRenderingEngine extends RenderingEngine 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 @@ public class MarlinRenderingEngine extends RenderingEngine } } 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 @@ public class MarlinRenderingEngine extends RenderingEngine } @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 @@ public class MarlinRenderingEngine extends RenderingEngine 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 @@ public class MarlinRenderingEngine extends RenderingEngine 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 @@ public class MarlinRenderingEngine extends RenderingEngine } } 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 @@ public class MarlinRenderingEngine extends RenderingEngine } 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 @@ public class MarlinRenderingEngine extends RenderingEngine 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 @@ public class MarlinRenderingEngine extends RenderingEngine 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); + 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); @@ -1052,6 +1134,20 @@ public class MarlinRenderingEngine extends RenderingEngine // 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 @@ public class MarlinRenderingEngine extends RenderingEngine + 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 824660fd68..2882d68aac 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 @@ final class MarlinTileGenerator implements AATileGenerator, MarlinConst { 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 @@ final class MarlinTileGenerator implements AATileGenerator, MarlinConst { 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 @@ final class MarlinTileGenerator implements AATileGenerator, MarlinConst { */ @Override public int getTileHeight() { - return TILE_SIZE; + return TILE_H; } /** @@ -112,6 +144,10 @@ final class MarlinTileGenerator implements AATileGenerator, MarlinConst { */ @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 class MarlinTileGenerator implements AATileGenerator, MarlinConst { 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 @@ final class MarlinTileGenerator implements AATileGenerator, MarlinConst { */ @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 class MarlinTileGenerator implements AATileGenerator, MarlinConst { 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 class MarlinTileGenerator implements AATileGenerator, MarlinConst { 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 @@ final class MarlinTileGenerator implements AATileGenerator, MarlinConst { } } - // 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 @@ final class MarlinTileGenerator implements AATileGenerator, MarlinConst { nextTile(); if (DO_MONITORS) { - rdrCtx.stats.mon_ptg_getAlpha.stop(); + rdrStats.mon_ptg_getAlpha.stop(); } } @@ -282,7 +323,7 @@ final class MarlinTileGenerator implements AATileGenerator, MarlinConst { 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 class MarlinTileGenerator implements AATileGenerator, MarlinConst { 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 @@ final class MarlinTileGenerator implements AATileGenerator, MarlinConst { 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); + + for (cy = y0; cy < y1; cy++) { + // empty line (default) + cx = x0; - if (rowAAEnc[cy] == 0) { - // Raw encoding: + if (rowAAEnc[cy] == 0) { + // Raw encoding: - final int aax1 = rowAAx1[cy]; // exclusive + 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 + // 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; + 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; + // 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: - // now: cx >= x0 but cx < aax0 (x1 < aax0) + // quick check if there is AA data + // corresponding to this tile [x0; x1[ + if (rowAAx1[cy] > x0) { // last pixel exclusive - // Copy AA data (sum alpha data): - addr = addr_rowAA + rowAAChunkIndex[cy] + (cx - aax0); + 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); + } + } - 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(); + } + + idx += skipRowPixels; + } + break; + + case 0: + default: + 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 { + for (end = x0; end < cx; end++) { + tile[idx++] = 0; + } + } + + // now: cx >= x0 and cx >= aax0 - // fill line start until first AA pixel rowAA exclusive: - for (int i = x0; i < cx; i++) { - tile[idx++] = 0; + // 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 + // 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]; + // reuse previous iteration position: + addr = addr_row + rowAAPos[cy]; - last_addr = 0L; + last_addr = 0L; - while ((cx < x1) && (addr < addr_end)) { - // keep current position: - last_addr = addr; + while ((cx < x1) && (addr < addr_end)) { + // keep current position: + last_addr = addr; - // packed value: - packed = _unsafe.getInt(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; - // last exclusive pixel x-coordinate: - cx1 = (packed >> 8); - // as bytes: - addr += SIZE_INT; + // ensure rx1 > rx0: + if (runLen > 0) { + packed &= 0xFF; // [0-255] - rx0 = cx; - if (rx0 < x0) { - rx0 = x0; + val = (byte) packed; // [0-255] + do { + tile[idx++] = val; + } while (--runLen > 0); + } } - rx1 = cx = cx1; - if (rx1 > x1) { - rx1 = x1; - cx = x1; // fix last x + + // Update last position in RLE entries: + if (last_addr != 0L) { + // Fix x0: + rowAAx0[cy] = cx; // inclusive + // Fix position: + rowAAPos[cy] = (last_addr - addr_row); } - // adjust runLen: - runLen = rx1 - rx0; + } + } - // ensure rx1 > rx0: - if (runLen > 0) { - val = (byte)(packed & 0xFF); // [0..255] + // fill line end + while (cx < x1) { + tile[idx++] = 0; + cx++; + } - do { - tile[idx++] = val; - } while (--runLen > 0); + 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: - // 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] + + 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++; - } + // 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)); + if (DO_TRACE) { + for (int i = idx - (x1 - x0); i < idx; i++) { + System.out.print(hex(tile[i], 2)); + } + System.out.println(); } - System.out.println(); - } - idx += skipRowPixels; + 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 5645e706b2..50b6475b8a 100644 --- a/src/share/classes/sun/java2d/marlin/MarlinUtils.java +++ b/src/share/classes/sun/java2d/marlin/MarlinUtils.java @@ -28,11 +28,13 @@ package sun.java2d.marlin; 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 final class MarlinUtils { 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 77b216b390..a1531af581 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 @@ final class OffHeapArray { // 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 @@ final class OffHeapArray { 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 @@ final class OffHeapArray { 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 @@ final class OffHeapArray { // 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 0000000000..3052725b21 --- /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 f8a9c7151e..bd7769b979 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { // 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; + + // 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 = 8 * error in subpixels - // pisces: 20 / 8 - // openjfx pisces: 8 / 3.2 - // multiply by 8 = error scale factor: + // 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { // 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { // 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { // 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { } } - 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { // 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; + // float 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.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_dec.add(count); + rdrCtx.stats.stat_rdr_curveBreak_inc.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. - - // 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; + // 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; + count <<= 1; if (DO_STATS) { - rdrCtx.stats.stat_rdr_curveBreak_inc.add(count); + rdrCtx.stats.stat_rdr_curveBreak_dec.add(count); } } - if (--count > 0) { - x1 += dx; - dx += ddx; - ddx += dddx; - y1 += dy; - dy += ddy; - ddy += dddy; - } else { - x1 = x3; - y1 = y3; + 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { 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 class Renderer implements PathConsumer2D, MarlinConst { 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { // 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { // 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { // 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { // 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { // 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.curve = rdrCtx.curve; + this.cache = rdrCtx.cache; - this.edges = new OffHeapArray(rdrCtx.cleanerObj, INITIAL_EDGES_CAPACITY); // 96K + this.edges = rdrCtx.newOffHeapArray(INITIAL_EDGES_CAPACITY); // 96K - this.curve = rdrCtx.curve; + edgeBuckets_ref = rdrCtx.newCleanIntArrayRef(INITIAL_BUCKET_ARRAY); // 64K + edgeBucketCounts_ref = rdrCtx.newCleanIntArrayRef(INITIAL_BUCKET_ARRAY); // 64K - edgeBuckets = edgeBuckets_initial; - edgeBucketCounts = edgeBucketCounts_initial; + edgeBuckets = edgeBuckets_ref.initial; + edgeBucketCounts = edgeBucketCounts_ref.initial; - alphaLine = alphaLine_initial; + // 4096 pixels large + alphaLine_ref = rdrCtx.newCleanIntArrayRef(INITIAL_AA_ARRAY); // 16K + alphaLine = alphaLine_ref.initial; - this.cache = rdrCtx.cache; + 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 - // ScanLine: - crossings = crossings_initial; - aux_crossings = aux_crossings_initial; - edgePtrs = edgePtrs_initial; - aux_edgePtrs = aux_edgePtrs_initial; + crossings = crossings_ref.initial; + aux_crossings = aux_crossings_ref.initial; + edgePtrs = edgePtrs_ref.initial; + aux_edgePtrs = aux_edgePtrs_ref.initial; - edgeCount = 0; - activeEdgeMaxUsed = 0; + 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { activeEdgeMaxUsed = 0; edges.used = 0; - edgeSumDeltaY = 0; - return this; // fluent API } @@ -595,41 +617,19 @@ final class Renderer implements PathConsumer2D, MarlinConst { 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { } @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 @@ final class Renderer implements PathConsumer2D, MarlinConst { } @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 @@ final class Renderer implements PathConsumer2D, MarlinConst { @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 @@ final class Renderer implements PathConsumer2D, MarlinConst { 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { // 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { */ 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { // 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { _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 @@ final class Renderer implements PathConsumer2D, MarlinConst { } } 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { // 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { _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 @@ final class Renderer implements PathConsumer2D, MarlinConst { } 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { // 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { // 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { 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 class Renderer implements PathConsumer2D, MarlinConst { 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { // 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { // 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { } } - 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 @@ final class Renderer implements PathConsumer2D, MarlinConst { } 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 a11a1e829d..2a63e9f237 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.awt.geom.Path2D; 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 @@ final class RendererContext extends ReentrantContext implements MarlinConst { * @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 class RendererContext extends ReentrantContext implements MarlinConst { 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 @@ final class RendererContext extends ReentrantContext implements MarlinConst { 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 @@ final class RendererContext extends ReentrantContext implements MarlinConst { * 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 @@ final class RendererContext extends ReentrantContext implements MarlinConst { } } - // 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); - } - - holder = new ArrayCachesHolder(); - - if (USE_CACHE_HARD_REF) { - // update hard reference: - hardRefArrayCaches = holder; - } else { - // update weak reference: - refArrayCaches = new WeakReference<ArrayCachesHolder>(holder); - } - } - } - return holder; - } - - // dirty byte array cache - ByteArrayCache getDirtyByteArrayCache(final int length) { - final int bucket = ArrayCache.getBucketDirtyBytes(length); - return getArrayCachesHolder().dirtyByteArrayCaches[bucket]; - } - - byte[] getDirtyByteArray(final int length) { - if (length <= MAX_DIRTY_BYTE_ARRAY_SIZE) { - return getDirtyByteArrayCache(length).getArray(); - } - - if (DO_STATS) { - incOversize(); - } - - if (DO_LOG_OVERSIZE) { - logInfo("getDirtyByteArray[oversize]: length=\t" + length); - } - - return new byte[length]; - } - - 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); - } - } - - 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; - } - - // int array cache - IntArrayCache getIntArrayCache(final int length) { - final int bucket = ArrayCache.getBucket(length); - return getArrayCachesHolder().intArrayCaches[bucket]; - } - - 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)); + Path2D.Float getPath2D() { + // resolve reference: + Path2D.Float p2d = (refPath2D != null) ? refPath2D.get() : null; - System.arraycopy(in, 0, res, 0, usedSize); // copy only used elements + // create a new Path2D ? + if (p2d == null) { + p2d = new Path2D.Float(WIND_NON_ZERO, INITIAL_EDGES_COUNT); // 32K - // 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); + // update weak reference: + refPath2D = new WeakReference<Path2D.Float>(p2d); } + // reset the path anyway: + p2d.reset(); + return p2d; } - // dirty int array cache - IntArrayCache getDirtyIntArrayCache(final int length) { - final int bucket = ArrayCache.getBucket(length); - return getArrayCachesHolder().dirtyIntArrayCaches[bucket]; + @Override + public RendererStats stats() { + return stats; } - int[] getDirtyIntArray(final int length) { - if (length <= MAX_ARRAY_SIZE) { - return getDirtyIntArrayCache(length).getArray(); - } - + @Override + public OffHeapArray newOffHeapArray(final long initialSize) { if (DO_STATS) { - incOversize(); + stats.totalOffHeapInitial += initialSize; } - - if (DO_LOG_OVERSIZE) { - logInfo("getDirtyIntArray[oversize]: length=\t" + length); - } - - return new int[length]; + return new OffHeapArray(cleanerObj, initialSize); } - 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; + @Override + public IntArrayCache.Reference newCleanIntArrayRef(final int initialSize) { + return cleanIntCache.createRef(initialSize); } - 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); - } + IntArrayCache.Reference newDirtyIntArrayRef(final int initialSize) { + return dirtyIntCache.createRef(initialSize); } - // dirty float array cache - FloatArrayCache getDirtyFloatArrayCache(final int length) { - final int bucket = ArrayCache.getBucket(length); - return getArrayCachesHolder().dirtyFloatArrayCaches[bucket]; + FloatArrayCache.Reference newDirtyFloatArrayRef(final int initialSize) { + return dirtyFloatCache.createRef(initialSize); } - 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 9c2fa7334a..66a9eb1c1f 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 @@ public final class RendererStats implements MarlinConst { = 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 @@ public final class RendererStats implements MarlinConst { = 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 @@ public final class RendererStats implements MarlinConst { = 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 @@ public final class RendererStats implements MarlinConst { = 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 @@ public final class RendererStats implements MarlinConst { = 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 @@ public final class RendererStats implements MarlinConst { 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 @@ public final class RendererStats implements MarlinConst { 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 @@ public final class RendererStats implements MarlinConst { 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 @@ public final class RendererStats implements MarlinConst { 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; + } - logInfo("Dirty Array caches for thread: " + rdrCtx.name); + 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>() { - for (IntArrayCache cache : holder.dirtyIntArrayCaches) { - cache.dumpStats(); + @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; } - for (FloatArrayCache cache : holder.dirtyFloatArrayCaches) { - cache.dumpStats(); + }); + + // Mimics Java2D Disposer: + 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 RendererStatsDisposer(), + "MarlinRenderer Disposer"); + t.setContextClassLoader(null); + t.setDaemon(true); + t.setPriority(Thread.MAX_PRIORITY - 2); + t.start(); + return null; } - 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 f25993b29e..2d67ef1dc6 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 @@ final class Stroker implements PathConsumer2D, MarlinConst { 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; - - /** - * 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; + // 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; - // 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; + // kappa = (4/3) * (SQRT(2) - 1) + private static final float C = (float)(4.0d * (Math.sqrt(2.0d) - 1.0d) / 3.0d); - 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 @@ final class Stroker implements PathConsumer2D, MarlinConst { 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 @@ final class Stroker implements PathConsumer2D, MarlinConst { // 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 @@ final class Stroker implements PathConsumer2D, MarlinConst { 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 @@ final class Stroker implements PathConsumer2D, MarlinConst { * <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 @@ final class Stroker implements PathConsumer2D, MarlinConst { 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 class Stroker implements PathConsumer2D, MarlinConst { 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 @@ final class Stroker implements PathConsumer2D, MarlinConst { 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 @@ final class Stroker implements PathConsumer2D, MarlinConst { 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 @@ final class Stroker implements PathConsumer2D, MarlinConst { // 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 @@ final class Stroker implements PathConsumer2D, MarlinConst { // 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 @@ final class Stroker implements PathConsumer2D, MarlinConst { // 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 @@ final class Stroker implements PathConsumer2D, MarlinConst { 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 @@ final class Stroker implements PathConsumer2D, MarlinConst { 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 @@ final class Stroker implements PathConsumer2D, MarlinConst { } @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; + } + } + + 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; } - this.sx0 = this.cx0 = x0; - this.sy0 = this.cy0 = y0; - this.cdx = this.sdx = 1f; - this.cdy = this.sdy = 0f; - this.prev = MOVE_TO; } @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 @@ final class Stroker implements PathConsumer2D, MarlinConst { 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); + drawJoin(cdx, cdy, cx0, cy0, sdx, sdy, cmx, cmy, smx, smy, sOutCode); - emitLineTo(sx0 + smx, sy0 + smy); + emitLineTo(sx0 + smx, sy0 + smy); - emitMoveTo(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; - emitClose(); + + if (opened) { + // do not emit close + opened = false; + } else { + emitClose(); + } } private void emitReverse() { @@ -484,7 +663,7 @@ final class Stroker implements PathConsumer2D, MarlinConst { @Override public void pathDone() { if (prev == DRAWING_OP_TO) { - finish(); + finish(cOutCode); } out.pathDone(); @@ -497,23 +676,39 @@ final class Stroker implements PathConsumer2D, MarlinConst { 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); - } - - 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); + 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(); } @@ -585,23 +780,25 @@ final class Stroker implements PathConsumer2D, MarlinConst { 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 @@ final class Stroker implements PathConsumer2D, MarlinConst { 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 @@ final class Stroker implements PathConsumer2D, MarlinConst { 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 @@ final class Stroker implements PathConsumer2D, MarlinConst { // 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 @@ final class Stroker implements PathConsumer2D, MarlinConst { 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 @@ final class Stroker implements PathConsumer2D, MarlinConst { // 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 @@ final class Stroker implements PathConsumer2D, MarlinConst { 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 @@ final class Stroker implements PathConsumer2D, MarlinConst { 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 @@ final class Stroker implements PathConsumer2D, MarlinConst { 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 class Stroker implements PathConsumer2D, MarlinConst { final float dx1 = x2 - x1; final float dy1 = y2 - y1; - // this computes the offsets at t = 0, 1 - 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 = 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; - return 6; - } + // 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. - private static boolean isFinite(float x) { - return (Float.NEGATIVE_INFINITY < x && x < Float.POSITIVE_INFINITY); - } + // 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 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 (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]; - } - } - } - 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; + if (p1eqp2 || p2eqp3) { + getLineOffsets(x1, y1, x3, y3, leftOff, rightOff); + return 4; } - 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); + // 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; - int nSplits = findSubdivPoints(curve, middle, subdivTs, type, lineWidth2); + if (Helpers.within(dotsq, l1sq * l3sq, 4.0f * Math.ulp(dotsq))) { + getLineOffsets(x1, y1, x3, y3, leftOff, rightOff); + return 4; + } - int kind = 0; - BreakPtrIterator it = curve.breakPtsAtTs(middle, type, subdivTs, nSplits); - while(it.hasNext()) { - int curCurveOff = it.next(); + // 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); - 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); - } + 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; - 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; + 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; } -****************************** 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) + @Override + public void curveTo(final float x1, final float y1, + final float x2, final float y2, + final float x3, final float y3) { - 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: + 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; + _moveTo(x3, y3, outcode0); + opened = true; + return; + } } - } 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); + this.cOutCode = outcode3; } - - // 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]; - - 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]; + float dxs = x1 - cx0; + float dys = y1 - cy0; + float dxf = x3 - x2; + float dyf = y3 - y2; + + 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]); - - int nSplits = findSubdivPoints(curve, mid, subdivTs, 8, lineWidth2); + drawJoin(cdx, cdy, cx0, cy0, dxs, dys, cmx, cmy, offset0[0], offset0[1], outcode0); + 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 @@ final class Stroker implements PathConsumer2D, MarlinConst { 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; - - mid[0] = cx0; mid[1] = cy0; - mid[2] = x1; mid[3] = y1; - mid[4] = x2; mid[5] = y2; + @Override + 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; + _moveTo(x2, y2, outcode0); + opened = true; + return; + } + } - // inlined version of somethingTo(8); - // See the TODO on somethingTo + this.cOutCode = outcode2; + } + _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 - 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]; + 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 == 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]); - - int nSplits = findSubdivPoints(curve, mid, subdivTs, 6, lineWidth2); + drawJoin(cdx, cdy, cx0, cy0, dxs, dys, cmx, cmy, offset0[0], offset0[1], outcode0); + 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 @@ final class Stroker implements PathConsumer2D, MarlinConst { 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 db8f8dd639..06500f87b9 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 @@ package sun.java2d.marlin; 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 Path2DWrapper wp_Path2DWrapper = new Path2DWrapper(); + private final RendererContext rdrCtx; - PathConsumer2D wrapPath2d(Path2D.Float p2d) - { - return wp_Path2DWrapper.init(p2d); - } + // 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(); // 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 @@ final class TransformingPathConsumer2D { 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 @@ final class TransformingPathConsumer2D { } } - static final class DeltaScaleFilter implements PathConsumer2D { private PathConsumer2D out; private float sx, sy; @@ -275,4 +402,777 @@ final class TransformingPathConsumer2D { 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 dc0a925597..b2b43be52d 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 @@ package sun.java2d.marlin; 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 dcb3c8b05c..76886029a5 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 50f906f708..9aca2a420b 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 @@ public class StatLong { @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 546246ca65..612e0c0902 100644 --- a/src/share/classes/sun/java2d/opengl/OGLTextRenderer.java +++ b/src/share/classes/sun/java2d/opengl/OGLTextRenderer.java @@ -71,12 +71,13 @@ class OGLTextRenderer extends BufferedTextPipe { 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 239d134fca..2a796b9111 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 @@ import sun.java2d.SunGraphics2D; * 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(); + + // 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(); + } + }; - CompositePipe outpipe; + 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 @@ public class AAShapePipe 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 @@ public class AAShapePipe 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 @@ public class AAShapePipe 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; - } - - // 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; + final TileState ts = TILE_STATE_PROVIDER.acquire(); + try { + final int[] abox = ts.abox; - private synchronized static byte[] getAlphaTile(int len) { - byte[] t = theTile; - if (t == null || t.length < len) { - t = new byte[len]; - } else { - theTile = null; + 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); } - 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); - - 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 boolean thin = (sg.strokeState <= SunGraphics2D.STROKE_THINDASHED); - renderTiles(sg, s, aatg, abox); + 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); + } } 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); + + for (int x = x0; x < x1; x += tw) { + final int w = Math.min(tw, x1 - x); + + final int a = aatg.getTypicalAlpha(); - int a = aatg.getTypicalAlpha(); - if (a == 0x00 || - outpipe.needTile(context, x, y, w, h) == false) - { + if (a == 0x00 || !outpipe.needTile(context, x, y, w, h)) { aatg.nextTile(); outpipe.skipTile(context, x, y); continue; @@ -198,8 +198,7 @@ public class AAShapePipe 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 @@ public class AAShapePipe 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 4abaebbf4e..baa8b8f0e4 100644 --- a/src/share/classes/sun/swing/SwingUtilities2.java +++ b/src/share/classes/sun/swing/SwingUtilities2.java @@ -140,9 +140,7 @@ public class SwingUtilities2 { 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 @@ public class SwingUtilities2 { 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 f34dd6c11c..36c87601aa 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 @@ public class TCChartReporter { 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 16414efac1..a8a4a7589c 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 @@ extern "C" { #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 @@ J2dTraceInit(); 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 6a70d404f8..cbd0ee8e71 100644 --- a/src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.c +++ b/src/share/native/sun/java2d/loops/GraphicsPrimitiveMgr.c @@ -75,6 +75,7 @@ jfieldID path2DWindingRuleID; jfieldID path2DFloatCoordsID; jfieldID sg2dStrokeHintID; jint sunHints_INTVAL_STROKE_PURE; +jint graphicsPrimitive_traceflags = 0; /* * Class: sun_java2d_loops_GraphicsPrimitiveMgr @@ -148,6 +149,13 @@ Java_sun_java2d_loops_GraphicsPrimitiveMgr_initIDs 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 6c674612f0..0249dae346 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 path2DWindingRuleID; 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 427c91da2b..51fdf281ee 100644 --- a/src/share/native/sun/java2d/opengl/OGLFuncs.h +++ b/src/share/native/sun/java2d/opengl/OGLFuncs.h @@ -131,6 +131,7 @@ typedef void (GLAPIENTRY *glViewportType)(GLint x, GLint y, GLsizei width, GLsiz * 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 @@ typedef void (GLAPIENTRY *glTextureBarrierNVType) (void); #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 186bab81aa..75681fe49b 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 @@ OGLTR_AddToGlyphCache(GlyphInfo *glyph, GLenum pixelFormat) 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 @@ OGLTR_UpdateCachedDestination(OGLSDOps *dstOps, GlyphInfo *ginfo, } 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 @@ OGLTR_DrawLCDGlyphViaCache(OGLContext *oglc, OGLSDOps *dstOps, } 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 @@ OGLTR_DrawLCDGlyphViaCache(OGLContext *oglc, OGLSDOps *dstOps, 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 @@ OGLTR_DrawLCDGlyphViaCache(OGLContext *oglc, OGLSDOps *dstOps, } // 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 @@ OGLTR_DrawGlyphList(JNIEnv *env, OGLContext *oglc, OGLSDOps *dstOps, { 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 @@ OGLTR_DrawGlyphList(JNIEnv *env, OGLContext *oglc, OGLSDOps *dstOps, } 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 @@ OGLTR_DrawGlyphList(JNIEnv *env, OGLContext *oglc, OGLSDOps *dstOps, 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 @@ OGLTR_DrawGlyphList(JNIEnv *env, OGLContext *oglc, OGLSDOps *dstOps, } } - // 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 @@ OGLTR_DrawGlyphList(JNIEnv *env, OGLContext *oglc, OGLSDOps *dstOps, 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 cd2d60c3a0..53c9a8a652 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 @@ typedef struct _J2DVertex { 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 @@ static jint maskCacheIndex = 0; 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 @@ OGLVertexCache_AddGlyphQuad(OGLContext *oglc, 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 ef418939cf..5572daa743 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 @@ void OGLVertexCache_AddGlyphQuad(OGLContext *oglc, 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 1cea1ee1fe..2648f1a073 100644 --- a/src/solaris/classes/sun/awt/X11/XBaseWindow.java +++ b/src/solaris/classes/sun/awt/X11/XBaseWindow.java @@ -586,7 +586,11 @@ public class XBaseWindow { 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 d85781b2dd..12fad951b1 100644 --- a/src/solaris/classes/sun/awt/X11/XWindowPeer.java +++ b/src/solaris/classes/sun/awt/X11/XWindowPeer.java @@ -1398,7 +1398,11 @@ class XWindowPeer extends XPanelPeer implements WindowPeer, */ 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 @@ class XWindowPeer extends XPanelPeer implements WindowPeer, 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 1b8bd5237d..74fae227cc 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 @@ typedef enum _DPI_AWARENESS { 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 @@ typedef AwtObject* PDATA; #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 f8dc397b64..0c0592b06e 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 @@ void AwtComponent::OpenCandidateWindow(int x, int y) ::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::WmImeSetContext(BOOL fSet, LPARAM *lplParam) 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 @@ HWND AwtComponent::GetProxyFocusOwner() 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 5dd1bcccbe..bf539dcda0 100644 --- a/test/java/awt/hidpi/ClientAreaOriginWindowsTest.java +++ b/test/java/awt/hidpi/ClientAreaOriginWindowsTest.java @@ -43,16 +43,15 @@ import java.util.function.Function; * 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 @@ public class ClientAreaOriginWindowsTest { 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 0000000000..1949ec270a --- /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 0000000000..bf2721c884 --- /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 2ef3224df1..a64030645f 100644 --- a/test/jb/javax/swing/JDialog/JDialog392.java +++ b/test/jb/javax/swing/JDialog/JDialog392.java @@ -156,7 +156,7 @@ public class JDialog392 implements Runnable { 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 0000000000..9a606ea3c0 --- /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 0000000000..f17d8bea09 --- /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 0000000000..a053ed5782 --- /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 43447f14fb..aa088ac311 100755 --- a/test/jb/sun/lwawt/macosx/LWCToolkit/lwctoolkit.sh +++ b/test/jb/sun/lwawt/macosx/LWCToolkit/lwctoolkit.sh @@ -66,10 +66,19 @@ echo "Running workload" ${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 0451e7920f..d4d83d3a92 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 - -# https://bugs.openjdk.java.net/browse/JDK-8140329 -java/awt/SplashScreen/FullscreenAfterSplash/FullScreenAfterSplash.java 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 +#java/awt/ScrollPane/ScrollPanePreferredSize/ScrollPanePreferredSize.java generic-all +#java/awt/ScrollPane/bug8077409Test.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 -# 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 - -# https://bugs.openjdk.java.net/browse/JDK-8198739 -ava/awt/Window/AlwaysOnTop/SyncAlwaysOnTopFieldTest.java windows-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/Window/AlwaysOnTop/AlwaysOnTopFieldTest.java 7081594 macosx-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 + +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 - -# 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/geom/AffineTransform/InvalidTransformParameterTest.java 8158356 generic-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/ImagePrinting/NullClipARGB.java generic-all 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 - -# https://bugs.openjdk.java.net/browse/JDK-8072130 -java/lang/instrument/BootClassPath/BootClassPathTest.sh macosx-all +java/lang/StringBuilder/HugeCapacity.java generic-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 @@ com/sun/management/DiagnosticCommandMBean/DcmdMBeanPermissionsTest.java generic- # 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 - -# 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 - -# 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 +com/sun/security/auth/callback/TextCallbackHandler/Password.java generic-all +com/sun/security/auth/callback/TextCallbackHandler/Default.java generic-all -# 8026393 -sun/security/tools/jarsigner/warnings/BadKeyUsageTest.java generic-all +sun/security/rsa/SpecTest.java 8075565 macosx-all -# 8158827 -sun/security/krb5/auto/tools/KinitConfPlusProps.java windows-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 + +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 - -# 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/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 + +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 @@ javax/swing/JTextArea/4697612/bug4697612.java linux-all # 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 @@ tools/launcher/MultipleJRE.sh windows_all # 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 - -## 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 +java/util/AbstractList/CheckForComodification.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 @@ sun/tools/jstatd/TestJstatdExternalRegistry.java generic-all # 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 - -# 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 +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-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 - -# https://bugs.openjdk.java.net/browse/JDK-8171303 -sun/java2d/pipe/InterpolationQualityTest.java generic-all - -# https://bugs.openjdk.java.net/browse/JDK-8058767 -sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java windows-all - -# https://bugs.openjdk.java.net/browse/JDK-8046046 -sun/security/pkcs11/Signature/TestDSAKeyLength.java 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/java2d/X11SurfaceData/SharedMemoryPixmapsTest/SharedMemoryPixmapsTest.sh 7184899 generic-all + +sun/java2d/pipe/InterpolationQualityTest.java 8171303 windows-all,linux-all,macosx-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 + +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 + +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 - -# https://bugs.openjdk.java.net/browse/JDK-8173145 -com/sun/java/swing/plaf/windows/Test8173145.java windows-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 + +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 - -# https://bugs.openjdk.java.net/browse/JDK-8146858 -sun/security/mscapi/PublicKeyInterop.sh windows-all - -# https://bugs.openjdk.java.net/browse/JDK-8023546 -sun/security/mscapi/ShortRSAKey1024.sh windows-all - -# https://bugs.openjdk.java.net/browse/JDK-8144559 -sun/security/mscapi/SignUsingNONEwithRSA.sh windows-all -sun/security/mscapi/SignUsingSHA2withRSA.sh windows-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 - -# https://bugs.openjdk.java.net/browse/JDK-6822627 -com/sun/jdi/ConstantPoolInfoGC.java generic-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/security/mscapi/nonUniqueAliases/NonUniqueAliases.sh generic-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 + +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 + +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 + +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 + +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 + +sun/tools/native2ascii/Native2AsciiTests.sh JRE-738 windows-all
\ No newline at end of file |